""" 能力评估服务 用于分析用户对话数据,生成能力评估报告和课程推荐 使用 Python 原生实现 """ import json import logging from typing import Dict, Any, List, Literal from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.models.ability import AbilityAssessment from app.services.ai import ability_analysis_service logger = logging.getLogger(__name__) class AbilityAssessmentService: """能力评估服务类""" async def analyze_yanji_conversations( self, user_id: int, phone: str, db: AsyncSession, yanji_service, engine: Literal["v2"] = "v2" ) -> Dict[str, Any]: """ 分析言迹对话并生成能力评估及课程推荐 Args: user_id: 用户ID phone: 用户手机号(用于获取言迹数据) db: 数据库会话 yanji_service: 言迹服务实例 engine: 引擎类型(v2=Python原生) Returns: 评估结果字典,包含: - assessment_id: 评估记录ID - total_score: 综合评分 - dimensions: 能力维度列表 - recommended_courses: 推荐课程列表 - conversation_count: 分析的对话数量 Raises: ValueError: 未找到员工的录音记录 Exception: API调用失败或其他错误 """ logger.info(f"开始分析言迹对话: user_id={user_id}, phone={phone}, engine={engine}") # 1. 获取员工对话数据(最多10条录音) conversations = await yanji_service.get_employee_conversations_for_analysis( phone=phone, limit=10 ) if not conversations: logger.warning(f"未找到员工的录音记录: user_id={user_id}, phone={phone}") raise ValueError("未找到该员工的录音记录") # 2. 合并所有对话历史 all_dialogues = [] for conv in conversations: all_dialogues.extend(conv['dialogue_history']) logger.info( f"准备分析: user_id={user_id}, " f"对话数={len(conversations)}, " f"总轮次={len(all_dialogues)}" ) used_engine = "v2" # Python 原生实现 logger.info(f"调用原生能力分析服务") # 将对话历史格式化为文本 dialogue_text = self._format_dialogues_for_analysis(all_dialogues) # 调用原生服务 result = await ability_analysis_service.analyze( db=db, user_id=user_id, dialogue_history=dialogue_text ) if not result.success: raise Exception(f"能力分析失败: {result.error}") # 转换为兼容格式 analysis_result = { "analysis": { "total_score": result.total_score, "ability_dimensions": [ {"name": d.name, "score": d.score, "feedback": d.feedback} for d in result.ability_dimensions ], "course_recommendations": [ { "course_id": c.course_id, "course_name": c.course_name, "recommendation_reason": c.recommendation_reason, "priority": c.priority, "match_score": c.match_score, } for c in result.course_recommendations ] } } logger.info( f"能力分析完成 - total_score: {result.total_score}, " f"provider: {result.ai_provider}, latency: {result.ai_latency_ms}ms" ) # 4. 提取结果 analysis = analysis_result.get('analysis', {}) ability_dims = analysis.get('ability_dimensions', []) course_recs = analysis.get('course_recommendations', []) total_score = analysis.get('total_score') logger.info( f"分析完成 (engine={used_engine}): total_score={total_score}, " f"dimensions={len(ability_dims)}, courses={len(course_recs)}" ) # 5. 保存能力评估记录到数据库 assessment = AbilityAssessment( user_id=user_id, source_type='yanji_badge', source_id=','.join([str(c['audio_id']) for c in conversations]), total_score=total_score, ability_dimensions=ability_dims, recommended_courses=course_recs, conversation_count=len(conversations) ) db.add(assessment) await db.commit() await db.refresh(assessment) logger.info( f"评估记录已保存: assessment_id={assessment.id}, " f"user_id={user_id}, total_score={total_score}" ) # 6. 返回评估结果 return { "assessment_id": assessment.id, "total_score": total_score, "dimensions": ability_dims, "recommended_courses": course_recs, "conversation_count": len(conversations), "analyzed_at": assessment.analyzed_at, "engine": used_engine, } def _format_dialogues_for_analysis(self, dialogues: List[Dict[str, Any]]) -> str: """ 将对话历史列表格式化为文本 Args: dialogues: 对话历史列表,每项包含 speaker, content 等字段 Returns: 格式化后的对话文本 """ lines = [] for i, d in enumerate(dialogues, 1): speaker = d.get('speaker', 'unknown') content = d.get('content', '') # 统一说话者标识 if speaker in ['consultant', 'employee', 'user', '员工']: speaker_label = '员工' elif speaker in ['customer', 'client', '顾客', '客户']: speaker_label = '顾客' else: speaker_label = speaker lines.append(f"[{i}] {speaker_label}: {content}") return '\n'.join(lines) async def get_user_assessment_history( self, user_id: int, db: AsyncSession, limit: int = 10 ) -> List[Dict[str, Any]]: """ 获取用户的能力评估历史记录 Args: user_id: 用户ID db: 数据库会话 limit: 返回记录数量限制 Returns: 评估历史记录列表 """ stmt = ( select(AbilityAssessment) .where(AbilityAssessment.user_id == user_id) .order_by(AbilityAssessment.analyzed_at.desc()) .limit(limit) ) result = await db.execute(stmt) assessments = result.scalars().all() history = [] for assessment in assessments: history.append({ "id": assessment.id, "source_type": assessment.source_type, "total_score": assessment.total_score, "ability_dimensions": assessment.ability_dimensions, "recommended_courses": assessment.recommended_courses, "conversation_count": assessment.conversation_count, "analyzed_at": assessment.analyzed_at.isoformat() if assessment.analyzed_at else None, "created_at": assessment.created_at.isoformat() if assessment.created_at else None }) logger.info(f"获取评估历史: user_id={user_id}, count={len(history)}") return history async def get_assessment_detail( self, assessment_id: int, db: AsyncSession ) -> Dict[str, Any]: """ 获取单个评估记录的详细信息 Args: assessment_id: 评估记录ID db: 数据库会话 Returns: 评估详细信息 Raises: ValueError: 评估记录不存在 """ stmt = select(AbilityAssessment).where(AbilityAssessment.id == assessment_id) result = await db.execute(stmt) assessment = result.scalar_one_or_none() if not assessment: raise ValueError(f"评估记录不存在: assessment_id={assessment_id}") return { "id": assessment.id, "user_id": assessment.user_id, "source_type": assessment.source_type, "source_id": assessment.source_id, "total_score": assessment.total_score, "ability_dimensions": assessment.ability_dimensions, "recommended_courses": assessment.recommended_courses, "conversation_count": assessment.conversation_count, "analyzed_at": assessment.analyzed_at.isoformat() if assessment.analyzed_at else None, "created_at": assessment.created_at.isoformat() if assessment.created_at else None } def get_ability_assessment_service() -> AbilityAssessmentService: """获取能力评估服务实例(依赖注入)""" return AbilityAssessmentService()