调用api进行对话
This commit is contained in:
parent
00deeb711b
commit
c0bba14ee8
@ -14,7 +14,7 @@ import os
|
||||
from pathlib import Path
|
||||
|
||||
# API 配置
|
||||
API_BASE_URL = 'http://81.69.223.133:48329'
|
||||
API_BASE_URL = 'http://180.163.88.62:30331'
|
||||
|
||||
DEPARTMENT_GROUPS = {
|
||||
"技术部": ["开发组", "测试组", "运维组"],
|
||||
|
@ -40,6 +40,8 @@ from django.utils.decorators import method_decorator
|
||||
import uuid
|
||||
from rest_framework import serializers
|
||||
import traceback
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
|
||||
@ -178,55 +180,145 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
|
||||
"""创建聊天记录"""
|
||||
try:
|
||||
data = request.data
|
||||
required_fields = ['dataset_id', 'dataset_name', 'question', 'answer']
|
||||
|
||||
# 检查必填字段
|
||||
for field in required_fields:
|
||||
if field not in data:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': f'缺少必填字段: {field}',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 获取或创建对话ID
|
||||
conversation_id = data.get('conversation_id', str(uuid.uuid4()))
|
||||
|
||||
# 获取知识库 - 不进行 UUID 转换
|
||||
try:
|
||||
knowledge_base = KnowledgeBase.objects.filter(id=data['dataset_id']).first()
|
||||
if not knowledge_base:
|
||||
return Response({
|
||||
'code': 404,
|
||||
'message': '知识库不存在',
|
||||
'data': None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
except Exception as e:
|
||||
|
||||
# 检查必填字段 - 支持单知识库或多知识库模式
|
||||
if 'question' not in data:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': f'无效的知识库ID: {str(e)}',
|
||||
'message': '缺少必填字段: question',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 检查知识库ID:支持dataset_id或dataset_id_list格式
|
||||
dataset_ids = []
|
||||
if 'dataset_id' in data:
|
||||
dataset_ids.append(data['dataset_id'])
|
||||
elif 'dataset_id_list' in data and isinstance(data['dataset_id_list'], list):
|
||||
dataset_ids = data['dataset_id_list']
|
||||
else:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '缺少必填字段: dataset_id 或 dataset_id_list',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not dataset_ids:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '至少需要提供一个知识库ID',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证所有知识库并收集external_ids
|
||||
external_id_list = []
|
||||
user = request.user
|
||||
primary_knowledge_base = None # 主知识库,用于关联聊天记录
|
||||
|
||||
for idx, kb_id in enumerate(dataset_ids):
|
||||
try:
|
||||
knowledge_base = KnowledgeBase.objects.filter(id=kb_id).first()
|
||||
if not knowledge_base:
|
||||
return Response({
|
||||
'code': 404,
|
||||
'message': f'知识库不存在: {kb_id}',
|
||||
'data': None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 保存第一个知识库作为主知识库
|
||||
if idx == 0:
|
||||
primary_knowledge_base = knowledge_base
|
||||
|
||||
# 检查知识库权限
|
||||
can_read = False
|
||||
|
||||
# 检查权限表
|
||||
permission = KBPermissionModel.objects.filter(
|
||||
knowledge_base=knowledge_base,
|
||||
user=user,
|
||||
can_read=True,
|
||||
status='active'
|
||||
).first()
|
||||
|
||||
if permission:
|
||||
can_read = True
|
||||
else:
|
||||
# 使用_can_read方法判断
|
||||
can_read = self._can_read(
|
||||
type=knowledge_base.type,
|
||||
user=user,
|
||||
department=knowledge_base.department,
|
||||
group=knowledge_base.group,
|
||||
creator_id=knowledge_base.user_id
|
||||
)
|
||||
|
||||
if not can_read:
|
||||
return Response({
|
||||
'code': 403,
|
||||
'message': f'无权访问知识库: {knowledge_base.name}',
|
||||
'data': None
|
||||
}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# 添加知识库的external_id到列表
|
||||
if knowledge_base.external_id:
|
||||
external_id_list.append(knowledge_base.external_id)
|
||||
else:
|
||||
logger.warning(f"知识库 {knowledge_base.id} ({knowledge_base.name}) 没有external_id")
|
||||
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': f'处理知识库ID出错: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not external_id_list:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '没有有效的知识库external_id',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 创建用户问题记录
|
||||
# 获取或创建对话ID
|
||||
conversation_id = data.get('conversation_id', str(uuid.uuid4()))
|
||||
|
||||
# 调用外部API获取答案 (传递多个knowledge base的external_id)
|
||||
answer = self._get_answer_from_external_api(
|
||||
dataset_external_id_list=external_id_list,
|
||||
question=data['question']
|
||||
)
|
||||
|
||||
if not answer:
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': '获取AI回答失败',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
# 创建用户问题记录 (关联到主知识库)
|
||||
question_record = ChatHistory.objects.create(
|
||||
user=request.user,
|
||||
knowledge_base=knowledge_base,
|
||||
knowledge_base=primary_knowledge_base,
|
||||
conversation_id=conversation_id,
|
||||
role='user',
|
||||
content=data['question'],
|
||||
metadata={'model_name': data.get('model_name', 'default')}
|
||||
metadata={
|
||||
'model_id': data.get('model_id', '58c5deb4-f2e2-11ef-9a1b-0242ac120009'),
|
||||
'dataset_id_list': dataset_ids
|
||||
}
|
||||
)
|
||||
|
||||
# 创建AI回答记录
|
||||
answer_record = ChatHistory.objects.create(
|
||||
user=request.user,
|
||||
knowledge_base=knowledge_base,
|
||||
knowledge_base=primary_knowledge_base,
|
||||
conversation_id=conversation_id,
|
||||
parent_id=str(question_record.id),
|
||||
role='assistant',
|
||||
content=data['answer'],
|
||||
metadata={'model_name': data.get('model_name', 'default')}
|
||||
content=answer,
|
||||
metadata={
|
||||
'model_id': data.get('model_id', '58c5deb4-f2e2-11ef-9a1b-0242ac120009'),
|
||||
'dataset_id_list': dataset_ids
|
||||
}
|
||||
)
|
||||
|
||||
return Response({
|
||||
@ -235,7 +327,8 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
|
||||
'data': {
|
||||
'id': answer_record.id,
|
||||
'conversation_id': conversation_id,
|
||||
'dataset_id': str(knowledge_base.id),
|
||||
'dataset_id': str(primary_knowledge_base.id),
|
||||
'dataset_name': primary_knowledge_base.name,
|
||||
'role': 'assistant',
|
||||
'content': answer_record.content,
|
||||
'created_at': answer_record.created_at.strftime('%Y-%m-%d %H:%M:%S')
|
||||
@ -250,6 +343,126 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
|
||||
'message': f'创建聊天记录失败: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
def _get_answer_from_external_api(self, dataset_external_id_list, question):
|
||||
"""调用外部API获取AI回答"""
|
||||
try:
|
||||
# 确保所有ID都是字符串
|
||||
dataset_external_ids = [str(id) if isinstance(id, uuid.UUID) else id for id in dataset_external_id_list]
|
||||
|
||||
logger.info(f"准备调用外部API,知识库ID列表: {dataset_external_ids}")
|
||||
|
||||
# 第一个API调用创建聊天
|
||||
chat_request_data = {
|
||||
"id": "d333dee2-b3c2-11ef-af2c-a4bb6dafa942",
|
||||
"model_id": "58c5deb4-f2e2-11ef-9a1b-0242ac120009",
|
||||
"dataset_id_list": dataset_external_ids,
|
||||
"multiple_rounds_dialogue": False,
|
||||
"dataset_setting": {
|
||||
"top_n": 10,
|
||||
"similarity": "0.3",
|
||||
"max_paragraph_char_number": 10000,
|
||||
"search_mode": "blend",
|
||||
"no_references_setting": {
|
||||
"value": "{question}",
|
||||
"status": "ai_questioning"
|
||||
}
|
||||
},
|
||||
"model_setting": {
|
||||
"prompt": "**相关文档内容**:{data} **回答要求**:如果相关文档内容中没有可用信息,请回答\"没有在知识库中查找到相关信息,建议咨询相关技术支持或参考官方文档进行操作\"。请根据相关文档内容回答用户问题。不要输出与用户问题无关的内容。请使用中文回答客户问题。**用户问题**:{question}"
|
||||
},
|
||||
"problem_optimization": False
|
||||
}
|
||||
|
||||
logger.info(f"发送创建聊天请求:{settings.API_BASE_URL}/api/application/chat/open")
|
||||
|
||||
try:
|
||||
# 测试JSON序列化,提前捕获可能的错误
|
||||
json_data = json.dumps(chat_request_data)
|
||||
logger.debug(f"请求数据序列化成功,长度: {len(json_data)}")
|
||||
except TypeError as e:
|
||||
logger.error(f"JSON序列化失败: {str(e)}")
|
||||
return None
|
||||
|
||||
chat_response = requests.post(
|
||||
url=f"{settings.API_BASE_URL}/api/application/chat/open",
|
||||
json=chat_request_data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30
|
||||
)
|
||||
|
||||
logger.info(f"API响应状态码: {chat_response.status_code}")
|
||||
|
||||
if chat_response.status_code != 200:
|
||||
logger.error(f"外部API调用失败: {chat_response.text}")
|
||||
return None
|
||||
|
||||
chat_data = chat_response.json()
|
||||
logger.debug(f"API响应数据: {chat_data}")
|
||||
|
||||
if chat_data.get('code') != 200 or not chat_data.get('data'):
|
||||
logger.error(f"外部API返回错误: {chat_data}")
|
||||
return None
|
||||
|
||||
chat_id = chat_data['data']
|
||||
logger.info(f"聊天创建成功,chat_id: {chat_id}")
|
||||
|
||||
# 第二个API调用发送消息
|
||||
message_request_data = {
|
||||
"message": question,
|
||||
"re_chat": False,
|
||||
"stream": True
|
||||
}
|
||||
|
||||
logger.info(f"发送聊天消息请求: {settings.API_BASE_URL}/api/application/chat_message/{chat_id}")
|
||||
message_response = requests.post(
|
||||
url=f"{settings.API_BASE_URL}/api/application/chat_message/{chat_id}",
|
||||
json=message_request_data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
stream=True,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
if message_response.status_code != 200:
|
||||
logger.error(f"外部API聊天消息调用失败: {message_response.status_code}, {message_response.text}")
|
||||
return None
|
||||
|
||||
# 拼接流式响应 - 修复SSE格式解析
|
||||
full_content = ""
|
||||
try:
|
||||
for line in message_response.iter_lines():
|
||||
if line:
|
||||
line_text = line.decode('utf-8')
|
||||
# 处理SSE格式 (data: {...})
|
||||
if line_text.startswith('data: '):
|
||||
json_str = line_text[6:] # 去掉 "data: " 前缀
|
||||
logger.debug(f"处理SSE数据: {json_str}")
|
||||
try:
|
||||
chunk = json.loads(json_str)
|
||||
if 'content' in chunk:
|
||||
content_part = chunk['content']
|
||||
full_content += content_part
|
||||
logger.debug(f"追加内容: '{content_part}'")
|
||||
if chunk.get('is_end', False):
|
||||
logger.debug("收到结束标记")
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"JSON解析错误: {str(e)}, 原始数据: {json_str}")
|
||||
else:
|
||||
logger.debug(f"收到非SSE格式数据: {line_text}")
|
||||
except Exception as e:
|
||||
logger.error(f"处理流式响应出错: {str(e)}")
|
||||
if full_content:
|
||||
logger.info(f"已接收部分内容: {len(full_content)} 字符")
|
||||
return full_content.strip()
|
||||
return None
|
||||
|
||||
logger.info(f"聊天回答拼接完成,总长度: {len(full_content)}")
|
||||
return full_content.strip() if full_content else "未能获取到有效回答"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"调用外部API获取回答失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return None
|
||||
|
||||
def update(self, request, pk=None):
|
||||
"""更新聊天记录"""
|
||||
|
Loading…
Reference in New Issue
Block a user