Suya OCR API — vLLM-backed, OpenAI-compatible OCR service

FastAPI service wrapping the Surya-OCR-2 model (datalab-to) served through vLLM:
legacy /v1/api/ai/* endpoints, an OpenAI-compatible /v1/chat/completions endpoint,
a coalescing request batcher, a local OCR CLI, Docker packaging, multilingual
example outputs, and quantization/concurrency benchmarks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Fu Dai
2026-06-17 10:20:02 +04:00
co-authored by Claude Opus 4.8
commit 1a585693be
147 changed files with 13827 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
import time
import click
import copy
import json
from collections import defaultdict
from surya.inference import SuryaInferenceManager
from surya.layout import LayoutPredictor
from surya.debug.draw import draw_polys_on_image
from surya.logging import configure_logging, get_logger
from surya.scripts.config import CLILoader
import os
configure_logging()
logger = get_logger()
@click.command(help="Detect layout of an input file or folder (PDFs or image).")
@CLILoader.common_options
def detect_layout_cli(input_path: str, **kwargs):
loader = CLILoader(input_path, kwargs)
manager = SuryaInferenceManager()
layout_predictor = LayoutPredictor(manager)
start = time.time()
layout_predictions = layout_predictor(loader.images)
if loader.debug:
logger.debug(f"Layout took {time.time() - start} seconds")
if loader.save_images:
for idx, (image, layout_pred, name) in enumerate(
zip(loader.images, layout_predictions, loader.names)
):
polygons = [p.polygon for p in layout_pred.bboxes]
labels = [f"{p.label}-{p.position}" for p in layout_pred.bboxes]
bbox_image = draw_polys_on_image(
polygons, copy.deepcopy(image), labels=labels
)
bbox_image.save(
os.path.join(loader.result_path, f"{name}_{idx}_layout.png")
)
predictions_by_page = defaultdict(list)
for idx, (pred, name, image) in enumerate(
zip(layout_predictions, loader.names, loader.images)
):
out_pred = pred.model_dump()
out_pred["page"] = len(predictions_by_page[name]) + 1
predictions_by_page[name].append(out_pred)
with open(
os.path.join(loader.result_path, "results.json"), "w+", encoding="utf-8"
) as f:
json.dump(predictions_by_page, f, ensure_ascii=False)
logger.info(f"Wrote results to {loader.result_path}")
if __name__ == "__main__":
detect_layout_cli()