Merge remote-tracking branch 'origin/test'

This commit is contained in:
root
2026-04-29 08:34:34 +08:00
4 changed files with 126 additions and 19 deletions

View File

@ -469,10 +469,15 @@ class BackendServer:
base_url = api_config.get("base_url", self._config.get("base_url", "https://api.deepseek.com")) base_url = api_config.get("base_url", self._config.get("base_url", "https://api.deepseek.com"))
model = api_config.get("model", self._config.get("model", "deepseek-v4-flash")) model = api_config.get("model", self._config.get("model", "deepseek-v4-flash"))
self.update_config(api_key, base_url, model) self.update_config(api_key, base_url, model)
# 通用配置字段(如 message_timeout # 通用配置字段(如 message_timeout, enable_web, enable_tui, web_port
for key in ["message_timeout"]: for key in ["message_timeout", "enable_web", "enable_tui", "web_port"]:
if key in api_config: if key in api_config:
self._config[key] = int(api_config[key]) if key == "web_port":
self._config[key] = int(api_config[key])
elif key in ["enable_web", "enable_tui"]:
self._config[key] = bool(api_config[key])
else:
self._config[key] = int(api_config[key])
limits_keys = [ limits_keys = [
"persona_update_max", "persona_update_max",

View File

@ -69,8 +69,9 @@ class GraphMemoryApp(App):
from core.migrate import need_migration, is_migrated from core.migrate import need_migration, is_migrated
# 检查是否需要登录 # 检查是否需要登录
migrated = is_migrated() # 如果已迁移,需要登录验证用户
need_login = migrated or not need_migration() # 如果需要迁移,显示迁移登录界面
need_login = is_migrated() or need_migration()
if need_login and not self.login_user: if need_login and not self.login_user:
# 显示登录界面 # 显示登录界面
@ -84,6 +85,10 @@ class GraphMemoryApp(App):
"""登录成功后调用""" """登录成功后调用"""
self.login_user = username self.login_user = username
self.login_user_info = user_info self.login_user_info = user_info
# 关闭登录界面
self.pop_screen()
# 更新 config section 的 admin 权限 # 更新 config section 的 admin 权限
from .widgets.config_section import ConfigSection from .widgets.config_section import ConfigSection
try: try:
@ -295,7 +300,10 @@ class GraphMemoryApp(App):
api_config = { api_config = {
"api_key": config.api_key, "api_key": config.api_key,
"base_url": config.base_url, "base_url": config.base_url,
"model": getattr(config, 'model', 'deepseek-v4-flash') "model": getattr(config, 'model', 'deepseek-v4-flash'),
"enable_web": getattr(config, 'enable_web', False),
"enable_tui": getattr(config, 'enable_tui', True),
"web_port": getattr(config, 'web_port', 4096),
} }
tool_limits = { tool_limits = {

View File

@ -61,6 +61,45 @@ ConfigSection Input {
color: $text; color: $text;
} }
ConfigSection Checkbox {
margin: 1 0;
}
/* Admin sections */
#admin-web-login-section,
#admin-web-service-section,
#admin-tui-service-section {
display: block;
}
/* Login Screen */
#login_container,
#migration_container {
width: 60;
height: auto;
padding: 2;
background: $surface;
border: solid $primary;
}
#login_title,
#migration_title {
color: $primary;
text-style: bold;
margin: 0 0 1 0;
}
#migration_subtitle {
color: $text-muted;
margin: 0 0 1 0;
}
#login_message,
#migration_message {
color: $warning;
margin: 1 0 0 0;
}
/* Other Components */ /* Other Components */
OperationLog { OperationLog {
background: $surface-darken-1; background: $surface-darken-1;

View File

@ -1,7 +1,7 @@
"""配置区组件""" """配置区组件"""
from textual.containers import Vertical from textual.containers import Vertical
from textual.widgets import Static, Input, Button from textual.widgets import Static, Input, Button, Checkbox
from textual.app import ComposeResult from textual.app import ComposeResult
from textual.message import Message from textual.message import Message
from ..models.config import AppConfig from ..models.config import AppConfig
@ -15,7 +15,7 @@ class ConfigSection(Vertical):
self.is_tool_limits = is_tool_limits self.is_tool_limits = is_tool_limits
super().__init__() super().__init__()
def __init__(self, config: AppConfig | None = None, is_admin: bool = True, **kwargs): def __init__(self, config: AppConfig | None = None, is_admin: bool = False, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self._config = config or AppConfig() self._config = config or AppConfig()
self._is_admin = is_admin self._is_admin = is_admin
@ -133,7 +133,6 @@ class ConfigSection(Vertical):
ws_hint.can_focus = False ws_hint.can_focus = False
yield ws_hint yield ws_hint
from textual.widgets import Checkbox
yield Checkbox( yield Checkbox(
"启用 Web 服务", "启用 Web 服务",
value=self._config.enable_web, value=self._config.enable_web,
@ -150,10 +149,30 @@ class ConfigSection(Vertical):
type="integer" type="integer"
) )
# 默认隐藏 admin 区域,等 login 后决定是否显示 sep4 = Static("", classes="config-sep")
self._apply_admin_visibility() sep4.can_focus = False
yield sep4
# TUI 服务控制 — 仅 admin 可见
with Vertical(id="admin-tui-service-section"):
tui_title = Static("━━ TUI 服务 ━━", classes="config-title")
tui_title.can_focus = False
yield tui_title
tui_hint = Static("控制终端文本界面是否允许连接", classes="config-hint")
tui_hint.can_focus = False
yield tui_hint
yield Checkbox(
"启用 TUI 服务",
value=self._config.enable_tui,
id="enable-tui-checkbox"
)
def on_mount(self) -> None: def on_mount(self) -> None:
# 应用管理员区域的可见性
self._apply_admin_visibility()
try: try:
api_key = self.query_one("#api-key-input", Input) api_key = self.query_one("#api-key-input", Input)
model = self.query_one("#model-input", Input) model = self.query_one("#model-input", Input)
@ -175,17 +194,30 @@ class ConfigSection(Vertical):
web_user.tab_index = 7 web_user.tab_index = 7
web_pwd.tab_index = 8 web_pwd.tab_index = 8
from textual.widgets import Checkbox
web_port = self.query_one("#web-port-input", Input) web_port = self.query_one("#web-port-input", Input)
try:
web_checkbox = self.query_one("#enable-web-checkbox", Checkbox)
except:
pass
web_port.tab_index = 9 web_port.tab_index = 9
except Exception: except Exception:
pass pass
def on_input_submitted(self, event: Input.Submitted) -> None: def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
"""处理复选框状态变化"""
try:
# Web 服务开关
if event.checkbox.id == "enable-web-checkbox":
self._update_config_from_ui()
# 发送配置更新消息
self.post_message(self.ConfigChanged(self._config, is_tool_limits=False))
# TUI 服务开关
elif event.checkbox.id == "enable-tui-checkbox":
self._update_config_from_ui()
# 发送配置更新消息
self.post_message(self.ConfigChanged(self._config, is_tool_limits=False))
except Exception:
pass
def _update_config_from_ui(self) -> None:
"""从UI组件更新配置对象"""
try: try:
api_key_input = self.query_one("#api-key-input", Input) api_key_input = self.query_one("#api-key-input", Input)
model_input = self.query_one("#model-input", Input) model_input = self.query_one("#model-input", Input)
@ -199,9 +231,15 @@ class ConfigSection(Vertical):
web_username = self.query_one("#web-username-input", Input) web_username = self.query_one("#web-username-input", Input)
web_password = self.query_one("#web-password-input", Input) web_password = self.query_one("#web-password-input", Input)
from textual.widgets import Checkbox
web_checkbox = self.query_one("#enable-web-checkbox", Checkbox) web_checkbox = self.query_one("#enable-web-checkbox", Checkbox)
web_port_input = self.query_one("#web-port-input", Input) web_port_input = self.query_one("#web-port-input", Input)
# TUI checkbox 可能不存在(非管理员)
tui_checkbox = None
try:
tui_checkbox = self.query_one("#enable-tui-checkbox", Checkbox)
except:
pass
self._config = AppConfig( self._config = AppConfig(
api_key=api_key_input.value, api_key=api_key_input.value,
@ -215,7 +253,14 @@ class ConfigSection(Vertical):
web_password=web_password.value, web_password=web_password.value,
enable_web=web_checkbox.value, enable_web=web_checkbox.value,
web_port=int(web_port_input.value) if web_port_input.value else 4096, web_port=int(web_port_input.value) if web_port_input.value else 4096,
enable_tui=tui_checkbox.value if tui_checkbox else True,
) )
except Exception:
pass
def on_input_submitted(self, event: Input.Submitted) -> None:
try:
self._update_config_from_ui()
# 先发送 API 配置更新is_tool_limits=False # 先发送 API 配置更新is_tool_limits=False
self.post_message(self.ConfigChanged(self._config, is_tool_limits=False)) self.post_message(self.ConfigChanged(self._config, is_tool_limits=False))
@ -241,6 +286,11 @@ class ConfigSection(Vertical):
service_section.styles.display = "block" if self._is_admin else "none" service_section.styles.display = "block" if self._is_admin else "none"
except Exception: except Exception:
pass pass
try:
tui_section = self.query_one("#admin-tui-service-section")
tui_section.styles.display = "block" if self._is_admin else "none"
except Exception:
pass
def get_config(self) -> AppConfig: def get_config(self) -> AppConfig:
return self._config return self._config
@ -264,11 +314,16 @@ class ConfigSection(Vertical):
self.query_one("#web-username-input", Input).value = config.web_username self.query_one("#web-username-input", Input).value = config.web_username
self.query_one("#web-password-input", Input).value = config.web_password self.query_one("#web-password-input", Input).value = config.web_password
from textual.widgets import Checkbox
try: try:
self.query_one("#enable-web-checkbox", Checkbox).value = config.enable_web self.query_one("#enable-web-checkbox", Checkbox).value = config.enable_web
except: except:
pass pass
self.query_one("#web-port-input", Input).value = str(config.web_port) self.query_one("#web-port-input", Input).value = str(config.web_port)
# TUI checkbox
try:
self.query_one("#enable-tui-checkbox", Checkbox).value = config.enable_tui
except:
pass
except Exception: except Exception:
pass pass