| import os |
| import tempfile |
| from fastapi import FastAPI, File, UploadFile, HTTPException |
| from fastapi.responses import JSONResponse |
|
|
| app = FastAPI(title="Scholarform Docling Service") |
|
|
| try: |
| from docling.document_converter import DocumentConverter |
| _converter = DocumentConverter() |
| DOCLING_OK = True |
| except Exception as e: |
| _converter = None |
| DOCLING_OK = False |
| DOCLING_ERR = str(e) |
|
|
| @app.get("/") |
| def root(): |
| return {"ok": True, "service": "docling", "docling_available": DOCLING_OK} |
|
|
| @app.get("/health") |
| def health(): |
| payload = {"ok": True, "service": "docling", "docling_available": DOCLING_OK} |
| if not DOCLING_OK: |
| payload["error"] = DOCLING_ERR |
| return payload |
|
|
| @app.post("/analyze") |
| async def analyze(file: UploadFile = File(...)): |
| if not DOCLING_OK: |
| raise HTTPException(status_code=503, detail=f"Docling unavailable: {DOCLING_ERR}") |
| if not file.filename.lower().endswith(".pdf"): |
| raise HTTPException(status_code=400, detail="Only PDF is supported") |
|
|
| with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp: |
| tmp.write(await file.read()) |
| path = tmp.name |
|
|
| try: |
| doc = _converter.convert(path).document |
| elements = [] |
|
|
| for item in getattr(doc, "texts", []): |
| text = getattr(item, "text", "") or "" |
| label = getattr(item, "label", "text") |
| bbox = None |
| prov = getattr(item, "prov", None) |
| if prov and len(prov) > 0 and getattr(prov[0], "bbox", None): |
| b = prov[0].bbox |
| bbox = {"x0": b.l, "y0": b.t, "x1": b.r, "y1": b.b, "page": getattr(prov[0], "page_no", 0)} |
| elements.append({"type": str(label), "text": text, "bbox": bbox}) |
|
|
| pages = getattr(doc, "num_pages", 0) |
| if callable(pages): |
| pages = pages() |
|
|
| return {"ok": True, "pages": pages, "elements": elements[:1000]} |
| except Exception as e: |
| raise HTTPException(status_code=500, detail=f"Docling analyze failed: {e}") |
| finally: |
| try: |
| os.remove(path) |
| except Exception: |
| pass |
|
|