2025-05-07 22:24:02 +08:00
|
|
|
|
# apps/common/services/chat_service.py
|
|
|
|
|
import logging
|
|
|
|
|
import json
|
|
|
|
|
from uuid import uuid4
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
from apps.accounts.models import User
|
|
|
|
|
from apps.knowledge_base.models import KnowledgeBase
|
|
|
|
|
from apps.chat.models import ChatHistory
|
|
|
|
|
from apps.permissions.services.permission_service import KnowledgeBasePermissionMixin
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
class ChatService(KnowledgeBasePermissionMixin):
|
|
|
|
|
@transaction.atomic
|
|
|
|
|
def create_chat_record(self, user, data, conversation_id=None):
|
|
|
|
|
"""创建聊天记录,供chat、gmail、feishu模块复用"""
|
|
|
|
|
try:
|
|
|
|
|
# 验证必填字段
|
|
|
|
|
if 'question' not in data:
|
|
|
|
|
raise ValueError("缺少必填字段: question")
|
|
|
|
|
|
|
|
|
|
# 如果未提供conversation_id,生成新的
|
|
|
|
|
if not conversation_id:
|
|
|
|
|
conversation_id = str(uuid4())
|
|
|
|
|
logger.info(f"生成新的会话ID: {conversation_id}")
|
|
|
|
|
|
|
|
|
|
# 处理知识库ID
|
|
|
|
|
dataset_ids = []
|
|
|
|
|
if 'dataset_id' in data:
|
|
|
|
|
dataset_ids.append(str(data['dataset_id']))
|
|
|
|
|
elif 'dataset_id_list' in data:
|
|
|
|
|
if isinstance(data['dataset_id_list'], str):
|
|
|
|
|
try:
|
|
|
|
|
dataset_list = json.loads(data['dataset_id_list'])
|
|
|
|
|
dataset_ids = [str(id) for id in dataset_list if isinstance(dataset_list, list)]
|
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
|
dataset_ids = [str(data['dataset_id_list'])]
|
|
|
|
|
else:
|
|
|
|
|
dataset_ids = [str(id) for id in data['dataset_id_list']]
|
|
|
|
|
|
|
|
|
|
if not dataset_ids:
|
|
|
|
|
raise ValueError("缺少必填字段: dataset_id 或 dataset_id_list")
|
|
|
|
|
|
|
|
|
|
# 验证知识库权限
|
|
|
|
|
knowledge_bases = []
|
|
|
|
|
external_id_list = []
|
|
|
|
|
for kb_id in dataset_ids:
|
|
|
|
|
knowledge_base = KnowledgeBase.objects.filter(id=kb_id).first()
|
|
|
|
|
if not knowledge_base:
|
|
|
|
|
raise ValueError(f"知识库不存在: {kb_id}")
|
|
|
|
|
|
|
|
|
|
if not self.check_knowledge_base_permission(knowledge_base, user, 'read'):
|
|
|
|
|
raise ValueError(f"无权访问知识库: {knowledge_base.name}")
|
|
|
|
|
|
|
|
|
|
knowledge_bases.append(knowledge_base)
|
|
|
|
|
if knowledge_base.external_id:
|
|
|
|
|
external_id_list.append(str(knowledge_base.external_id))
|
|
|
|
|
|
|
|
|
|
# 创建metadata
|
|
|
|
|
metadata = {
|
|
|
|
|
'model_id': data.get('model_id', '7a214d0e-e65e-11ef-9f4a-0242ac120006'),
|
|
|
|
|
'dataset_id_list': dataset_ids,
|
|
|
|
|
'dataset_external_id_list': external_id_list,
|
|
|
|
|
'dataset_names': [kb.name for kb in knowledge_bases]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 设置标题
|
|
|
|
|
title = data.get('title', 'New chat')
|
|
|
|
|
|
|
|
|
|
# 创建用户问题记录
|
|
|
|
|
question_record = ChatHistory.objects.create(
|
|
|
|
|
user=user,
|
|
|
|
|
knowledge_base=knowledge_bases[0], # 使用第一个知识库
|
|
|
|
|
conversation_id=conversation_id,
|
|
|
|
|
title=title,
|
|
|
|
|
role='user',
|
|
|
|
|
content=data['question'],
|
|
|
|
|
metadata=metadata
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return question_record, conversation_id, metadata, knowledge_bases, external_id_list
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"创建聊天记录失败: {str(e)}")
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
def get_conversation_detail(self, user, conversation_id):
|
|
|
|
|
"""获取会话详情,供chat、gmail、feishu模块复用"""
|
|
|
|
|
try:
|
|
|
|
|
# 获取用户有权限的知识库ID
|
|
|
|
|
accessible_kb_ids = [
|
|
|
|
|
kb.id for kb in KnowledgeBase.objects.all()
|
|
|
|
|
if self.check_knowledge_base_permission(kb, user, 'read')
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# 查询会话记录
|
|
|
|
|
messages = ChatHistory.objects.filter(
|
|
|
|
|
conversation_id=conversation_id,
|
|
|
|
|
is_deleted=False
|
|
|
|
|
).filter(
|
|
|
|
|
Q(user=user) | Q(knowledge_base_id__in=accessible_kb_ids)
|
|
|
|
|
).order_by('created_at')
|
|
|
|
|
|
|
|
|
|
if not messages.exists():
|
|
|
|
|
raise ValueError("对话不存在或无权限")
|
|
|
|
|
|
|
|
|
|
# 获取知识库信息
|
|
|
|
|
first_message = messages.first()
|
|
|
|
|
dataset_info = []
|
|
|
|
|
if first_message and first_message.metadata and 'dataset_id_list' in first_message.metadata:
|
|
|
|
|
datasets = KnowledgeBase.objects.filter(id__in=first_message.metadata['dataset_id_list'])
|
|
|
|
|
accessible_datasets = [
|
|
|
|
|
ds for ds in datasets if self.check_knowledge_base_permission(ds, user, 'read')
|
|
|
|
|
]
|
|
|
|
|
dataset_info = [
|
|
|
|
|
{'id': str(ds.id), 'name': ds.name, 'type': ds.type}
|
|
|
|
|
for ds in accessible_datasets
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# 构建消息列表
|
|
|
|
|
message_list = [
|
|
|
|
|
{
|
|
|
|
|
'id': str(msg.id),
|
|
|
|
|
'parent_id': msg.parent_id,
|
|
|
|
|
'role': msg.role,
|
|
|
|
|
'content': msg.content,
|
|
|
|
|
'created_at': msg.created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
|
|
|
|
'metadata': msg.metadata
|
|
|
|
|
}
|
|
|
|
|
for msg in messages
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
'conversation_id': conversation_id,
|
|
|
|
|
'datasets': dataset_info,
|
|
|
|
|
'messages': message_list
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"获取会话详情失败: {str(e)}")
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|