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
+17 -8
View File
@@ -1,12 +1,10 @@
import { ref, readonly } from 'vue'
/**
* Audio playback composable wrapping the Web Audio API.
*
* Usage:
* const { playing, isSupported, play, stop } = useVoiceAudio()
* await play(wavBlob)
*/
const VOLUME_KEY = 'fa_voice_volume'
// Shared volume across all instances — persisted to localStorage per device
const _volume = ref<number>(parseFloat(localStorage.getItem(VOLUME_KEY) ?? '1.0'))
export function useVoiceAudio() {
const playing = ref(false)
const isSupported = typeof AudioContext !== 'undefined' || typeof (window as unknown as Record<string, unknown>).webkitAudioContext !== 'undefined'
@@ -32,7 +30,12 @@ export function useVoiceAudio() {
const source = ctx.createBufferSource()
source.buffer = audioBuffer
source.connect(ctx.destination)
const gain = ctx.createGain()
gain.gain.value = _volume.value
source.connect(gain)
gain.connect(ctx.destination)
currentSource = source
playing.value = true
@@ -53,8 +56,14 @@ export function useVoiceAudio() {
return {
playing: readonly(playing),
volume: _volume,
isSupported,
play,
stop,
}
}
export function setVoiceVolume(v: number) {
_volume.value = Math.max(0, Math.min(1, v))
localStorage.setItem(VOLUME_KEY, String(_volume.value))
}