Some checks failed
continuous-integration/drone/push Build is failing
更新内容: - 后端 AI 服务优化(能力分析、知识点解析等) - 前端考试和陪练界面更新 - 修复多个 prompt 和 JSON 解析问题 - 更新 Coze 语音客户端
318 lines
14 KiB
Python
318 lines
14 KiB
Python
"""
|
||
考试相关的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")
|
||
round: int = Field(1, description="考试轮次(1/2/3)")
|
||
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="是否为最终轮次(如果是,则同时更新总分和状态)")
|