---
name: project_glasses_speech_stack
description: "Glasses speech stack — keep Whisper for transcription (now multilingual), move synthesis to ElevenLabs eventually; omid-fleet migration gaps"
metadata: 
  node_type: memory
  type: project
  originSessionId: 8f78bb8f-e174-4aa6-b0c2-b71cb9b605ae
---

The glasses hub (serve.py on omid-fleet :8094) speech stack, as of 2026-06-23:

**Transcription (input):** Whisper (faster-whisper "small") via `/api/transcribe`.
Cameron likes it — KEEP IT. Was broken after the omid-fleet migration (faster-whisper
not installed in serve.py's `.venv`); fixed by `pip install faster-whisper` (brings
PyAV, so no system ffmpeg needed). Made multilingual: `language=None` (auto-detect) so
it handles English AND Persian; was hard-coded `language="en"`. Optional `?language=`
form-field override exists. KEY: Whisper-small almost always MISLABELS Persian as Arabic
`ar` (~97% conf) and mangles the script (Arabic letter forms), so pure auto-detect gives
garbled output. Fix (2026-06-23): when auto-detect returns a Persian-script neighbour
(`ar`/`ps`/`ur`/`tg`/`ckb`), re-transcribe forcing `language="fa"` → clean Farsi. Cameron
speaks only en+fa (never Arabic), so it's safe; costs a 2nd transcribe pass on Persian
clips only (English stays single-pass `en`). Trade-off: global auto-detect could rarely
mis-detect a short English command — if that regresses, go per-tab (needs a client change
to thread language through the record action).

**Synthesis (output) — GLASSES TTS DISABLED 2026-06-24:** Cameron rarely hears the
glasses voice replies and the shared ElevenLabs account ran out of credits (free tier,
39,493 char quota, hit 0 — both glasses TTS and the website 401 with `quota_exceeded`).
So glasses synthesis is OFF: `/api/tts` returns 204 and the `tts` auto-play field was
dropped from chat + persian feeds. The Persian WEBSITE keeps its own synthesis (persian
app `/api/ask`, separate from `/api/tts`) — it's the only intended consumer now, so when
the monthly quota resets the website gets it all. Re-enable glasses TTS: uncomment
`_tts_cached(text)` in `api_tts` + restore the `tts={...}` fields in chat_view/persian_view.
NOTE: the glasses Persian tab still proxies to the persian app which *attempts* audio gen
(small, into the shared cache) — not yet suppressed; the key lacks `user_read` so quota/
reset date must be read from the ElevenLabs dashboard, not the API. Below is the prior
(now-inactive) ElevenLabs wiring, kept for re-enable:

ALL TTS went through ElevenLabs (multilingual v2) as of 2026-06-23 — Piper fully removed. Unified path: `_tts_cached(text)`
content-hash caches every clip; Persian phrases reuse the persian app's pre-generated
files (`/data/cameron/life/projects/persian/static/audio/`), everything else caches under
`/data/cameron/agents_stuff/agents/glasses/tts_cache/`. Creds come from the persian app's
`.env` (one ElevenLabs account powers everything): `ELEVENLABS_API_KEY` +
`ELEVENLABS_VOICE_ID`. A `GLASSES_TTS_VOICE_ID` in that .env overrides the English/general
voice if set (else falls back to the Persian voice — multilingual handles both).
WATCH: every Chat reply now bills ElevenLabs characters — if on free tier, quota may run
out; Cameron may want a paid plan and/or a nicer dedicated English voice via
`GLASSES_TTS_VOICE_ID`. (Piper leftovers — missing `python` on PATH, no piper in venv,
absent voice model — are now irrelevant.)

See [[project_persian_agent_shipped]] and [[project_dual_host_architecture]]. Persian
audio mechanism: `/api/tts` detects Arabic-script (U+0600–U+06FF) and serves the persian
app's content-hash-cached ElevenLabs mp3.
