feat: 初始化考培练系统项目
- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
199
backend/app/services/coze_service.py
Normal file
199
backend/app/services/coze_service.py
Normal file
@@ -0,0 +1,199 @@
|
||||
"""
|
||||
Coze AI对话服务
|
||||
"""
|
||||
import logging
|
||||
from typing import Optional
|
||||
from cozepy import Coze, COZE_CN_BASE_URL, Message
|
||||
from cozepy.exception import CozeError, CozeAPIError
|
||||
|
||||
from app.core.config import settings
|
||||
from app.services.ai.coze.client import get_auth_manager
|
||||
|
||||
# 注意:不再直接使用 TokenAuth,统一通过 get_auth_manager() 管理认证
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CozeService:
|
||||
"""Coze对话服务"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化Coze客户端"""
|
||||
if not settings.COZE_PRACTICE_BOT_ID:
|
||||
raise ValueError("COZE_PRACTICE_BOT_ID 未配置")
|
||||
|
||||
self.bot_id = settings.COZE_PRACTICE_BOT_ID
|
||||
self._auth_manager = get_auth_manager()
|
||||
|
||||
logger.info(
|
||||
f"CozeService初始化成功,Bot ID={self.bot_id}, "
|
||||
f"Base URL={COZE_CN_BASE_URL}"
|
||||
)
|
||||
|
||||
@property
|
||||
def client(self) -> Coze:
|
||||
"""获取Coze客户端(每次获取确保OAuth token有效)"""
|
||||
return self._auth_manager.get_client(force_new=True)
|
||||
|
||||
def build_scene_prompt(
|
||||
self,
|
||||
scene_name: str,
|
||||
scene_background: str,
|
||||
scene_ai_role: str,
|
||||
scene_objectives: list,
|
||||
scene_keywords: Optional[list] = None,
|
||||
scene_description: Optional[str] = None,
|
||||
user_message: str = ""
|
||||
) -> str:
|
||||
"""
|
||||
构建场景提示词(Markdown格式)
|
||||
|
||||
参数:
|
||||
scene_name: 场景名称
|
||||
scene_background: 场景背景
|
||||
scene_ai_role: AI角色描述
|
||||
scene_objectives: 练习目标列表
|
||||
scene_keywords: 关键词列表
|
||||
scene_description: 场景描述(可选)
|
||||
user_message: 用户第一句话
|
||||
|
||||
返回:
|
||||
完整的场景提示词(Markdown格式)
|
||||
"""
|
||||
# 构建练习目标
|
||||
objectives_text = "\n".join(
|
||||
f"{i+1}. {obj}" for i, obj in enumerate(scene_objectives)
|
||||
)
|
||||
|
||||
# 构建关键词
|
||||
keywords_text = ", ".join(scene_keywords) if scene_keywords else ""
|
||||
|
||||
# 构建完整提示词
|
||||
prompt = f"""# 陪练场景设定
|
||||
|
||||
## 场景名称
|
||||
{scene_name}
|
||||
"""
|
||||
|
||||
# 添加场景描述(如果有)
|
||||
if scene_description:
|
||||
prompt += f"""
|
||||
## 场景描述
|
||||
{scene_description}
|
||||
"""
|
||||
|
||||
prompt += f"""
|
||||
## 场景背景
|
||||
{scene_background}
|
||||
|
||||
## AI角色要求
|
||||
{scene_ai_role}
|
||||
|
||||
## 练习目标
|
||||
{objectives_text}
|
||||
"""
|
||||
|
||||
# 添加关键词(如果有)
|
||||
if keywords_text:
|
||||
prompt += f"""
|
||||
## 关键词
|
||||
{keywords_text}
|
||||
"""
|
||||
|
||||
prompt += f"""
|
||||
---
|
||||
|
||||
现在开始陪练对话。请你严格按照上述场景设定扮演角色,与学员进行实战对话练习。
|
||||
不要提及"场景设定"或"角色扮演"等元信息,直接进入角色开始对话。
|
||||
|
||||
学员的第一句话:{user_message}
|
||||
"""
|
||||
|
||||
return prompt
|
||||
|
||||
def create_stream_chat(
|
||||
self,
|
||||
user_id: str,
|
||||
message: str,
|
||||
conversation_id: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
创建流式对话
|
||||
|
||||
参数:
|
||||
user_id: 用户ID
|
||||
message: 消息内容
|
||||
conversation_id: 对话ID(续接对话时使用)
|
||||
|
||||
返回:
|
||||
Coze流式对话迭代器
|
||||
"""
|
||||
try:
|
||||
logger.info(
|
||||
f"创建Coze流式对话,user_id={user_id}, "
|
||||
f"conversation_id={conversation_id}, "
|
||||
f"message_length={len(message)}"
|
||||
)
|
||||
|
||||
stream = self.client.chat.stream(
|
||||
bot_id=self.bot_id,
|
||||
user_id=user_id,
|
||||
additional_messages=[Message.build_user_question_text(message)],
|
||||
conversation_id=conversation_id
|
||||
)
|
||||
|
||||
# 记录LogID用于排查问题
|
||||
if hasattr(stream, 'response') and hasattr(stream.response, 'logid'):
|
||||
logger.info(f"Coze对话创建成功,logid={stream.response.logid}")
|
||||
|
||||
return stream
|
||||
|
||||
except (CozeError, CozeAPIError) as e:
|
||||
logger.error(f"Coze API调用失败: {e}")
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"创建Coze对话失败: {e}")
|
||||
raise
|
||||
|
||||
def cancel_chat(self, conversation_id: str, chat_id: str):
|
||||
"""
|
||||
中断对话
|
||||
|
||||
参数:
|
||||
conversation_id: 对话ID
|
||||
chat_id: 聊天ID
|
||||
"""
|
||||
try:
|
||||
logger.info(f"中断Coze对话,conversation_id={conversation_id}, chat_id={chat_id}")
|
||||
|
||||
result = self.client.chat.cancel(
|
||||
conversation_id=conversation_id,
|
||||
chat_id=chat_id
|
||||
)
|
||||
|
||||
logger.info(f"对话中断成功")
|
||||
return result
|
||||
|
||||
except (CozeError, CozeAPIError) as e:
|
||||
logger.error(f"中断对话失败: {e}")
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"中断对话异常: {e}")
|
||||
raise
|
||||
|
||||
|
||||
# 单例模式
|
||||
_coze_service: Optional[CozeService] = None
|
||||
|
||||
|
||||
def get_coze_service() -> CozeService:
|
||||
"""
|
||||
获取CozeService单例
|
||||
|
||||
用于FastAPI依赖注入
|
||||
"""
|
||||
global _coze_service
|
||||
if _coze_service is None:
|
||||
_coze_service = CozeService()
|
||||
return _coze_service
|
||||
|
||||
Reference in New Issue
Block a user