From db114269f98e45e5196bb807c7e0f274ee2242ec Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Thu, 9 Apr 2026 18:29:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增功能: - 对话页面 (/chat) - 选择不同模型进行对话 - 历史对话保存和加载 - 支持继续历史对话 API: - GET /api/chat/models - 获取可用模型 - GET /api/chat/list - 获取对话列表 - GET /api/chat/ - 获取对话详情 - POST /api/chat/send - 发送消息 - DELETE /api/chat/ - 删除对话 - POST /api/chat//clear - 清空对话 --- admin/app.py | 204 ++++++++++++++ admin/templates/auto-profiles.html | 3 + admin/templates/chat.html | 415 +++++++++++++++++++++++++++++ admin/templates/config.html | 3 + admin/templates/index.html | 3 + admin/templates/models.html | 3 + admin/templates/providers.html | 3 + 7 files changed, 634 insertions(+) create mode 100644 admin/templates/chat.html diff --git a/admin/app.py b/admin/app.py index 51b6ef8..d7a0601 100644 --- a/admin/app.py +++ b/admin/app.py @@ -94,6 +94,10 @@ def logs_page(): def config_page(): return render_template('config.html') +@app.route('/chat') +def chat_page(): + return render_template('chat.html') + @app.route('/auto-profiles') def auto_profiles_page(): return render_template('auto-profiles.html') @@ -431,6 +435,206 @@ def api_reload_config(): # 这里只返回成功,实际重载由主服务自己处理 return jsonify({'success': True, 'message': 'Config saved, restart main service to apply'}) + +# ============ 对话功能 ============ + +CHATS_FILE = DATA_DIR / 'chats.json' + +def load_chats(): + """加载对话数据""" + if CHATS_FILE.exists(): + return json.loads(CHATS_FILE.read_text(encoding='utf-8')) + return {'chats': []} + +def save_chats(data): + """保存对话数据""" + CHATS_FILE.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8') + + +@app.route('/api/chat/models') +def api_chat_models(): + """获取可用模型列表""" + providers = get_providers() + profiles = get_auto_profiles() + + models = [] + added = set() + + # 添加所有auto配置 + for name, profile in profiles.items(): + if name not in added: + models.append({ + 'id': name, + 'description': profile.get('description', 'Auto-select') + }) + added.add(name) + + # 添加提供商的模型 + for provider in providers: + if not provider['enabled']: + continue + for model in provider['models']: + if model not in added: + models.append({ + 'id': model, + 'description': provider['name'] + }) + added.add(model) + + return jsonify(models) + + +@app.route('/api/chat/list') +def api_chat_list(): + """获取对话列表""" + data = load_chats() + + chats = [] + for chat in data.get('chats', []): + chats.append({ + 'id': chat['id'], + 'title': chat.get('title', '新对话'), + 'model': chat.get('model', 'auto'), + 'message_count': len(chat.get('messages', [])), + 'created_at': chat.get('created_at'), + 'updated_at': chat.get('updated_at') + }) + + # 按更新时间倒序 + chats.sort(key=lambda x: x.get('updated_at', ''), reverse=True) + + return jsonify(chats) + + +@app.route('/api/chat/') +def api_chat_detail(chat_id): + """获取对话详情""" + data = load_chats() + + for chat in data.get('chats', []): + if chat['id'] == chat_id: + return jsonify(chat) + + return jsonify({'error': 'Chat not found'}), 404 + + +@app.route('/api/chat/send', methods=['POST']) +def api_chat_send(): + """发送消息""" + req = request.get_json() + + user_message = req.get('message', '') + model = req.get('model', 'auto') + chat_id = req.get('chat_id') + + if not user_message: + return jsonify({'error': 'Message is required'}), 400 + + data = load_chats() + + # 查找或创建对话 + chat = None + if chat_id: + for c in data['chats']: + if c['id'] == chat_id: + chat = c + break + + if not chat: + chat_id = str(uuid.uuid4())[:8] + chat = { + 'id': chat_id, + 'title': '新对话', + 'model': model, + 'messages': [], + 'created_at': datetime.now().isoformat(), + 'updated_at': datetime.now().isoformat() + } + data['chats'].append(chat) + + # 添加用户消息 + chat['messages'].append({ + 'role': 'user', + 'content': user_message, + 'time': datetime.now().isoformat() + }) + + # 调用LLM API + try: + proxy_url = f"http://localhost:{SERVER_CONFIG['port']}/v1/chat/completions" + + # 构建消息历史 + messages = [] + for msg in chat['messages'][-20:]: # 最多保留20条历史 + messages.append({ + 'role': msg['role'], + 'content': msg['content'] + }) + + response = requests.post(proxy_url, json={ + 'model': model, + 'messages': messages, + 'stream': False + }, timeout=120) + + if response.status_code == 200: + result = response.json() + assistant_message = result['choices'][0]['message']['content'] + used_model = result.get('model', model) + + # 添加助手消息 + chat['messages'].append({ + 'role': 'assistant', + 'content': assistant_message, + 'model': used_model, + 'time': datetime.now().isoformat() + }) + + # 更新标题(如果是第一条消息) + if len(chat['messages']) == 2: + chat['title'] = user_message[:30] + ('...' if len(user_message) > 30 else '') + + chat['updated_at'] = datetime.now().isoformat() + save_chats(data) + + return jsonify({ + 'success': True, + 'chat_id': chat_id, + 'response': assistant_message, + 'model': used_model, + 'title': chat['title'] + }) + else: + error_msg = response.json().get('error', {}).get('message', 'Unknown error') + return jsonify({'error': error_msg}), response.status_code + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +@app.route('/api/chat/', methods=['DELETE']) +def api_delete_chat(chat_id): + """删除对话""" + data = load_chats() + data['chats'] = [c for c in data['chats'] if c['id'] != chat_id] + save_chats(data) + return jsonify({'success': True}) + + +@app.route('/api/chat//clear', methods=['POST']) +def api_clear_chat(chat_id): + """清空对话消息""" + data = load_chats() + + for chat in data['chats']: + if chat['id'] == chat_id: + chat['messages'] = [] + chat['updated_at'] = datetime.now().isoformat() + save_chats(data) + return jsonify({'success': True}) + + return jsonify({'error': 'Chat not found'}), 404 + @app.route('/api/requests/recent') def api_recent_requests(): """获取最近请求记录""" diff --git a/admin/templates/auto-profiles.html b/admin/templates/auto-profiles.html index 7fbda91..6e2be03 100644 --- a/admin/templates/auto-profiles.html +++ b/admin/templates/auto-profiles.html @@ -34,6 +34,9 @@ Auto配置 + + 对话 + 日志查看 diff --git a/admin/templates/chat.html b/admin/templates/chat.html new file mode 100644 index 0000000..93df615 --- /dev/null +++ b/admin/templates/chat.html @@ -0,0 +1,415 @@ + + + + + + 对话 - LLM Proxy + + + + + + +
+ + + + +
+ +
+
+

历史对话

+ +
+
+

加载中...

+
+
+ + +
+ +
+
+ + 新对话 +
+
+ +
+
+ + +
+
+ +

开始新对话

+
+
+ + +
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/admin/templates/config.html b/admin/templates/config.html index c99eb96..6048d05 100644 --- a/admin/templates/config.html +++ b/admin/templates/config.html @@ -33,6 +33,9 @@ Auto配置 + + 对话 + 日志查看 diff --git a/admin/templates/index.html b/admin/templates/index.html index 2702741..004d2cc 100644 --- a/admin/templates/index.html +++ b/admin/templates/index.html @@ -34,6 +34,9 @@ Auto配置 + + 对话 + 日志查看 diff --git a/admin/templates/models.html b/admin/templates/models.html index 5084ef4..47a043b 100644 --- a/admin/templates/models.html +++ b/admin/templates/models.html @@ -33,6 +33,9 @@ Auto配置 + + 对话 + 日志查看 diff --git a/admin/templates/providers.html b/admin/templates/providers.html index 5e9c5f8..71c44fa 100644 --- a/admin/templates/providers.html +++ b/admin/templates/providers.html @@ -35,6 +35,9 @@ Auto配置 + + 对话 + 日志查看