---
title: Polyglot Tutor
emoji: ๐
colorFrom: indigo
colorTo: green
sdk: docker
app_port: 7860
pinned: false
---
# ๐ Polyglot Tutor
> Adaptive language tutor covering the four skills (reading, listening, writing, speaking),
> driven by a CEFR classifier and a predictive spaced-repetition learner model.
> Runs for free on a Hugging Face Space (CPU) with an optional local-GPU "premium" mode.
**Status: M0 โ walking skeleton.** CI, Docker โ GHCR, HF Space deploy and all service
contracts (LLM / ASR / TTS / storage) are live; features land milestone by milestone.
## TL;DR (for recruiters)
- **ML core**: fine-tuned multilingual CEFR (A1โC2) text classifier benchmarked against a
published baseline; FSRS-style spaced repetition evaluated offline on public review logs;
LLM-generated exercises gated by an LLM-as-judge.
- **Engineering**: provider-agnostic services (`typing.Protocol` + env-driven factories),
pinned toolchain (uv, ruff, pre-commit), tested fakes, CI โ GHCR, free-tier deployment with
documented constraints (ephemeral disk, cold starts, rate limits).
- **Honest evals**: every milestone ships metrics with caveats, tracked in MLflow
(see `docs/evals/`).
## Architecture
```mermaid
flowchart LR
UI[Gradio UI
4 skill tabs] --> EX[Exercise generators
+ cache]
EX --> LLM[LLMClient
Gemini / Mistral / Ollama / fake]
EX --> ASR[ASRClient
faster-whisper / remote / fake]
EX --> TTS[TTSClient
edge-tts / local / fake]
EX --> CEFR[CEFR classifier
ONNX int8, CPU]
UI --> SRS[Learner model
FSRS + ability estimate]
SRS --> DB[(Repository
memory / SQLite / Supabase)]
EX --> DB
```
Each box on the right is a `Protocol` with swappable implementations selected by environment
variables โ the same image runs as the free Space ("light") or against a local GPU box over
Tailscale ("premium"). See `docs/adr/` for the reasoning.
## Quickstart (dev)
```bash
uv sync # runtime + dev deps (pinned via uv.lock)
uv run pre-commit install
cp .env.example .env # defaults to the offline fake provider
uv run python -m tutor.app.main # http://localhost:7860
uv run pytest
```
To talk to a real LLM, set in `.env`: `LLM_PROVIDER=gemini`, `LLM_API_KEY=...`
(free key at https://aistudio.google.com/apikey), then check the *Diagnostics* tab โ *Ping LLM*.
Dataset download / EDA (kept out of the runtime image):
```bash
uv run --group data python scripts/download_data.py
```
## Deployment
1. **CI (GitHub Actions)** โ lint + tests on every push/PR; on `main`, the Docker image is
pushed to `ghcr.io//polyglot-tutor`.
2. **HF Space (Docker, cpu-basic)** โ create the Space once, then set:
- GitHub โ *Secrets*: `HF_TOKEN` (write) ยท *Variables*: `HF_SPACE=/`
- Space โ *Settings*: `LLM_PROVIDER`, `LLM_MODEL`, `LLM_API_KEY`,
`GRADIO_AUTH_USERNAME`, `GRADIO_AUTH_PASSWORD`
Every push to `main` syncs the repo to the Space, which rebuilds from the same Dockerfile
(a Docker Space cannot pull the GHCR image โ GHCR is the CI artifact, see ADR 0001).
## Roadmap
| Milestone | Scope | Headline eval |
|---|---|---|
| **M0** โ
| Walking skeleton: CI, GHCR, Space, Protocols + fakes | CI green, live Space |
| **M1** | CEFR classifier + reading comprehension (LLM questions, cached & judge-gated) | macro-F1 / adjacent acc. / QWK vs published UniversalCEFR baseline |
| **M2** | TTS + dictation with light ASR | WER (incl. non-native audio) justifying tiny vs small |
| **M3** | Supabase persistence + writing correction (typed errors via ERRANT, per-learner profile) | error-type P/R on W&I+LOCNESS sample |
| **M4** | Learner model: FSRS scheduling + ability estimate, next-exercise policy | AUC / log-loss / calibration on public Anki review logs |
| **M5** | Pronunciation scoring + premium local-GPU mode (Tailscale) | correlation with expert scores on speechocean762 |
| **M6** (stretch) | Real-time voice conversation tab (Gemini Live API behind a ConversationClient Protocol) | qualitative demo; latency budget documented |
## Data & licensing
This is a **non-commercial portfolio/demo project**. CEFR-labeled corpora come from
[UniversalCEFR](https://huggingface.co/UniversalCEFR) (per-subset, mostly research-only
licenses โ original papers cited); SRS benchmarks use the open Anki review-log datasets;
pronunciation evaluation uses speechocean762 (free for any use). No licensed text is
committed to this repo; `data/` is gitignored and rebuilt by `scripts/download_data.py`.
Details and caveats: `docs/adr/0003-datasets-and-licensing.md`.