Replay now matches the robots and no longer cuts words: - read the turn to turnComplete, not generationComplete, and drain the socket before each send; breaking early truncated every sentence and left frames that the next turn mis-read as its own reply - accept a take only if the model's own transcript covers the text AND the audio is long enough to contain it (the transcript reports the full text even for a 0.8s clip) - pitch gate: reject an off-tone take and re-ask, per voice, using a pure-Python F0 estimator (no numpy on the host) - continuation: speak the words a voice skipped instead of retrying a line it stops on deterministically - fresh Live session per replay; delivery drifts as turns accumulate Live Gemini tab: browser talks to Gemini directly (the reverse proxy cannot upgrade a WebSocket), with a persona library - named personas, per-robot selection, built-ins that cannot be overwritten. Dashboard: records search + voice filter, log panel falls back to polling, sign-in history with CSV/JSON export, and JS errors now show on the page instead of silently blanking a tab.
46 lines
1.6 KiB
JSON
46 lines
1.6 KiB
JSON
{
|
|
"_description": "Tunables for voice/* modules. Loaded via core.config_loader.load('voice').",
|
|
"speaker": {
|
|
"_comment": "G1 built-in speaker — AudioClient.PlayStream wrapper",
|
|
"app_name": "sanad",
|
|
"begin_stream_pause_sec": 0.15,
|
|
"wait_finish_margin_sec": 0.3
|
|
},
|
|
"vad": {
|
|
"_comment": "Gemini Live server-side voice-activity-detection config",
|
|
"start_sensitivity": "START_SENSITIVITY_HIGH",
|
|
"end_sensitivity": "END_SENSITIVITY_LOW",
|
|
"prefix_padding_ms": 20,
|
|
"silence_duration_ms": 200
|
|
},
|
|
"barge_in": {
|
|
"threshold": 500,
|
|
"loud_chunks_needed": 3,
|
|
"cooldown_sec": 0.3,
|
|
"echo_suppress_below": 500,
|
|
"ai_speak_grace_sec": 0.15
|
|
},
|
|
"recording": {
|
|
"enabled": true,
|
|
"dir_relative": "data/recordings"
|
|
},
|
|
"typed_replay": {
|
|
"_comment": "voice/typed_replay.py — max_text_len comes from dashboard.api_input",
|
|
"monitor_chunk_size": 512,
|
|
"monitor_tail_sec": 0.2,
|
|
"fresh_session_per_replay": true,
|
|
"warm_session_voices": []
|
|
},
|
|
"local_tts": {
|
|
"_comment": "voice/local_tts.py — offline Coqui TTS",
|
|
"model_subdir": "speecht5_tts_clartts_ar",
|
|
"vocoder_subdir": "speecht5_hifigan",
|
|
"xvector_filename": "arabic_xvector_embedding.pt",
|
|
"sample_rate": 16000,
|
|
"channels": 1
|
|
},
|
|
"live": {
|
|
"allow_direct_key": true,
|
|
"_comment": "User-authorised: hands the Gemini API key to the browser for live conversation. Ephemeral tokens are refused for AI-Studio AQ. express keys (verified: the key opens a Live session directly, a token minted from it is refused in all four documented forms). While this is on, anyone who can open the dashboard can read the key."
|
|
}
|
|
} |