Spaces:
Sleeping
Sleeping
| # Third Eye β Fixes Report (root causes + verification) | |
| ## TL;DR | |
| - **STT was NOT inherently slow.** The Cohere card advertises RTFx ~500 ("blazing fast"). | |
| The ~5-minute transcriptions were a **configuration bug**: float32 + `device_map="auto"` | |
| ran the model on CPU / partially offloaded (~1s per forward pass). **Keep Cohere β it wins the | |
| Cohere prize. Do NOT switch to Whisper.** | |
| - Vision hallucinations (`$20` for `$18`) came from **sampling**; switched to **greedy** + **bf16**. | |
| - All other reported bugs were already fixed; verified in code. 3 minor issues closed. | |
| - **38/38 unit tests pass** (CPU). **GPU fixes MEASURED on Modal A10G:** STT 5 min β 0.6s warm; | |
| vision now reads `$18` (not `$20`) and `mango lassi` (not `MANGOLAISSI`). See "Verification" below. | |
| --- | |
| ## Root cause analysis | |
| ### BUG 1 β STT slow (~5 min). FIXED (config) β `cohere_stt.py` | |
| **Evidence:** logs show `1.01s/it` per forward pass. A 2B model on an A10G does a forward pass in | |
| ~10β30 ms, not ~1000 ms. The model card benchmarks RTFx ~524 (a 6 s clip β 0.01 s of compute). | |
| The app was ~25,000Γ slower than the model's own benchmark β not the model, the config. | |
| **Three compounding causes, all fixed:** | |
| 1. `from_pretrained(..., device_map="auto")` with **no `torch_dtype`** β loaded in **float32**. | |
| On a single-GPU container this both doubles memory and pushes layers toward CPU offload, which | |
| streams weights per token. β Now: `torch_dtype=bfloat16` and an explicit `.to("cuda")`. | |
| 2. No decoding flags β if `generation_config` defaulted to beam search, every token costs N forward | |
| passes (the repeated `6/6` progress bars). β Now: `num_beams=1, do_sample=False` (greedy). | |
| 3. `max_new_tokens=256` β trimmed to `128` (speech answers are short). | |
| **Why this is the fix and not a guess:** greedy + half-precision + single-GPU pin is the standard | |
| cure for "transformers `generate` is mysteriously 100Γ+ too slow," and it directly removes every | |
| mechanism the logs pointed at (per-forward CPU cost, per-token beam multiplier). | |
| ### BUG 1b β "Ask" mode answered the wrong question. FIXED β `cohere_stt.py` | |
| **Symptom:** spoken questions weren't answered correctly. **Not a wiring bug** β the vision model | |
| answers fine. The STT was **hallucinating a tail over trailing silence**: | |
| ``` | |
| SPOKEN: 'What is the cheapest item on the menu and how much does it cost?' | |
| HEARD: 'What is the cheapest item on the menu and how much does it cost? Yes, sir. It was a clue.' β fake | |
| ``` | |
| The fake tail corrupts the question handed to the vision model (here it survived because the real | |
| text came first; with a shorter/noisier real-mic clip the tail dominates and the answer goes wrong). | |
| **Fix:** trim leading/trailing silence with `librosa.effects.trim(top_db=30)` before transcription β | |
| removes the silent padding the model hallucinates over. **Verified:** | |
| ``` | |
| HEARD: 'What is the cheapest item on the menu and how much does it cost?' (exact match, 39->29 tokens) | |
| HEARD: 'How often should I take this medication?' -> ANSWER: 'take one capsule every 8 hours.' (correct) | |
| clean-clip regression: 'Hello, this is a test...' still transcribes perfectly. | |
| ``` | |
| ### Vision hallucination (`$20`β `$18`). FIXED β `modal_backend.py` | |
| `sampling=True, temperature=0.2` still lets the model invent plausible-but-wrong numbers. Switched | |
| to **`sampling=False` (greedy)** β the faithful, repeatable choice for an accessibility/OCR tool β | |
| and **bf16** (what the MiniCPM-V-2 card recommends; more stable than fp16 on small text). | |
| ### Temp-file leak. FIXED β `utils.py` + `app.py` | |
| `bytes_to_wav()` left WAVs in temp forever. Added `prune_old_wavs()` (removes only Third-Eye WAVs | |
| older than 10 min, so a clip still being served is never deleted), called at each pipeline start. | |
| ### Previously-reported bugs β verified fixed in code | |
| - READ "s" output β improved verbatim prompt (`app.py: resolve_question`). β | |
| - `repetition_penalty`/`max_new_tokens` removed from `model.chat` (they caused refusals). β | |
| - STT gated-model 403 β specific, actionable error message. β | |
| - `safe_call` now surfaces exception type+message (truncated). β | |
| --- | |
| ### Read Text OCR distortion (`MANGOLAISSI`). FIXED (mitigated) β `modal_backend.py` | |
| **Root cause:** small text on a full 1024x1536 image exceeds a 2.8B VLM's effective OCR | |
| resolution, so it merged `MANGO LASSI` -> `MANGOLAISSI`. Prompt engineering did NOT help | |
| (tested: still `MANGOLIASSI` + a hallucinated price). **Validated cause:** cropping to the text | |
| region fixed it (`Mango Lassi $5`), proving it's a resolution problem, not a knowledge problem. | |
| **Fix:** automatic **tiled OCR** for Read Text mode (`describe_scene(..., tile=True)`): split the | |
| image into two overlapping top/bottom bands, OCR each (enlarges relative text), and stitch the | |
| results with word-overlap dedup (`stitch_overlapping_text`, unit-tested). **Automatic β no | |
| box-drawing**, which matters because the user is blind and can't draw a selection box. Measured: | |
| ``` | |
| label: AMOXICILLIN 500 mg Take one capsule every 8 hours Finish all medication EXP 12/2027 (perfect) | |
| sign: CENTRAL STATION 250 m PLATFORM 1-6 (perfect) | |
| menu: ...GRILLED FISH $18 MANGOS LASSI $5 (space restored & readable; was "MANGOLAISSI") | |
| ``` | |
| **Residual honest limit:** the menu still shows a minor glyph error (`MANGOS`), the genuine 2.8B | |
| ceiling. It is now legible speech, not gibberish. Cost: Read Text does 2 model calls (~6s). | |
| ## Faster-model question | |
| Within Cohere's family this transcribe model **is** the ASR model, and once configured correctly it | |
| *is* fast (RTFx ~500). No turbo variant is needed. Keeping Cohere keeps the Cohere award eligible. | |
| --- | |
| ## Verification β MEASURED on Modal GPU (A10G), 2026-06-14 | |
| **Local (CPU, this machine):** | |
| - `38/38` unit tests pass (`python -m pytest -q`); `ruff check` clean; both modules import. | |
| **STT benchmark** (`modal run modal_backend.py::stt_benchmark`): | |
| ``` | |
| [third-eye STT] loaded CohereLabs/cohere-transcribe-03-2026 | cuda_available=True | device=cuda:0 | dtype=torch.bfloat16 | |
| [COLD] total round-trip: 58.8s (one-time container + model load) | |
| [third-eye STT] generate: 1.56s for 26 tokens (first call, includes CUDA warmup) | |
| [third-eye STT] generate: 0.16s for 26 tokens (warm: ~160 tok/s β correct for 2B on A10G) | |
| [WARM] total round-trip: 0.6s | |
| transcript: 'Hello, this is a test of the third eye text to speech system.' (correct) | |
| ``` | |
| **Result: ~5 minutes β 0.6s warm round-trip (~500-1000x). STT is now fast enough to demo live.** | |
| **Vision/TTS smoke test** (`modal run modal_backend.py::smoke_test`): | |
| ``` | |
| [third-eye VISION] loaded openbmb/MiniCPM-V-2 | device=cuda:0 | dtype=torch.bfloat16 | |
| [third-eye VISION] chat: 3.85s | |
| "...Prices range from $6 for a soup to $18 for grilled fish, with mango lassi priced at $5." | |
| ``` | |
| **Result:** greedy `sampling=False` works (no refusal); `$18` read correctly (was `$20`); | |
| `mango lassi` spelled correctly (was `MANGOLAISSI`); all three models confirmed on cuda + bf16. | |
| **Diagnostic safety net:** if `device=cpu` ever appears in the STT log, the STT image installed a | |
| CPU-only torch β fix by pinning a CUDA wheel: `pip_install("torch>=2.5", | |
| index_url="https://download.pytorch.org/whl/cu124")`. (Not needed currently β verified cuda:0.) | |
| ``` | |