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