The Problem

Extracting usable text from images and scanned PDFs is a common but fiddly task: OCR models return raw text, and getting it into a shareable format (Markdown, Word, HTML) usually means manual cleanup. This app wraps DeepSeek-OCR with a web UI and format conversion so a non-technical user can upload a document and download a clean, structured result.

What This Does

A React frontend (frontend/src/App.jsx) talks to a FastAPI backend (backend/main.py) that runs DeepSeek-OCR. It supports single-image OCR with four modes (plain, describe, find, freeform) and multi-page PDF processing with progress tracking. Results export to Markdown, HTML, DOCX, or JSON via backend/format_converter.py.

The whole thing deploys with docker compose up --build. The backend image is based on nvcr.io/nvidia/pytorch:25.09-py3 and downloads the model (~5–10GB) on first run.

How It Is Wired

Execution starts in frontend/src/main.jsx, which mounts App.jsx. App is the clear hub: it has 5 outgoing imports and 0 incoming, giving it instability 0.83 — every feature routes through it. The five components (ImageUpload, PDFProcessor, ModeSelector, ResultPanel, AdvancedSettings) are all leaves (Ca 1, Ce 0): nothing imports them except App, so they are cheap to replace but App itself is the single point of change.

On the backend, backend/main.py is the API entry point. It handles uploads, calls the OCR model, and delegates file handling to pdf_utils.py (PDF extraction) and format_converter.py (export formats). The import graph shows 14 internal modules, 6 edges, and no cycles — the structure is simple and acyclic. App.jsx is the file with the widest blast radius because all UI state and API calls pass through it.

How To Use It

git clone https://github.com/moses-y/deepseek_ocr_app
cd deepseek_ocr_app
cp .env.example .env
docker compose up --build

Then open http://localhost:3000 (frontend) and http://localhost:8000/docs (API docs). The .env file configures ports and upload limits. The first run downloads the model, which takes time.

Real-World Use

A document digitization workflow: a user uploads a scanned 50-page PDF in PDFProcessor, the backend runs OCR page-by-page with progress tracking, and the result converts to .docx for editing in Word. The same pipeline handles academic papers, preserving LaTeX formulas and table structure.

Code Health & Issues

Static analysis found 6 issues (2 high, 4 medium). High: deep nesting in backend/format_converter.py, backend/main.py, and frontend/src/App.jsx (max indentation depth 8) — control flow is hard to follow; fix with early returns and extraction. Medium: backend/pdf_utils.py opens files without a context manager (handle leak risk), and backend/main.py uses broad exception handling that swallows errors.

The broader audit flags: no test suite across 17 source files, no CI configuration, no lockfile beside frontend/package.json (non-reproducible builds), a wildcard CORS origin paired with credentials in backend/main.py, an unpinned base image, and no non-root USER in the backend Dockerfile. No committed secrets were detected.

The Bottom Line

A working, demo-grade OCR app with a clean client-server split and genuinely useful PDF/format-conversion features. It is not production-ready: no tests, no CI, and a wildcard CORS config that browsers will reject with credentials anyway. Fine for a self-hosted tool or a starting point; add tests and a lockfile before putting it behind real traffic.