diff --git a/README.md b/README.md index df0b6d5..1288ecd 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ db_host: localhost db_port: 3306 db_user: root db_password: "" -db_name: glm_chat +db_name: nano_claw ``` ### 3. 初始化数据库 ```bash -mysql -u root -p -e "CREATE DATABASE glm_chat CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" +mysql -u root -p -e "CREATE DATABASE nano_claw CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" ``` diff --git a/backend/models.py b/backend/models.py index 0454439..3186f40 100644 --- a/backend/models.py +++ b/backend/models.py @@ -1,4 +1,5 @@ from datetime import datetime, timezone +from sqlalchemy.dialects.mysql import LONGTEXT from . import db @@ -45,7 +46,7 @@ class Message(db.Model): thinking_content = db.Column(db.Text, default="") # Tool call support - tool_calls = db.Column(db.Text) # JSON string: tool call requests (assistant messages) + tool_calls = db.Column(LONGTEXT) # JSON string: tool call requests (assistant messages) tool_call_id = db.Column(db.String(64)) # Tool call ID (tool messages) name = db.Column(db.String(64)) # Tool name (tool messages) diff --git a/docs/Design.md b/docs/Design.md index 605d4ea..9e41208 100644 --- a/docs/Design.md +++ b/docs/Design.md @@ -349,7 +349,13 @@ GET /api/models ```json { "code": 0, - "data": ["glm-5", "glm-4", "glm-3-turbo"] + "data": [ + {"id": "glm-5", "name": "GLM-5"}, + {"id": "glm-5-turbo", "name": "GLM-5 Turbo"}, + {"id": "glm-4.5", "name": "GLM-4.5"}, + {"id": "glm-4.6", "name": "GLM-4.6"}, + {"id": "glm-4.7", "name": "GLM-4.7"} + ] } ``` diff --git a/docs/ToolSystemDesign.md b/docs/ToolSystemDesign.md index f6d66f9..3357a53 100644 --- a/docs/ToolSystemDesign.md +++ b/docs/ToolSystemDesign.md @@ -361,7 +361,7 @@ classDiagram class SearchService: """搜索服务""" def __init__(self, engine=None): - from duckduckgo_search import DDGS + from ddgs import DDGS self.engine = engine or DDGS() def search(self, query: str, max_results: int = 5) -> list: @@ -431,7 +431,7 @@ from .factory import tool def init_tools(): """初始化所有内置工具""" # 导入即自动注册 - from .builtin import crawler, data, file_ops + from .builtin import crawler, data, weather # 使用时 init_tools() @@ -446,10 +446,10 @@ init_tools() | crawler | `web_search` | 网页搜索 | SearchService | | crawler | `fetch_page` | 单页抓取 | FetchService | | crawler | `crawl_batch` | 批量爬取 | FetchService | -| data | `calculator` | 数学计算 | - | -| data | `data_analysis` | 数据分析 | - | -| file | `file_reader` | 文件读取 | - | -| file | `file_writer` | 文件写入 | - | +| data | `calculator` | 数学计算 | CalculatorService | +| data | `text_process` | 文本处理 | - | +| data | `json_process` | JSON处理 | - | +| weather | `get_weather` | 天气查询 | - (模拟数据) | --- diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 9a6da0d..5b78353 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -1,5 +1,8 @@ const BASE = '/api' +// Cache for models list +let modelsCache = null + async function request(url, options = {}) { const res = await fetch(`${BASE}${url}`, { headers: { 'Content-Type': 'application/json' }, @@ -17,6 +20,34 @@ export const modelApi = { list() { return request('/models') }, + + // Get cached models or fetch from server + async getCached() { + if (modelsCache) { + return { data: modelsCache } + } + + // Try localStorage cache first + const cached = localStorage.getItem('models_cache') + if (cached) { + try { + modelsCache = JSON.parse(cached) + return { data: modelsCache } + } catch (_) {} + } + + // Fetch from server + const res = await this.list() + modelsCache = res.data + localStorage.setItem('models_cache', JSON.stringify(modelsCache)) + return res + }, + + // Clear cache (e.g., when models changed on server) + clearCache() { + modelsCache = null + localStorage.removeItem('models_cache') + } } export const statsApi = { diff --git a/frontend/src/components/ChatView.vue b/frontend/src/components/ChatView.vue index 02b63ae..5d28087 100644 --- a/frontend/src/components/ChatView.vue +++ b/frontend/src/components/ChatView.vue @@ -290,7 +290,8 @@ defineExpose({ scrollToBottom }) .message-bubble { display: flex; gap: 12px; - padding: 16px 0; + padding: 0; + margin-bottom: 16px; } .message-bubble .avatar { @@ -312,6 +313,11 @@ defineExpose({ scrollToBottom }) flex: 1; min-width: 0; overflow: hidden; + padding: 16px; + border: 1px solid var(--border-light); + border-radius: 12px; + background: var(--bg-primary); + transition: background 0.2s, border-color 0.2s; } .streaming-content { diff --git a/frontend/src/components/MessageBubble.vue b/frontend/src/components/MessageBubble.vue index 5775b27..816b802 100644 --- a/frontend/src/components/MessageBubble.vue +++ b/frontend/src/components/MessageBubble.vue @@ -70,7 +70,8 @@ function copyContent() { .message-bubble { display: flex; gap: 12px; - padding: 16px 0; + padding: 0; + margin-bottom: 16px; } .message-bubble.user { @@ -108,6 +109,11 @@ function copyContent() { .message-body { flex: 1; min-width: 0; + padding: 16px; + border: 1px solid var(--border-light); + border-radius: 12px; + background: var(--bg-primary); + transition: background 0.2s, border-color 0.2s; } .message-content { diff --git a/frontend/src/components/SettingsPanel.vue b/frontend/src/components/SettingsPanel.vue index 9fe1cef..6b6dcfc 100644 --- a/frontend/src/components/SettingsPanel.vue +++ b/frontend/src/components/SettingsPanel.vue @@ -97,11 +97,6 @@ -
-