A local-first daily speaking-practice tool. Pick a track, get a topic, prepare, record yourself, and review your session — with clean architectural seams for real transcription and analysis to be added later, once real speech analysis actually exists (it doesn't yet — see below).
Built as a personal project to get better at speaking and to practice building real software architecture: local AI inference boundaries, audio handling, a real state machine, asynchronous job design, and honest error handling — not just a UI over a mock API.
The full local practice workflow — track/topic/mode selection, timers, browser microphone recording, review, self-reflection, results, and history — is built and working, backed by SQLite and local file storage. The transcript, metrics, and feedback you see are simulated, clearly labeled as such throughout the UI. No real speech-to-text or speech analysis has been built yet — see docs/SCORING_AND_LIMITATIONS.md.
See docs/PROJECT_STATUS.md for exact test results, known limitations, and what's next.
Requires Python 3.11+ and Node 20+. Two processes, both local, nothing cloud-hosted:
git clone <repository-url>
cd SpeakLab
# Backend
cd backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000# Frontend (separate terminal)
cd frontend
npm install
npm run devOpen the URL Vite prints (typically http://127.0.0.1:5173). See
docs/DEPLOYMENT.md for the production build and its limitations.
A SvelteKit frontend talks to a FastAPI backend over a small JSON/multipart REST API (relative
URLs only, proxied by Vite in dev — see docs/ARCHITECTURE.md). The
backend owns SQLite (WAL mode, real migrations, no ORM) and local recording storage, and
processes each recording through three provider interfaces
(TranscriptionProvider / MetricsProvider / FeedbackProvider) — today backed entirely by
deterministic mocks, designed so a real whisper.cpp / real analytics / optional local-Ollama
implementation can be swapped in later without touching the rest of the app. See
docs/AI_MODEL_STRATEGY.md.
| Doc | What's in it |
|---|---|
| docs/PRODUCT_VISION.md | What this is and isn't, who it's for |
| docs/PRD.md | Exact Phase 1 scope and acceptance criteria |
| docs/ARCHITECTURE.md | System layout, processing model, API routing |
| docs/DATA_FLOW.md | Request-by-request success and failure paths |
| docs/DATA_MODEL.md | Schema, and the topic seed-vs-runtime split |
| docs/TOPIC_TAXONOMY.md | The 50-topic bank and selection logic |
| docs/SCORING_AND_LIMITATIONS.md | What's simulated, honestly |
| docs/AI_MODEL_STRATEGY.md | Mock → real provider swap plan |
| docs/PRIVACY_AND_SECURITY.md | What stays local, upload validation, deletion |
| docs/TESTING.md | Automated / mocked / integration / manual test tiers |
| docs/DEPLOYMENT.md | Running locally; why no Docker/cloud |
| docs/ROADMAP.md | Recommended Phase 2+ scope |
| docs/PROJECT_STATUS.md | Exact current state, test results, known gaps |
| docs/LEARNING_NOTES.md | Plain-language architecture walkthrough |
| docs/adr/ | Five architectural decision records |
| AGENTS.md | Rules for any coding agent working in this repo |
| SECURITY.md | How to report a security/privacy issue |
Everything stays on your machine by default: the backend only binds 127.0.0.1, recordings are
stored locally and never uploaded anywhere, and there's no analytics/telemetry. See
docs/PRIVACY_AND_SECURITY.md for the specifics, including what
upload validation does and doesn't guarantee, and how deletion works.
cd backend && source .venv/bin/activate && pytest -q # 49 passed
cd frontend && npx vitest run # 26 passed
cd frontend && npm run check && npm run lint # type-check + lint
cd frontend && npm run build # production buildSee docs/TESTING.md for what each tier actually covers, and docs/PROJECT_STATUS.md for exact current results.
Provider interfaces are worth their extra boilerplate the moment you can name the second implementation that's coming — they turned the eventual whisper.cpp swap from "rewrite the app" into "write one class." Honest status machines with explicit failure/cleanup paths (see docs/DATA_FLOW.md) catch real bugs that unit tests with idealized fixtures miss — a manual pass through the real UI against the real backend found a genuine MIME-type handling bug that 48 passing automated tests hadn't (see docs/PROJECT_STATUS.md). And writing the documentation as the system was built, not after, made it obvious when a design decision didn't actually have a good reason behind it yet.
MIT — see LICENSE.