← HOMEEGL LEARNING LABS · PLATFORM DECK
← → arrows · space · click edges
Early Grade Learning · Cambodia · MOEYS Ecosystem

EGL Learning Labs

The classroom video-collection & AI-analysis platform: teachers upload lesson videos from the web or Telegram, the system transcribes Khmer/English audio, corrects it with an LLM, scores it against Early Grade Learning teaching practices, and routes it to a staff review workflow.

The Problem

Why this platform exists

Classroom practice is invisible

Early-grade teaching quality across Cambodian provinces can't be observed at scale. In-person observation is expensive, slow, and reaches a handful of classrooms.

Khmer is a low-resource language

Almost no commercial AI service transcribes Khmer classroom audio reliably. Off-the-shelf tools built for English don't transfer.

Teachers need a zero-friction path

Many teachers work primarily from phones with Telegram, not laptops with browsers. Collection has to meet them where they are.

Scale of the Build

Platform at a glance

15
frontend routes (teacher + admin areas)
82
REST API endpoints across 13 routers
31
database tables · 13 Alembic migrations
9
provider integrations, secrets encrypted at rest
~18k
lines of code (10.6k TS/TSX + 7.0k Python)
2 GB
max upload per video (browser + API + nginx aligned)
14,372
villages in the bundled NCDD gazetteer (bilingual)
3
interchangeable LLM providers (Anthropic · OpenRouter · Mistral)
How It's Built

Architecture — one domain, two apps

🌐
egl.openplp.comnginx TLS termination. / → SSR frontend, /api → FastAPI, /api/uploads → video files.
→
:3000
TanStack Start SSRFile-based routing, auth gate on _authenticated/, JWT in localStorage, dark/light theming, Framer Motion.
→
:8000
FastAPI backendJWT bearer auth, streamed uploads (1 MB chunks), background AI pipeline, dynamic encrypted provider settings.
→
:5432
PostgreSQL + diskAlembic-owned schema. Videos stored on local disk at /var/egl/uploads, served back via nginx.

Auth options

Email/password · Google Sign-In · Telegram Login Widget · Cloudflare Turnstile bot-check gate · SMTP password recovery. First user created becomes super_admin.

Dynamic secrets

No API keys in .env. Super-admin settings UI writes AES-256-GCM-encrypted credentials to per-provider tables; secrets are write-only over the wire, every change audited.

Self-hosted Telegram API

A local telegram-bot-api server lifts the cloud 20 MB download cap to ~2 GB so real classroom videos can flow in through the bot.

How It Works · Web

The teacher journey

1
Sign inEmail, Google, or Telegram. Turnstile guards signup when enabled.
→
2
Complete profileCascading school picker (live MSS data) + separate home-village picker (NCDD gazetteer).
→
3
Upload lessonMetadata + video with progress bar. Optional in-browser 720p compression (ffmpeg.wasm) when source is HD.
→
4
Track processingStatus auto-polls; in-app + Telegram notification when ready or failed.
→
5
Review resultsPlayer, bilingual transcript (raw ⇄ corrected toggle), EGL analysis, reviewer feedback, consent state.

My Videos + Search

Filterable list with processing badges; global search over title/subject/notes (staff see everything, teachers see their own).

Consent management

Blanket consent covers all existing + future videos; per-video withdrawal supported; state persists across reloads and shows on every video detail page.

Progress & guidelines

Personal stats page plus static recording guidelines so teachers know what a good lesson video looks like.

How It Works · Mobile-First Path

Telegram bot upload — no browser required

1
Link onceTeacher generates a 10-minute code in their profile, sends /start <code> to the bot.
→
2
Send the videoStraight from the phone camera roll. Webhook is HMAC-verified and deduplicated, so retries can't double-ingest.
→
3
Tag via buttonsBot replies with inline keyboards in Khmer: grade 1–6, subject, consent toggle — no typing needed.
→
4
Get notifiedDM with a direct link when processing finishes: “✅ Processed and ready to review.”
How It Works · Intelligence

The AI processing pipeline

uploaded→ transcribing→ analyzing→ ready or failed

1 · Optimize

ffmpeg transcodes HD → 720p H.264 MP4 (same UUID, URL stays valid) — only kept if smaller. A storage/playback win; transcription cost is set by audio duration, not resolution.

2 · Transcribe

faster-whisper large-v3 (best available for Khmer). Audio decoded to 16 kHz mono once, then two passes: native language (auto-detected) + English translation.

3 · Correct

Post-ASR LLM pass fixes Whisper's systematic Khmer errors (homophones, word segmentation, numerals). Timestamps preserved; raw output kept for audit; skipped for English audio.

4 · Analyze

Claude (tool-use, structured output) scores the lesson 0–100 and extracts EGL practices — modelling, checking understanding, wait time, feedback, scaffolding, student talk — each with evidence + timestamp.

The Differentiator — and Its Ceiling

Khmer language handling

WHAT WORKS
  • Whisper large-v3 with per-video language auto-detect — correct for code-switched Khmer/English classrooms
  • Dual transcript: native Khmer + English translation, both timestamped, from a single audio decode
  • LLM correction pass measurably cleans homophones, segmentation, and numeral/date errors
  • Raw Whisper output preserved under raw_segments — corrections are auditable, never destructive
  • VAD off by default because it drops real classroom speech (recitation, chorus answers)
HARD LIMITS
  • Whisper is the only viable Khmer ASR here — Mistral Voxtral has no Khmer at all; OpenRouter/Gemini won't reliably transcribe Khmer audio; Claude has no audio API
  • large-v3 is still a low-resource-language model: base accuracy is well below English, and the LLM pass corrects but cannot recover what ASR never heard
  • large-v3 on CPU is slow — roughly real-time or worse per audio hour; volume requires a GPU
  • Correction quality is capped by the active LLM provider; with no key configured, raw Whisper output ships as-is
  • EGL analysis reasons over the English translation — translation errors propagate into scoring
How It Works · Staff Side

Admin, review & oversight

Org-wide dashboard

Staff see a 30-day upload trend, geographic breakdowns by province/school (inherited from teacher MSS profiles), teacher coverage, and review outcomes (approved / needs work / rejected / pending).

Review workflow

One review per reviewer per video: approve / needs-work / reject, optional 1–5 rating + comment. Teacher gets a named notification on every decision. Review queue lives in the admin videos grid.

User management

Role changes (teacher ⇄ reviewer ⇄ admin ⇄ super_admin) with safeguards: no self-escalation, the last super_admin can't be demoted. Linked identities (Google/Telegram) visible per user.

Settings hub

Tabbed provider configuration — Anthropic, OpenRouter, Mistral, Google, Telegram, Turnstile, SMTP, PLP MSS — all encrypted at rest, write-only over the wire, with per-provider “test” actions.

Geographic sync

One-click background sync pulls the full MSS hierarchy (zone → school, ~13 API calls), idempotent upserts, status polling in the UI, cron-callable endpoint for automation.

Email reminders

Super-admin can trigger reminder emails to teachers with videos still in the pipeline; endpoint is cron-callable for scheduled nudging later.

Data Foundation

Two geographic hierarchies, deliberately separate

PLP MSS · LIVE SYNC

School placement

Zone → province → district → commune → cluster → school, pulled from the MSS API with encrypted credentials. Drives the profile school picker; every video inherits its uploader's geography, powering the province/school dashboards.

Gap: MSS has no villages — the geo_villages table exists but stays empty.

NCDD GAZETTEER · BUNDLED

Home village

Complete national tree — 25 provinces, 197 districts, 1,646 communes, 14,372 villages, bilingual Khmer + Latin — seeded from a static JSON file with no network or credentials needed.

Why not merged: the datasets share only ~70% of names / ~80% of school codes — welding them would orphan data, so they intentionally power two independent pickers.

Status Check

Feature matrix

Capability Status
Web + Telegram video upload ✓ shipped
Khmer/English transcription + translation ✓ shipped
LLM transcript correction ✓ shipped
EGL analysis (score + practices) ✓ shipped
Consent (blanket + per-video) ✓ shipped
Notifications (in-app + Telegram + email) ✓ shipped
Admin: users, videos, settings, stats ✓ shipped
Geographic sync + gazetteer ✓ shipped
Search ✓ shipped
Capability Status
Dedicated reviewer UI (submit reviews) ◐ backend full, frontend partial
Khmer-language UI ✗ English-only (Khmer in bot only)
CSV/XLSX export ✗ planned
In-browser recording ✗ planned
Live transcript (websocket) ✗ planned
Audit-log viewer UI ✗ table exists, no UI
2FA ✗ not implemented
Cloud storage / CDN ✗ local disk only
Persistent job queue ✗ in-process threads
Barriers · 1 of 3

Infrastructure limitations

SINGLE POINT OF FAILURE
  • Everything — SSR frontend, API, PostgreSQL, and every uploaded video — lives on one VPS. No failover, no replication, no documented backup routine
  • Videos sit on local disk with no S3/object storage and no CDN; disk fill or host loss means data loss and total outage
  • Serving 2 GB videos from the app host competes with API and transcription for the same CPU, disk, and bandwidth
FRAGILE PROCESSING
  • Background pipeline is an in-process thread pool (2 workers) — no Celery/RQ/persistent queue. A restart mid-job silently strands videos in “transcribing”
  • Whisper large-v3 on CPU processes roughly at (or slower than) real time — a burst of 10 uploads creates an hours-long backlog with no horizontal scaling path
  • No rate limiting on the API and no retry/backoff strategy around provider calls
Barriers · 2 of 3

AI & language limitations

ASR CEILING

Khmer transcription accuracy is bounded by Whisper large-v3 — the best option available, but still a low-resource-language model. Noisy classrooms, young children's voices, and chorus responses degrade it further. No commercial provider currently offers a better Khmer alternative.

ERROR PROPAGATION

The chain is transcript → translation → Claude analysis. An ASR mistake survives correction, skews the English translation, and can shift the EGL score. Scores should be treated as a triage signal for human reviewers, not a measurement instrument.

COST & DEPENDENCY

Every video incurs LLM cost (correction + analysis) plus heavy CPU for Whisper. Analysis quality depends on external API availability and keys configured by the admin; with none configured, videos are collected but never analyzed — the platform silently becomes a plain video locker.

Barriers · 3 of 3

Product & adoption gaps

LANGUAGE MISMATCH
  • The web UI is English-only — for a platform whose entire user base teaches in Khmer. Only the Telegram bot buttons speak Khmer today
  • This makes the bot the de-facto primary interface for teachers, while the richer web experience (transcripts, analysis, feedback) stays behind a language barrier
REVIEWER LOOP INCOMPLETE
  • Review backend is complete (endpoints, notifications, stats), but the frontend lacks a dedicated review-submission UI — the loop that turns AI triage into human feedback isn't fully closed
OPERATIONAL & TRUST GAPS
  • No data export (CSV/XLSX) — program staff can't yet pull evidence into reports, the main consumption path for MEL teams
  • JWT lives in localStorage (XSS-exposed, no httpOnly cookie) and there is no 2FA — acceptable for a pilot, weak for a ministry system holding videos of children
  • Consent is recorded but not enforced anywhere downstream (no gating of review/analysis on consent state), and there's no audit-log viewer, retention policy, or deletion workflow for child-safeguarding compliance
  • No frontend tests and no CI — regressions are caught manually
Solutions · 1 of 2

Dedicated server sizing for bulk video

ffmpeg 720p transcode→ Whisper large-v3 · CPU int8 · 2 passes→ Claude correction + analysis (API)

The bottleneck is transcription: large-v3 on CPU with beam 5 costs roughly 1–2× the video's duration on 16 modern cores — a 40-minute lesson ties up a worker for 40–80 minutes. Everything else (RAM, transcode, LLM calls) is comfortably cheap.

Volume CPU RAM Storage Network Est. price / mo
Pilot · ≤20 videos/day (~500/mo) 16 cores (dual Xeon Silver 4208 or equiv.) 64 GB 2× 1 TB NVMe 1 Gbps $228–241
Bulk · 50–100/day (~1,500–3,000/mo) 32 cores (dual Xeon Gold 5218 / EPYC 7313), or 16 cores + GPU ≥16 GB 128 GB 4× 1–2 TB NVMe 1 Gbps unmetered $285–302
Heavy · 100+/day GPU server (L4 · A4000 · RTX 4090) — Whisper runs 10–20× realtime 64–128 GB 4 TB+ NVMe 1 Gbps unmetered $300–450
Solutions · 2 of 2

Total monthly budget — server + Claude Sonnet API

$0.57
Claude API per 40-min Khmer lesson at standard pricing ($3 in / $15 out per 1M tokens) — halves to $0.28 via the Batch API
$0.38
per video at the Sonnet introductory rate ($2 / $10 per 1M tokens, through Aug 2026)
$0.11
per English-audio video — correction pass skipped, only the EGL analysis call runs
Scale Videos / mo Dedicated server (est. / mo) Claude API (standard) Claude API (Batch −50%) Total / mo (est.) Package price (+50% margin)
Pilot 500 16-core · 64 GB · 2×1 TB NVMe — $228–241 ~$285 ~$143 $371 – $526 $557 – $789
Bulk 1,500 32-core · 128 GB · 4×1–2 TB NVMe — $285–302 ~$855 ~$430 $715 – $1,157 $1,073 – $1,736
Heavy 3,000 GPU server (L4 / A4000 / 4090) — $300–450 ~$1,710 ~$855 $1,155 – $2,160 $1,733 – $3,240
National 5,000 GPU server + storage growth — $400–550 ~$2,850 ~$1,425 $1,825 – $3,400 $2,738 – $5,100
Where to Go Next

Recommended sequence

Now
Protect the pilotNightly DB + uploads backup off-host · close the reviewer UI loop · make stuck “transcribing” videos recoverable on restart.
→
Next
Unlock adoptionKhmer UI localization · CSV/XLSX export for MEL staff · consent enforcement + retention/deletion policy.
→
Then
Scale the pipelinePersistent job queue · object storage for videos · GPU (or hosted) Whisper · rate limiting + monitoring.
→
Later
Prove the AIGold-standard human-reviewed set to benchmark Khmer ASR + EGL scoring · calibrate scores against reviewer decisions.
Summary

A complete pilot-grade platform
with a clear path to scale.

Strong today

End-to-end teacher flow on web + Telegram, a genuinely rare Khmer AI pipeline with auditable corrections, encrypted-by-design integrations, and national geographic data built in.

Honest constraints

Single-VPS, local-disk, thread-pool architecture; Khmer ASR at the mercy of Whisper's ceiling; English-only UI; review loop and exports unfinished.

The ask

Treat AI scores as reviewer triage, invest in backups + Khmer UI before scaling, and build a gold-standard set so quality becomes measurable instead of assumed.