File size: 1,994 Bytes
a3953cb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""
detect_text.py — POST /detect-text

Runs PaddleOCR on the original image stored by /upload and returns a list
of axis-aligned bounding boxes in original-image pixel coordinates.

Why axis-aligned boxes, not raw quads?
---------------------------------------
PaddleOCR returns rotated quadrilaterals (4 corner points per region).
Converting to the minimum enclosing axis-aligned rect (min/max of the 4 x
and y values) allows mask_service.build_masks() to rasterize them with zero
changes — it already accepts {"x", "y", "width", "height"} dicts.  The
slight extra background at rotated-text corners is absorbed by the dilation
and feathering steps, so the composite seam is invisible.

Zero detections is not an error
---------------------------------
If OCR finds no text, {"boxes": []} is returned with HTTP 200.  The frontend
displays a "nothing detected" hint; the user can still paint manually.
"""

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

from app.jobs_store import get_job
from app.services.ocr_service import detect_text_regions

router = APIRouter()


class DetectTextRequest(BaseModel):
    job_id: str


@router.post("")
def detect_text(body: DetectTextRequest) -> dict:
    """Run OCR on the uploaded image and return detected text bounding boxes.

    Response
    --------
    {"boxes": [{"x": int, "y": int, "width": int, "height": int}, ...]}

    All coordinates are in original-image pixels — the same space the mask
    JSON contract uses — so the frontend can put them directly into the
    ``boxes`` array of buildMaskJson() without any scaling.

    Raises 404 if the job_id is not found.
    Returns {"boxes": []} with HTTP 200 if no text is detected.
    """
    job = get_job(body.job_id)
    if job is None:
        raise HTTPException(
            status_code=404,
            detail=f"Job '{body.job_id}' not found.",
        )

    boxes = detect_text_regions(job.steps[0].original_image)
    return {"boxes": boxes}