Transcription
Historical document transcription system for family-history documents.
The app lets you upload a document image/PDF, queues a background transcription job, and then shows job status and results in a web UI.
What the app does
- Upload document files (
.jpg,.jpeg,.png,.tif,.tiff,.pdf) - Persist document + job records in SQLite
- Process jobs in a background worker (
queued -> processing -> transcribed/failed) - Store transcript text (or failure detail)
- Show status and results in the NiceGUI interface
Quick start
1) Install dependencies
uv sync
2) Configure environment
Create a .env file in the project root with the required OpenRouter API key:
OPENROUTER_API_KEY=your_openrouter_api_key
Settings are read from CLI arguments first, then environment variables, then .env, then the defaults below.
Configuration Source Precedence
When the same setting is provided in multiple places, the value is chosen in this order (highest priority first):
- CLI arguments (for example
--port 9999) - Settings constructor arguments (used mainly in tests)
- Environment variables
.envfile values- Model defaults in code
Practical examples:
--port 9999overrides bothPORT=8000in the shell andPORT=7000in.env.DATABASE__PATH=prod.dbin the shell overridesDATABASE__PATH=dev.dbin.env.
Server and runtime
| Environment variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Address on which the server listens. |
PORT |
8000 |
Server port. |
LOG_LEVEL |
info |
Uvicorn and application log level. |
RELOAD |
false |
Restart the development server when source files change. |
ENVIRONMENT |
development |
Runtime environment: development, test, or production. |
Provider
| Environment variable | Default | Description |
|---|---|---|
PROVIDER |
openrouter |
Transcription provider. |
OPENROUTER_API_KEY |
Required | OpenRouter API key. |
PROVIDER_MODEL |
Provider default | Optional model override. |
OPENROUTER_HTTP_REFERER |
Unset | Optional OpenRouter attribution URL. |
OPENROUTER_APP_TITLE |
Unset | Optional OpenRouter attribution title. |
Database and files
Use nested env vars for database settings (recommended):
DATABASE__DRIVER=sqlite
DATABASE__PATH=app.db
# BOOTSTRAP_SCHEMA_ON_STARTUP=true
SQLITE_CHECK_SAME_THREAD=false
UPLOAD_DIR=./uploads
PROMPT_DIR=./prompts
For PostgreSQL:
DATABASE__DRIVER=postgres
DATABASE__HOST=localhost
DATABASE__PORT=5432
DATABASE__DATABASE=transcription
DATABASE__USER=postgres
DATABASE__PASSWORD=change-me
This uses Pydantic nested settings (env_nested_delimiter='__') and avoids JSON blobs in .env. A top-level DATABASE={...} JSON value is still supported as a fallback, and nested keys such as DATABASE__PATH take precedence over conflicting JSON keys.
BOOTSTRAP_SCHEMA_ON_STARTUP creates missing tables when the app starts. When unset, it is enabled in development and test, and disabled in production; set it explicitly to override that policy. SQLITE_CHECK_SAME_THREAD defaults to false.
Worker
WORKER_MAX_RETRIES=0
WORKER_RETRY_BACKOFF_SECONDS=0
WORKER_PROVIDER_TIMEOUT_SECONDS=20
WORKER_MIN_TRANSCRIPTION_CHARS=0
WORKER_MIN_TRANSCRIPTION_LINES=0
WORKER_FAIL_ON_FINISH_REASON_LENGTH=false
3) Run the app
uv run python -m transcription --port 9999 --reload --database.driver sqlite --bootstrap-schema-on-startup
This starts the development server with SQLite, creates missing tables, and enables automatic reload. Run uv run python -m transcription --help for all CLI options; CLI names use kebab case and nested database options use dot notation, such as --database.path ./data/transcription.db.
4) Open in browser
- GUI: http://localhost:9999/ui
- Health check: http://localhost:9999/healthz
Replace localhost with the server's hostname or IP address when connecting from another machine.
How to navigate the GUI
-
Upload page (
/ui)- Select a supported file to upload.
- The app creates a queued transcription job.
- Use the View jobs link to inspect progress.
-
Jobs page (
/ui/jobs)- See all jobs and their status.
- Use Refresh to reload current states.
- Open a specific job to see details.
-
Job detail page (
/ui/jobs/{job_id})- Shows job metadata and status.
- Displays transcript text when successful.
- Displays failure detail when transcription fails.
Prompt artifacts
Prompt files are stored in prompts/ and loaded from PROMPT_DIR (default: ./prompts).
The canonical MVP prompt is:
prompts/transcribe_document.md