conversation_id显示用户对话

This commit is contained in:
wanjia 2025-03-21 15:10:29 +08:00
parent c0bba14ee8
commit 9153594375
3 changed files with 527 additions and 96 deletions

View File

@ -0,0 +1,22 @@
# Generated by Django 5.1.5 on 2025-03-21 04:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user_management', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='chathistory',
name='metadata',
field=models.JSONField(blank=True, default=dict, help_text="\n {\n 'model_id': 'xxx',\n 'dataset_id_list': ['id1', 'id2', ...],\n 'dataset_external_id_list': ['ext1', 'ext2', ...],\n 'primary_knowledge_base': 'id1'\n }\n "),
),
migrations.AddIndex(
model_name='chathistory',
index=models.Index(fields=['conversation_id', 'is_deleted'], name='chat_histor_convers_89bc43_idx'),
),
]

View File

@ -1,3 +1,4 @@
from itertools import count
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
@ -286,13 +287,23 @@ class ChatHistory(models.Model):
] ]
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)
# 保留与主知识库的关联
knowledge_base = models.ForeignKey('KnowledgeBase', on_delete=models.CASCADE) knowledge_base = models.ForeignKey('KnowledgeBase', on_delete=models.CASCADE)
# 用于标识知识库组合的对话
conversation_id = models.CharField(max_length=100, db_index=True) conversation_id = models.CharField(max_length=100, db_index=True)
parent_id = models.CharField(max_length=100, null=True, blank=True) parent_id = models.CharField(max_length=100, null=True, blank=True)
role = models.CharField(max_length=20, choices=ROLE_CHOICES) role = models.CharField(max_length=20, choices=ROLE_CHOICES)
content = models.TextField() content = models.TextField()
tokens = models.IntegerField(default=0, help_text="消息token数") tokens = models.IntegerField(default=0, help_text="消息token数")
metadata = models.JSONField(default=dict, blank=True) # 扩展metadata字段用于存储知识库组合信息
metadata = models.JSONField(default=dict, blank=True, help_text="""
{
'model_id': 'xxx',
'dataset_id_list': ['id1', 'id2', ...],
'dataset_external_id_list': ['ext1', 'ext2', ...],
'primary_knowledge_base': 'id1'
}
""")
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
is_deleted = models.BooleanField(default=False) is_deleted = models.BooleanField(default=False)
@ -302,6 +313,8 @@ class ChatHistory(models.Model):
indexes = [ indexes = [
models.Index(fields=['conversation_id', 'created_at']), models.Index(fields=['conversation_id', 'created_at']),
models.Index(fields=['user', 'created_at']), models.Index(fields=['user', 'created_at']),
# 添加新的索引以支持知识库组合查询
models.Index(fields=['conversation_id', 'is_deleted']),
] ]
def __str__(self): def __str__(self):
@ -315,11 +328,69 @@ class ChatHistory(models.Model):
is_deleted=False is_deleted=False
).order_by('created_at') ).order_by('created_at')
@classmethod
def get_conversations_by_knowledge_bases(cls, dataset_ids, user):
"""根据知识库组合获取对话历史"""
# 对知识库ID列表排序以确保一致性
sorted_kb_ids = sorted(dataset_ids)
conversation_id = str(uuid.uuid5(
uuid.NAMESPACE_DNS,
'-'.join(sorted_kb_ids)
))
return cls.objects.filter(
conversation_id=conversation_id,
user=user,
is_deleted=False
).order_by('created_at')
@classmethod
def get_knowledge_base_combinations(cls, user):
"""获取用户的所有知识库组合"""
return cls.objects.filter(
user=user,
is_deleted=False
).values('conversation_id').annotate(
last_message=max('created_at'),
message_count=count('id')
).values(
'conversation_id',
'last_message',
'message_count',
'metadata'
).order_by('-last_message')
def get_knowledge_bases(self):
"""获取此消息关联的所有知识库"""
if self.metadata and 'dataset_id_list' in self.metadata:
return KnowledgeBase.objects.filter(
id__in=self.metadata['dataset_id_list']
)
return KnowledgeBase.objects.filter(id=self.knowledge_base.id)
def soft_delete(self): def soft_delete(self):
"""软删除消息""" """软删除消息"""
self.is_deleted = True self.is_deleted = True
self.save() self.save()
def to_dict(self):
"""转换为字典格式"""
return {
'id': str(self.id),
'conversation_id': self.conversation_id,
'role': self.role,
'content': self.content,
'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
'metadata': self.metadata,
'knowledge_bases': [
{
'id': str(kb.id),
'name': kb.name,
'type': kb.type
} for kb in self.get_knowledge_bases()
]
}
class UserProfile(models.Model): class UserProfile(models.Model):
"""用户档案模型""" """用户档案模型"""
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')

View File

@ -26,7 +26,7 @@ import os
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.http import Http404 from django.http import Http404, HttpResponse
from django.db import IntegrityError from django.db import IntegrityError
from channels.exceptions import ChannelFull from channels.exceptions import ChannelFull
from django.conf import settings from django.conf import settings
@ -93,79 +93,73 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
) )
def list(self, request): def list(self, request):
"""获取聊天记录列表""" """获取对话列表概览"""
try: try:
# 获取查询参数 # 获取查询参数
dataset_id = request.query_params.get('dataset_id')
page = int(request.query_params.get('page', 1)) page = int(request.query_params.get('page', 1))
page_size = int(request.query_params.get('page_size', 10)) page_size = int(request.query_params.get('page_size', 10))
query = self.get_queryset() # 获取所有对话的概览
latest_chats = self.get_queryset().values(
'conversation_id'
).annotate(
latest_id=Max('id'),
message_count=Count('id'),
last_message=Max('created_at')
).order_by('-last_message')
if dataset_id: # 计算分页
# 获取特定知识库的完整对话历史 total = latest_chats.count()
records = query.filter( start = (page - 1) * page_size
knowledge_base__id=dataset_id end = start + page_size
).order_by('created_at') chats = latest_chats[start:end]
conversation = { results = []
'dataset_id': dataset_id, for chat in chats:
'dataset_name': records.first().knowledge_base.name if records.exists() else None, # 获取最新消息记录
'messages': [{ latest_record = ChatHistory.objects.get(id=chat['latest_id'])
'id': record.id,
'role': record.role, # 从metadata中获取完整的知识库信息
'content': record.content, dataset_info = []
'created_at': record.created_at.strftime('%Y-%m-%d %H:%M:%S') if latest_record.metadata:
} for record in records] dataset_id_list = latest_record.metadata.get('dataset_id_list', [])
dataset_names = latest_record.metadata.get('dataset_names', [])
# 如果有知识库ID列表
if dataset_id_list:
# 如果同时有名称列表且长度匹配
if dataset_names and len(dataset_names) == len(dataset_id_list):
dataset_info = [{
'id': str(id),
'name': name
} for id, name in zip(dataset_id_list, dataset_names)]
else:
# 如果没有名称列表则只返回ID
datasets = KnowledgeBase.objects.filter(id__in=dataset_id_list)
dataset_info = [{
'id': str(ds.id),
'name': ds.name
} for ds in datasets]
results.append({
'conversation_id': chat['conversation_id'],
'message_count': chat['message_count'],
'last_message': latest_record.content,
'last_time': chat['last_message'].strftime('%Y-%m-%d %H:%M:%S'),
'dataset_id_list': [ds['id'] for ds in dataset_info], # 添加完整的知识库ID列表
'datasets': dataset_info # 包含ID和名称的完整信息
})
return Response({
'code': 200,
'message': '获取成功',
'data': {
'total': total,
'page': page,
'page_size': page_size,
'results': results
} }
})
return Response({
'code': 200,
'message': '获取成功',
'data': conversation
})
else:
# 获取所有对话的概览
latest_chats = query.values(
'conversation_id',
'knowledge_base__id',
'knowledge_base__name'
).annotate(
latest_id=Max('id'),
message_count=Count('id'),
last_message=Max('created_at')
).order_by('-last_message')
# 计算分页
total = latest_chats.count()
start = (page - 1) * page_size
end = start + page_size
# 获取分页数据
chats = latest_chats[start:end]
results = []
for chat in chats:
latest_record = ChatHistory.objects.get(id=chat['latest_id'])
results.append({
'conversation_id': chat['conversation_id'],
'dataset_id': str(chat['knowledge_base__id']),
'dataset_name': chat['knowledge_base__name'],
'message_count': chat['message_count'],
'last_message': latest_record.content,
'last_time': chat['last_message'].strftime('%Y-%m-%d %H:%M:%S')
})
return Response({
'code': 200,
'message': '获取成功',
'data': {
'total': total,
'page': page,
'page_size': page_size,
'results': results
}
})
except Exception as e: except Exception as e:
logger.error(f"获取聊天记录失败: {str(e)}") logger.error(f"获取聊天记录失败: {str(e)}")
@ -176,6 +170,119 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
'data': None 'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@action(detail=False, methods=['get'])
def conversation_detail(self, request):
"""获取特定对话的详细信息"""
try:
conversation_id = request.query_params.get('conversation_id')
if not conversation_id:
return Response({
'code': 400,
'message': '缺少conversation_id参数',
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
# 获取对话历史
messages = self.get_queryset().filter(
conversation_id=conversation_id
).order_by('created_at')
if not messages.exists():
return Response({
'code': 404,
'message': '对话不存在',
'data': None
}, status=status.HTTP_404_NOT_FOUND)
# 获取知识库信息
first_message = messages.first()
dataset_info = []
if first_message and first_message.metadata:
if 'dataset_id_list' in first_message.metadata:
datasets = KnowledgeBase.objects.filter(
id__in=first_message.metadata['dataset_id_list']
)
dataset_info = [{
'id': str(ds.id),
'name': ds.name,
'type': ds.type
} for ds in datasets]
return Response({
'code': 200,
'message': '获取成功',
'data': {
'conversation_id': conversation_id,
'datasets': dataset_info,
'messages': [{
'id': str(msg.id),
'role': msg.role,
'content': msg.content,
'created_at': msg.created_at.strftime('%Y-%m-%d %H:%M:%S')
} for msg in messages]
}
})
except Exception as e:
logger.error(f"获取对话详情失败: {str(e)}")
logger.error(traceback.format_exc())
return Response({
'code': 500,
'message': f'获取对话详情失败: {str(e)}',
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@action(detail=False, methods=['get'])
def available_datasets(self, request):
"""获取用户可访问的知识库列表"""
try:
user = request.user
# 获取用户有权限访问的知识库
accessible_datasets = []
# 1. 获取用户通过权限表直接授权的知识库
permission_datasets = KnowledgeBase.objects.filter(
id__in=KBPermissionModel.objects.filter(
user=user,
can_read=True,
status='active'
).values_list('knowledge_base_id', flat=True)
)
# 2. 获取用户根据角色可以访问的知识库
role_datasets = KnowledgeBase.objects.filter(
Q(type='member', department=user.department) | # 成员级知识库
Q(type='leader', department=user.department) | # 部门级知识库,组长可访问
Q(type='admin') # 管理级知识库,管理员可访问
).exclude(
Q(type='private') & ~Q(user_id=str(user.id)) # 排除不属于自己的私人知识库
)
# 3. 合并并去重
accessible_datasets = list(set(list(permission_datasets) + list(role_datasets)))
return Response({
'code': 200,
'message': '获取成功',
'data': [{
'id': str(ds.id),
'name': ds.name,
'type': ds.type,
'department': ds.department,
'description': ds.desc
} for ds in accessible_datasets]
})
except Exception as e:
logger.error(f"获取可用知识库列表失败: {str(e)}")
logger.error(traceback.format_exc())
return Response({
'code': 500,
'message': f'获取可用知识库列表失败: {str(e)}',
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def create(self, request): def create(self, request):
"""创建聊天记录""" """创建聊天记录"""
try: try:
@ -192,9 +299,23 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
# 检查知识库ID支持dataset_id或dataset_id_list格式 # 检查知识库ID支持dataset_id或dataset_id_list格式
dataset_ids = [] dataset_ids = []
if 'dataset_id' in data: if 'dataset_id' in data:
dataset_ids.append(data['dataset_id']) dataset_id = data['dataset_id']
elif 'dataset_id_list' in data and isinstance(data['dataset_id_list'], list): # 直接使用标准UUID格式
dataset_ids = data['dataset_id_list'] dataset_ids.append(str(dataset_id))
elif 'dataset_id_list' in data and isinstance(data['dataset_id_list'], (list, str)):
# 处理可能的字符串格式
if isinstance(data['dataset_id_list'], str):
try:
# 尝试解析JSON字符串
dataset_list = json.loads(data['dataset_id_list'])
if isinstance(dataset_list, list):
dataset_ids = [str(id) for id in dataset_list]
except json.JSONDecodeError:
# 如果解析失败可能是单个ID
dataset_ids = [str(data['dataset_id_list'])]
else:
# 如果已经是列表直接使用标准UUID格式
dataset_ids = [str(id) for id in data['dataset_id_list']]
else: else:
return Response({ return Response({
'code': 400, 'code': 400,
@ -212,9 +333,9 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
# 验证所有知识库并收集external_ids # 验证所有知识库并收集external_ids
external_id_list = [] external_id_list = []
user = request.user user = request.user
primary_knowledge_base = None # 主知识库,用于关联聊天记录 knowledge_bases = [] # 存储所有知识库对象
for idx, kb_id in enumerate(dataset_ids): for kb_id in dataset_ids:
try: try:
knowledge_base = KnowledgeBase.objects.filter(id=kb_id).first() knowledge_base = KnowledgeBase.objects.filter(id=kb_id).first()
if not knowledge_base: if not knowledge_base:
@ -224,9 +345,7 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
'data': None 'data': None
}, status=status.HTTP_404_NOT_FOUND) }, status=status.HTTP_404_NOT_FOUND)
# 保存第一个知识库作为主知识库 knowledge_bases.append(knowledge_base)
if idx == 0:
primary_knowledge_base = knowledge_base
# 检查知识库权限 # 检查知识库权限
can_read = False can_read = False
@ -242,7 +361,6 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
if permission: if permission:
can_read = True can_read = True
else: else:
# 使用_can_read方法判断
can_read = self._can_read( can_read = self._can_read(
type=knowledge_base.type, type=knowledge_base.type,
user=user, user=user,
@ -279,7 +397,20 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
}, status=status.HTTP_400_BAD_REQUEST) }, status=status.HTTP_400_BAD_REQUEST)
# 获取或创建对话ID # 获取或创建对话ID
conversation_id = data.get('conversation_id', str(uuid.uuid4())) conversation_id = data.get('conversation_id')
# 如果没有提供 conversation_id根据知识库组合生成新的ID
if not conversation_id:
# 对知识库ID列表排序以确保相同组合生成相同的hash
sorted_kb_ids = sorted(dataset_ids)
# 使用知识库ID组合生成唯一的conversation_id
conversation_id = str(uuid.uuid5(
uuid.NAMESPACE_DNS,
'-'.join(sorted_kb_ids)
))
logger.info(f"为知识库组合 {sorted_kb_ids} 生成新的conversation_id: {conversation_id}")
else:
logger.info(f"使用现有conversation_id: {conversation_id}")
# 调用外部API获取答案 (传递多个knowledge base的external_id) # 调用外部API获取答案 (传递多个knowledge base的external_id)
answer = self._get_answer_from_external_api( answer = self._get_answer_from_external_api(
@ -294,41 +425,44 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
'data': None 'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
# 创建用户问题记录 (关联到主知识库) # 准备完整的metadata
metadata = {
'model_id': data.get('model_id', '58c5deb4-f2e2-11ef-9a1b-0242ac120009'),
'dataset_id_list': [str(id) for id in dataset_ids],
'dataset_external_id_list': [str(id) for id in external_id_list],
'dataset_names': [kb.name for kb in knowledge_bases] # 添加知识库名称列表
}
# 创建用户问题记录
question_record = ChatHistory.objects.create( question_record = ChatHistory.objects.create(
user=request.user, user=request.user,
knowledge_base=primary_knowledge_base, knowledge_base=knowledge_bases[0], # 仍然需要一个主知识库,使用第一个
conversation_id=conversation_id, conversation_id=str(conversation_id),
role='user', role='user',
content=data['question'], content=data['question'],
metadata={ metadata=metadata
'model_id': data.get('model_id', '58c5deb4-f2e2-11ef-9a1b-0242ac120009'),
'dataset_id_list': dataset_ids
}
) )
# 创建AI回答记录 # 创建AI回答记录
answer_record = ChatHistory.objects.create( answer_record = ChatHistory.objects.create(
user=request.user, user=request.user,
knowledge_base=primary_knowledge_base, knowledge_base=knowledge_bases[0], # 仍然需要一个主知识库,使用第一个
conversation_id=conversation_id, conversation_id=str(conversation_id),
parent_id=str(question_record.id), parent_id=str(question_record.id),
role='assistant', role='assistant',
content=answer, content=answer,
metadata={ metadata=metadata
'model_id': data.get('model_id', '58c5deb4-f2e2-11ef-9a1b-0242ac120009'),
'dataset_id_list': dataset_ids
}
) )
# 返回完整的响应
return Response({ return Response({
'code': 200, 'code': 200,
'message': '创建成功', 'message': '创建成功',
'data': { 'data': {
'id': answer_record.id, 'id': str(answer_record.id),
'conversation_id': conversation_id, 'conversation_id': str(conversation_id),
'dataset_id': str(primary_knowledge_base.id), 'dataset_id_list': [str(id) for id in dataset_ids],
'dataset_name': primary_knowledge_base.name, 'dataset_names': [kb.name for kb in knowledge_bases], # 返回所有知识库名称
'role': 'assistant', 'role': 'assistant',
'content': answer_record.content, 'content': answer_record.content,
'created_at': answer_record.created_at.strftime('%Y-%m-%d %H:%M:%S') 'created_at': answer_record.created_at.strftime('%Y-%m-%d %H:%M:%S')
@ -342,7 +476,7 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
'code': 500, 'code': 500,
'message': f'创建聊天记录失败: {str(e)}', 'message': f'创建聊天记录失败: {str(e)}',
'data': None 'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) }, status.HTTP_500_INTERNAL_SERVER_ERROR)
def _get_answer_from_external_api(self, dataset_external_id_list, question): def _get_answer_from_external_api(self, dataset_external_id_list, question):
"""调用外部API获取AI回答""" """调用外部API获取AI回答"""
@ -354,7 +488,7 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
# 第一个API调用创建聊天 # 第一个API调用创建聊天
chat_request_data = { chat_request_data = {
"id": "d333dee2-b3c2-11ef-af2c-a4bb6dafa942", "id": "65031f4d-c86d-430e-8089-d8ff2731a837",
"model_id": "58c5deb4-f2e2-11ef-9a1b-0242ac120009", "model_id": "58c5deb4-f2e2-11ef-9a1b-0242ac120009",
"dataset_id_list": dataset_external_ids, "dataset_id_list": dataset_external_ids,
"multiple_rounds_dialogue": False, "multiple_rounds_dialogue": False,
@ -617,6 +751,210 @@ class ChatHistoryViewSet(viewsets.ModelViewSet):
'message': f'搜索失败: {str(e)}', 'message': f'搜索失败: {str(e)}',
'data': None 'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@action(detail=False, methods=['get'])
def export(self, request):
"""导出聊天记录为Excel文件"""
try:
# 获取查询参数
conversation_id = request.query_params.get('conversation_id')
dataset_id = request.query_params.get('dataset_id')
history_days = request.query_params.get('history_days', '7') # 默认导出最近7天
# 至少需要一个筛选条件
if not conversation_id and not dataset_id:
return Response({
'code': 400,
'message': '需要提供conversation_id或dataset_id参数',
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
# 验证权限
user = request.user
if dataset_id:
knowledge_base = KnowledgeBase.objects.filter(id=dataset_id).first()
if not knowledge_base:
return Response({
'code': 404,
'message': '知识库不存在',
'data': None
}, status=status.HTTP_404_NOT_FOUND)
# 检查是否有读取权限
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 = 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': '无权访问该知识库',
'data': None
}, status=status.HTTP_403_FORBIDDEN)
# 查询确认有聊天记录存在
query = self.get_queryset()
if conversation_id:
records = query.filter(conversation_id=conversation_id)
elif dataset_id:
records = query.filter(knowledge_base__id=dataset_id)
if not records.exists():
return Response({
'code': 404,
'message': '未找到相关对话记录',
'data': None
}, status=status.HTTP_404_NOT_FOUND)
# 调用外部API导出Excel文件 - 使用GET请求
application_id = "65031f4d-c86d-430e-8089-d8ff2731a837" # 固定值
export_url = f"{settings.API_BASE_URL}/api/application/{application_id}/chat/export?history_day={history_days}"
logger.info(f"发送导出请求:{export_url}")
export_response = requests.get(
url=export_url,
timeout=60,
stream=True # 使用流式传输处理大文件
)
# 检查响应状态
if export_response.status_code != 200:
logger.error(f"导出API调用失败: {export_response.status_code}, {export_response.text}")
return Response({
'code': 500,
'message': '导出失败,外部服务返回错误',
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
# 创建响应对象并设置文件下载头
response = HttpResponse(
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
response['Content-Disposition'] = 'attachment; filename="data.xlsx"'
# 将API响应内容写入响应对象
for chunk in export_response.iter_content(chunk_size=8192):
if chunk:
response.write(chunk)
logger.info("导出成功完成")
return response
except Exception as e:
logger.error(f"导出聊天记录失败: {str(e)}")
logger.error(traceback.format_exc())
return Response({
'code': 500,
'message': f'导出聊天记录失败: {str(e)}',
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@action(detail=False, methods=['get'])
def chat_list(self, request):
"""获取对话列表"""
try:
# 获取查询参数
history_days = request.query_params.get('history_days', '7') # 默认7天
# 构建API请求
application_id = "65031f4d-c86d-430e-8089-d8ff2731a837"
api_url = f"{settings.API_BASE_URL}/api/application/{application_id}/chat"
# 添加查询参数
params = {
'history_day': history_days
}
logger.info(f"发送获取对话列表请求:{api_url}")
# 调用外部API
response = requests.get(
url=api_url,
params=params,
timeout=30
)
if response.status_code != 200:
logger.error(f"获取对话列表失败: {response.status_code}, {response.text}")
return Response({
'code': 500,
'message': '获取对话列表失败,外部服务返回错误',
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
# 解析响应数据
try:
result = response.json()
if result.get('code') != 200:
logger.error(f"外部API返回错误: {result}")
return Response({
'code': result.get('code', 500),
'message': result.get('message', '获取对话列表失败'),
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
# 处理返回的数据
chat_list = result.get('data', [])
# 格式化返回数据
formatted_chats = []
for chat in chat_list:
formatted_chat = {
'id': chat['id'],
'chat_id': chat['chat_id'],
'abstract': chat['abstract'],
'message_count': chat['chat_record_count'],
'created_at': datetime.fromisoformat(chat['create_time'].replace('Z', '+00:00')).strftime('%Y-%m-%d %H:%M:%S'),
'updated_at': datetime.fromisoformat(chat['update_time'].replace('Z', '+00:00')).strftime('%Y-%m-%d %H:%M:%S'),
'star_count': chat['star_num'],
'trample_count': chat['trample_num'],
'mark_sum': chat['mark_sum'],
'is_deleted': chat['is_deleted']
}
formatted_chats.append(formatted_chat)
return Response({
'code': 200,
'message': '获取成功',
'data': {
'total': len(formatted_chats),
'results': formatted_chats
}
})
except json.JSONDecodeError as e:
logger.error(f"解析响应数据失败: {str(e)}")
return Response({
'code': 500,
'message': '解析响应数据失败',
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except Exception as e:
logger.error(f"获取对话列表失败: {str(e)}")
logger.error(traceback.format_exc())
return Response({
'code': 500,
'message': f'获取对话列表失败: {str(e)}',
'data': None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def _highlight_keyword(self, text, keyword): def _highlight_keyword(self, text, keyword):
"""高亮关键词""" """高亮关键词"""