Self-hosted service
vorojar/Folio-OCR avatar
vorojar/Folio-OCR

Folio-OCR: a local batch OCR workbench built on Ollama and GLM-OCR

Open-source batch OCR workbench — a free, local alternative to ABBYY FineReader. Powered by Ollama + GLM-OCR + PP-DocLayoutV3, ~0.5s/page on RTX 4090. Three-panel editor, layout-aware, PDF/image batch processing, Markdown/Word export. 批量OCR工作台,纯本地运行,免费平替ABBYY,适合书籍文档数字化。

472 stars63 forksPythonMIT

At a glance

What is it?
Folio-OCR wraps PP-DocLayoutV3 layout detection and GLM-OCR vision recognition in a three-panel browser editor with SQLite persistence. It is aimed at people digitizing books and scanned documents who do not want pages leaving their machine.
Who is it for?
Adopt Folio-OCR if you already run Ollama, your documents are scanned pages rather than photographed receipts, and you want Markdown, DOCX or EPUB out of a local pipeline. Skip it if you need handwriting recognition, if you cannot give the layout model CPU headroom or the OCR model several gigabytes of VRAM, or if you need a supported product with a service contract.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 90 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Folio-OCR addresses, and who has it

The README frames the project around one concrete task: turning scanned PDFs, book photographs, exam papers and document images into editable text in batches, while keeping headings, body text and tables in a structure that survives export. The stated audience is book digitization, scanned-document cleanup, table transcription, and offline or privacy-sensitive OCR.

The constraint that shapes everything else is locality. Folio-OCR runs against a local Ollama instance by default, so pages are not uploaded to a third-party OCR service. That matters for anyone handling unpublished manuscripts, internal records or personal documents, and it also means the quality ceiling is whatever GLM-OCR can do on your hardware rather than whatever a cloud vendor's largest model can do.

The project describes itself as a free, local alternative to ABBYY FineReader. That comparison is about workflow shape, not feature parity: a three-panel editor, batch processing, layout-aware recognition and Word export. Anyone expecting ABBYY's handwriting engines, language packs or document-classification rules will not find them here.

How the pipeline works: layout detection, then vision OCR through Ollama

The README describes a two-stage pipeline. PP-DocLayoutV3 performs layout detection, partitioning each page into regions. GLM-OCR then performs vision OCR on those regions through Ollama.

A detail worth noting is that adjacent text regions are merged before recognition, which the README says reduces OCR calls (its example is 11 regions collapsing to 3 groups, described as a 2.5x speedup). That is a design decision with a trade-off: fewer calls means faster batch runs, but merging regions can blur the boundary between, say, a caption and the paragraph beneath it.

On the input side, PyMuPDF renders PDF pages with a 2x scaling matrix, and the stated reason is OCR quality. Images arrive as PNG, JPG, GIF or BMP, and mixed uploads of images and PDFs are accepted. Output is written to SQLite (`folio_ocr.db`) with uploaded files and split PDF pages under `uploads/`, so results survive a service restart. The frontend is vanilla JavaScript served by a FastAPI backend, with SSE streaming the page list as uploads proceed.

Two post-processing steps are documented: LaTeX fragments are mapped to Unicode through `folio_ocr/latex_unicode.json` (the README's example is `$\textcircled{1}$` becoming `①`), and stray ```markdown fences are stripped from model output.

Installing Folio-OCR with uvx or Docker Compose

The README gives two install paths. The first assumes Python and Ollama are already present, and needs no clone. Pull the model, then run the published command:

bash
ollama pull glm-ocr
uvx --from git+https://github.com/vorojar/Folio-OCR folio-ocr

After that, the README says to open http://localhost:3000. A pipx variant is documented as `pipx run --spec git+https://github.com/vorojar/Folio-OCR folio-ocr`.

The second path puts Ollama and the app in containers. Note that the model pull happens inside the Ollama container after startup, not during the build:

bash
git clone https://github.com/vorojar/Folio-OCR.git
cd Folio-OCR
docker compose up -d
docker compose exec ollama ollama pull glm-ocr

Again, the documented address is http://localhost:3000. The compose file maps `11434:11434` for Ollama and `3000:3000` for the app, and sets `LAYOUT_DEVICE=cpu` plus `OLLAMA_NUM_CTX=16384` in the app environment. GPU acceleration is not automatic: the README says to edit `docker-compose.yml` and uncomment the `deploy:` block.

Running from source requires Python 3.10 to 3.12 (3.11 recommended) with `ollama` on PATH. The documented sequence is `pip install -r requirements.txt`, `ollama pull glm-ocr`, then `python server.py`, or `uvicorn folio_ocr.server:app --reload --host 0.0.0.0 --port 3000` for hot reload. Windows users get `start.bat`. The first real use is to upload a mixed batch and press OCR All Pages; the README notes a cold-start first request of about 50 seconds before steady-state recognition begins.

Limits: hardware pressure, timeouts and the wrong kind of document

The documented failure modes are the most useful part of this README, and they are all resource-related.

Cold start is the first one. The README's performance section states roughly 50 seconds for the first request after the model loads, then about 0.5 seconds per page. The 0.5-second figure is tied to an RTX 4090 in the project description; the README does not publish a CPU-only per-page number, so anyone planning a CPU deployment is guessing.

Memory is the second. The default `OLLAMA_NUM_CTX=16384` exists because GLM-OCR can trigger a RoPE or KV cache assertion (`GGML_ASSERT(a->ne[2] * 4 == b->ne[0]) failed`) when the context window is too small. The README offers `OLLAMA_NUM_CTX=24576` as a workaround for stubborn cases and says to keep or raise the default on complex, high-resolution scans. That is a real constraint: the fix for an OCR error is more memory, not a different flag.

Timeouts are the third. There is a documented issue where a PDF of about 1 MB times out on Ollama v0.30.6. The frontend timeout is already 300 seconds via `OCR_REQUEST_TIMEOUT_MS`, and the README suggests raising it to 600000 for slow machines, or temporarily pinning `OLLAMA_VERSION=0.19.0` to test compatibility. Diagnosing whether the browser or the Ollama runner stalled means reading both `docker compose logs -f app` and `docker compose logs -f ollama`.

Where it is the wrong tool: the README claims support for scanned documents, book photos, exam papers and document images. It does not claim handwriting recognition, multi-language model selection, or automatic document classification. If your source material is handwritten, or you need a vendor to answer a support ticket, this project is not the fit.

Folio-OCR compared with a general-purpose OCR stack

The obvious alternative is assembling the same parts yourself: PyMuPDF for page rendering, a layout model for region detection, and an Ollama call to a vision model, with your own storage and export code. Folio-OCR's contribution is the work between those steps. It merges adjacent text regions to cut recognition calls, maps LaTeX output to Unicode, strips markdown fences, persists pages and edits to SQLite with an 800ms debounced autosave, and exposes exports for Markdown, TXT, DOCX and EPUB. The DOCX path uses python-docx and the README says it produces a real Word document with section breaks and page numbers.

The difference in approach is the interface. A script gives you a batch result and nothing to review; Folio-OCR gives you a three-panel editor with page thumbnails, image preview and OCR text, bidirectional highlighting between a layout box and its text block, `Ctrl+F` full-text search across pages, and arrow-key page navigation. For a 400-page book where a fraction of pages need correction, that review loop is the actual product. For a one-off conversion of ten pages, it is overhead you will pay for in container startup and model loading.

The second alternative is a cloud OCR API. That removes the GPU requirement and the cold start, and it usually wins on hard pages. It also means your documents leave the machine, which is precisely what the README's privacy framing is built to avoid. The choice is not about accuracy in the abstract; it is about whether the documents are allowed to travel.

Maintenance, configuration surface and licence

The last push to the repository was on 2026-06-18, the same day v3.4.0 was released, which added the `folio-ocr` command, `uvx` startup, GitHub Release packaging, a licence file, CI and long-PDF timeout configuration. Earlier releases in the same cycle were v3.3.1 on 2026-05-28 and v3.3.0 on 2026-05-25. The repository is not archived. Nothing in the project's own documentation describes a deprecation timeline, a support window or a long-term roadmap.

The upgrade cost is mostly environmental rather than code. `pyproject.toml` pins `requires-python` to `>=3.10,<3.13`, so Python 3.13 is outside the declared range. The dependency list pulls in `torch`, `torchvision` and `transformers` for layout detection, which dominates image size and install time. Ollama itself is a moving target: the README documents a compatibility workaround that pins `OLLAMA_VERSION=0.19.0` in compose, which tells you that model behaviour can shift between Ollama releases and that upgrades should be tested rather than assumed.

The licence is MIT, declared in `pyproject.toml` with `license-files = ["LICENSE"]` and a LICENSE file at the repository root. MIT is permissive, but it covers Folio-OCR's own code, not the models it downloads. GLM-OCR is hosted on Hugging Face and PP-DocLayoutV3 ships through the transformers stack, so their terms are separate from this project's. Check those terms yourself against how you intend to use the output; that is not something a licence identifier settles.

Editorial conclusion

Adopt Folio-OCR if you already run Ollama, your documents are scanned pages rather than photographed receipts, and you want Markdown, DOCX or EPUB out of a local pipeline. Skip it if you need handwriting recognition, if you cannot give the layout model CPU headroom or the OCR model several gigabytes of VRAM, or if you need a supported product with a service contract. Before committing a large batch, verify three things on your own hardware: that `ollama pull glm-ocr` completes and the model loads, that a 30 to 50 page PDF survives a full OCR All Pages run without an Ollama runner timeout, and that the DOCX or EPUB export preserves the tables and headings you care about. The README's own performance note, roughly 50 seconds for the first cold request and about 0.5 seconds per page after that, is the number to reproduce before you plan a digitization schedule around it.

Frequently asked questions

What is Folio-OCR and who is it for?

It is a local batch OCR workbench for PDFs and scanned images, built on Ollama and GLM-OCR with PP-DocLayoutV3 for layout detection. The README targets book digitization, scanned-document cleanup, table transcription and offline or privacy-sensitive OCR.

How do I install and start Folio-OCR?

With Python and Ollama already present, run `ollama pull glm-ocr` then `uvx --from git+https://github.com/vorojar/Folio-OCR folio-ocr`, or use Docker Compose with `docker compose up -d` followed by `docker compose exec ollama ollama pull glm-ocr`. Both paths are documented as serving at http://localhost:3000.

Can Folio-OCR run without a GPU?

Yes, the compose file sets `LAYOUT_DEVICE=cpu` by default and the README calls that the safest option, leaving GPU memory for Ollama. The published per-page timing is tied to an RTX 4090, and the README does not give a CPU-only throughput figure.

What export formats does Folio-OCR produce?

Markdown, plain text, Word `.docx` and EPUB. The DOCX export is built with python-docx and the README states it includes section breaks and page numbers.

Why does Folio-OCR set OLLAMA_NUM_CTX to 16384?

The README says GLM-OCR can trigger a RoPE or KV cache assertion when the context window is too small during image OCR, so v3.3.1 onward sends `num_ctx: 16384` with `/api/chat` requests. It suggests raising it to 24576 if the error still appears.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. vorojar/Folio-OCR on GitHub
Community notes

Community notes