Coordinator hotfix: Gemini model env-overridable, default gemini-3.1-flash-lite

Google retired gemini-2.5-flash for new API keys (404). Verified
gemini-3.1-flash-lite live: inline video + structured output, 3/3 synthetic
candidates classified. FESTIVAL4D_GEMINI_MODEL overrides. Round 3 addendum
documents the local .env (gitignored) with Gemini + OpenRouter creds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-16 10:18:43 +10:00
parent b83e577870
commit 8dca2f5154
4 changed files with 27 additions and 6 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ __pycache__/
.venv/ .venv/
.DS_Store .DS_Store
frontend/dist/ frontend/dist/
.env

View File

@ -34,7 +34,7 @@ fully offline and local; the only optional cloud piece is moment classification.
| **ffmpeg** / **ffprobe** on `PATH` | yes | audio extraction, frame sampling, clip cutting | | **ffmpeg** / **ffprobe** on `PATH` | yes | audio extraction, frame sampling, clip cutting |
| **Node 18+** | yes | frontend (Vite + Three.js) | | **Node 18+** | yes | frontend (Vite + Three.js) |
| **COLMAP** on `PATH` | optional | 3D reconstruction. Without it the app still runs — you get synced videos + timeline, just no 3D scene. `brew install colmap` on macOS. | | **COLMAP** on `PATH` | optional | 3D reconstruction. Without it the app still runs — you get synced videos + timeline, just no 3D scene. `brew install colmap` on macOS. |
| A classifier API key | optional | AI moment labels. Default **Gemini 2.5 Flash** (`GEMINI_API_KEY`); also Claude or any OpenAI-compatible/local/OpenRouter endpoint via `FESTIVAL4D_CLASSIFIER`. Without a key you still get audio-detected candidate moments, just unlabeled. | | A classifier API key | optional | AI moment labels. Default **Gemini flash** (`GEMINI_API_KEY`; model `gemini-3.1-flash-lite`, override with `FESTIVAL4D_GEMINI_MODEL`); also Claude or any OpenAI-compatible/local/OpenRouter endpoint via `FESTIVAL4D_CLASSIFIER`. Without a key you still get audio-detected candidate moments, just unlabeled. |
--- ---
@ -92,7 +92,7 @@ corrupts existing data.
To enable AI moment labels, set a key before `events`: To enable AI moment labels, set a key before `events`:
```bash ```bash
export GEMINI_API_KEY=... # default provider (Gemini 2.5 Flash, native video) export GEMINI_API_KEY=... # default provider (Gemini flash, native video)
# or: export FESTIVAL4D_CLASSIFIER=claude ANTHROPIC_API_KEY=... # or: export FESTIVAL4D_CLASSIFIER=claude ANTHROPIC_API_KEY=...
# or: export FESTIVAL4D_CLASSIFIER=local FESTIVAL4D_OPENAI_BASE_URL=... FESTIVAL4D_OPENAI_MODEL=... # or: export FESTIVAL4D_CLASSIFIER=local FESTIVAL4D_OPENAI_BASE_URL=... FESTIVAL4D_OPENAI_MODEL=...
``` ```

View File

@ -102,13 +102,18 @@ _CLASSIFY_PROMPT = (
# only pydantic present; construction reads the key/endpoint from the environment. # only pydantic present; construction reads the key/endpoint from the environment.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
class GeminiClassifier: class GeminiClassifier:
"""Default provider — Gemini 2.5 Flash, native video input (``GEMINI_API_KEY``).""" """Default provider — Gemini flash tier, native video input (``GEMINI_API_KEY``).
model = "gemini-2.5-flash" Model is overridable via ``FESTIVAL4D_GEMINI_MODEL``. Default was ``gemini-2.5-flash``
until Google retired it for new API keys (404 "no longer available to new users",
field-found 2026-07-16); ``gemini-3.1-flash-lite`` is the cheapest current model verified
to accept inline video + JSON-schema structured output.
"""
def __init__(self) -> None: def __init__(self) -> None:
from google import genai from google import genai
self.model = os.environ.get("FESTIVAL4D_GEMINI_MODEL", "gemini-3.1-flash-lite")
self._genai = genai self._genai = genai
self._client = genai.Client() # reads GEMINI_API_KEY from the environment self._client = genai.Client() # reads GEMINI_API_KEY from the environment

View File

@ -46,8 +46,23 @@ Content verified accurate — ratified as written. Rule stands for future rounds
**For the human (unchanged + one new):** (a) open the app in a normal focused browser window **For the human (unchanged + one new):** (a) open the app in a normal focused browser window
once and confirm the sync panel stays green during continuous playback; (b) shoot or collect once and confirm the sync panel stays green during continuous playback; (b) shoot or collect
24 overlapping clips of the same performance for the field test; (c) optionally set 24 overlapping clips of the same performance for the field test; (c) ~~optionally set
`GEMINI_API_KEY` before `events` to see real moment labels. `GEMINI_API_KEY`~~ done — see addendum.
**Round 3 addendum (coordinator, same day) — real API keys wired + first field finding:**
- A local **`.env`** now exists at the repo root (gitignored, chmod 600, **never commit**) with
`GEMINI_API_KEY` (default provider) and OpenRouter creds mapped to the `local` provider
(`FESTIVAL4D_OPENAI_*`, model `google/gemini-2.5-flash`). Load with
`set -a; . ./.env; set +a` before `python -m festival4d events`. Phase-4 agent: the file is
machine-local — if it's missing in your worktree, ask the coordinator, don't recreate keys.
- **Field finding #1 (fixed by coordinator hotfix):** Google retired `gemini-2.5-flash` for new
API keys (404 "no longer available to new users"). The Gemini model is now env-overridable
(`FESTIVAL4D_GEMINI_MODEL`) with default `gemini-3.1-flash-lite` — verified live: inline
video + JSON-schema structured output OK; **3/3 synthetic candidates classified correctly**
(`light_show`/`bass_drop`, coherent descriptions). Suite still 101 passed. The degradation
path also behaved exactly as designed during the failure — good lane D work.
- Phase-4 agent: consider a `plan/ISSUES.md` entry template seeded from this finding's shape
(symptom → root cause → fix → evidence).
## Round 2 — 2026-07-16 — Integration complete; v0.1.0 shipped ## Round 2 — 2026-07-16 — Integration complete; v0.1.0 shipped