generated from john/python-template
Change references to handwriting, expand options for LLMs
This commit is contained in:
@@ -236,7 +236,7 @@ Control:
|
||||
|
||||
Risk:
|
||||
|
||||
- transcription quality varies by handwriting and image quality
|
||||
- transcription quality varies by document type, handwriting legibility, and image quality
|
||||
|
||||
Control:
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
## Handwriting Transcription System
|
||||
## Document Transcription System
|
||||
|
||||
This project is a production application for transcribing and preserving historical family documents. It is intentionally designed for personal-scale use, with a simplicity-first architecture that is easy to operate and easy to extend.
|
||||
|
||||
|
||||
+26
-19
@@ -1,14 +1,14 @@
|
||||
## MVP Definition: Historical Document Transcription System
|
||||
|
||||
### 1. MVP Objective
|
||||
Deliver the thinnest possible end-to-end vertical slice — a user uploads an image of a handwritten document, the system transcribes it via an AI provider, and the user reads the resulting transcript — with just enough persistence and structure to validate the core value proposition: *can AI-driven transcription, guided by curated prompts, produce useful verbatim transcripts of historical family documents?*
|
||||
Deliver the thinnest possible end-to-end vertical slice — a user uploads an image of a document, the system transcribes it via a configurable AI provider, and the user reads the resulting transcript — with just enough persistence and structure to validate the core value proposition: *can AI-driven transcription, guided by curated prompts, produce useful verbatim transcripts of historical family documents?*
|
||||
|
||||
The MVP deliberately defers full-text search, export, revision history, MongoDB, timeline assembly, and multi-provider routing. These are additive features that don't need validation before the core transcription loop is proven.
|
||||
The MVP deliberately defers full-text search, export, revision history, MongoDB, and timeline assembly. These are additive features that don't need validation before the core transcription loop is proven.
|
||||
|
||||
---
|
||||
|
||||
### 2. Core User Story
|
||||
*As a family historian, I can upload a photo of a handwritten letter, wait for it to be transcribed, and read the verbatim transcript — so I can evaluate whether this system will work for my thousands of documents.*
|
||||
*As a family historian, I can upload a photo of a historical document, wait for it to be transcribed, and read the verbatim transcript — so I can evaluate whether this system will work for my thousands of documents.*
|
||||
|
||||
---
|
||||
|
||||
@@ -47,12 +47,12 @@ The MVP deliberately defers full-text search, export, revision history, MongoDB,
|
||||
* An in-process background worker (Python asyncio task or BackgroundTasks) that:
|
||||
1. Picks up queued jobs.
|
||||
2. Transitions status to processing.
|
||||
3. Sends the image + the curated Markdown prompt to an AI vision model (OpenAI API — already a dependency).
|
||||
3. Sends the image + the curated Markdown prompt to an AI vision model via the configured provider (OpenRouter or Gemini).
|
||||
4. On success: saves the transcript text, transitions to transcribed.
|
||||
5. On failure: saves the error detail, transitions to failed.
|
||||
|
||||
#### Feature 3: Transcription Prompt (Markdown Asset)
|
||||
* A single Markdown file (prompts/transcribe_handwriting.md) encoding the verbatim transcription rules from Intent.md (the Document Issues table, scholarly guidelines, etc.).
|
||||
* A single Markdown file (prompts/transcribe_document.md) encoding the verbatim transcription rules from Intent.md (the Document Issues table, scholarly guidelines, etc.).
|
||||
* The worker reads this file at invocation time and injects it as the system/user prompt.
|
||||
|
||||
#### Feature 4: Job Status & Transcript Viewer (UI)
|
||||
@@ -71,8 +71,10 @@ The MVP deliberately defers full-text search, export, revision history, MongoDB,
|
||||
|
||||
#### Feature 6: Centralized Configuration
|
||||
* A single config.py (or Pydantic BaseSettings) loading:
|
||||
* OPENAI_API_KEY (required)
|
||||
* OPENAI_MODEL (default: gpt-4o)
|
||||
* PROVIDER (default: openrouter; options: openrouter, gemini)
|
||||
* PROVIDER_API_KEY (required)
|
||||
* PROVIDER_MODEL (default: provider-appropriate default)
|
||||
* PROVIDER_BASE_URL (default: provider-appropriate default; overridable)
|
||||
* DATABASE_URL (default: sqlite:///./transcription.db)
|
||||
* UPLOAD_DIR (default: ./uploads)
|
||||
* PROMPT_DIR (default: ./prompts)
|
||||
@@ -94,10 +96,10 @@ The MVP deliberately defers full-text search, export, revision history, MongoDB,
|
||||
│ │ (upload, job lifecycle) │ │
|
||||
│ └─────┬─────────────┬───────┘ │
|
||||
│ │ │ │
|
||||
│ ┌─────▼─────┐ ┌─────▼─────────────┐ │
|
||||
│ ┌─────▼─────┐ ┌─────▼───────────────┐ │
|
||||
│ │ SQLite DB │ │ Background Worker │ │
|
||||
│ │ (SQLModel)│ │ → OpenAI Vision │ │
|
||||
│ └───────────┘ └───────────────────┘ │
|
||||
│ │ (SQLModel)│ │ → AI Vision Provider│ │
|
||||
│ └───────────┘ └─────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼──────┐ │
|
||||
│ │ prompts/ │ │
|
||||
@@ -114,18 +116,23 @@ The MVP deliberately defers full-text search, export, revision history, MongoDB,
|
||||
project-root/
|
||||
├── docs/ # (existing)
|
||||
├── prompts/
|
||||
│ └── transcribe_handwriting.md # curated transcription prompt
|
||||
│ └── transcribe_document.md # curated transcription prompt
|
||||
├── src/
|
||||
│ └── handwriting/
|
||||
│ └── transcription/
|
||||
│ ├── __init__.py
|
||||
│ ├── app.py # FastAPI + NiceGUI app entrypoint
|
||||
│ ├── config.py # Pydantic BaseSettings
|
||||
│ ├── models.py # SQLModel: Document, Job, Transcript
|
||||
│ ├── db.py # engine, session, create_all
|
||||
│ ├── providers/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── base.py # provider interface (transcribe contract)
|
||||
│ │ ├── openrouter.py # OpenRouter via openai client
|
||||
│ │ └── gemini.py # Google Gemini
|
||||
│ ├── services/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── upload.py # save file + create records
|
||||
│ │ └── transcription.py # call AI provider, update job
|
||||
│ │ └── transcription.py # call provider, update job
|
||||
│ ├── worker.py # background job loop
|
||||
│ └── ui/
|
||||
│ ├── __init__.py
|
||||
@@ -144,8 +151,8 @@ project-root/
|
||||
#### 7. MVP Validation Criteria
|
||||
The MVP is considered validated when:
|
||||
|
||||
1. ✅ A user can upload an image of a handwritten document through the browser.
|
||||
2. ✅ The system asynchronously sends the image to OpenAI's vision model with the curated prompt.
|
||||
1. ✅ A user can upload an image of a document through the browser.
|
||||
2. ✅ The system asynchronously sends the image to the configured AI vision model with the curated prompt.
|
||||
3. ✅ The transcript (or failure reason) is persisted and visible in the UI.
|
||||
4. ✅ The transcription follows verbatim scholarly rules defined in Intent.md (spot-checked by the user on real family documents).
|
||||
5. ✅ The transcription prompt is stored as a standalone Markdown file and can be edited without code changes.
|
||||
@@ -158,7 +165,7 @@ These are the real unknowns this MVP exists to resolve:
|
||||
|
||||
| # | Question | How We Learn |
|
||||
| --- | --- | --- |
|
||||
| 1 | Is AI transcription quality good enough for this handwriting corpus? | User reviews 20–50 real transcriptions against originals. |
|
||||
| 1 | Is AI transcription quality good enough for this document corpus? | User reviews 20–50 real transcriptions against originals. |
|
||||
| 2 | Does the verbatim prompt produce scholarly-quality output, or does it need major rework? | Compare output to the Document Issues table rules in Intent.md. |
|
||||
| 3 | What document types are hardest (old cursive, faded ink, pencil, postcards)? | Track which uploads produce failed or low-quality results. |
|
||||
| 4 | Is single-image upload sufficient, or is batch upload needed early? | User friction during real scanning sessions. |
|
||||
@@ -184,10 +191,10 @@ Recommended build order for the MVP (each step produces a testable increment):
|
||||
| Step | Deliverable | Validates |
|
||||
| --- | --- | --- |
|
||||
| 1 | config.py + models.py + db.py — data layer with SQLite | Schema and config foundation |
|
||||
| 2 | prompts/transcribe_handwriting.md — curated prompt from Intent.md | Prompt asset pattern |
|
||||
| 3 | services/transcription.py — call OpenAI vision API with prompt + image | Core AI integration |
|
||||
| 2 | prompts/transcribe_document.md — curated prompt from Intent.md | Prompt asset pattern |
|
||||
| 3 | services/transcription.py + providers/ — call AI vision provider with prompt + image | Core AI integration |
|
||||
| 4 | services/upload.py + worker.py — upload handling + background job loop | End-to-end pipeline (CLI-testable) |
|
||||
| 5 | ui/upload_page.py + ui/jobs_page.py — NiceGUI pages | User-facing interface |
|
||||
| 6 | tests/ — unit + integration tests Automated verification |
|
||||
|
||||
This MVP is deliberately narrow: **one prompt, one provider, one user, one image at a time, SQLite, no containers**. Every omission is intentional — the goal is to get real family documents through the transcription pipeline as fast as possible and let the quality of the output guide every subsequent decision.
|
||||
This MVP is deliberately narrow: **one prompt, one configurable provider, one user, one image at a time, SQLite, no containers**. Every omission is intentional — the goal is to get real family documents through the transcription pipeline as fast as possible and let the quality of the output guide every subsequent decision.
|
||||
@@ -5,6 +5,7 @@ description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"google-genai>=1.0.0",
|
||||
"openai>=2.43.0",
|
||||
"pydantic>=2.13.4",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user