| --- |
| title: OvisOCR2 |
| emoji: ๐ |
| colorFrom: blue |
| colorTo: gray |
| sdk: gradio |
| sdk_version: 6.20.0 |
| python_version: "3.12.12" |
| app_file: app.py |
| pinned: false |
| license: apache-2.0 |
| hardware: zero-gpu |
| startup_duration_timeout: 30m |
| models: |
| - ATH-MaaS/OvisOCR2 |
| preload_from_hub: |
| - ATH-MaaS/OvisOCR2 |
| short_description: Stream structured Markdown from document images and PDFs. |
| --- |
| |
| # OvisOCR2 โ document OCR demo |
|
|
| A focused image and PDF document parsing demo for |
| [ATH-MaaS/OvisOCR2](https://huggingface.co/ATH-MaaS/OvisOCR2). It preserves |
| reading order and emits Markdown with LaTeX formulas, HTML tables, and rendered |
| visual-region crops. Model tokens stream into the interface as they are generated. |
| PDFs are rasterized locally and processed one page at a time in Base mode. Up to |
| four pages share one streamed GPU request by default, while each page is still |
| inferred independently and sequentially. The browser merges the results, so long |
| documents do not have to fit inside one ZeroGPU lease. GPU duration is estimated |
| from the number of pages that actually remain in each group, so a short second |
| group does not reserve the same ZeroGPU quota as a four-page group. If a Gradio |
| stream closes without an explicit backend error, the browser reconnects from the |
| first unfinished page while retaining every completed page. This demo |
| intentionally does not expose a separate Long mode. |
|
|
| The five packaged examples cover two financial tables, two Chinese handwriting |
| pages, and one formula-rich OmniDocBench research-paper page. They are selectable |
| directly in the interface and are also covered by the local smoke-test workflow. |
| The workspace opens empty so examples remain an explicit user choice rather than |
| an automatic input. |
|
|
| ## Local run |
|
|
| The verified local model directory is `/root/models/ATH-MaaS/OvisOCR2`. |
|
|
| ```bash |
| conda env create -f environment.yml |
| conda activate ovisocr2-demo |
| npm ci |
| npm run build |
| CUDA_VISIBLE_DEVICES=0 \ |
| OVISOCR_MODEL_PATH=/root/models/ATH-MaaS/OvisOCR2 \ |
| python app.py |
| ``` |
|
|
| Open `http://127.0.0.1:7860`. |
|
|
| ### DSW proxy |
|
|
| The server already listens on `0.0.0.0`. Set a DSW id and the public proxy URL |
| is generated from the same `PORT` automatically: |
|
|
| ```bash |
| CUDA_VISIBLE_DEVICES=0 \ |
| PORT=7869 \ |
| OVISOCR_DSW_ID=1976932 \ |
| OVISOCR_MODEL_PATH=/root/models/ATH-MaaS/OvisOCR2 \ |
| python app.py |
| ``` |
|
|
| The corresponding URL is |
| `https://1976932-proxy-7869.dsw-gateway-cn-hangzhou.data.aliyun.com/`. |
| For a different gateway or an explicit public URL, set `OVISOCR_ROOT_PATH` |
| instead; it takes precedence over `OVISOCR_DSW_ID`. |
|
|
| DSW's per-port proxy uses its own hostname and serves at `/`, so the ASGI root |
| path stays empty. If an explicit URL contains a real subpath, such as |
| `https://example.test/ocr/`, the app passes only `/ocr` to Gradio's `root_path`; |
| passing the whole URL into this custom FastAPI server would break static mounts. |
|
|
| For a UI-only smoke that does not load the model: |
|
|
| ```bash |
| OVISOCR_TEST_MODE=1 python app.py |
| ``` |
|
|
| ## Hugging Face Space |
|
|
| The checked-in `dist/` directory is the production frontend, so the folder can |
| be uploaded directly to a Gradio Space without a Node build step. Select |
| ZeroGPU hardware in the Space settings. The README metadata pins Python 3.12.12 |
| and Gradio 6.20.0 |
| and declares `hardware: zero-gpu`; `app.py` decorates only the inference endpoint |
| with `@spaces.GPU` and loads the model on CUDA at module scope, following the |
| ZeroGPU loading contract. |
|
|
| On Hugging Face, the model source automatically falls back from the local path |
| to `ATH-MaaS/OvisOCR2`. PDFs are limited to 50 pages by default. Groups of up to |
| four pages share a ZeroGPU reservation while the frontend preserves already |
| completed pages. |
|
|
| ## Runtime knobs |
|
|
| - `OVISOCR_MODEL_PATH`: local directory or Hub model id. |
| - `OVISOCR_MAX_NEW_TOKENS`: defaults to `16384`, matching the model README inference configuration. |
| - `OVISOCR_MAX_PDF_PAGES`: defaults to `50`. |
| - `OVISOCR_PAGES_PER_GPU_REQUEST`: defaults to `4` and is capped at `5`. |
| - `OVISOCR_PDF_RENDER_SCALE`: PDF rasterization scale, defaults to `2.0`. |
| - `OVISOCR_STREAM_MIN_CHARS`: minimum new characters between stream updates, defaults to `64`. |
| - `OVISOCR_STREAM_MAX_INTERVAL`: maximum seconds between available stream updates, defaults to `0.25`. |
| - `OVISOCR_GPU_SECONDS_PER_PAGE`: duration-estimation budget, defaults to `30` seconds per page. |
| - `OVISOCR_GPU_DURATION_FLOOR`: minimum per-group ZeroGPU reservation, defaults to `45` seconds. |
| - `OVISOCR_GPU_DURATION_CEILING`: maximum estimated per-group reservation, defaults to `120` seconds. |
| - `OVISOCR_GPU_DURATION`: optional fixed per-group override; unset by default so dynamic duration is used. |
| - `OVISOCR_ATTN_IMPLEMENTATION`: defaults to `sdpa`. |
| - `OVISOCR_DSW_ID`: generates the Hangzhou DSW proxy root using the active `PORT`. |
| - `OVISOCR_ROOT_PATH`: explicit proxy URL or ASGI path prefix; overrides `OVISOCR_DSW_ID`. |
| - `OVISOCR_TEST_MODE=1`: deterministic mock inference for UI/integration tests. |
|
|