Commit Graph

633 Commits

Author SHA1 Message Date
clement f55da57b2c fix(tts): strip Apple FLLR chunk -> canonical WAV
Repo State / repo-state (pull_request) Failing after 41s
Repo State / repo-state (push) Failing after 41s
Validate Zacus refactor / validate (pull_request) Failing after 5m52s
Validate Zacus refactor / validate (push) Failing after 6m6s
macOS say inserts a ~4 KB FLLR filler chunk between fmt and data. The
PLIP firmware parses only a small header buffer and never reaches a
data chunk pushed past it (WAV parse failed -> silent). Rebuild a
canonical 44-byte-header RIFF/fmt/data WAV before staging. Verified:
Zacus greeting plays 5.05s from /sdcard on pickup, no gateway/model.
2026-06-18 18:16:27 +02:00
clement fbe9c7dfb7 chore: bump ESP32_ZACUS (PLIP greeting from SD)
Repo State / repo-state (pull_request) Failing after 41s
Repo State / repo-state (push) Failing after 42s
Validate Zacus refactor / validate (pull_request) Failing after 5m52s
Validate Zacus refactor / validate (push) Failing after 6m7s
2026-06-18 18:09:27 +02:00
clement e73db8800c feat(tts): PLIP SD voice-pack generator + bump fw
Repo State / repo-state (pull_request) Failing after 55s
Validate Zacus refactor / validate (pull_request) Failing after 6m2s
Validate Zacus refactor / validate (push) Failing after 6m7s
Repo State / repo-state (push) Failing after 13m24s
Pre-render directory greetings + scene hints with macOS say (16 kHz
mono FR) and stage them on the PLIP microSD via POST /game/file — gives
the phone local voice content with no model in RAM. Reusable/idempotent
(tools/tts/generate_plip_sd_pack.py). Bumps ESP32_ZACUS for the SD write
path. Generated WAVs gitignored (reproducible).
2026-06-18 17:43:08 +02:00
clement 92cbff1858 chore: bump ESP32_ZACUS (wire scene notify)
Repo State / repo-state (pull_request) Failing after 53s
Validate Zacus refactor / validate (pull_request) Failing after 5m37s
Repo State / repo-state (push) Failing after 44s
Validate Zacus refactor / validate (push) Failing after 5m45s
2026-06-18 15:53:23 +02:00
clement 26046a859b chore: bump ESP32_ZACUS (async gateway notify)
Repo State / repo-state (pull_request) Failing after 1m28s
Validate Zacus refactor / validate (push) Failing after 11m0s
Repo State / repo-state (push) Failing after 11m27s
Validate Zacus refactor / validate (pull_request) Failing after 11m35s
2026-06-18 15:18:40 +02:00
clement b80744d231 feat(game): warning scene auto-calls Zacus
Repo State / repo-state (pull_request) Failing after 46s
Validate Zacus refactor / validate (pull_request) Failing after 6m6s
Validate Zacus refactor / validate (push) Failing after 6m4s
Repo State / repo-state (push) Failing after 12m16s
Enable call_on_scene SCENE_WARNING -> 0142738200: Professeur Zacus
rings the PLIP when the scenario reaches the warning scene.
2026-06-18 15:02:51 +02:00
clement 37eab47f63 feat(voice): scenario-driven incoming calls
Repo State / repo-state (pull_request) Failing after 1m5s
Repo State / repo-state (push) Failing after 55s
Validate Zacus refactor / validate (pull_request) Failing after 6m20s
Validate Zacus refactor / validate (push) Failing after 13m3s
The phone now rings on cue from the game with NO firmware change. A
call_on_scene map (phone_directory.yaml: {SCENE_X: number}) tells the
gateway which scenes are scripted incoming calls; since the runtime
already pushes the scene to /game/step, the gateway auto-rings the PLIP
with that NPC on scene entry (deduped, once per entry). Factored a
_ring_board helper (shared by /game/call + auto-ring). Map ships empty
(no surprise rings) with commented examples for the designer.
2026-06-18 14:57:08 +02:00
clement 42a3b22823 feat(voice): NPC hints follow runtime scene
Repo State / repo-state (pull_request) Failing after 44s
Repo State / repo-state (push) Failing after 57s
Validate Zacus refactor / validate (pull_request) Failing after 6m47s
Validate Zacus refactor / validate (push) Failing after 5m45s
The gateway now hints on the SCENE the runtime pushes (idf_zacus POSTs
its native SCENE_* to /game/step?scene=…) — no step<->scene mapping
needed since both sides use the same SCENE_* ids. _active_scene() uses
the pushed scene (falling back to the current step's scene). Bump
ESP32_ZACUS to 653a299 (npc_engine pushes scene changes).
2026-06-18 14:05:35 +02:00
clement dffcca961b feat(voice): rotate NPC hint variants per turn
Repo State / repo-state (pull_request) Failing after 55s
Validate Zacus refactor / validate (push) Failing after 6m40s
Validate Zacus refactor / validate (pull_request) Failing after 13m40s
Repo State / repo-state (push) Failing after 14m55s
2026-06-18 12:58:06 +02:00
clement 892fb13bb3 feat(voice): /game/call — runtime rings NPC
The runtime triggers a scenario phone call: POST /game/call?number=18
[&step=STEP_X] rings the PLIP handset with the chosen NPC (resolved via
the boards registry) and sets the current step so the NPC disguises that
step's hint. Completes the game->phone trigger path (chantier #2).
2026-06-18 12:40:04 +02:00
clement 5d7550b993 feat(voice): scenario-driven NPC hints
Wire the phone NPCs to the scenario state machine + hint bank so a call
ADVANCES the puzzle instead of being generic chat. load_scenario_hints
maps each step (zacus_v3.yaml screen_scene_id) to npc_phrases.yaml
hints[scene][level]; voice/reply weaves the CURRENT step's hint into the
NPC persona, escalating the level (subtle->near-explicit) with the
conversation. New GET/POST /game/step lets the runtime set the current
step as the player progresses.
2026-06-18 10:47:55 +02:00
clement 44cd100a80 fix(voice): RMS-amplify STT input for weak voice
Repo State / repo-state (push) Failing after 51s
Validate Zacus refactor / validate (pull_request) Failing after 6m24s
Validate Zacus refactor / validate (push) Failing after 5m57s
Repo State / repo-state (pull_request) Failing after 10m40s
Condition the handset capture by RMS (not peak) before whisper: the
voice body is ~0.5-1.5% FS and a transient peak defeated peak-normalise,
leaving it inaudible. RMS-normalise to ~20% FS + clip. Recovers weak
captures whisper returned '' for (verified: -> 'C'est parti !').
2026-06-18 00:31:37 +02:00
clement 73fa3650a1 feat(voice): Whisper STT (robust to handset voice)
Validate Zacus refactor / validate (push) Failing after 12m37s
Repo State / repo-state (push) Failing after 13m3s
Validate Zacus refactor / validate (pull_request) Failing after 13m17s
Repo State / repo-state (pull_request) Failing after 13m35s
Switch the voice-loop STT from Kyutai to whisper.cpp large-v3-turbo
(subprocess, high-pass conditioned): it decodes the weak/noisy SLIC
handset captures Kyutai returned '' for. Filter whisper's silence/noise
hallucinations (sous-titrage, radio-canada, tipeurs, '...') so the NPC
never replies to a phantom line. Bump ESP32_ZACUS to 54022ed (VAD
recalibration for the quiet voice + bell stop on pickup).
2026-06-18 00:08:59 +02:00
clement 643c3852de feat(voice): local-only LLM + faster turns
Repo State / repo-state (pull_request) Failing after 43s
Validate Zacus refactor / validate (pull_request) Failing after 6m35s
Repo State / repo-state (push) Failing after 45s
Validate Zacus refactor / validate (push) Failing after 13m52s
Gateway: drop the remote ailiance fallback — the NPC LLM is now the
on-box granite ONLY (local spoken line on failure, never remote).
Prewarm the persona KV-cache in the background at greeting time so the
first reply is fast instead of paying ~17 s of cold prompt processing.
Add temperature + repetition_penalty so granite4-tiny stops looping.
STT: cut the trailing-silence pad 2 s -> 0.5 s (callers already pad),
shaving STT latency. Bump ESP32_ZACUS to cfe429d (hook debounce).
2026-06-17 19:49:10 +02:00
clement 0764c873a7 chore: bump firmware + faster LLM failover
Repo State / repo-state (pull_request) Failing after 1m14s
Repo State / repo-state (push) Failing after 1m10s
Validate Zacus refactor / validate (push) Failing after 13m51s
Bump ESP32_ZACUS to 82759ee (voice-activated two-phase capture, mic
diag). Gateway: drop the local-LLM (granite) timeout 70s -> 8s so a
cold/hung local model fails over to the remote backend fast instead of
stalling the whole turn past the firmware's reply timeout.
2026-06-17 14:41:02 +02:00
electron 27ab75fded Merge pull request 'fix(plip): handset mic capture — ES8388 DLL + STT high-pass' (#164) from fix/plip-mic-stt-highpass into main
Repo State / repo-state (push) Failing after 1m2s
Validate Zacus refactor / validate (push) Failing after 11m22s
2026-06-17 07:24:28 +00:00
clement af7c02d1a7 chore: bump ESP32_ZACUS (no hook forcing)
Repo State / repo-state (pull_request) Failing after 1m6s
Repo State / repo-state (push) Failing after 11m16s
Validate Zacus refactor / validate (pull_request) Failing after 19m7s
Pull in ESP32_ZACUS fix(plip) 8c076d8: gate audio playback on the real
SHK line and remove all hook forcing (s_hook_override,
phone_force_offhook, /debug/offhook). Fixes the silent incoming-call
greeting caused by the two off-hook flags desyncing during ring.
2026-06-17 09:06:19 +02:00
clement fb71e9ceeb fix(stt): reset LM KV-cache per request
Repo State / repo-state (push) Failing after 10m58s
Repo State / repo-state (pull_request) Failing after 11m34s
Validate Zacus refactor / validate (pull_request) Failing after 11m39s
The Lm holds a persistent rotating transformer_cache shared by every
LmGen. LmGen only resets its own gen_sequence/step_idx, so across
requests the cache kept accumulating stream positions until it
saturated and the model emitted only padding tokens, returning empty
transcriptions ('') for every request. Reset transformer_cache (and
depformer_cache) per request, mirroring Lm.warmup(). Validated: 40
consecutive requests of a known-good sample, 0 empty.
2026-06-17 08:26:05 +02:00
clement f703611388 chore: bump ESP32_ZACUS — status + capture fix
Repo State / repo-state (push) Failing after 2m3s
Repo State / repo-state (pull_request) Failing after 10m11s
Validate Zacus refactor / validate (pull_request) Failing after 15m3s
2026-06-16 19:19:35 +02:00
clement f8e576ba5a chore: bump ESP32_ZACUS — incoming mode + volume
Repo State / repo-state (pull_request) Failing after 10m51s
Repo State / repo-state (push) Failing after 12m5s
Validate Zacus refactor / validate (pull_request) Failing after 18m38s
2026-06-16 10:32:43 +02:00
clement 8d90a25756 fix(gateway): snappier LLM keep-warm + higher timeout
- keep-warm interval 600s -> 240s (avoids ~47s cold-start fallback)
- local backend timeout 60s -> 70s (tolerates cold reload under 90s)
2026-06-16 10:32:37 +02:00
clement 1e15bba258 chore: bump ESP32_ZACUS — ES8388 DLL ADC fix
Repo State / repo-state (pull_request) Failing after 10m56s
Repo State / repo-state (push) Failing after 12m4s
2026-06-16 09:35:20 +02:00
clement bc5363cf2c fix(gateway): STT high-pass + gain for SLIC mic
SLIC handset injects low-frequency rumble/DC drift that swamps speech
and causes Kyutai STT to output nothing. Apply a box moving-average
high-pass (~110 Hz) before peak-normalisation. Also raise gain cap to
x40 and target_peak to 0.7 (mic is still very quiet post-ES8388 fix).
Verified: same capture transcribes empty without HP, clean French with.
2026-06-16 09:35:00 +02:00
clement 49ec7d9dc7 chore: bump ESP32_ZACUS (es8388 debug endpoint)
Validate Zacus refactor / validate (push) Failing after 10m8s
Repo State / repo-state (pull_request) Failing after 13m58s
Repo State / repo-state (push) Failing after 14m57s
Validate Zacus refactor / validate (pull_request) Failing after 22m47s
2026-06-16 08:42:40 +02:00
clement 20c0431f51 feat(gateway): normalize low-level STT capture
Add _wav_pcm(), _build_wav(), _normalize_wav_for_stt() (peak-normalize
with capped gain) to handle the PLIP handset mic low signal level and
placeholder 0xFFFFFFFF WAV headers from /voice/capture stream.
Rewire _pad_wav_silence() and _transcribe_kyutai via these helpers.
2026-06-16 08:41:43 +02:00
clement 68c81fa3c9 feat(gateway): say TTS, local LLM, STT padding
- Replace Kyutai TTS with macOS say (16 kHz mono FR);
  NPC voice map _SAY_VOICE_MAP; helper _tts_say_sync
- Local vllm-mlx :8520 as primary LLM (_chat_one),
  ailiance as fallback, spoken phrase as last resort;
  _chat_reply never raises (loop stays alive on 502)
- Pad 800 ms silence before /transcribe (_pad_wav_silence)
  to prevent last-word truncation
- Background _keep_llm_warm ping every 600 s (cold start)
- Root log level INFO; X-Zacus-Heard/Said headers
- test_chat_reply: empty_choices expects spoken fallback
2026-06-15 22:18:55 +02:00
clement da205ffc99 feat(gateway): Kyutai STT/TTS + voice reply loop
Repo State / repo-state (pull_request) Failing after 40s
Validate Zacus refactor / validate (pull_request) Failing after 6m12s
Validate Zacus refactor / validate (push) Failing after 5m38s
Repo State / repo-state (push) Failing after 11m29s
- tools/kyutai-stt: local FastAPI STT server
  (kyutai_stt_server.py, stt_from_file_mlx.py)
  + TTS server (kyutai_tts_server.py, tts_mlx.py)
  using MLX Kyutai models
- gateway /v1/voice/reply: STT → LLM → TTS pipeline
  + dynamic soxr resample + compressor/limiter chain
  + greeting cache + warm-up at startup
- tests/gateway/test_voice_reply.py: pytest coverage
- bump ESP32_ZACUS submodule to plip voice loop (aa7ae27)
2026-06-15 21:14:25 +02:00
electron 97303f0c58 Merge pull request 'chore: bump ESP32_ZACUS — PLIP mic LIN2' (#161) from chore/bump-plip-lin2 into main
Repo State / repo-state (push) Failing after 45s
Validate Zacus refactor / validate (push) Failing after 5m55s
2026-06-15 07:52:07 +00:00
clemsail 81e02a897a chore: bump ESP32_ZACUS — PLIP mic on ADC LIN2 (voice captured)
Validate Zacus refactor / validate (pull_request) Failing after 11m45s
Repo State / repo-state (pull_request) Failing after 12m23s
Repo State / repo-state (push) Failing after 12m55s
2026-06-15 09:51:50 +02:00
electron 87aeb58171 Merge pull request 'chore: bump ESP32_ZACUS — PLIP hook polarity' (#160) from chore/bump-plip-hook into main
Repo State / repo-state (push) Failing after 41s
Validate Zacus refactor / validate (push) Failing after 6m8s
2026-06-15 07:44:46 +00:00
clemsail 0b75fc6ddb chore: bump ESP32_ZACUS — PLIP hook polarity active-LOW
Repo State / repo-state (pull_request) Failing after 41s
Repo State / repo-state (push) Failing after 1m0s
Validate Zacus refactor / validate (pull_request) Failing after 6m1s
2026-06-15 09:44:25 +02:00
electron 81e6a786c5 Merge pull request 'chore: bump ESP32_ZACUS — PLIP SLIC + I2S mic fix' (#159) from chore/bump-plip-slic into main
Repo State / repo-state (push) Failing after 38s
Validate Zacus refactor / validate (push) Failing after 5m32s
2026-06-14 23:02:14 +00:00
clemsail 74fe9639d9 chore: bump ESP32_ZACUS — PLIP SLIC integration + I2S RX mic fix
Repo State / repo-state (pull_request) Failing after 1m8s
Repo State / repo-state (push) Failing after 28s
Validate Zacus refactor / validate (pull_request) Failing after 5m46s
2026-06-15 01:02:00 +02:00
electron 5d9b735a2d Merge pull request 'chore: bump ESP32_ZACUS — PLIP phone stage 2' (#158) from chore/bump-plip-stage2 into main
Repo State / repo-state (push) Failing after 30s
Validate Zacus refactor / validate (push) Failing after 11m32s
2026-06-14 20:45:38 +00:00
clemsail 9c84ef9d3d chore: bump ESP32_ZACUS — PLIP phone stage 2 (turn_client + GREET)
Repo State / repo-state (push) Failing after 26s
Repo State / repo-state (pull_request) Failing after 26s
Validate Zacus refactor / validate (pull_request) Failing after 5m39s
2026-06-14 22:45:24 +02:00
electron 5e88ddef65 Merge pull request 'feat(gateway): téléphone PLIP stage 2 — annuaire + /v1/voice/turn (greeting)' (#157) from feat/gateway-voice-turn into main
Repo State / repo-state (push) Failing after 26s
Validate Zacus refactor / validate (push) Failing after 5m28s
2026-06-14 20:34:32 +00:00
clemsail 502aa8dc5b fix(gateway): voice session TTL sweep + 502 on backend down + chat parse guard + reply user msg
Repo State / repo-state (pull_request) Failing after 33s
Repo State / repo-state (push) Failing after 29s
Validate Zacus refactor / validate (pull_request) Failing after 5m35s
2026-06-14 22:33:09 +02:00
clemsail 0e517829f1 feat(gateway): POST /v1/voice/turn (greeting path) + /v1/voice/end 2026-06-14 22:24:50 +02:00
clemsail f5de35342c feat(gateway): ailiance chat helper for NPC replies 2026-06-14 22:22:52 +02:00
clemsail 40373a5693 feat(gateway): in-memory voice sessions (history + TTL) 2026-06-14 22:22:04 +02:00
clemsail 3066e63b24 feat(gateway): phone directory loader (numéro → persona/voix) 2026-06-14 22:21:27 +02:00
electron b66724889b Merge pull request 'chore: bump ESP32_ZACUS — PLIP phone stage 1' (#156) from chore/bump-plip-stage1 into main
Repo State / repo-state (push) Failing after 34s
Validate Zacus refactor / validate (push) Failing after 5m32s
2026-06-14 20:18:04 +00:00
clemsail 8f3991eca9 chore: bump ESP32_ZACUS — PLIP phone stage 1 (tones+dialer+state machine)
Repo State / repo-state (pull_request) Failing after 41s
Repo State / repo-state (push) Failing after 42s
Validate Zacus refactor / validate (pull_request) Failing after 5m44s
2026-06-14 22:17:44 +02:00
electron 2b53c5be8e Merge pull request 'docs(plip): plan implémentation téléphone conversationnel' (#155) from docs/plip-telephone-plan into main
Repo State / repo-state (push) Failing after 35s
Validate Zacus refactor / validate (push) Failing after 5m40s
2026-06-14 19:23:07 +00:00
clemsail 5da6ec4c11 docs(plip): implementation plan — téléphone conversationnel (4 stages, TDD)
Repo State / repo-state (push) Failing after 32s
Repo State / repo-state (pull_request) Failing after 36s
Validate Zacus refactor / validate (pull_request) Failing after 5m47s
2026-06-14 21:23:00 +02:00
electron 6ccbf2c5c7 Merge pull request 'docs(plip): design téléphone conversationnel France Télécom' (#154) from docs/plip-telephone-design into main
Repo State / repo-state (push) Failing after 28s
Validate Zacus refactor / validate (push) Failing after 5m27s
2026-06-14 19:13:48 +00:00
clemsail 904a77a08b docs(plip): design — téléphone conversationnel France Télécom (annuaire 12/3615/15/17/18, /v1/voice/turn)
Repo State / repo-state (pull_request) Failing after 39s
Repo State / repo-state (push) Failing after 30s
Validate Zacus refactor / validate (pull_request) Failing after 5m43s
2026-06-14 21:13:40 +02:00
electron ddb194f32b Merge pull request 'chore: bump ESP32_ZACUS — PLIP mute on-hook' (#153) from chore/bump-plip-mute into main
Repo State / repo-state (push) Failing after 25s
Validate Zacus refactor / validate (push) Failing after 5m34s
2026-06-14 18:45:47 +00:00
clemsail 8232adb446 chore: bump ESP32_ZACUS — PLIP mute audio on-hook
Repo State / repo-state (pull_request) Failing after 1m14s
Repo State / repo-state (push) Failing after 33s
Validate Zacus refactor / validate (pull_request) Failing after 6m2s
2026-06-14 20:45:38 +02:00
electron e9563f693f Merge pull request 'fix(gateway): raise /v1/voice/say cap 64K->240K (full TTS phrases)' (#152) from fix/voice-say-240k into main
Repo State / repo-state (push) Failing after 27s
Validate Zacus refactor / validate (push) Failing after 5m37s
2026-06-14 18:33:21 +00:00