Files
wehub-resource-sync 9f97f3abbe
CI - Python Bindings / sdist (push) Failing after 1s
CI - Python Bindings / Build x86_64-unknown-linux-musl (push) Failing after 1s
CI / fmt (push) Failing after 1s
E2E Output Validation / compare-outputs (push) Failing after 1s
Sync Docs to Developer Hub / sync-docs (push) Failing after 1s
CI - Python Bindings / Build x86_64-unknown-linux-gnu (push) Failing after 1s
CI - WASM Bindings / Build WASM (push) Failing after 0s
CI / clippy (push) Failing after 1s
CI / build-and-test (ubuntu-latest) (push) Failing after 0s
CI - WASM Bindings / Edge runtime PDF parse test (push) Has been skipped
CI - WASM Bindings / Browser PDF parse test (push) Has been skipped
Deploy Demo to GitHub Pages / deploy (push) Failing after 1s
CI / build-docker-image (push) Failing after 3s
CI - Node Bindings / Build darwin-x64 (push) Has been cancelled
CI - Node Bindings / Test win32-x64-msvc (push) Has been cancelled
CI - Node Bindings / Build linux-arm64-gnu (push) Has been cancelled
CI - Node Bindings / Build linux-x64-gnu (push) Has been cancelled
CI - Node Bindings / Build linux-x64-musl (push) Has been cancelled
CI - Node Bindings / Build win32-arm64-msvc (push) Has been cancelled
CI - Node Bindings / Build win32-x64-msvc (push) Has been cancelled
CI - Node Bindings / Test darwin-arm64 (push) Has been cancelled
CI - Node Bindings / Test darwin-x64 (push) Has been cancelled
CI - Node Bindings / Test linux-x64-gnu (push) Has been cancelled
CI - Node Bindings / Test linux-x64-musl (push) Has been cancelled
CI - Node Bindings / Test win32-arm64-msvc (push) Has been cancelled
CI - Python Bindings / Build aarch64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Build x86_64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Build x86_64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Build aarch64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Build aarch64-unknown-linux-gnu (push) Has been cancelled
CI - Node Bindings / Build darwin-arm64 (push) Has been cancelled
CI - Python Bindings / Test x86_64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Test aarch64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Test x86_64-unknown-linux-gnu (push) Has been cancelled
CI - Python Bindings / Test x86_64-unknown-linux-musl (push) Has been cancelled
CI - Python Bindings / Test aarch64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Test x86_64-pc-windows-msvc (push) Has been cancelled
CI / build-and-test (macos-26-intel) (push) Has been cancelled
CI / build-and-test (macos-latest) (push) Has been cancelled
CI / build-and-test (windows-11-arm) (push) Has been cancelled
CI / build-and-test (windows-latest) (push) Has been cancelled
E2E Output Validation / upload-dataset (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:44 +08:00

99 lines
3.2 KiB
Python

import io
import logging
from typing import Any
import easyocr
import numpy as np
import uvicorn
from fastapi import FastAPI
from fastapi.datastructures import UploadFile
from fastapi.param_functions import File, Form
from PIL import Image
from pydantic import BaseModel
LANG_MAP = {"eng": "en"}
class OcrResponse(BaseModel):
results: list[Any]
class StatusResponse(BaseModel):
status: str
class EasyOCRServer:
def __init__(self) -> None:
self.reader: easyocr.Reader | None = None
self.current_language: str | None = None
def _create_ocr_server(self) -> FastAPI:
app = FastAPI()
@app.post("/ocr")
async def ocr_endpoint(
file: UploadFile = File(...), language: str = Form(default="en")
) -> OcrResponse:
print(
f"Language: {language}. Received file {file.filename or 'no name'} with size {file.size or 'unknown size'} and type {file.content_type or 'unknown type'}",
flush=True,
)
# Get language from request
language = language.lower()
# Normalize language
if language in LANG_MAP:
language = LANG_MAP[language]
if self.reader is None or self.current_language != language:
print(f"Initializing EasyOCR reader for language: {language}")
self.reader = easyocr.Reader([language], gpu=False)
self.current_language = language
image_data = await file.read()
image = Image.open(io.BytesIO(image_data))
# Convert to numpy array
image_array = np.array(image)
# Run OCR
results = self.reader.readtext(image_array) # type: ignore
# Format results according to LiteParse OCR API spec
# Convert from EasyOCR format: [[[x1,y1], [x2,y2], [x3,y3], [x4,y4]], text, confidence]
# To standard format: { text, bbox: [x1, y1, x2, y2], confidence }
formatted = []
for coords, text, confidence in results:
# Convert polygon to axis-aligned bounding box
# coords is [[x1,y1], [x2,y2], [x3,y3], [x4,y4]]
if isinstance(coords, np.ndarray):
coords = coords.tolist()
# int casting is necessary for pydantic serialization (np.Int32 are not serializable)
xs = [int(point[0]) for point in coords]
ys = [int(point[1]) for point in coords]
bbox = [min(xs), min(ys), max(xs), max(ys)]
formatted.append(
{"text": text, "bbox": bbox, "confidence": float(confidence)}
)
return OcrResponse(results=formatted)
@app.get("/health")
def health() -> StatusResponse:
return StatusResponse(status="healthy")
return app
def serve(self) -> None:
app = self._create_ocr_server()
uvicorn.run(app, host="0.0.0.0", port=8828)
if __name__ == "__main__":
logging.basicConfig(
level=logging.DEBUG,
)
logging.info("Starting server on port 8828")
server = EasyOCRServer()
server.serve()