""" 考试相关的Schema定义 """ from typing import List, Optional, Dict, Any from datetime import datetime from pydantic import BaseModel, Field class StartExamRequest(BaseModel): """开始考试请求""" course_id: int = Field(..., description="课程ID") count: int = Field(10, ge=1, le=100, description="题目数量") class StartExamResponse(BaseModel): """开始考试响应""" exam_id: int = Field(..., description="考试ID") class ExamAnswer(BaseModel): """考试答案""" question_id: str = Field(..., description="题目ID") answer: str = Field(..., description="答案") class SubmitExamRequest(BaseModel): """提交考试请求""" exam_id: int = Field(..., description="考试ID") answers: List[ExamAnswer] = Field(..., description="答案列表") class SubmitExamResponse(BaseModel): """提交考试响应""" exam_id: int = Field(..., description="考试ID") total_score: float = Field(..., description="总分") pass_score: float = Field(..., description="及格分") is_passed: bool = Field(..., description="是否通过") correct_count: int = Field(..., description="正确题数") total_count: int = Field(..., description="总题数") accuracy: float = Field(..., description="正确率") class QuestionInfo(BaseModel): """题目信息""" id: str = Field(..., description="题目ID") type: str = Field(..., description="题目类型") title: str = Field(..., description="题目标题") content: Optional[str] = Field(None, description="题目内容") options: Optional[Dict[str, Any]] = Field(None, description="选项") score: float = Field(..., description="分值") class ExamResultInfo(BaseModel): """答题结果信息""" question_id: int = Field(..., description="题目ID") user_answer: Optional[str] = Field(None, description="用户答案") is_correct: bool = Field(..., description="是否正确") score: float = Field(..., description="得分") class ExamDetailResponse(BaseModel): """考试详情响应""" id: int = Field(..., description="考试ID") course_id: int = Field(..., description="课程ID") exam_name: str = Field(..., description="考试名称") question_count: int = Field(..., description="题目数量") total_score: float = Field(..., description="总分") pass_score: float = Field(..., description="及格分") start_time: Optional[str] = Field(None, description="开始时间") end_time: Optional[str] = Field(None, description="结束时间") duration_minutes: int = Field(..., description="考试时长(分钟)") status: str = Field(..., description="考试状态") score: Optional[float] = Field(None, description="得分") is_passed: Optional[bool] = Field(None, description="是否通过") questions: Optional[Dict[str, Any]] = Field(None, description="题目数据") results: Optional[List[ExamResultInfo]] = Field(None, description="答题结果") answers: Optional[Dict[str, Any]] = Field(None, description="用户答案") class ExamRecordInfo(BaseModel): """考试记录信息""" id: int = Field(..., description="考试ID") course_id: int = Field(..., description="课程ID") exam_name: str = Field(..., description="考试名称") question_count: int = Field(..., description="题目数量") total_score: float = Field(..., description="总分") score: Optional[float] = Field(None, description="得分") is_passed: Optional[bool] = Field(None, description="是否通过") status: str = Field(..., description="考试状态") start_time: Optional[str] = Field(None, description="开始时间") end_time: Optional[str] = Field(None, description="结束时间") created_at: str = Field(..., description="创建时间") # 新增统计字段 accuracy: Optional[float] = Field(None, description="正确率(%)") correct_count: Optional[int] = Field(None, description="正确题数") wrong_count: Optional[int] = Field(None, description="错题数") duration_seconds: Optional[int] = Field(None, description="考试用时(秒)") course_name: Optional[str] = Field(None, description="课程名称") question_type_stats: Optional[List[Dict[str, Any]]] = Field(None, description="分题型统计") class ExamRecordResponse(BaseModel): """考试记录列表响应""" items: List[ExamRecordInfo] = Field(..., description="考试记录列表") total: int = Field(..., description="总数") page: int = Field(..., description="当前页") size: int = Field(..., description="每页数量") pages: int = Field(..., description="总页数") # ==================== AI服务响应Schema ==================== class MistakeRecord(BaseModel): """错题记录详情""" question_id: Optional[int] = Field(None, description="题目ID") knowledge_point_id: Optional[int] = Field(None, description="知识点ID") question_content: str = Field(..., description="题目内容") correct_answer: str = Field(..., description="正确答案") user_answer: str = Field(..., description="用户答案") class GenerateExamRequest(BaseModel): """生成考试试题请求""" course_id: int = Field(..., description="课程ID") position_id: Optional[int] = Field(None, description="岗位ID,如果不提供则从用户信息中自动获取") current_round: int = Field(1, ge=1, le=3, description="当前轮次(1/2/3)") exam_id: Optional[int] = Field(None, description="已存在的exam_id(第2、3轮传入)") mistake_records: Optional[str] = Field(None, description="错题记录JSON字符串,第一轮不传此参数,第二三轮传入上一轮错题的JSON字符串") single_choice_count: int = Field(4, ge=0, le=50, description="单选题数量") multiple_choice_count: int = Field(2, ge=0, le=30, description="多选题数量") true_false_count: int = Field(1, ge=0, le=20, description="判断题数量") fill_blank_count: int = Field(2, ge=0, le=10, description="填空题数量") essay_count: int = Field(1, ge=0, le=10, description="问答题数量") difficulty_level: int = Field(3, ge=1, le=5, description="难度系数(1-5)") class GenerateExamResponse(BaseModel): """生成考试试题响应""" result: str = Field(..., description="试题JSON数组(字符串格式)") workflow_run_id: Optional[str] = Field(None, description="AI服务调用ID") task_id: Optional[str] = Field(None, description="任务ID") exam_id: int = Field(..., description="考试ID(真实的数据库ID)") class JudgeAnswerRequest(BaseModel): """判断主观题答案请求""" question: str = Field(..., description="题目内容") correct_answer: str = Field(..., description="标准答案") user_answer: str = Field(..., description="用户提交的答案") analysis: str = Field(..., description="正确答案的解析(来源于试题生成器)") class JudgeAnswerResponse(BaseModel): """判断主观题答案响应""" is_correct: bool = Field(..., description="是否正确") correct_answer: str = Field(..., description="标准答案") feedback: Optional[str] = Field(None, description="判断反馈信息") class RecordMistakeRequest(BaseModel): """记录错题请求""" exam_id: int = Field(..., description="考试ID") question_id: Optional[int] = Field(None, description="题目ID(AI生成的题目可能为空)") knowledge_point_id: Optional[int] = Field(None, description="知识点ID") question_content: str = Field(..., description="题目内容") correct_answer: str = Field(..., description="正确答案") user_answer: str = Field(..., description="用户答案") question_type: Optional[str] = Field(None, description="题型(single/multiple/judge/blank/essay)") class RecordMistakeResponse(BaseModel): """记录错题响应""" id: int = Field(..., description="错题记录ID") created_at: datetime = Field(..., description="创建时间") class MistakeRecordItem(BaseModel): """错题记录项""" id: int = Field(..., description="错题记录ID") question_id: Optional[int] = Field(None, description="题目ID") knowledge_point_id: Optional[int] = Field(None, description="知识点ID") question_content: str = Field(..., description="题目内容") correct_answer: str = Field(..., description="正确答案") user_answer: str = Field(..., description="用户答案") created_at: datetime = Field(..., description="创建时间") class GetMistakesResponse(BaseModel): """获取错题记录响应""" mistakes: List[MistakeRecordItem] = Field(..., description="错题列表") # ==================== 成绩报告和错题本相关Schema ==================== class RoundScores(BaseModel): """三轮得分""" round1: Optional[float] = Field(None, description="第一轮得分") round2: Optional[float] = Field(None, description="第二轮得分") round3: Optional[float] = Field(None, description="第三轮得分") class ExamReportOverview(BaseModel): """成绩报告概览""" avg_score: float = Field(..., description="平均成绩(基于round1_score)") total_exams: int = Field(..., description="考试总数") pass_rate: float = Field(..., description="及格率") total_questions: int = Field(..., description="答题总数") class ExamTrendItem(BaseModel): """成绩趋势项""" date: str = Field(..., description="日期(YYYY-MM-DD)") avg_score: float = Field(..., description="平均分") class SubjectStatItem(BaseModel): """科目统计项""" course_id: int = Field(..., description="课程ID") course_name: str = Field(..., description="课程名称") avg_score: float = Field(..., description="平均分") exam_count: int = Field(..., description="考试次数") max_score: float = Field(..., description="最高分") min_score: float = Field(..., description="最低分") pass_rate: float = Field(..., description="及格率") class RecentExamItem(BaseModel): """最近考试记录项""" id: int = Field(..., description="考试ID") course_id: int = Field(..., description="课程ID") course_name: str = Field(..., description="课程名称") score: Optional[float] = Field(None, description="最终得分") total_score: float = Field(..., description="总分") is_passed: Optional[bool] = Field(None, description="是否通过") duration_seconds: Optional[int] = Field(None, description="考试用时(秒)") start_time: str = Field(..., description="开始时间") end_time: Optional[str] = Field(None, description="结束时间") round_scores: RoundScores = Field(..., description="三轮得分") class ExamReportResponse(BaseModel): """成绩报告响应""" overview: ExamReportOverview = Field(..., description="概览数据") trends: List[ExamTrendItem] = Field(..., description="趋势数据") subjects: List[SubjectStatItem] = Field(..., description="科目分析") recent_exams: List[RecentExamItem] = Field(..., description="最近考试记录") class MistakeListItem(BaseModel): """错题列表项""" id: int = Field(..., description="错题记录ID") exam_id: int = Field(..., description="考试ID") course_id: int = Field(..., description="课程ID") course_name: str = Field(..., description="课程名称") question_content: str = Field(..., description="题目内容") correct_answer: str = Field(..., description="正确答案") user_answer: str = Field(..., description="用户答案") question_type: Optional[str] = Field(None, description="题型") knowledge_point_id: Optional[int] = Field(None, description="知识点ID") knowledge_point_name: Optional[str] = Field(None, description="知识点名称") created_at: datetime = Field(..., description="创建时间") class MistakeListResponse(BaseModel): """错题列表响应""" items: List[MistakeListItem] = Field(..., description="错题列表") total: int = Field(..., description="总数") page: int = Field(..., description="当前页") size: int = Field(..., description="每页数量") pages: int = Field(..., description="总页数") class MistakeByCourse(BaseModel): """按课程统计错题""" course_id: int = Field(..., description="课程ID") course_name: str = Field(..., description="课程名称") count: int = Field(..., description="错题数量") class MistakeByType(BaseModel): """按题型统计错题""" type: str = Field(..., description="题型代码") type_name: str = Field(..., description="题型名称") count: int = Field(..., description="错题数量") class MistakeByTime(BaseModel): """按时间统计错题""" week: int = Field(..., description="最近一周") month: int = Field(..., description="最近一月") quarter: int = Field(..., description="最近三月") class MistakesStatisticsResponse(BaseModel): """错题统计响应""" total: int = Field(..., description="错题总数") by_course: List[MistakeByCourse] = Field(..., description="按课程统计") by_type: List[MistakeByType] = Field(..., description="按题型统计") by_time: MistakeByTime = Field(..., description="按时间统计") class UpdateRoundScoreRequest(BaseModel): """更新轮次得分请求""" round: int = Field(..., ge=1, le=3, description="轮次(1/2/3)") score: float = Field(..., ge=0, le=100, description="得分") is_final: bool = Field(False, description="是否为最终轮次(如果是,则同时更新总分和状态)")