错题处理失败时直接显示具体错误信息。

This commit is contained in:
dekun
2026-06-28 13:54:43 +08:00
parent a2a6d59f7c
commit a145f38606
9 changed files with 159 additions and 106 deletions
+1
View File
@@ -133,6 +133,7 @@ class WrongQuestion(Base):
solution_text: Mapped[str | None] = mapped_column(Text, nullable=True)
mark_regions_json: Mapped[str | None] = mapped_column(Text, nullable=True)
annotated_image_path: Mapped[str | None] = mapped_column(String(512), nullable=True)
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
status: Mapped[WrongQuestionStatus] = mapped_column(
Enum(WrongQuestionStatus), default=WrongQuestionStatus.pending
)
+22 -7
View File
@@ -19,6 +19,13 @@ from app.services.student_access import get_student_for_user
router = APIRouter(tags=["wrong_questions"])
def _short_error(exc: BaseException, prefix: str = "") -> str:
msg = str(exc).strip() or type(exc).__name__
if len(msg) > 500:
msg = msg[:500] + ""
return f"{prefix}{msg}" if prefix else msg
def _parse_mark_regions(raw: str | None) -> list[dict] | None:
if not raw:
return None
@@ -43,6 +50,7 @@ def _wq_to_out(wq: WrongQuestion) -> WrongQuestionOut:
solution_text=wq.solution_text,
mark_regions=_parse_mark_regions(wq.mark_regions_json),
has_annotated_image=bool(wq.annotated_image_path),
error_message=wq.error_message,
status=wq.status,
created_at=wq.created_at,
)
@@ -74,6 +82,7 @@ async def _run_ai_pipeline(wq: WrongQuestion, db: Session, ocr_lines: list[dict]
wq.solution_approach = approach
wq.solution_text = solution_body if approach else solution_full
wq.status = WrongQuestionStatus.solved
wq.error_message = None
def _process_wrong_question(question_id: uuid.UUID):
@@ -88,22 +97,26 @@ def _process_wrong_question(question_id: uuid.UUID):
if wq is None:
return
wq.error_message = None
image_full = Path(settings.UPLOAD_DIR) / wq.image_path
try:
ocr_result = ocr_service.run_ocr_with_regions(str(image_full))
ocr_text = ocr_result["text"]
ocr_lines = ocr_result["lines"]
wq.ocr_raw_text = ocr_text or None
wq.status = WrongQuestionStatus.ocr_done if ocr_text else WrongQuestionStatus.failed
if not ocr_text:
wq.status = WrongQuestionStatus.failed
wq.error_message = "OCR 未识别到文字,请拍摄更清晰、光线充足的题目照片"
db.commit()
return
wq.status = WrongQuestionStatus.ocr_done
db.commit()
except Exception:
except Exception as exc:
wq.status = WrongQuestionStatus.failed
wq.error_message = _short_error(exc, "OCR 识别失败:")
db.commit()
return
if not ocr_text:
return
import asyncio
loop = asyncio.new_event_loop()
@@ -111,8 +124,9 @@ def _process_wrong_question(question_id: uuid.UUID):
try:
loop.run_until_complete(_run_ai_pipeline(wq, db, ocr_lines, ocr_text))
db.commit()
except Exception:
wq.status = WrongQuestionStatus.ocr_done
except Exception as exc:
wq.status = WrongQuestionStatus.failed
wq.error_message = _short_error(exc, "AI 处理失败:")
db.commit()
finally:
loop.close()
@@ -293,6 +307,7 @@ def retry_ocr(
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="错题不存在")
wq.status = WrongQuestionStatus.pending
wq.error_message = None
db.commit()
background_tasks.add_task(_process_wrong_question, wq.id)
return _wq_to_out(wq)
+1
View File
@@ -237,6 +237,7 @@ class WrongQuestionOut(BaseModel):
solution_text: str | None
mark_regions: list[dict] | None = None
has_annotated_image: bool = False
error_message: str | None = None
status: WrongQuestionStatusEnum
created_at: datetime
+2
View File
@@ -75,6 +75,8 @@ def run_migrations() -> None:
wq_alters.append("ADD COLUMN mark_regions_json TEXT")
if "annotated_image_path" not in wq_columns:
wq_alters.append("ADD COLUMN annotated_image_path VARCHAR(512)")
if "error_message" not in wq_columns:
wq_alters.append("ADD COLUMN error_message TEXT")
if wq_alters:
with engine.begin() as conn:
for clause in wq_alters: