mirror of
https://gitcode.com/JianFeeeee/TrulyMEM-TrueHumanMEM.git
synced 2026-10-04 00:14:26 +00:00
docs: 重构为双语文档结构,添加人设图机制
- 拆分为 docs/(CN) 和 docs_en/(EN) 两个文件夹 - 主 README 索引对应语言文档 - 新增 persona.md (人设图机制详细说明) - 文件重命名为英文名
This commit is contained in:
58
ui/app.py
58
ui/app.py
@ -34,16 +34,23 @@ class GraphMemoryApp(App):
|
||||
from .widgets.status_bar import StatusBar
|
||||
from .models.config import AppConfig
|
||||
|
||||
initial_config = AppConfig()
|
||||
|
||||
if self._backend_client:
|
||||
result = self._backend_client.get_config()
|
||||
config_data = result.get("data", {})
|
||||
initial_config = AppConfig(
|
||||
api_key=config_data.get("api_key", ""),
|
||||
base_url=config_data.get("base_url", "https://api.deepseek.com"),
|
||||
model=config_data.get("model", "deepseek-chat")
|
||||
)
|
||||
else:
|
||||
initial_config = AppConfig()
|
||||
config_result = self._backend_client.get_config()
|
||||
config_data = config_result.get("data", {})
|
||||
initial_config.api_key = config_data.get("api_key", "")
|
||||
initial_config.base_url = config_data.get("base_url", "https://api.deepseek.com")
|
||||
initial_config.model = config_data.get("model", "deepseek-chat")
|
||||
|
||||
limits_result = self._backend_client.get_tool_limits()
|
||||
limits_data = limits_result.get("data", {})
|
||||
initial_config.persona_query_max = limits_data.get("persona_query_max", 1)
|
||||
initial_config.persona_update_max = limits_data.get("persona_update_max", 1)
|
||||
initial_config.task_query_max = limits_data.get("task_query_max", 4)
|
||||
initial_config.task_update_max = limits_data.get("task_update_max", 2)
|
||||
initial_config.memory_query_max = limits_data.get("memory_query_max", 20)
|
||||
initial_config.memory_update_max = limits_data.get("memory_update_max", 10)
|
||||
|
||||
yield LeftPanel()
|
||||
yield RightPanel(config=initial_config)
|
||||
@ -140,15 +147,16 @@ class GraphMemoryApp(App):
|
||||
status_bar.set_processing(False)
|
||||
|
||||
def on_config_section_config_changed(self, event) -> None:
|
||||
"""处理配置变更事件"""
|
||||
if not self._backend_client:
|
||||
self.notify("后端未初始化,无法保存配置", title="错误", severity="error")
|
||||
return
|
||||
|
||||
config = event.config
|
||||
|
||||
# 异步更新配置,避免阻塞UI
|
||||
asyncio.create_task(self._update_config_async(config))
|
||||
if event.is_tool_limits:
|
||||
asyncio.create_task(self._update_tool_limits_async(config))
|
||||
else:
|
||||
asyncio.create_task(self._update_config_async(config))
|
||||
|
||||
async def _update_config_async(self, config) -> None:
|
||||
"""异步更新配置"""
|
||||
@ -193,5 +201,31 @@ class GraphMemoryApp(App):
|
||||
else:
|
||||
error = result.get("error", "未知错误")
|
||||
self.notify(f"❌ 配置失败: {error}", title="配置失败", severity="error")
|
||||
except Exception as e:
|
||||
self.notify(f"❌ 配置异常: {str(e)}", title="配置失败", severity="error")
|
||||
|
||||
async def _update_tool_limits_async(self, config) -> None:
|
||||
from .widgets.status_bar import StatusBar
|
||||
|
||||
status_bar = self.query_one(StatusBar)
|
||||
|
||||
try:
|
||||
result = await asyncio.get_event_loop().run_in_executor(
|
||||
None,
|
||||
lambda: self._backend_client.update_tool_limits(
|
||||
persona_query_max=config.persona_query_max,
|
||||
persona_update_max=config.persona_update_max,
|
||||
task_query_max=config.task_query_max,
|
||||
task_update_max=config.task_update_max,
|
||||
memory_query_max=config.memory_query_max,
|
||||
memory_update_max=config.memory_update_max,
|
||||
)
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
self.notify("✅ 工具限制已保存", title="配置成功", severity="information")
|
||||
else:
|
||||
error = result.get("error", "未知错误")
|
||||
self.notify(f"❌ 配置失败: {error}", title="配置失败", severity="error")
|
||||
except Exception as e:
|
||||
self.notify(f"❌ 配置异常: {str(e)}", title="配置失败", severity="error")
|
||||
@ -13,19 +13,29 @@ class AppConfig:
|
||||
api_key: str = ""
|
||||
model: str = "deepseek-chat"
|
||||
base_url: str = "https://api.deepseek.com"
|
||||
persona_query_max: int = 1
|
||||
persona_update_max: int = 1
|
||||
task_query_max: int = 4
|
||||
task_update_max: int = 2
|
||||
memory_query_max: int = 20
|
||||
memory_update_max: int = 10
|
||||
|
||||
@classmethod
|
||||
def from_env(cls) -> "AppConfig":
|
||||
"""从环境变量加载配置"""
|
||||
return cls(
|
||||
api_key=os.getenv("DEEPSEEK_API_KEY", ""),
|
||||
model=os.getenv("MODEL_NAME", "deepseek-chat"),
|
||||
base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com"),
|
||||
persona_query_max=int(os.getenv("PERSONA_QUERY_MAX", 1)),
|
||||
persona_update_max=int(os.getenv("PERSONA_UPDATE_MAX", 1)),
|
||||
task_query_max=int(os.getenv("TASK_QUERY_MAX", 4)),
|
||||
task_update_max=int(os.getenv("TASK_UPDATE_MAX", 2)),
|
||||
memory_query_max=int(os.getenv("MEMORY_QUERY_MAX", 20)),
|
||||
memory_update_max=int(os.getenv("MEMORY_UPDATE_MAX", 10)),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, path: Path) -> "AppConfig":
|
||||
"""从文件加载配置"""
|
||||
if not path.exists():
|
||||
return cls()
|
||||
|
||||
@ -36,10 +46,15 @@ class AppConfig:
|
||||
api_key=data.get("api_key", ""),
|
||||
model=data.get("model", "deepseek-chat"),
|
||||
base_url=data.get("base_url", "https://api.deepseek.com"),
|
||||
persona_query_max=data.get("persona_query_max", 1),
|
||||
persona_update_max=data.get("persona_update_max", 1),
|
||||
task_query_max=data.get("task_query_max", 4),
|
||||
task_update_max=data.get("task_update_max", 2),
|
||||
memory_query_max=data.get("memory_query_max", 20),
|
||||
memory_update_max=data.get("memory_update_max", 10),
|
||||
)
|
||||
|
||||
def save(self, path: Path) -> None:
|
||||
"""保存配置到文件"""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
"""配置区组件"""
|
||||
|
||||
from textual.containers import Vertical
|
||||
from textual.widgets import Static, Input, Collapsible
|
||||
from textual.widgets import Static, Input, Button
|
||||
from textual.app import ComposeResult
|
||||
from textual.message import Message
|
||||
from ..models.config import AppConfig
|
||||
|
||||
|
||||
class ConfigSection(Vertical):
|
||||
"""可折叠配置区"""
|
||||
|
||||
class ConfigChanged(Message):
|
||||
"""配置变更事件"""
|
||||
def __init__(self, config: AppConfig) -> None:
|
||||
def __init__(self, config: AppConfig, is_tool_limits: bool = False) -> None:
|
||||
self.config = config
|
||||
self.is_tool_limits = is_tool_limits
|
||||
super().__init__()
|
||||
|
||||
def __init__(self, config: AppConfig | None = None, **kwargs):
|
||||
@ -21,8 +20,6 @@ class ConfigSection(Vertical):
|
||||
self._config = config or AppConfig()
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""构建配置区"""
|
||||
# 直接显示配置,不使用Collapsible
|
||||
title = Static("━━ 配置 ━━", classes="config-title")
|
||||
title.can_focus = False
|
||||
yield title
|
||||
@ -58,23 +55,58 @@ class ConfigSection(Vertical):
|
||||
id="base-url-input"
|
||||
)
|
||||
|
||||
sep = Static("", classes="config-sep")
|
||||
sep.can_focus = False
|
||||
yield sep
|
||||
|
||||
limits_title = Static("━━ 工具限制 ━━", classes="config-title")
|
||||
limits_title.can_focus = False
|
||||
yield limits_title
|
||||
|
||||
l1 = Static("人设图查询:", classes="config-label")
|
||||
l1.can_focus = False
|
||||
yield l1
|
||||
yield Input(value=str(self._config.persona_query_max), placeholder="1", id="persona-query-max")
|
||||
|
||||
l2 = Static("人设图修改:", classes="config-label")
|
||||
l2.can_focus = False
|
||||
yield l2
|
||||
yield Input(value=str(self._config.persona_update_max), placeholder="1", id="persona-update-max")
|
||||
|
||||
l3 = Static("工作记忆查询:", classes="config-label")
|
||||
l3.can_focus = False
|
||||
yield l3
|
||||
yield Input(value=str(self._config.task_query_max), placeholder="4", id="task-query-max")
|
||||
|
||||
l4 = Static("工作记忆修改:", classes="config-label")
|
||||
l4.can_focus = False
|
||||
yield l4
|
||||
yield Input(value=str(self._config.task_update_max), placeholder="2", id="task-update-max")
|
||||
|
||||
l5 = Static("一般记忆查询:", classes="config-label")
|
||||
l5.can_focus = False
|
||||
yield l5
|
||||
yield Input(value=str(self._config.memory_query_max), placeholder="20", id="memory-query-max")
|
||||
|
||||
l6 = Static("一般记忆修改:", classes="config-label")
|
||||
l6.can_focus = False
|
||||
yield l6
|
||||
yield Input(value=str(self._config.memory_update_max), placeholder="10", id="memory-update-max")
|
||||
|
||||
hint = Static("按Enter保存配置", classes="config-hint")
|
||||
hint.can_focus = False
|
||||
yield hint
|
||||
|
||||
def on_mount(self) -> None:
|
||||
"""组件挂载时设置Tab顺序并加载配置"""
|
||||
try:
|
||||
api_key = self.query_one("#api-key-input", Input)
|
||||
model = self.query_one("#model-input", Input)
|
||||
base_url = self.query_one("#base-url-input", Input)
|
||||
|
||||
# 设置Tab索引
|
||||
api_key.tab_index = 0
|
||||
model.tab_index = 1
|
||||
base_url.tab_index = 2
|
||||
|
||||
# 如果配置有值,更新输入框
|
||||
if self._config.api_key:
|
||||
api_key.value = self._config.api_key
|
||||
if self._config.model:
|
||||
@ -84,37 +116,39 @@ class ConfigSection(Vertical):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def on_input_changed(self, event: Input.Changed) -> None:
|
||||
"""处理输入变更事件"""
|
||||
# 防抖:只在用户停止输入时更新
|
||||
pass # 不在输入时实时更新,避免卡顿
|
||||
|
||||
def on_input_submitted(self, event: Input.Submitted) -> None:
|
||||
"""处理输入提交事件(按Enter或Tab)"""
|
||||
# 只在提交时更新配置
|
||||
try:
|
||||
api_key_input = self.query_one("#api-key-input", Input)
|
||||
model_input = self.query_one("#model-input", Input)
|
||||
base_url_input = self.query_one("#base-url-input", Input)
|
||||
|
||||
persona_query = self.query_one("#persona-query-max", Input)
|
||||
persona_update = self.query_one("#persona-update-max", Input)
|
||||
task_query = self.query_one("#task-query-max", Input)
|
||||
task_update = self.query_one("#task-update-max", Input)
|
||||
memory_query = self.query_one("#memory-query-max", Input)
|
||||
memory_update = self.query_one("#memory-update-max", Input)
|
||||
|
||||
# 更新配置
|
||||
self._config = AppConfig(
|
||||
api_key=api_key_input.value,
|
||||
model=model_input.value,
|
||||
base_url=base_url_input.value
|
||||
base_url=base_url_input.value,
|
||||
persona_query_max=int(persona_query.value or 1),
|
||||
persona_update_max=int(persona_update.value or 1),
|
||||
task_query_max=int(task_query.value or 4),
|
||||
task_update_max=int(task_update.value or 2),
|
||||
memory_query_max=int(memory_query.value or 20),
|
||||
memory_update_max=int(memory_update.value or 10),
|
||||
)
|
||||
|
||||
# 发送配置变更事件
|
||||
self.post_message(self.ConfigChanged(self._config))
|
||||
except Exception as e:
|
||||
self.post_message(self.ConfigChanged(self._config, is_tool_limits=True))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def get_config(self) -> AppConfig:
|
||||
"""获取当前配置"""
|
||||
return self._config
|
||||
|
||||
def set_config(self, config: AppConfig) -> None:
|
||||
"""设置配置"""
|
||||
self._config = config
|
||||
try:
|
||||
api_key_input = self.query_one("#api-key-input", Input)
|
||||
@ -124,5 +158,12 @@ class ConfigSection(Vertical):
|
||||
api_key_input.value = config.api_key
|
||||
model_input.value = config.model
|
||||
base_url_input.value = config.base_url
|
||||
|
||||
self.query_one("#persona-query-max", Input).value = str(config.persona_query_max)
|
||||
self.query_one("#persona-update-max", Input).value = str(config.persona_update_max)
|
||||
self.query_one("#task-query-max", Input).value = str(config.task_query_max)
|
||||
self.query_one("#task-update-max", Input).value = str(config.task_update_max)
|
||||
self.query_one("#memory-query-max", Input).value = str(config.memory_query_max)
|
||||
self.query_one("#memory-update-max", Input).value = str(config.memory_update_max)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user