Repository navigation
Expand file tree
/
Copy pathdesktop.py
More file actions
97 lines (71 loc) · 2.82 KB
/
Copy pathdesktop.py
File metadata and controls
97 lines (71 loc) · 2.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""桌面版启动入口(pywebview)。"""
from __future__ import annotations
import logging
import os
import socket
import sys
import threading
import time
from contextlib import closing
import uvicorn
try:
import webview
except ModuleNotFoundError as exc:
missing_module_error = exc
webview = None
else:
missing_module_error = None
from src.app_meta import display_name
from webui import create_uvicorn_config, setup_application
logger = logging.getLogger(__name__)
def _is_port_open(host: str, port: int) -> bool:
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
sock.settimeout(0.3)
return sock.connect_ex((host, port)) == 0
def _find_available_port(host: str, preferred_port: int, max_attempts: int = 20) -> int:
for port in range(preferred_port, preferred_port + max_attempts):
if not _is_port_open(host, port):
return port
raise RuntimeError(f"无法为桌面版找到可用端口,起始端口: {preferred_port}")
def _wait_for_server(host: str, port: int, timeout: float = 15.0) -> None:
deadline = time.time() + timeout
while time.time() < deadline:
if _is_port_open(host, port):
return
time.sleep(0.2)
raise RuntimeError(f"本地服务启动超时: http://{host}:{port}")
def _build_server(host: str, port: int) -> uvicorn.Server:
settings = setup_application()
# 桌面模式强制使用本地回环地址,避免暴露到局域网。
os.environ["APP_HOST"] = host
os.environ["APP_PORT"] = str(port)
from src.config.settings import update_settings
from src.web.app import app
update_settings(webui_host=host, webui_port=port, debug=False)
config = uvicorn.Config(**create_uvicorn_config(settings, app=app, host=host, port=port, reload=False))
return uvicorn.Server(config)
def main():
if webview is None:
raise SystemExit(
"缺少依赖 pywebview,请先安装后再启动桌面版:\n"
" /usr/bin/pip3 install pywebview\n"
"或安装项目依赖后重试。"
) from missing_module_error
host = "127.0.0.1"
preferred_port = int(os.environ.get("APP_PORT", "8000"))
port = _find_available_port(host, preferred_port)
server = _build_server(host, port)
server_thread = threading.Thread(target=server.run, name="desktop-webui-server", daemon=True)
server_thread.start()
_wait_for_server(host, port)
window_title = os.environ.get("APP_WINDOW_TITLE", display_name())
url = f"http://{host}:{port}"
logger.info("桌面版已启动: %s", url)
try:
webview.create_window(window_title, url, width=1440, height=960, min_size=(1100, 720))
webview.start()
finally:
server.should_exit = True
server_thread.join(timeout=5)
if __name__ == "__main__":
main()