mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
feat: add STT transcript echo toggle
This commit is contained in:
parent
95fc3c6b45
commit
bfc5262725
4 changed files with 67 additions and 7 deletions
|
|
@ -603,6 +603,7 @@ class GatewayConfig:
|
|||
|
||||
# STT settings
|
||||
stt_enabled: bool = True # Whether to auto-transcribe inbound voice messages
|
||||
stt_echo_transcripts: bool = True # Whether to echo raw STT transcripts back to the user
|
||||
|
||||
# Session isolation in shared chats
|
||||
group_sessions_per_user: bool = True # Isolate group/channel sessions per participant when user IDs are available
|
||||
|
|
@ -726,6 +727,7 @@ class GatewayConfig:
|
|||
"always_log_local": self.always_log_local,
|
||||
"filter_silence_narration": self.filter_silence_narration,
|
||||
"stt_enabled": self.stt_enabled,
|
||||
"stt_echo_transcripts": self.stt_echo_transcripts,
|
||||
"group_sessions_per_user": self.group_sessions_per_user,
|
||||
"thread_sessions_per_user": self.thread_sessions_per_user,
|
||||
"max_concurrent_sessions": self.max_concurrent_sessions,
|
||||
|
|
@ -772,6 +774,13 @@ class GatewayConfig:
|
|||
stt_enabled = data.get("stt_enabled")
|
||||
if stt_enabled is None:
|
||||
stt_enabled = data.get("stt", {}).get("enabled") if isinstance(data.get("stt"), dict) else None
|
||||
stt_echo_transcripts = data.get("stt_echo_transcripts")
|
||||
if stt_echo_transcripts is None:
|
||||
stt_echo_transcripts = (
|
||||
data.get("stt", {}).get("echo_transcripts")
|
||||
if isinstance(data.get("stt"), dict)
|
||||
else None
|
||||
)
|
||||
|
||||
group_sessions_per_user = data.get("group_sessions_per_user")
|
||||
thread_sessions_per_user = data.get("thread_sessions_per_user")
|
||||
|
|
@ -815,6 +824,7 @@ class GatewayConfig:
|
|||
data.get("filter_silence_narration"), True
|
||||
),
|
||||
stt_enabled=_coerce_bool(stt_enabled, True),
|
||||
stt_echo_transcripts=_coerce_bool(stt_echo_transcripts, True),
|
||||
group_sessions_per_user=_coerce_bool(group_sessions_per_user, True),
|
||||
thread_sessions_per_user=_coerce_bool(thread_sessions_per_user, False),
|
||||
multiplex_profiles=_coerce_bool(multiplex_profiles, False),
|
||||
|
|
|
|||
|
|
@ -10147,10 +10147,11 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
message_text,
|
||||
audio_paths,
|
||||
)
|
||||
# Echo each successful transcript back to the user immediately,
|
||||
# before the agent loop runs. Lets the user verify STT quality
|
||||
# in real-time and see the raw whisper output verbatim.
|
||||
if _successful_transcripts:
|
||||
# Echo each successful transcript back to the user immediately
|
||||
# when configured. Lets users verify STT quality in real-time,
|
||||
# while allowing quiet STT for users who only want the agent to
|
||||
# receive the transcription.
|
||||
if _successful_transcripts and self._should_echo_stt_transcripts():
|
||||
_echo_adapter = self.adapters.get(source.platform)
|
||||
_echo_meta = self._thread_metadata_for_source(source, self._reply_anchor_for_event(event))
|
||||
if _echo_adapter:
|
||||
|
|
@ -12638,6 +12639,10 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
|
||||
return True
|
||||
|
||||
def _should_echo_stt_transcripts(self) -> bool:
|
||||
"""Return whether inbound voice/STT transcripts should be echoed to chat."""
|
||||
return bool(getattr(self.config, "stt_echo_transcripts", True))
|
||||
|
||||
async def _send_voice_reply(self, event: MessageEvent, text: str) -> None:
|
||||
"""Generate TTS audio and send as a voice message before the text reply."""
|
||||
import uuid as _uuid
|
||||
|
|
@ -14738,9 +14743,9 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
enriched_text, successful_transcripts = await self._enrich_message_with_transcription(
|
||||
text, audio_paths,
|
||||
)
|
||||
# Echo raw transcripts back to the user so voice interrupts
|
||||
# feel identical to fresh voice messages.
|
||||
if successful_transcripts:
|
||||
# Echo raw transcripts back to the user when configured so voice
|
||||
# interrupts feel identical to fresh voice messages.
|
||||
if successful_transcripts and self._should_echo_stt_transcripts():
|
||||
echo_adapter = self.adapters.get(source.platform)
|
||||
echo_meta = {"thread_id": source.thread_id} if source.thread_id else None
|
||||
if echo_adapter:
|
||||
|
|
|
|||
|
|
@ -2017,6 +2017,10 @@ DEFAULT_CONFIG = {
|
|||
|
||||
"stt": {
|
||||
"enabled": True,
|
||||
# When true, gateway voice messages are transcribed for the agent and
|
||||
# the raw transcript is also echoed back to the user as a 🎙️ message.
|
||||
# Set false to keep STT for the agent while suppressing that user-facing echo.
|
||||
"echo_transcripts": True,
|
||||
"provider": "local", # "local" (free, faster-whisper) | "groq" | "openai" (Whisper API) | "mistral" (Voxtral Transcribe) | "elevenlabs" (Scribe)
|
||||
"local": {
|
||||
"model": "base", # tiny, base, small, medium, large-v3
|
||||
|
|
|
|||
41
tests/gateway/test_stt_transcript_echo_config.py
Normal file
41
tests/gateway/test_stt_transcript_echo_config.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
from types import SimpleNamespace
|
||||
|
||||
from gateway.config import GatewayConfig
|
||||
from gateway.run import GatewayRunner
|
||||
|
||||
|
||||
def test_stt_echo_transcripts_defaults_on_for_backwards_compatibility():
|
||||
cfg = GatewayConfig.from_dict({})
|
||||
|
||||
assert cfg.stt_enabled is True
|
||||
assert cfg.stt_echo_transcripts is True
|
||||
assert cfg.to_dict()["stt_echo_transcripts"] is True
|
||||
|
||||
|
||||
def test_stt_echo_transcripts_can_be_disabled_in_stt_section():
|
||||
cfg = GatewayConfig.from_dict({"stt": {"enabled": True, "echo_transcripts": False}})
|
||||
|
||||
assert cfg.stt_enabled is True
|
||||
assert cfg.stt_echo_transcripts is False
|
||||
|
||||
|
||||
def test_top_level_stt_echo_transcripts_takes_precedence():
|
||||
cfg = GatewayConfig.from_dict({
|
||||
"stt_echo_transcripts": False,
|
||||
"stt": {"echo_transcripts": True},
|
||||
})
|
||||
|
||||
assert cfg.stt_echo_transcripts is False
|
||||
|
||||
|
||||
def test_gateway_runner_uses_stt_echo_transcripts_flag():
|
||||
runner = GatewayRunner.__new__(GatewayRunner)
|
||||
|
||||
runner.config = SimpleNamespace(stt_echo_transcripts=False)
|
||||
assert runner._should_echo_stt_transcripts() is False
|
||||
|
||||
runner.config = SimpleNamespace(stt_echo_transcripts=True)
|
||||
assert runner._should_echo_stt_transcripts() is True
|
||||
|
||||
runner.config = SimpleNamespace()
|
||||
assert runner._should_echo_stt_transcripts() is True
|
||||
Loading…
Add table
Add a link
Reference in a new issue