Add wakeword-specific audio cues (detected / captured)
Two optional WAVs in the Hands-free section: "Sound: detected" plays when the wakeword fires (your cue to speak now) and "Sound: captured" plays when the command is taken (silence/stop). For hands-free sessions these take precedence over the general [sounds] cues, falling back to them and then to the built-in system sound. The general cues are relabelled "Audio cues (manual dictation)". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
87eee3f103
commit
8e1419e828
@ -80,6 +80,8 @@ class Config:
|
|||||||
wakeword_enabled: bool = False
|
wakeword_enabled: bool = False
|
||||||
wakeword_uri: str = "tcp://127.0.0.1:10400"
|
wakeword_uri: str = "tcp://127.0.0.1:10400"
|
||||||
wakeword_model: str = "okay_computer"
|
wakeword_model: str = "okay_computer"
|
||||||
|
wakeword_sound_detected: str = "" # WAV played when the wakeword fires (speak now)
|
||||||
|
wakeword_sound_done: str = "" # WAV played when the command is captured
|
||||||
# workflows
|
# workflows
|
||||||
workflows: list[Workflow] = field(default_factory=list)
|
workflows: list[Workflow] = field(default_factory=list)
|
||||||
|
|
||||||
@ -172,6 +174,8 @@ def load(path: Path = CONFIG_PATH) -> Config:
|
|||||||
wakeword_enabled=bool(ww.get("enabled", False)),
|
wakeword_enabled=bool(ww.get("enabled", False)),
|
||||||
wakeword_uri=ww.get("uri", "tcp://127.0.0.1:10400"),
|
wakeword_uri=ww.get("uri", "tcp://127.0.0.1:10400"),
|
||||||
wakeword_model=ww.get("model", "okay_computer"),
|
wakeword_model=ww.get("model", "okay_computer"),
|
||||||
|
wakeword_sound_detected=ww.get("sound_detected", ""),
|
||||||
|
wakeword_sound_done=ww.get("sound_done", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
for entry in data.get("workflow", []):
|
for entry in data.get("workflow", []):
|
||||||
@ -279,6 +283,8 @@ def save(cfg: Config, path: Path = CONFIG_PATH) -> None:
|
|||||||
"enabled": cfg.wakeword_enabled,
|
"enabled": cfg.wakeword_enabled,
|
||||||
"uri": cfg.wakeword_uri,
|
"uri": cfg.wakeword_uri,
|
||||||
"model": cfg.wakeword_model,
|
"model": cfg.wakeword_model,
|
||||||
|
"sound_detected": cfg.wakeword_sound_detected,
|
||||||
|
"sound_done": cfg.wakeword_sound_done,
|
||||||
},
|
},
|
||||||
"stt": {"active": cfg.stt_active},
|
"stt": {"active": cfg.stt_active},
|
||||||
"stt_engine": [
|
"stt_engine": [
|
||||||
@ -398,6 +404,11 @@ threshold = 0.82 # 0..1 fuzzy-match strictness (higher = stricter)
|
|||||||
enabled = false
|
enabled = false
|
||||||
uri = "tcp://127.0.0.1:10400"
|
uri = "tcp://127.0.0.1:10400"
|
||||||
model = "okay_computer"
|
model = "okay_computer"
|
||||||
|
# Optional WAV cues for hands-free use (override the [sounds] cues when the
|
||||||
|
# wakeword triggers): played when the wakeword fires (speak now) and when the
|
||||||
|
# command is captured.
|
||||||
|
sound_detected = ""
|
||||||
|
sound_done = ""
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# Speech-to-text engines (presets). The active one is used for transcription.
|
# Speech-to-text engines (presets). The active one is used for transcription.
|
||||||
|
|||||||
@ -147,12 +147,15 @@ class Daemon:
|
|||||||
sound.play(fallback=sound_name)
|
sound.play(fallback=sound_name)
|
||||||
|
|
||||||
def _play_cue(self, cue: str) -> None:
|
def _play_cue(self, cue: str) -> None:
|
||||||
"""Play the user's WAV for 'before'/'after', else a built-in system sound."""
|
"""Play an audio cue. Hands-free (wakeword) sessions prefer the wakeword
|
||||||
|
sounds, then the general [sounds] cues, then a built-in system sound."""
|
||||||
from . import sound
|
from . import sound
|
||||||
if cue == "before":
|
if cue == "before":
|
||||||
sound.play(self.cfg.sound_before, fallback="device-added")
|
custom = (self.cfg.wakeword_sound_detected if self._session_silent else "") or self.cfg.sound_before
|
||||||
|
sound.play(custom, fallback="device-added")
|
||||||
else:
|
else:
|
||||||
sound.play(self.cfg.sound_after, fallback="complete")
|
custom = (self.cfg.wakeword_sound_done if self._session_silent else "") or self.cfg.sound_after
|
||||||
|
sound.play(custom, fallback="complete")
|
||||||
|
|
||||||
# -- recording control ----------------------------------------------------
|
# -- recording control ----------------------------------------------------
|
||||||
def start_dictation(self, workflow: Workflow | None = None) -> None:
|
def start_dictation(self, workflow: Workflow | None = None) -> None:
|
||||||
|
|||||||
@ -765,8 +765,15 @@ class SettingsDialog:
|
|||||||
box = Gtk.Box(spacing=10); box.pack_start(self.ww_test_btn, False, False, 0); box.pack_start(self.ww_test_lbl, False, False, 0)
|
box = Gtk.Box(spacing=10); box.pack_start(self.ww_test_btn, False, False, 0); box.pack_start(self.ww_test_lbl, False, False, 0)
|
||||||
_labeled(page, "", box)
|
_labeled(page, "", box)
|
||||||
|
|
||||||
|
self.ww_snd_detected = self._sound_field(
|
||||||
|
page, "Sound: detected", self.cfg.wakeword_sound_detected,
|
||||||
|
"Played right after the wakeword is recognised — your cue that Blitztext is listening, speak now.")
|
||||||
|
self.ww_snd_done = self._sound_field(
|
||||||
|
page, "Sound: captured", self.cfg.wakeword_sound_done,
|
||||||
|
"Played when your command is captured (silence or stop) — confirms your input was taken.")
|
||||||
|
|
||||||
page.pack_start(Gtk.Separator(), False, False, 8)
|
page.pack_start(Gtk.Separator(), False, False, 8)
|
||||||
page.pack_start(Gtk.Label(label="Audio cues", xalign=0.0), False, False, 2)
|
page.pack_start(Gtk.Label(label="Audio cues (manual dictation)", xalign=0.0), False, False, 2)
|
||||||
self.snd_before = self._sound_field(
|
self.snd_before = self._sound_field(
|
||||||
page, "Play before", self.cfg.sound_before,
|
page, "Play before", self.cfg.sound_before,
|
||||||
"Sound played when recording starts — your confirmation that Blitztext is listening.")
|
"Sound played when recording starts — your confirmation that Blitztext is listening.")
|
||||||
@ -1118,6 +1125,8 @@ class SettingsDialog:
|
|||||||
c.wakeword_enabled = self.ww_enabled.get_active()
|
c.wakeword_enabled = self.ww_enabled.get_active()
|
||||||
c.wakeword_uri = self.ww_uri.get_text().strip()
|
c.wakeword_uri = self.ww_uri.get_text().strip()
|
||||||
c.wakeword_model = _combo_text(self.ww_model)
|
c.wakeword_model = _combo_text(self.ww_model)
|
||||||
|
c.wakeword_sound_detected = self.ww_snd_detected.get_filename() or ""
|
||||||
|
c.wakeword_sound_done = self.ww_snd_done.get_filename() or ""
|
||||||
c.mic = self._selected_mic_name()
|
c.mic = self._selected_mic_name()
|
||||||
c.output = self.gen_output.get_active_text() or "type"
|
c.output = self.gen_output.get_active_text() or "type"
|
||||||
c.language = self.gen_lang.get_text().strip()
|
c.language = self.gen_lang.get_text().strip()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user