142 lines
5.6 KiB
Python
142 lines
5.6 KiB
Python
# 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
|
||
|