feat: listen mode + volume knob in chat; briefing discuss auto-send; fix LLM proactive note search

- ChatView: listen mode toggle (auto-reads new responses via TTS), volume popup
  with range slider persisted per-device in localStorage via GainNode
- useVoiceAudio: shared module-level _volume ref with localStorage persistence,
  GainNode for volume control, exported setVoiceVolume()
- tts.py: pre-warm all Kokoro voices at pipeline load to eliminate HuggingFace
  HEAD requests at synthesis time (reduces TTS latency)
- BriefingView: discuss article button now auto-sends instead of just filling input;
  prompt capped to 15 sentences; send() accepts optional overrideText
- llm.py: instruct LLM not to proactively search notes or comment on note absence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-31 16:52:11 -04:00
parent ab397e78f3
commit baeb0b14e5
5 changed files with 169 additions and 22 deletions
+12 -5
View File
@@ -46,11 +46,18 @@ async def load_tts_model() -> None:
logger.info("Loading Kokoro TTS pipeline...")
loop = asyncio.get_running_loop()
_pipeline = await loop.run_in_executor(
None,
lambda: KPipeline(lang_code="a"), # "a" = American English
)
logger.info("Kokoro TTS pipeline loaded")
def _load_and_warm():
p = KPipeline(lang_code="a") # "a" = American English
# Pre-load all voice tensors so synthesis never hits HuggingFace at request time
for v in _VOICES:
try:
p.load_voice(v["id"])
except Exception:
pass
return p
_pipeline = await loop.run_in_executor(None, _load_and_warm)
logger.info("Kokoro TTS pipeline loaded and voices pre-warmed")
except Exception:
_load_error = "Failed to load Kokoro TTS pipeline"
logger.exception(_load_error)