Skip to content

Instantly share code, notes, and snippets.

@Somberor
Created January 18, 2026 21:32
Show Gist options
  • Select an option

  • Save Somberor/d37de741f057860ec0f8013e698cc912 to your computer and use it in GitHub Desktop.

Select an option

Save Somberor/d37de741f057860ec0f8013e698cc912 to your computer and use it in GitHub Desktop.
OCR server
import io, time
from typing import Optional
import easyocr, numpy as np
from PIL import Image
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
app = FastAPI(title="GPU OCR Server")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
ocr_reader: Optional[easyocr.Reader] = None
@app.on_event("startup")
async def load_model():
global ocr_reader
print("[OCR] Loading model with GPU...")
start = time.time()
ocr_reader = easyocr.Reader(['en'], gpu=True, verbose=False)
print(f"[OCR] Ready in {time.time()-start:.1f}s")
@app.get("/health")
async def health(): return {"status": "ok", "gpu": ocr_reader is not None}
@app.post("/ocr")
async def ocr(file: UploadFile = File(...)):
if not ocr_reader: raise HTTPException(503, "Model not loaded")
t0 = time.time()
img = np.array(Image.open(io.BytesIO(await file.read())))
t1 = time.time()
results = ocr_reader.readtext(img)
t2 = time.time()
return {
"results": [{"text": t, "confidence": float(c), "bbox": [[int(p[0]),int(p[1])] for p in b], "center": [(int(b[0][0])+int(b[2][0]))//2, (int(b[0][1])+int(b[2][1]))//2]} for b,t,c in results],
"timing": {"read_ms": int((t1-t0)*1000), "ocr_ms": int((t2-t1)*1000), "total_ms": int((t2-t0)*1000)},
"count": len(results)
}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8765)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment