Files
012-kaopeilian/backend/app/services/coze_service.py
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

200 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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