Spaces:
Runtime error
Runtime error
| 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. | |
| <!-- The YAML front-matter above is Hugging Face Space metadata: this repo is synced | |
| as-is to a Docker Space by .github/workflows/deploy-space.yml --> | |
| ## 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<br/>4 skill tabs] --> EX[Exercise generators<br/>+ cache] | |
| EX --> LLM[LLMClient<br/>Gemini / Mistral / Ollama / fake] | |
| EX --> ASR[ASRClient<br/>faster-whisper / remote / fake] | |
| EX --> TTS[TTSClient<br/>edge-tts / local / fake] | |
| EX --> CEFR[CEFR classifier<br/>ONNX int8, CPU] | |
| UI --> SRS[Learner model<br/>FSRS + ability estimate] | |
| SRS --> DB[(Repository<br/>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/<owner>/polyglot-tutor`. | |
| 2. **HF Space (Docker, cpu-basic)** β create the Space once, then set: | |
| - GitHub β *Secrets*: `HF_TOKEN` (write) Β· *Variables*: `HF_SPACE=<user>/<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`. | |