From 7d723b9bd621ff235169ccfd9b59e89c26217a92 Mon Sep 17 00:00:00 2001 From: JianFeeeee <109188060+JianFeeeee@users.noreply.github.com> Date: Mon, 13 Apr 2026 08:36:41 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=B9=B6=E4=BF=AE=E6=AD=A3=E6=89=93=E5=8C=85=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 docs/api.md 后端API文档 - 修正文档中启动流程示例 - 移除不存在的F4快捷键 - 前端直接工具调用不受次数限制 - 打包脚本添加 config_service hidden-import - Linux脚本添加python3检查 --- README.md | 17 +- build/build_linux.sh | 6 + build/build_macos.sh | 1 + build/build_windows.bat | 1 + core/server.py | 13 +- docs/README.md | 1 + docs/api.md | 466 ++++++++++++++++++++++++++++++++++++++++ docs/一键启动指南.md | 1 - docs/架构.md | 19 +- 9 files changed, 501 insertions(+), 24 deletions(-) create mode 100644 docs/api.md diff --git a/README.md b/README.md index 6220e8e..d29d8ee 100644 --- a/README.md +++ b/README.md @@ -100,17 +100,22 @@ TrulyMEM-TrueHumanMEM/ ### 启动流程 ```python -# 1. 创建后端 -server = BackendServer(db_path="graph_memory.db") -server.start(api_key="your-key") +# 1. 加载配置 +from ui.services.config_service import ConfigService +config_service = ConfigService(config_file="config.json") +config = config_service.get_config() -# 2. 创建UI(可选,后端可独立使用) -app = GraphMemoryApp(backend_server=server) +# 2. 创建后端 +server = BackendServer(db_path="graph_memory.db", use_embedded_db=True) +server.start(api_key=config.api_key, base_url=config.base_url) + +# 3. 创建UI(可选,后端可独立使用) +app = GraphMemoryApp(backend_server=server, config_service=config_service) app.run() # 或直接使用后端 client = BackendClient(server) -result = client.send_message("hello") +result = client.process_message("hello") ``` --- diff --git a/build/build_linux.sh b/build/build_linux.sh index 0b26548..33cf6f9 100644 --- a/build/build_linux.sh +++ b/build/build_linux.sh @@ -9,6 +9,11 @@ cd "$PROJECT_ROOT" echo "Project root: $PROJECT_ROOT" +if ! command -v python3 &> /dev/null; then + echo "Error: python3 not found" + exit 1 +fi + echo "Installing dependencies..." pip3 install -r requirements.txt 2>/dev/null || pip install -r requirements.txt @@ -50,6 +55,7 @@ python3 -m PyInstaller trulymem_entry.py \ --hidden-import ui.handlers \ --hidden-import ui.services \ --hidden-import ui.services.config_manager \ + --hidden-import ui.services.config_service \ --collect-all textual \ --noconfirm diff --git a/build/build_macos.sh b/build/build_macos.sh index 34c0381..b7b7750 100644 --- a/build/build_macos.sh +++ b/build/build_macos.sh @@ -55,6 +55,7 @@ python3 -m PyInstaller trulymem_entry.py \ --hidden-import ui.handlers \ --hidden-import ui.services \ --hidden-import ui.services.config_manager \ + --hidden-import ui.services.config_service \ --collect-all textual \ --noconfirm diff --git a/build/build_windows.bat b/build/build_windows.bat index 40733a2..fcb6d58 100644 --- a/build/build_windows.bat +++ b/build/build_windows.bat @@ -49,6 +49,7 @@ python -m PyInstaller trulymem_entry.py ^ --hidden-import ui.handlers ^ --hidden-import ui.services ^ --hidden-import ui.services.config_manager ^ + --hidden-import ui.services.config_service ^ --collect-all textual ^ --noconfirm diff --git a/core/server.py b/core/server.py index ce438aa..5bd3d69 100644 --- a/core/server.py +++ b/core/server.py @@ -225,21 +225,12 @@ class BackendServer: )) def _handle_execute_tool(self, request: BackendRequest) -> None: + """处理直接工具调用请求(前端直接调用,不受次数限制)""" try: tool_name = request.payload.get("tool_name") arguments = request.payload.get("arguments", {}) - allowed, reason = self._tool_limiter.can_call(tool_name, arguments) - if not allowed: - self._send_response(request, BackendResponse( - request_id=request.request_id, - success=False, - error=f"工具调用被拒绝: {reason}" - )) - return - - self._tool_limiter.record_call(tool_name, arguments) - + # 前端直接调用的工具不受次数限制,直接执行 result = execute_tool(self._graph, tool_name, arguments) self._send_response(request, BackendResponse( diff --git a/docs/README.md b/docs/README.md index fc25b92..b806f03 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,6 +7,7 @@ - [架构设计](架构.md) - 系统架构和技术设计 - [快速开始](一键启动指南.md) - 一键启动指南 - [工作记忆链机制说明](工作记忆链机制说明.md) - 连续性任务处理 +- [BackendServer API](api.md) - 后端 API 接口文档(供扩展开发) ## 项目简介 diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..d7cd31e --- /dev/null +++ b/docs/api.md @@ -0,0 +1,466 @@ +# BackendServer API 文档 + +本文档描述后端服务器的 API 接口,供开发者扩展其他连接方式(如网络接口、WebSocket 等)。 + +## 概述 + +TrulyMEM 后端采用**请求-响应队列模式**,通过 `queue.Queue` 实现线程安全通信。后端在独立线程中运行,处理来自客户端的请求。 + +### 核心组件 + +| 组件 | 说明 | +|------|------| +| `BackendServer` | 后端服务器,独立线程运行 | +| `BackendClient` | 客户端封装,提供便捷方法 | +| `MessageType` | 请求类型枚举 | +| `BackendRequest` | 请求数据包 | +| `BackendResponse` | 响应数据包 | + +--- + +## 请求类型 (MessageType) + +```python +class MessageType(Enum): + PROCESS_MESSAGE = "process_message" # 处理消息 + EXECUTE_TOOL = "execute_tool" # 执行工具 + GET_STATUS = "get_status" # 获取状态 + GET_CONFIG = "get_config" # 获取配置 + SET_CONFIG = "set_config" # 设置配置 + GET_HISTORY = "get_history" # 获取历史 + SAVE_HISTORY = "save_history" # 保存历史 + SHUTDOWN = "shutdown" # 关闭服务 +``` + +--- + +## 数据包格式 + +### BackendRequest + +```python +@dataclass +class BackendRequest: + request_id: str # 请求唯一标识 + message_type: MessageType # 请求类型 + payload: Dict[str, Any] # 请求参数 + response_queue: queue.Queue # 响应队列(用于返回结果) +``` + +### BackendResponse + +```python +@dataclass +class BackendResponse: + request_id: str # 对应的请求ID + success: bool # 是否成功 + data: Any = None # 返回数据 + error: Optional[str] = None # 错误信息 +``` + +--- + +## API 接口详情 + +### 1. PROCESS_MESSAGE - 处理消息 + +发送用户消息,AI 将处理并返回回复(可能包含工具调用)。 + +**请求参数:** +```python +payload = { + "user_input": str # 用户输入的消息 +} +``` + +**响应数据:** +```python +data = { + "content": str, # AI 回复内容 + "tool_calls": [ # 工具调用记录 + { + "name": str, # 工具名称 + "arguments": dict,# 工具参数 + "result": str # 工具执行结果 + } + ], + "rejected_tools": [ # 被拒绝的工具调用 + (str, str) # (工具名, 拒绝原因) + ] +} +``` + +**示例:** +```python +from core import BackendClient + +client = BackendClient(server) +result = client.process_message("你好,请记住我的名字是小明") +# result = {"success": True, "data": {"content": "...", "tool_calls": [...]}} +``` + +--- + +### 2. EXECUTE_TOOL - 执行工具 + +直接执行指定的记忆工具。 + +> **注意**:前端直接调用的工具**不受次数限制**,只有模型发起的工具调用才受限制。 + +**请求参数:** +```python +payload = { + "tool_name": str, # 工具名称 + "arguments": dict # 工具参数 +} +``` + +**响应数据:** +```python +data = { + "result": str # 工具执行结果 +} +``` + +**示例:** +```python +result = client.execute_tool("memory_recall", {"query_intent": "用户信息"}) +``` + +--- + +### 3. GET_STATUS - 获取状态 + +获取后端运行状态。 + +**请求参数:** +```python +payload = {} # 无参数 +``` + +**响应数据:** +```python +data = { + "graph_initialized": bool, # 图数据库是否初始化 + "client_initialized": bool, # API 客户端是否初始化 + "running": bool # 后端是否运行中 +} +``` + +**示例:** +```python +status = client.get_status() +# status = {"success": True, "data": {"running": True, ...}} +``` + +--- + +### 4. GET_CONFIG - 获取配置 + +获取当前 API 配置。 + +**请求参数:** +```python +payload = {} # 无参数 +``` + +**响应数据:** +```python +data = { + "api_key": str, # API Key + "base_url": str # API Base URL +} +``` + +--- + +### 5. SET_CONFIG - 设置配置 + +更新 API 配置(API Key 和 Base URL)。 + +**请求参数:** +```python +payload = { + "api_key": str, # API Key + "base_url": str # API Base URL (默认: https://api.deepseek.com) +} +``` + +**响应数据:** +```python +data = { + "status": "config_updated" +} +``` + +**示例:** +```python +result = client.update_config( + api_key="sk-xxxxx", + base_url="https://api.deepseek.com" +) +``` + +--- + +### 6. GET_HISTORY - 获取消息历史 + +获取保存的消息历史。 + +**请求参数:** +```python +payload = {} # 无参数 +``` + +**响应数据:** +```python +data = { + "history": list # 消息历史列表 +} +``` + +--- + +### 7. SAVE_HISTORY - 保存消息历史 + +保存消息历史到内存。 + +**请求参数:** +```python +payload = { + "messages": list # 消息列表 +} +``` + +**响应数据:** +```python +data = { + "status": "history_saved" +} +``` + +--- + +### 8. SHUTDOWN - 关闭服务 + +关闭后端服务器。 + +**请求参数:** +```python +payload = {} # 无参数 +``` + +**响应数据:** +```python +data = { + "status": "shutdown" +} +``` + +--- + +## 使用示例 + +### 基础使用 + +```python +from core import BackendServer, BackendClient + +# 1. 创建并启动后端 +server = BackendServer(db_path="graph_memory.db", use_embedded_db=True) +server.start(api_key="your-api-key", base_url="https://api.deepseek.com") + +# 2. 创建客户端 +client = BackendClient(server) + +# 3. 发送消息 +result = client.process_message("你好") +print(result["data"]["content"]) + +# 4. 关闭 +client.shutdown() +``` + +### 直接使用请求队列 + +```python +import queue +from core import BackendServer, MessageType, BackendRequest, BackendResponse + +server = BackendServer() +server.start(api_key="your-key") + +# 创建请求 +response_queue = queue.Queue() +request = BackendRequest( + request_id="req-001", + message_type=MessageType.PROCESS_MESSAGE, + payload={"user_input": "你好"}, + response_queue=response_queue +) + +# 发送请求 +server._request_queue.put(request) + +# 等待响应 +response = response_queue.get(timeout=30.0) +print(response.data) +``` + +--- + +## 扩展指南 + +### 扩展为 HTTP API + +```python +from flask import Flask, request, jsonify +from core import BackendServer, BackendClient + +app = Flask(__name__) +server = BackendServer() +client = BackendClient(server) + +@app.route("/message", methods=["POST"]) +def send_message(): + data = request.json + result = client.process_message(data["message"]) + return jsonify(result) + +@app.route("/config", methods=["POST"]) +def update_config(): + data = request.json + result = client.update_config(data["api_key"], data.get("base_url")) + return jsonify(result) + +@app.route("/status", methods=["GET"]) +def get_status(): + result = client.get_status() + return jsonify(result) + +if __name__ == "__main__": + server.start() + app.run(port=8080) +``` + +### 扩展为 WebSocket + +```python +import asyncio +import websockets +import json +from core import BackendServer, BackendClient + +server = BackendServer() +client = BackendClient(server) + +async def handler(websocket): + async for message in websocket: + data = json.loads(message) + msg_type = data["type"] + + if msg_type == "message": + result = client.process_message(data["content"]) + elif msg_type == "config": + result = client.update_config(data["api_key"], data.get("base_url")) + elif msg_type == "status": + result = client.get_status() + else: + result = {"success": False, "error": "unknown type"} + + await websocket.send(json.dumps(result)) + +async def main(): + server.start() + async with websockets.serve(handler, "localhost", 8765): + await asyncio.Future() # run forever + +asyncio.run(main()) +``` + +### 扩展为 gRPC + +```protobuf +// truly_mem.proto +syntax = "proto3"; + +service TrulyMEM { + rpc ProcessMessage(MessageRequest) returns (MessageResponse); + rpc UpdateConfig(ConfigRequest) returns (ConfigResponse); + rpc GetStatus(Empty) returns (StatusResponse); +} + +message MessageRequest { + string message = 1; +} + +message MessageResponse { + bool success = 1; + string content = 2; + string error = 3; +} +``` + +--- + +## 线程安全说明 + +- `BackendServer` 使用 `threading.Lock` 保护共享资源 +- 所有请求通过 `queue.Queue` 传递,线程安全 +- 响应通过每个请求独立的 `response_queue` 返回 +- 默认超时时间:30 秒 + +--- + +## 工具调用限制 + +### 限制范围 + +| 调用方式 | 是否受限 | 说明 | +|---------|---------|------| +| 模型发起的工具调用 | ✅ 受限 | 通过 `PROCESS_MESSAGE` 触发,模型自动调用工具 | +| 前端直接调用工具 | ❌ 不受限 | 通过 `EXECUTE_TOOL` 直接调用 | + +### 限制规则(仅限模型发起) + +| 类别 | 操作 | 每轮上限 | +|------|------|---------| +| 人设图 | 查询 | 1 次 | +| 人设图 | 修改 | 1 次 | +| 工作记忆链 | 查询 | 4 次 | +| 工作记忆链 | 修改 | 2 次 | +| 一般记忆 | 查询 | 20 次 | +| 一般记忆 | 修改 | 10 次 | + +### 重置机制 + +- 每次调用 `PROCESS_MESSAGE` 时,计数器自动重置 +- 前端直接调用 `EXECUTE_TOOL` 不会重置计数器 + +--- + +## 错误处理 + +所有 API 返回统一格式: + +```python +# 成功 +{ + "success": True, + "data": {...} +} + +# 失败 +{ + "success": False, + "error": "错误描述" +} +``` + +常见错误: + +| 错误信息 | 说明 | +|---------|------| +| `API Key 未配置` | 未设置 API Key | +| `timeout` | 请求超时 | +| `工具调用被拒绝: ...` | 工具调用频率超限 | diff --git a/docs/一键启动指南.md b/docs/一键启动指南.md index f92b62d..ae34979 100644 --- a/docs/一键启动指南.md +++ b/docs/一键启动指南.md @@ -48,7 +48,6 @@ TrulyMEM.exe | F1 | 帮助 | | F2 | 切换侧边栏 | | F3 | 工具详情 | -| F4 | 聚焦查询框 | | F5 | 清屏 | | F6 | 退出 | diff --git a/docs/架构.md b/docs/架构.md index c710c4d..a6f3a4a 100644 --- a/docs/架构.md +++ b/docs/架构.md @@ -55,8 +55,7 @@ TrulyMEM-TrueHumanMEM/ │ ├── services/ # 服务层 │ │ ├── config_manager.py │ │ ├── config_service.py -│ │ ├── chat_service.py -│ │ └── tool_service.py +│ │ └── chat_service.py │ └── styles/ # 样式文件 │ ├── app.css │ ├── components.css @@ -129,10 +128,19 @@ MessageHistory 显示 ```python # trulymem_entry.py def main(): - backend_server = BackendServer(db_path="graph_memory.db") - backend_server.start(api_key=config.api_key) + # 配置文件保存在应用根目录 + config_file = application_path / "config.json" - app = GraphMemoryApp(backend_server=backend_server) + # 加载配置 + config_service = ConfigService(config_file=config_file) + config = config_service.get_config() + + # 创建后端 + backend_server = BackendServer(db_path="graph_memory.db", use_embedded_db=True) + backend_server.start(api_key=config.api_key, base_url=config.base_url) + + # 创建UI + app = GraphMemoryApp(backend_server=backend_server, config_service=config_service) app.run() backend_server.shutdown() @@ -183,7 +191,6 @@ def main(): | F1 | 显示帮助 | | F2 | 切换侧边栏 | | F3 | 工具详情 | -| F4 | 聚焦查询框 | | F5 | 清屏 | | F6 | 退出 |