From c709360c7c62f49375371613d86605b9874acc14 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 3 Jul 2026 12:03:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(server-release):=20=E5=87=BA=E9=A2=98?= =?UTF-8?q?=E6=89=B9=E9=98=85=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20=E2=80=94=20=E7=A7=BB=E9=99=A420=E9=A2=98=E9=99=90?= =?UTF-8?q?=E5=88=B6=E3=80=81max=5Ftotal=E6=94=AF=E6=8C=81=E3=80=81?= =?UTF-8?q?=E5=A1=AB=E7=A9=BA=E9=A2=98=E6=A0=BC=E5=BC=8F=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E3=80=81=E4=BF=AE=E6=AD=A3=E8=AE=A4=E8=AF=81=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - exam_pkg/api.py: 移除总题数20道上限,改为50道警告;修正认证错误使用正确的UNAUTHORIZED/FORBIDDEN状态码;端点保持同步模式 - exam_pkg/generator.py: AI智能出题prompt支持max_total参数 - exam_pkg/grader.py: 填空题增加学生答案格式校验(列表类型+字符串元素) --- exam_pkg/api.py | 21 +++++++++++---------- exam_pkg/generator.py | 2 +- exam_pkg/grader.py | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/exam_pkg/api.py b/exam_pkg/api.py index d05f3e9..623c90d 100644 --- a/exam_pkg/api.py +++ b/exam_pkg/api.py @@ -29,7 +29,7 @@ from auth.gateway import ( ) # 导入统一响应格式 -from core.status_codes import EXAM_SUCCESS, GRADE_SUCCESS, EXAM_ERROR, GRADE_ERROR, BAD_REQUEST, NO_CONTENT, LLM_ERROR +from core.status_codes import EXAM_SUCCESS, GRADE_SUCCESS, EXAM_ERROR, GRADE_ERROR, BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NO_CONTENT, LLM_ERROR from api.response_utils import success_response, error_response # 合法题型 @@ -152,13 +152,14 @@ def api_generate_questions(): if diff_error: return error_response("INVALID_PARAMS", BAD_REQUEST, diff_error, http_status=400) - # 校验总题数上限 - MAX_TOTAL_QUESTIONS = 20 + # 校验总题数(不设上限,但提醒用户大量出题可能影响性能) total_requested = sum(question_types.values()) - if total_requested > MAX_TOTAL_QUESTIONS: + if total_requested <= 0: return error_response("INVALID_PARAMS", BAD_REQUEST, - f"总题数不能超过 {MAX_TOTAL_QUESTIONS} 道,当前请求 {total_requested} 道", + "总题数必须大于0", http_status=400) + if total_requested > 50: + logger.warning(f"[出题] 请求生成 {total_requested} 道题,可能影响性能") # 校验排除题干列表(可选) exclude_stems = data.get('exclude_stems') @@ -169,7 +170,7 @@ def api_generate_questions(): # 获取当前用户 user = get_current_user() if not user: - return error_response("UNAUTHORIZED", BAD_REQUEST, "未认证", http_status=401) + return error_response("UNAUTHORIZED", UNAUTHORIZED, "未认证", http_status=401) # 检查向量库访问权限 if not check_collection_permission( @@ -178,9 +179,9 @@ def api_generate_questions(): collection_name=collection, operation="read" ): - return error_response("FORBIDDEN", BAD_REQUEST, "权限不足", http_status=403) + return error_response("FORBIDDEN", FORBIDDEN, "权限不足", http_status=403) - # 调用新版出题接口 + # 调用新版出题接口(同步) result = generate_questions_from_file( file_path=file_path, collection=collection, @@ -251,7 +252,7 @@ def api_generate_smart(): # 获取当前用户 user = get_current_user() if not user: - return error_response("UNAUTHORIZED", BAD_REQUEST, "未认证", http_status=401) + return error_response("UNAUTHORIZED", UNAUTHORIZED, "未认证", http_status=401) # 检查向量库访问权限 if not check_collection_permission( @@ -260,7 +261,7 @@ def api_generate_smart(): collection_name=collection, operation="read" ): - return error_response("FORBIDDEN", BAD_REQUEST, "权限不足", http_status=403) + return error_response("FORBIDDEN", FORBIDDEN, "权限不足", http_status=403) # 1. 调用 AI 分析文件,获取推荐的题型和数量 from exam_pkg.manager import analyze_file_for_exam diff --git a/exam_pkg/generator.py b/exam_pkg/generator.py index eda54c6..7b3d5e4 100644 --- a/exam_pkg/generator.py +++ b/exam_pkg/generator.py @@ -1055,7 +1055,7 @@ def analyze_document_for_exam(chunks: List[Dict], max_total: int = None) -> Dict 注意: - 不适合的题型数量设为 0 -- 所有数量之和不要超过 {min(total_knowledge_points * 2, 20)} +- 所有数量之和不要超过 {min(total_knowledge_points * 2, max_total if max_total else 20)} - 必须返回合法 JSON,不要有其他内容 请直接输出 JSON:""" diff --git a/exam_pkg/grader.py b/exam_pkg/grader.py index 18f0e1b..e4bd05b 100644 --- a/exam_pkg/grader.py +++ b/exam_pkg/grader.py @@ -219,6 +219,29 @@ def grade_fill_blank(answer: Dict) -> Dict: student_answers = answer.get('student_answer', []) max_score = answer.get('max_score', 4.0) + # 校验学生答案格式(必须是列表) + if not isinstance(student_answers, list): + logger.warning(f"填空题学生答案格式错误: 期望列表,实际为 {type(student_answers).__name__}: {student_answers}") + return { + "question_id": answer.get('question_id'), + "score": 0, + "max_score": max_score, + "grading_status": "failed", + "details": {"error": f"学生答案格式错误,期望列表,实际为 {type(student_answers).__name__}"} + } + + # 校验学生答案列表中的每个元素必须是字符串 + for i, ans in enumerate(student_answers): + if not isinstance(ans, str): + logger.warning(f"填空题学生答案第 {i+1} 项格式错误: 期望字符串,实际为 {type(ans).__name__}: {ans}") + return { + "question_id": answer.get('question_id'), + "score": 0, + "max_score": max_score, + "grading_status": "failed", + "details": {"error": f"填空题学生答案第 {i+1} 项格式错误,期望字符串,实际为 {type(ans).__name__}"} + } + # 归一化答案格式(修复 LLM 生成的扁平数组问题) blank_count = question_content.get('data', {}).get('blank_count', 0) correct_answers = _normalize_fill_blank_answer(correct_answers, blank_count)