From fd1b71dd750bbe63bea6419a581dc69d738faec4 Mon Sep 17 00:00:00 2001 From: lixinran Date: Mon, 8 Sep 2025 18:20:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=80=9D=E7=BB=B4=E5=AF=BC?= =?UTF-8?q?=E5=9B=BE=E5=AE=9E=E6=97=B6=E6=B8=B2=E6=9F=93=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/django_mindmap/settings.py | 38 +++++ backend/mindmap.db | Bin 2252800 -> 2437120 bytes backend/mindmap/ai_service.py | 123 +++++++++----- backend/mindmap/urls.py | 4 +- backend/mindmap/views_doc.py | 140 ++++++++++++++++ frontend/src/App.vue | 13 +- frontend/src/components/AISidebar.vue | 221 ++++++++++++++++++++++++-- frontend/src/components/MindMap.vue | 161 +++++++++++++++++-- 8 files changed, 636 insertions(+), 64 deletions(-) diff --git a/backend/django_mindmap/settings.py b/backend/django_mindmap/settings.py index b8dce01..5541cf7 100644 --- a/backend/django_mindmap/settings.py +++ b/backend/django_mindmap/settings.py @@ -103,6 +103,44 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # CORS settings CORS_ALLOW_ALL_ORIGINS = True CORS_ALLOW_CREDENTIALS = True +CORS_ALLOW_HEADERS = [ + 'accept', + 'accept-encoding', + 'authorization', + 'content-type', + 'dnt', + 'origin', + 'user-agent', + 'x-csrftoken', + 'x-requested-with', +] +CORS_ALLOW_METHODS = [ + 'DELETE', + 'GET', + 'OPTIONS', + 'PATCH', + 'POST', + 'PUT', +] + +# REST Framework settings +REST_FRAMEWORK = { + 'DEFAULT_RENDERER_CLASSES': [ + 'rest_framework.renderers.JSONRenderer', + ], + 'DEFAULT_PARSER_CLASSES': [ + 'rest_framework.parsers.JSONParser', + 'rest_framework.parsers.MultiPartParser', + 'rest_framework.parsers.FormParser', + ], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 100, +} + +# File upload settings +MAX_UPLOAD_SIZE = 16 * 1024 * 1024 # 16MB +ALLOWED_FILE_TYPES = ['.docx', '.pdf', '.txt', '.md'] + # REST Framework settings REST_FRAMEWORK = { diff --git a/backend/mindmap.db b/backend/mindmap.db index 7f95f7addd7eb2024899f8c592a9ed53d51bec8d..fc6b5fb8ade522e052ad438cc4cb4b79a898b975 100644 GIT binary patch delta 105592 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 VR)IY$U5Tp;suiQvz`&>M{{dbQZ8rb_ diff --git a/backend/mindmap/ai_service.py b/backend/mindmap/ai_service.py index 8cc26de..84b2c80 100644 --- a/backend/mindmap/ai_service.py +++ b/backend/mindmap/ai_service.py @@ -2,7 +2,7 @@ import re import traceback import json -def call_ai_api(system_prompt, user_prompt, model="glm-4.5", base_url="https://open.bigmodel.cn/api/paas/v4/", api_key="ce39bdd4fcf34ec0aec75072bc9ff988.hAp7HZTVUwy7vImn"): +def call_ai_api(system_prompt, user_prompt, model="glm-4.5", base_url="https://open.bigmodel.cn/api/paas/v4/", api_key="ce39bdd4fcf34ec0aec75072bc9ff988.hAp7HZTVUwy7vImn", stream=False): """ 调用AI API生成Markdown """ @@ -12,7 +12,33 @@ def call_ai_api(system_prompt, user_prompt, model="glm-4.5", base_url="https://o from openai import OpenAI except ImportError: print("OpenAI库未安装,返回模拟数据") - return f"""# {user_prompt} + if stream: + # 返回模拟流式数据 + def mock_stream(): + mock_content = f"""# {user_prompt} + +## 概述 +{user_prompt}是一个重要的概念和领域。 + +## 核心要素 +- 要素1 +- 要素2 +- 要素3 + +## 应用场景 +- 场景1 +- 场景2 +- 场景3 + +## 发展趋势 +- 趋势1 +- 趋势2 +- 趋势3""" + for char in mock_content: + yield char + return mock_stream() + else: + return f"""# {user_prompt} ## 概述 {user_prompt}是一个重要的概念和领域。 @@ -40,57 +66,76 @@ def call_ai_api(system_prompt, user_prompt, model="glm-4.5", base_url="https://o print(f"发送AI API请求到: {base_url}") print(f"模型: {model}") + print(f"流式模式: {stream}") # 创建OpenAI客户端 client = OpenAI(api_key=api_key, base_url=base_url) - # 使用非流式调用,更简单可靠 + # 根据stream参数决定是否使用流式调用 try: response = client.chat.completions.create( model=model, messages=messages, temperature=0.7, max_tokens=8000, # 增加token限制,避免内容截断 - stream=False + stream=stream ) except Exception as e: print(f"API调用失败: {e}") # 如果API调用失败,抛出异常而不是返回模拟数据 raise Exception(f"AI API调用失败: {e}") - # 获取响应内容 - content = response.choices[0].message.content - print(f"AI原始响应: {content}") - - # 处理可能的JSON格式响应 - try: - # 尝试解析为JSON - json_data = json.loads(content) - if 'answer' in json_data: - content = json_data['answer'] - print(f"从JSON中提取answer: {content[:100]}...") - elif 'content' in json_data: - content = json_data['content'] - print(f"从JSON中提取content: {content[:100]}...") - elif 'markdown' in json_data: - content = json_data['markdown'] - print(f"从JSON中提取markdown: {content[:100]}...") - except json.JSONDecodeError: - # 不是JSON格式,直接使用内容 - print("响应不是JSON格式,直接使用内容") - - # 清理内容 - content = content.strip() - - # 如果返回的内容包含代码块标记,提取其中的内容 - markdown_match = re.search(r"```(?:markdown)?\n(.*?)```", content, re.DOTALL) - if markdown_match: - content = markdown_match.group(1).strip() - - # 如果内容为空,返回模拟数据 - if not content: - print("AI返回内容为空,使用模拟数据") - return f"""# {user_prompt} + if stream: + # 流式响应处理 + def generate_stream(): + full_content = "" + try: + for chunk in response: + if chunk.choices[0].delta.content is not None: + content_chunk = chunk.choices[0].delta.content + full_content += content_chunk + yield content_chunk + print(f"流式响应完成,总长度: {len(full_content)}") + except Exception as e: + print(f"流式响应处理失败: {e}") + raise e + return full_content + + return generate_stream() + else: + # 非流式响应处理 + content = response.choices[0].message.content + print(f"AI原始响应: {content}") + + # 处理可能的JSON格式响应 + try: + # 尝试解析为JSON + json_data = json.loads(content) + if 'answer' in json_data: + content = json_data['answer'] + print(f"从JSON中提取answer: {content[:100]}...") + elif 'content' in json_data: + content = json_data['content'] + print(f"从JSON中提取content: {content[:100]}...") + elif 'markdown' in json_data: + content = json_data['markdown'] + print(f"从JSON中提取markdown: {content[:100]}...") + except json.JSONDecodeError: + # 不是JSON格式,直接使用内容 + print("响应不是JSON格式,直接使用内容") + + # 清理内容 + content = content.strip() + + # 如果返回的内容包含代码块标记,提取其中的内容 + markdown_match = re.search(r"```(?:markdown)?\n(.*?)```", content, re.DOTALL) + if markdown_match: + content = markdown_match.group(1).strip() + + # 如果内容为空,返回模拟数据 + if not content: + print("AI返回内容为空,使用模拟数据") + return f"""# {user_prompt} ## 概述 {user_prompt}是一个重要的概念和领域。 @@ -109,8 +154,8 @@ def call_ai_api(system_prompt, user_prompt, model="glm-4.5", base_url="https://o - 趋势1 - 趋势2 - 趋势3""" - - return content + + return content except Exception as e: print(f"AI API调用异常: {e}") diff --git a/backend/mindmap/urls.py b/backend/mindmap/urls.py index e2baa83..0a91384 100644 --- a/backend/mindmap/urls.py +++ b/backend/mindmap/urls.py @@ -11,4 +11,6 @@ urlpatterns = [ # AI接口 path('ai/generate-markdown', views_doc.generate_markdown), -] + path('ai/generate-stream', views_doc.generate_ai_content_stream), + path('ai/test-stream', views_doc.test_stream), # 添加测试端点 +] \ No newline at end of file diff --git a/backend/mindmap/views_doc.py b/backend/mindmap/views_doc.py index 7f93aaf..942112b 100644 --- a/backend/mindmap/views_doc.py +++ b/backend/mindmap/views_doc.py @@ -3,6 +3,8 @@ from rest_framework.response import Response from rest_framework import status from django.db import transaction from django.utils import timezone +from django.http import StreamingHttpResponse +import json from .models import mindMap, Node from .serializers import map_mindmap_to_doc, map_node_to_doc @@ -468,3 +470,141 @@ def generate_markdown(request): }, status=500) +@api_view(['POST', 'OPTIONS']) +def generate_ai_content_stream(request): + """ + 流式生成AI内容 + """ + # 处理OPTIONS请求(CORS预检请求) + if request.method == 'OPTIONS': + response = Response() + response['Access-Control-Allow-Origin'] = '*' + response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS' + response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Cache-Control, X-Requested-With' + response['Access-Control-Allow-Credentials'] = 'true' + response['Access-Control-Max-Age'] = '86400' + return response + + try: + data = request.data + user_prompt = data.get('user_prompt', '') + system_prompt = data.get('system_prompt', '你是一个专业的思维导图内容生成助手,请根据用户的需求生成结构化的Markdown内容。') + model = data.get('model', 'glm-4.5') + base_url = data.get('base_url', 'https://open.bigmodel.cn/api/paas/v4/') + api_key = data.get('api_key', '') + + if not user_prompt: + return Response({'error': '用户提示词不能为空'}, status=400) + + # 导入AI服务 + from .ai_service import call_ai_api + + def generate_stream(): + try: + print(f"开始调用流式AI API...") + # 调用流式AI API + stream = call_ai_api(system_prompt, user_prompt, model, base_url, api_key, stream=True) + + if stream is None: + print("AI API返回None,发送错误信号") + yield f"data: {json.dumps({'type': 'error', 'content': 'AI API调用失败'})}\n\n" + return + + print("开始发送流式数据...") + # 发送开始信号 + yield f"data: {json.dumps({'type': 'start', 'content': ''})}\n\n" + + # 发送流式内容 + chunk_count = 0 + for chunk in stream: + if chunk: + chunk_count += 1 + print(f"发送第{chunk_count}个数据块: {chunk[:50]}...") + yield f"data: {json.dumps({'type': 'chunk', 'content': chunk})}\n\n" + + print(f"流式数据发送完成,总共{chunk_count}个数据块") + # 发送结束信号 + yield f"data: {json.dumps({'type': 'end', 'content': ''})}\n\n" + + except Exception as e: + print(f"流式生成过程中发生错误: {e}") + import traceback + traceback.print_exc() + # 发送错误信号 + yield f"data: {json.dumps({'type': 'error', 'content': str(e)})}\n\n" + + response = StreamingHttpResponse( + generate_stream(), + content_type='text/event-stream' + ) + + # 修复CORS配置,移除不允许的头部 + response['Cache-Control'] = 'no-cache' + response['Access-Control-Allow-Origin'] = '*' + response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS' + response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Cache-Control, X-Requested-With' + response['Access-Control-Allow-Credentials'] = 'true' + response['Access-Control-Max-Age'] = '86400' + + return response + + except Exception as e: + print(f"流式API处理过程中发生错误: {e}") + import traceback + traceback.print_exc() + return Response({ + 'error': str(e), + 'success': False + }, status=500) + + +@api_view(['POST', 'OPTIONS']) +def test_stream(request): + """ + 测试流式响应 + """ + # 处理OPTIONS请求(CORS预检请求) + if request.method == 'OPTIONS': + response = Response() + response['Access-Control-Allow-Origin'] = '*' + response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS' + response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Cache-Control, X-Requested-With' + response['Access-Control-Allow-Credentials'] = 'true' + response['Access-Control-Max-Age'] = '86400' + return response + + def generate_test_stream(): + try: + # 发送开始信号 + yield f"data: {json.dumps({'type': 'start', 'content': ''})}\n\n" + + # 发送测试数据 + test_content = "# 测试思维导图\n\n## 主要主题\n- 主题1\n- 主题2\n\n## 详细内容\n- 内容1\n- 内容2" + for i, char in enumerate(test_content): + yield f"data: {json.dumps({'type': 'chunk', 'content': char})}\n\n" + # 添加小延迟模拟流式效果 + import time + time.sleep(0.01) + + # 发送结束信号 + yield f"data: {json.dumps({'type': 'end', 'content': ''})}\n\n" + + except Exception as e: + yield f"data: {json.dumps({'type': 'error', 'content': str(e)})}\n\n" + + response = StreamingHttpResponse( + generate_test_stream(), + content_type='text/event-stream' + ) + + # 修复CORS配置,移除不允许的头部 + response['Cache-Control'] = 'no-cache' + response['Access-Control-Allow-Origin'] = '*' + response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS' + response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Cache-Control, X-Requested-With' + response['Access-Control-Allow-Credentials'] = 'true' + response['Access-Control-Max-Age'] = '86400' + + return response + + diff --git a/frontend/src/App.vue b/frontend/src/App.vue index e5ee3da..4557a84 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,7 +1,7 @@