作业帮式错题标注:OCR 定位错误红框 + 解题思路。
- PaddleOCR 行级坐标 + AI 识别错答区域,生成标注图 - 解法拆分为「解题思路」与「详细解答」 - 详情页标注图/原图切换,列表显示标注缩略图
This commit is contained in:
+51
-10
@@ -1,5 +1,7 @@
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
_ocr_engine = None
|
||||
@@ -14,18 +16,52 @@ def get_ocr_engine():
|
||||
return _ocr_engine
|
||||
|
||||
|
||||
def run_ocr(image_path: str) -> str:
|
||||
def _bbox_from_box(box: list) -> list[float]:
|
||||
xs = [float(p[0]) for p in box]
|
||||
ys = [float(p[1]) for p in box]
|
||||
return [min(xs), min(ys), max(xs), max(ys)]
|
||||
|
||||
|
||||
def run_ocr_with_regions(image_path: str) -> dict:
|
||||
"""Return OCR text plus line-level bounding boxes for annotation."""
|
||||
engine = get_ocr_engine()
|
||||
result = engine.ocr(image_path, cls=True)
|
||||
if not result or not result[0]:
|
||||
return ""
|
||||
lines = []
|
||||
for line in result[0]:
|
||||
if line and len(line) >= 2:
|
||||
text = line[1][0]
|
||||
if text:
|
||||
lines.append(text)
|
||||
return "\n".join(lines)
|
||||
lines: list[dict] = []
|
||||
if result and result[0]:
|
||||
for item in result[0]:
|
||||
if not item or len(item) < 2:
|
||||
continue
|
||||
box, rec = item[0], item[1]
|
||||
text = rec[0] if rec else ""
|
||||
conf = float(rec[1]) if rec and len(rec) > 1 else 0.0
|
||||
if not text:
|
||||
continue
|
||||
lines.append(
|
||||
{
|
||||
"text": text,
|
||||
"confidence": conf,
|
||||
"box": box,
|
||||
"bbox": _bbox_from_box(box),
|
||||
}
|
||||
)
|
||||
|
||||
width, height = 0, 0
|
||||
try:
|
||||
with Image.open(image_path) as img:
|
||||
width, height = img.size
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return {
|
||||
"text": "\n".join(line["text"] for line in lines),
|
||||
"lines": lines,
|
||||
"width": width,
|
||||
"height": height,
|
||||
}
|
||||
|
||||
|
||||
def run_ocr(image_path: str) -> str:
|
||||
return run_ocr_with_regions(image_path)["text"]
|
||||
|
||||
|
||||
def save_upload_file(user_id: str, question_id: str, filename: str, content: bytes) -> str:
|
||||
@@ -38,3 +74,8 @@ def save_upload_file(user_id: str, question_id: str, filename: str, content: byt
|
||||
full_path = Path(settings.UPLOAD_DIR) / rel_path
|
||||
full_path.write_bytes(content)
|
||||
return rel_path
|
||||
|
||||
|
||||
def annotated_rel_path(original_rel: str) -> str:
|
||||
p = Path(original_rel)
|
||||
return str(p.parent / f"{p.stem}_marked.jpg")
|
||||
|
||||
Reference in New Issue
Block a user