fix: 修复Windows打包后WebUI无法加载HTML页面及TUI配置持久化问题
This commit is contained in:
@ -21,6 +21,17 @@ from core.activity_recorder import get_recorder
|
||||
from core.embedded_db import EmbeddedGraphDB
|
||||
|
||||
|
||||
def get_resource_path(relative_path):
|
||||
"""获取资源文件的绝对路径,兼容开发环境和PyInstaller打包环境"""
|
||||
if hasattr(sys, 'frozen'):
|
||||
# PyInstaller打包后的环境
|
||||
base_path = sys._MEIPASS
|
||||
else:
|
||||
# 开发环境
|
||||
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
return os.path.join(base_path, relative_path)
|
||||
|
||||
|
||||
# 登录安全限制
|
||||
LOGIN_MAX_ATTEMPTS = 5 # 最大尝试次数
|
||||
LOGIN_WAIT_MINUTES = 5 # 超过次数后等待分钟数
|
||||
@ -142,7 +153,7 @@ def save_web_config(updates: dict) -> bool:
|
||||
|
||||
WEB_CONFIG = load_web_config()
|
||||
|
||||
_ui_dir = os.path.join(os.path.dirname(__file__), '..', 'ui')
|
||||
_ui_dir = get_resource_path('ui')
|
||||
app = Flask(__name__, static_folder=os.path.join(_ui_dir, 'static'), static_url_path='', template_folder=os.path.join(_ui_dir, 'templates'))
|
||||
app.secret_key = WEB_CONFIG.get("SECRET_KEY", "trulymem-secret-key-2026")
|
||||
app.permanent_session_lifetime = timedelta(days=7)
|
||||
|
||||
46
ui/app.py
46
ui/app.py
@ -51,6 +51,9 @@ class GraphMemoryApp(App):
|
||||
initial_config.api_key = api_config.get("api_key", "")
|
||||
initial_config.base_url = api_config.get("base_url", "https://api.deepseek.com")
|
||||
initial_config.model = api_config.get("model", "deepseek-v4-flash")
|
||||
initial_config.enable_web = api_config.get("enable_web", False)
|
||||
initial_config.web_port = api_config.get("web_port", 4096)
|
||||
initial_config.enable_tui = api_config.get("enable_tui", True)
|
||||
|
||||
tool_limits = settings_data.get("tool_limits", {})
|
||||
initial_config.persona_update_max = tool_limits.get("persona_update_max", 1)
|
||||
@ -145,6 +148,23 @@ class GraphMemoryApp(App):
|
||||
welcome = Message(role="assistant", content=welcome_msg)
|
||||
history.add_message(welcome)
|
||||
|
||||
# 自动启动Web服务(如果配置中启用了)
|
||||
if self._backend_client:
|
||||
settings_result = self._backend_client.get_settings()
|
||||
settings_data = settings_result.get("data", {})
|
||||
api_config = settings_data.get("api_config", {})
|
||||
enable_web = api_config.get("enable_web", False)
|
||||
web_port = api_config.get("web_port", 4096)
|
||||
|
||||
# 更新状态栏的Web服务状态
|
||||
try:
|
||||
status_bar.set_web_status(self._web_running, web_port if self._web_running else 0)
|
||||
except:
|
||||
pass
|
||||
|
||||
if enable_web:
|
||||
self._start_web_server(web_port)
|
||||
|
||||
def _start_web_server(self, port: int = 4096) -> None:
|
||||
"""在当前进程通过线程启动 Web 服务(无需子进程)"""
|
||||
if self._web_running:
|
||||
@ -153,10 +173,20 @@ class GraphMemoryApp(App):
|
||||
|
||||
try:
|
||||
from web_api import run_web_server
|
||||
from .widgets.status_bar import StatusBar
|
||||
|
||||
run_web_server(port=port)
|
||||
self._web_running = True
|
||||
if self._backend_client:
|
||||
self._backend_client.report_web_status(True, port)
|
||||
|
||||
# 更新状态栏
|
||||
try:
|
||||
status_bar = self.query_one(StatusBar)
|
||||
status_bar.set_web_status(True, port)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.notify(f"Web 服务已启动 → http://0.0.0.0:{port}", title="Web 服务")
|
||||
except Exception as e:
|
||||
self.notify(f"启动 Web 服务失败: {e}", severity="error")
|
||||
@ -166,12 +196,22 @@ class GraphMemoryApp(App):
|
||||
if self._web_running:
|
||||
try:
|
||||
from web_api import stop_web_server
|
||||
from .widgets.status_bar import StatusBar
|
||||
|
||||
stop_web_server()
|
||||
except Exception:
|
||||
pass
|
||||
self._web_running = False
|
||||
if self._backend_client:
|
||||
self._backend_client.report_web_status(False, 0)
|
||||
|
||||
# 更新状态栏
|
||||
try:
|
||||
status_bar = self.query_one(StatusBar)
|
||||
status_bar.set_web_status(False)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.notify("Web 服务已停止", title="Web 服务")
|
||||
|
||||
def on_unmount(self) -> None:
|
||||
@ -371,6 +411,12 @@ class GraphMemoryApp(App):
|
||||
else:
|
||||
self._stop_web_server()
|
||||
|
||||
# 更新状态栏的Web服务状态
|
||||
try:
|
||||
status_bar.set_web_status(self._web_running, config.web_port if self._web_running else 0)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.notify("✅ 配置已保存并生效", title="配置成功", severity="information")
|
||||
else:
|
||||
error = result.get("error", "未知错误")
|
||||
|
||||
@ -18,6 +18,7 @@ class StatusBar(Static):
|
||||
self._shortcuts = "F1:帮助 F2:侧边栏 F3:工具详情 F5:清屏 F6:退出"
|
||||
self._license_info = "本项目由jianf设计,以GPLv3形式开源"
|
||||
self._api_status = "未配置"
|
||||
self._web_status = "未启动"
|
||||
self._processing = False
|
||||
|
||||
def on_mount(self) -> None:
|
||||
@ -27,8 +28,9 @@ class StatusBar(Static):
|
||||
def _update_display(self) -> None:
|
||||
"""更新显示"""
|
||||
status_icon = "●" if self._api_status == "已配置" else "○"
|
||||
web_icon = "●" if self._web_status != "未启动" else "○"
|
||||
processing_indicator = " [处理中...]" if self._processing else ""
|
||||
self.update(f"{status_icon} API: {self._api_status}{processing_indicator} | {self._license_info} | {self._shortcuts}")
|
||||
self.update(f"{status_icon} API: {self._api_status} | {web_icon} Web: {self._web_status}{processing_indicator} | {self._license_info} | {self._shortcuts}")
|
||||
|
||||
def set_api_status(self, configured: bool) -> None:
|
||||
"""设置API状态"""
|
||||
@ -39,3 +41,11 @@ class StatusBar(Static):
|
||||
"""设置处理状态"""
|
||||
self._processing = processing
|
||||
self._update_display()
|
||||
|
||||
def set_web_status(self, running: bool, port: int = 0) -> None:
|
||||
"""设置Web服务状态"""
|
||||
if running:
|
||||
self._web_status = f"运行中(:{port})"
|
||||
else:
|
||||
self._web_status = "未启动"
|
||||
self._update_display()
|
||||
|
||||
Reference in New Issue
Block a user