Update desktop app to android app capabilities.

This commit is contained in:
2026-09-13 16:23:52 -06:00
parent 3a0959f55d
commit 2a2cf38399
13 changed files with 485 additions and 206 deletions
+29 -19
View File
@@ -54,31 +54,41 @@ WAKE_WORD_THRESHOLD = float(os.environ.get("WAKE_WORD_THRESHOLD", "0.5"))
# heartbeat poll in controller.py during quiet stretches with no wake word.
WAKE_CHECK_INTERVAL_SECONDS = float(os.environ.get("WAKE_CHECK_INTERVAL_SECONDS", "1.2"))
# ── STT (Deepgram, same as bolt_desk.py) ────────────────────────────────────
# ── STT (server-hosted, same /desk/stt relay the Android app uses) ─────────
# No local Deepgram account needed any more: audio/stt_stream.py opens a
# websocket to this pet's own BOLT_SERVER_URL/DESK_API_KEY, which the server
# relays to Deepgram and meters it against the same credit ledger as a chat turn.
# There is no separate one-shot REST path server-side, so audio/stt.py's
# "guaranteed" fallback uses this exact same connection too — just fed the
# whole utterance at once instead of frame-by-frame.
DEEPGRAM_API_KEY = os.environ.get("DEEPGRAM_API_KEY", "")
DEEPGRAM_MODEL = os.environ.get("DEEPGRAM_MODEL", "nova-3")
# Transcribe *while* you talk instead of uploading the finished clip: frames go
# up as they are captured, so the transcript is ready the moment the VAD says
# you stopped. Needs `websocket-client`; falls back to the one-shot upload
# whenever it can't connect, so turning it on can only help.
# Transcribe *while* you talk instead of waiting for the utterance to end:
# frames go up as they are captured, so the transcript is ready the moment the
# VAD says you stopped. Needs `websocket-client` (in requirements.txt); when
# it can't connect the one-shot path (audio/stt.py) still tries the same
# server relay itself, so turning this off only costs latency, not the
# ability to transcribe at all.
STT_STREAMING = os.environ.get("STT_STREAMING", "true").lower() in ("1", "true", "yes", "on")
# ── TTS (ElevenLabs, requested as raw PCM so playback needs no external
# player binary — cross-platform via sounddevice instead of shelling out to
# mpv/ffplay like bolt_desk.py does on Linux) ───────────────────────────────
# ── TTS (server-hosted, same /desk/tts endpoint the Android app uses) ──────
# No local ElevenLabs account needed for the normal reply voice any more —
# audio/tts.py posts to this pet's own BOLT_SERVER_URL/DESK_API_KEY and gets
# back raw 16 kHz mono PCM16, same as the phone. Falls back to offline
# pyttsx3 if the server call fails.
#
# ELEVENLABS_API_KEY is still read directly by this client for exactly one
# feature the server has no endpoint for: multi-voice `dialoguectl` scenes
# (audio/tts.synthesize_dialogue, see dialogue.py) — leave it blank and
# everything except that one feature works with zero local API keys.
ELEVENLABS_API_KEY = os.environ.get("ELEVENLABS_API_KEY", "")
# Which voice to ask the server for — an ElevenLabs voice id (or a "vb:"-
# prefixed cloned voice, if this desk key owns one). The server picks the
# synthesis model itself now; there is nothing left for this client to choose.
ELEVENLABS_VOICE_ID = os.environ.get("ELEVENLABS_VOICE_ID", "")
ELEVENLABS_MODEL_ID = os.environ.get("ELEVENLABS_MODEL_ID", "eleven_flash_v2")
# eleven_flash_v2 is English-only, and the two cases that swap the voice
# (server-picked `speak_as`, or a reply with non-ASCII in it) are usually
# exactly the cases where the reply isn't English — see tts.model_for().
ELEVENLABS_MULTILINGUAL_MODEL_ID = os.environ.get(
"ELEVENLABS_MULTILINGUAL_MODEL_ID", "eleven_flash_v2_5"
)
# ElevenLabs PCM output formats are named pcm_<sample_rate>.
TTS_SAMPLE_RATE = int(os.environ.get("TTS_SAMPLE_RATE", "24000"))
# Fixed by the server (ai/desk_media.py's PCM_SAMPLE_RATE) — not a free
# tunable any more, but still an env override in case that ever changes.
TTS_SAMPLE_RATE = int(os.environ.get("TTS_SAMPLE_RATE", "16000"))
# Does a voice the server picks (its speak_as marker — "talk like a pirate",
# "say that in Japanese") stay on for later replies, or last one reply only?