A newer version of the Gradio SDK is available: 6.20.0
BUILD PROMPT β paste everything below this line into Codex / OpenCode
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
You are a senior Python + Gradio engineer. Build a Hugging Face Space called "Third Eye": a fully voice-driven accessibility app for blind / low-vision users. The user points a webcam at something (menu, medicine label, sign, scene), speaks a question, and hears the answer back in their language. Zero typing required on the happy path.
Work in the current project folder. Build incrementally and verify at every checkpoint. Do not write the whole app at once. Do not invent APIs. Follow these rules exactly.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ABSOLUTE RULES (do not break these)
- Verify before coding inference. Model load/call APIs differ by version. For every model, open its Hugging Face model card and confirm the exact model ID, load call, and inference call BEFORE writing that stage. If a tool to fetch docs is available (e.g. context7), use it. If a model ID does not resolve, STOP and report it β never silently substitute another model.
- Sponsor models ONLY (table below). No OpenAI/Whisper/Google/etc. anywhere.
- Build in phases. Stop at each CHECKPOINT and confirm it passes before continuing.
- Never show a raw traceback to the user. Every stage is wrapped; failures become
gr.Warning("friendly message")and a graceful fallback. - MUST-HAVE before SHOULD-HAVE before NICE-TO-HAVE. A working minimal app beats a broken complete one. If you run low on time, ship the vertical slice.
- When unsure about an API after reading the card, write the smallest possible test script and run it before wiring that stage into the UI.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
MODELS (only these β verify each card before use)
| Role | Model ID | Params | Sponsor |
|---|---|---|---|
| Vision + OCR (PRIMARY) | openbmb/MiniCPM-V-2_0 |
2.8B | OpenBMB |
| Vision + OCR (FALLBACK only if quality unacceptable) | openbmb/MiniCPM-V-4_5 |
8B | OpenBMB |
| Speech-to-text | CohereLabs/cohere-transcribe-03-2026 |
2B | Cohere |
| Text-to-speech | openbmb/VoxCPM2 |
2B | OpenBMB |
Primary param budget = 2.8B (β€ 4B β qualifies for Tiny Titan). If you must use the 8B fallback, write in the README: "fallback used, Tiny Titan badge forfeited." Never swap silently.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TECH STACK
- Gradio 5.x (
gr.Blocks) on a Hugging Face Space (sdk: gradio). - Modal serverless GPU (A10G) runs vision + TTS + STT.
- Python 3.11. No other cloud APIs.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TARGET FILE TREE
app.py # Gradio UI + orchestration
modal_backend.py # Modal app: describe_scene(), speak(), transcribe_audio()
cohere_stt.py # Cohere Transcribe wrapper (imported by modal_backend)
utils.py # image<->bytes, bytes<->wav, safe_call wrapper
requirements.txt
.env.example # MODAL_TOKEN_ID, MODAL_TOKEN_SECRET, HF_TOKEN
README.md # HF frontmatter + story + edge section
BLOG.md # Field Notes draft
DEMO_SCRIPT.md # 45s shot list
assets/
custom.css # "Iris" design system
sample_menu.jpg sample_label.jpg sample_sign.jpg (use 3 royalty-free / your own photos)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 0 β VERIFY REALITY (do this first, write NO inference code yet)
For each model (MiniCPM-V-2_0, VoxCPM2, cohere-transcribe-03-2026):
- Confirm the model ID resolves on Hugging Face.
- Read the card's usage example. Record the EXACT: import,
from_pretrainedargs (trust_remote_code, dtype, etc.), and the inference call signature. - Note especially: MiniCPM-V's
model.chat(...)signature varies β some versions takeimage=<PIL>, msgs=[{"role":"user","content":<str>}]; others takeimage=None, msgs=[{"role":"user","content":[<PIL>, <str>]}]. Use whatever THIS card shows. - For VoxCPM2: find the real synthesis call (it may need a reference voice / a
generatemethod, notmodel.synthesize). For Cohere Transcribe: confirm whether it loads viatransformerspipeline("automatic-speech-recognition", ...)or needs a custom call.
CHECKPOINT 0: Output a short table of the verified API for each model (load call + infer call). If anything can't be verified, list it explicitly and propose the smallest fix. Then continue.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 1 β SCAFFOLD (UI renders with fake data)
Create all files. Use STUB functions that return canned data so the UI runs with no GPU.
requirements.txt:
gradio>=5.0
modal
pillow
soundfile
numpy
(Add transformers, torch, accelerate, sentencepiece, timm to the Modal image, not the
Space requirements β the Space does not run the models locally.)
utils.py β implement:
import io, base64, tempfile, numpy as np
from PIL import Image
def image_to_bytes(image) -> bytes:
if isinstance(image, np.ndarray):
image = Image.fromarray(image)
buf = io.BytesIO(); image.convert("RGB").save(buf, format="JPEG"); return buf.getvalue()
def bytes_to_wav(audio_bytes: bytes) -> str:
f = tempfile.NamedTemporaryFile(delete=False, suffix=".wav")
f.write(audio_bytes); f.close(); return f.name
def safe_call(fn, *args, fallback=None, warn="Something went wrong.", **kwargs):
import gradio as gr
try:
return fn(*args, **kwargs)
except Exception as e:
gr.Warning(f"{warn} ({type(e).__name__})")
return fallback
app.py β build gr.Blocks(css=open("assets/custom.css").read()) with:
- A header with the Iris orb (a
gr.HTMLdiv, classiris idle) + an ARIA live status line. - A language
gr.Dropdown(English, Hindi, German, Tamil, Telugu, Kannada), default English. - Three
gr.Tabs: Describe, Ask, Read Text. Each has agr.Image(sources=["webcam","upload"]), Ask also hasgr.Audio(sources=["microphone"]), plus a large primary button, agr.Audiooutput (setautoplay=True), and a large-fontgr.Textboxoutput for the transcript. - The 3 sample images wired as
gr.Examplesso judges can test with no webcam. - For now, button click calls a STUB
run_pipeline(...)that returns a placeholder wav path + text.
CHECKPOINT 1: python app.py launches locally; UI loads; clicking a button shows placeholder
text and the Iris orb is visible. No GPU involved yet.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 2 β MODAL VISION (real description)
modal_backend.py: create the Modal app + GPU image, implement describe_scene using the
verified MiniCPM-V API from Phase 0.
import modal
app = modal.App("third-eye-backend")
vision_image = modal.Image.debian_slim().pip_install(
"transformers>=4.40","torch","pillow","accelerate","sentencepiece","timm","soundfile")
@app.function(gpu="A10G", image=vision_image, timeout=180)
def describe_scene(image_bytes: bytes, question: str, lang: str = "en") -> str:
import io, torch
from PIL import Image
from transformers import AutoModel, AutoTokenizer
model_id = "openbmb/MiniCPM-V-2_0"
model = AutoModel.from_pretrained(model_id, trust_remote_code=True,
torch_dtype=torch.float16).cuda().eval()
tok = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
prompt = question.strip() or "Describe everything you see in detail."
# >>> USE THE EXACT .chat() SIGNATURE YOU VERIFIED IN PHASE 0 <<<
return model.chat(image=image, msgs=[{"role":"user","content":prompt}], tokenizer=tok)
Deploy: modal deploy modal_backend.py. Then write test_vision.py that reads sample_menu.jpg,
calls describe_scene.remote(...), prints the answer.
CHECKPOINT 2: Real, sensible text comes back for the menu image. If quality is unusable, switch
to MiniCPM-V-4_5 and note the forfeit in README (do not do this lightly).
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 3 β MODAL TTS (real speech)
Add speak(text, lang) to modal_backend.py using the verified VoxCPM2 API. Return WAV bytes.
Write test_tts.py that synthesizes "Hello, this is Third Eye." and saves out.wav.
CHECKPOINT 3: out.wav plays intelligible speech. (If multilingual needs a lang/voice arg, wire
lang through now.)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 4 β WIRE "DESCRIBE" END-TO-END β MINIMUM VALID SUBMISSION
Replace the stub run_pipeline in app.py:
def run_pipeline(image, audio_path, mode, lang):
if image is None:
gr.Warning("No image captured. Point the camera and try again.")
return None, "No image captured.", ""
img_bytes = image_to_bytes(image)
if mode == "Ask" and audio_path:
question = safe_call(transcribe_audio.remote, audio_path,
warn="Couldn't hear you β type your question instead.", fallback="")
elif mode == "Read Text":
question = "Read all text visible in this image, word by word, exactly as written."
else:
question = "Describe everything in this image in detail for a blind user."
answer = safe_call(describe_scene.remote, img_bytes, question, lang,
warn="Vision model is waking up β try once more.", fallback="")
if not answer:
return None, "Could not analyze the image.", question
audio_bytes = safe_call(speak.remote, answer, lang, warn="Voice unavailable β showing text.",
fallback=None)
audio_out = bytes_to_wav(audio_bytes) if audio_bytes else None
return audio_out, answer, question
Show gr.Progress with "Loading AI models (first run: ~30s)β¦" around the first heavy call.
CHECKPOINT 4: In the running Space/app, pick sample_menu.jpg in the Describe tab β audio
auto-plays a description + the transcript shows. THIS IS THE MINIMUM VALID SUBMISSION. Commit here.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 5 β STT + "ASK" (zero-typing loop)
Implement transcribe_audio(audio_path) in modal_backend.py (delegates to cohere_stt.py) using
the verified Cohere Transcribe API. Wire the Ask tab: mic β transcribe β describe β speak.
CHECKPOINT 5: Record a spoken question about the sample image β hear a spoken answer. No typing.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 6 β "READ TEXT" + LANGUAGE + CSS POLISH
- Read Text tab uses the fixed OCR prompt (already in run_pipeline).
- Confirm the language dropdown changes TTS output language (test English + Hindi minimum).
- Build the real Iris
assets/custom.css(see DESIGN SPEC below). Drive orb state fromapp.pyby updating the orb HTML's class (idle / listening / seeing / thinking / speaking) at each stage.
CHECKPOINT 6: All three tabs work; Hindi TTS works; UI matches the Iris spec.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 7 β HARDENING
- Cold-start progress shown on first call.
- Mic failure β reveal a
gr.Textboxtyped-question fallback (never block). - TTS failure β large-font text output only, with a
gr.Warning. - Every stage wrapped in
safe_call; no traceback ever reaches the user. - Confirm 3 examples load and run with no webcam.
CHECKPOINT 7: Manually break the mic and break TTS β the app degrades gracefully, never crashes.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PHASE 8 β SUBMISSION ASSETS
README.md β start with this frontmatter VERBATIM:
```yaml
title: Third Eye emoji: ποΈ colorFrom: indigo colorTo: blue sdk: gradio sdk_version: "5.0" app_file: app.py pinned: false tags: - hackathon - build-small - backyard-ai - accessibility - blind - openbmb/MiniCPM-V-2_0 - openbmb/VoxCPM2 - cohere/cohere-transcribe-03-2026 - tiny-titan - off-brand
Then write: what it is, who it's for, how to use, models+sizes table (call out 2.8B Tiny Titan),
architecture paragraph, **on-device/edge section** (honest claim + roadmap: these models quantize to
int4 GGUF and can run offline on a phone via llama.cpp β framed as roadmap, not a shipped phone
build), accessibility & Iris design, run-it-yourself (env vars + `modal deploy` + Space secrets:
MODAL_TOKEN_ID / MODAL_TOKEN_SECRET / HF_TOKEN), credits (OpenBMB, Cohere, Modal, HF).
`BLOG.md` β a Field Notes draft: "What VLM quality really feels like at 2.8B" (what worked, where
MiniCPM-V-2 struggled vs the 8B fallback, OCR accuracy notes). `DEMO_SCRIPT.md` β the 45β60s shot
list (eye opens β blindfolded menu read aloud in Hindi β label/sign cuts β tagline).
**CHECKPOINT 8:** Space builds clean, loads on a cold visit, all assets present.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PHASE 9 β NICE-TO-HAVE (only if time remains, in this order)
1. Bounding-box "Zoom & Read" tab via `gr.ImageEditor`: user draws a rectangle, the crop is sent to
MiniCPM-V with "Read the text in this image exactly as written."
2. Cache model weights on a `modal.Volume` to cut cold-start time.
3. A small GGUF int4 on-device proof + a benchmark table in README (params, int4 size, target device).
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DESIGN SPEC β "Iris" custom CSS (Off-Brand track)
Accessibility constraints rendered as a futuristic aesthetic. Pure CSS so it's reliable to build.
- **Background** `#06070A` + faint radial vignette; optional subtle grain.
- **Accent gradient** `#5B7CFA β #3DE0FF`; glows via layered `box-shadow`.
- **Text** `#F5F7FA`; base font 20px, output text 24px+, line-height 1.7; contrast β₯ WCAG AA.
- **Iris orb**: a centered circular `div` (~140px) with the accent radial gradient and a soft outer
glow. Define keyframe animations per state class:
- `.iris.idle` slow breathing scale 1.0β1.04 (~4s).
- `.iris.listening` pulsing ring.
- `.iris.seeing` a scan-line sweep.
- `.iris.thinking` faster, tighter pulse.
- `.iris.speaking` waveform-like glow pulse synced loosely to playback.
- **Primary button**: large pill / circle, min 96px hit target, accent gradient, thick cyan focus ring.
- **Surfaces**: glass panels β `backdrop-filter: blur(12px)`, 1px hairline border, subtle inner glow.
- **Motion**: wrap ALL animations in `@media (prefers-reduced-motion: reduce)` to disable them.
- **Focus**: visible thick cyan focus ring on every interactive element (serves keyboard + the look).
- The ARIA `live=polite` status line mirrors the orb state in words for screen-reader users.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# DONE = ALL OF THIS TRUE
- [ ] Describe / Ask / Read Text all work end-to-end, zero typing on the happy path.
- [ ] Audio answers auto-play; transcript shown large.
- [ ] Language dropdown drives multilingual TTS (English + Hindi verified).
- [ ] 3 bundled examples run with no webcam.
- [ ] Cold-start progress + mic/TTS fallbacks + `gr.Warning` everywhere; no raw tracebacks.
- [ ] Iris custom CSS live (Off-Brand); WCAG-AA contrast.
- [ ] README frontmatter verbatim; edge/on-device section honest; BLOG.md + DEMO_SCRIPT.md present.
- [ ] Primary model 2.8B β€ 4B (Tiny Titan) β stated in README.
- [ ] Space builds clean and loads cold.
Report which checkpoints passed and paste the final file tree when done.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ