# 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