mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-10-20 05:15:31 +00:00
fix(tools): address Copilot review on Groq STT language hint
- Normalize stt.groq.language: cast to str, strip, treat empty/whitespace as unset (parity with xAI's str().strip()). - Clarify "blank = auto-detect" inline comments in 4 docs/configs to reflect the env-var fallback (HERMES_LOCAL_STT_LANGUAGE). - Document that HERMES_LOCAL_STT_LANGUAGE also drives the local faster-whisper provider, not just the CLI fallback. - Add unit tests covering: omitted language when unset, config-supplied language, env fallback, config-over-env precedence, whitespace normalized to unset. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a355db1ef5
commit
be10998264
7 changed files with 101 additions and 10 deletions
|
|
@ -1128,7 +1128,7 @@ stt:
|
|||
model: "base" # tiny | base | small | medium | large-v3 | turbo
|
||||
# language: "" # auto-detect; set to "en", "es", "fr", etc. to force
|
||||
# groq:
|
||||
# language: "" # auto-detect; set to "en", "es", "fr", etc. to force
|
||||
# language: "" # blank = use HERMES_LOCAL_STT_LANGUAGE if set, else auto-detect
|
||||
openai:
|
||||
model: "whisper-1" # whisper-1 | gpt-4o-mini-transcribe | gpt-4o-transcribe
|
||||
language: "" # auto-detect; set to "en", "es", "fr", etc. to force
|
||||
|
|
|
|||
|
|
@ -311,6 +311,95 @@ class TestTranscribeGroq:
|
|||
assert result["success"] is False
|
||||
assert "Permission denied" in result["error"]
|
||||
|
||||
def test_language_hint_omitted_when_unset(self, monkeypatch, sample_wav):
|
||||
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
|
||||
monkeypatch.delenv("HERMES_LOCAL_STT_LANGUAGE", raising=False)
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.audio.transcriptions.create.return_value = "hi"
|
||||
|
||||
with patch("tools.transcription_tools._HAS_OPENAI", True), \
|
||||
patch("openai.OpenAI", return_value=mock_client), \
|
||||
patch("tools.transcription_tools._load_stt_config", return_value={}):
|
||||
from tools.transcription_tools import _transcribe_groq
|
||||
_transcribe_groq(sample_wav, "whisper-large-v3-turbo")
|
||||
|
||||
kwargs = mock_client.audio.transcriptions.create.call_args.kwargs
|
||||
assert "language" not in kwargs
|
||||
|
||||
def test_language_hint_from_config(self, monkeypatch, sample_wav):
|
||||
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
|
||||
monkeypatch.delenv("HERMES_LOCAL_STT_LANGUAGE", raising=False)
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.audio.transcriptions.create.return_value = "hola"
|
||||
|
||||
with patch("tools.transcription_tools._HAS_OPENAI", True), \
|
||||
patch("openai.OpenAI", return_value=mock_client), \
|
||||
patch(
|
||||
"tools.transcription_tools._load_stt_config",
|
||||
return_value={"groq": {"language": "es"}},
|
||||
):
|
||||
from tools.transcription_tools import _transcribe_groq
|
||||
_transcribe_groq(sample_wav, "whisper-large-v3-turbo")
|
||||
|
||||
kwargs = mock_client.audio.transcriptions.create.call_args.kwargs
|
||||
assert kwargs["language"] == "es"
|
||||
|
||||
def test_language_hint_from_env_when_config_missing(self, monkeypatch, sample_wav):
|
||||
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
|
||||
monkeypatch.setenv("HERMES_LOCAL_STT_LANGUAGE", "hu")
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.audio.transcriptions.create.return_value = "szia"
|
||||
|
||||
with patch("tools.transcription_tools._HAS_OPENAI", True), \
|
||||
patch("openai.OpenAI", return_value=mock_client), \
|
||||
patch("tools.transcription_tools._load_stt_config", return_value={}):
|
||||
from tools.transcription_tools import _transcribe_groq
|
||||
_transcribe_groq(sample_wav, "whisper-large-v3-turbo")
|
||||
|
||||
kwargs = mock_client.audio.transcriptions.create.call_args.kwargs
|
||||
assert kwargs["language"] == "hu"
|
||||
|
||||
def test_language_config_overrides_env(self, monkeypatch, sample_wav):
|
||||
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
|
||||
monkeypatch.setenv("HERMES_LOCAL_STT_LANGUAGE", "hu")
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.audio.transcriptions.create.return_value = "hello"
|
||||
|
||||
with patch("tools.transcription_tools._HAS_OPENAI", True), \
|
||||
patch("openai.OpenAI", return_value=mock_client), \
|
||||
patch(
|
||||
"tools.transcription_tools._load_stt_config",
|
||||
return_value={"groq": {"language": "en"}},
|
||||
):
|
||||
from tools.transcription_tools import _transcribe_groq
|
||||
_transcribe_groq(sample_wav, "whisper-large-v3-turbo")
|
||||
|
||||
kwargs = mock_client.audio.transcriptions.create.call_args.kwargs
|
||||
assert kwargs["language"] == "en"
|
||||
|
||||
def test_language_whitespace_treated_as_unset(self, monkeypatch, sample_wav):
|
||||
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
|
||||
monkeypatch.delenv("HERMES_LOCAL_STT_LANGUAGE", raising=False)
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.audio.transcriptions.create.return_value = "hi"
|
||||
|
||||
with patch("tools.transcription_tools._HAS_OPENAI", True), \
|
||||
patch("openai.OpenAI", return_value=mock_client), \
|
||||
patch(
|
||||
"tools.transcription_tools._load_stt_config",
|
||||
return_value={"groq": {"language": " "}},
|
||||
):
|
||||
from tools.transcription_tools import _transcribe_groq
|
||||
_transcribe_groq(sample_wav, "whisper-large-v3-turbo")
|
||||
|
||||
kwargs = mock_client.audio.transcriptions.create.call_args.kwargs
|
||||
assert "language" not in kwargs
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# _transcribe_openai — additional tests
|
||||
|
|
|
|||
|
|
@ -1321,7 +1321,9 @@ def _transcribe_groq(file_path: str, model_name: str) -> Dict[str, Any]:
|
|||
model_name = DEFAULT_GROQ_STT_MODEL
|
||||
|
||||
groq_cfg = _load_stt_config().get("groq", {})
|
||||
language = groq_cfg.get("language") or os.getenv(LOCAL_STT_LANGUAGE_ENV)
|
||||
language = str(
|
||||
groq_cfg.get("language") or os.getenv(LOCAL_STT_LANGUAGE_ENV) or ""
|
||||
).strip() or None
|
||||
|
||||
try:
|
||||
from openai import OpenAI, APIError, APIConnectionError, APITimeoutError
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ Hermes reads environment variables from the process environment and, for user-ma
|
|||
| `HERMES_MODEL` | Override model name at process level (used by cron scheduler; prefer `config.yaml` for normal use) |
|
||||
| `VOICE_TOOLS_OPENAI_KEY` | Preferred OpenAI key for OpenAI speech-to-text and text-to-speech providers |
|
||||
| `HERMES_LOCAL_STT_COMMAND` | Optional local speech-to-text command template. Supports `{input_path}`, `{output_dir}`, `{language}`, and `{model}` placeholders |
|
||||
| `HERMES_LOCAL_STT_LANGUAGE` | Default language hint for STT. Used by `HERMES_LOCAL_STT_COMMAND`, the local `whisper` CLI fallback (default: `en`), Groq, and xAI when no per-provider `language` is set in `config.yaml` |
|
||||
| `HERMES_LOCAL_STT_LANGUAGE` | Default language hint for STT. Used by the `local` (faster-whisper) provider, `HERMES_LOCAL_STT_COMMAND`, the local `whisper` CLI fallback (default: `en`), Groq, and xAI when no per-provider `language` is set in `config.yaml` |
|
||||
| `HERMES_HOME` | Override Hermes config directory (default: `~/.hermes`). Also scopes the gateway PID file and systemd service name, so multiple installations can run concurrently |
|
||||
| `HERMES_GIT_BASH_PATH` | **Windows only.** Override `bash.exe` discovery for the terminal tool. Points at any bash — full Git-for-Windows install, WSL bash via symlink, MSYS2, Cygwin. The installer sets this automatically to the PortableGit it provisioned. See the [Windows (Native) Guide](../user-guide/windows-native.md#how-hermes-runs-shell-commands-on-windows) |
|
||||
| `HERMES_DISABLE_WINDOWS_UTF8` | **Windows only.** Set to `1` to disable the UTF-8 stdio shim (`configure_windows_stdio()`) and fall back to the console's locale code page. Useful for bisecting encoding bugs; rarely the right setting in normal operation |
|
||||
|
|
|
|||
|
|
@ -1715,9 +1715,9 @@ stt:
|
|||
provider: "local" # "local" | "groq" | "openai" | "mistral"
|
||||
local:
|
||||
model: "base" # tiny, base, small, medium, large-v3
|
||||
language: "" # optional ISO-639-1 hint (e.g. "en"); blank = auto-detect
|
||||
language: "" # optional ISO-639-1 hint; blank = use HERMES_LOCAL_STT_LANGUAGE if set, else auto-detect
|
||||
groq:
|
||||
language: "" # optional ISO-639-1 hint (e.g. "en"); blank = auto-detect
|
||||
language: "" # optional ISO-639-1 hint; blank = use HERMES_LOCAL_STT_LANGUAGE if set, else auto-detect
|
||||
openai:
|
||||
model: "whisper-1" # whisper-1 | gpt-4o-mini-transcribe | gpt-4o-transcribe
|
||||
language: "" # auto-detect; set to "en", "es", "fr", etc. to force
|
||||
|
|
|
|||
|
|
@ -429,16 +429,16 @@ stt:
|
|||
provider: "local" # "local" | "groq" | "openai" | "mistral" | "xai"
|
||||
local:
|
||||
model: "base" # tiny, base, small, medium, large-v3
|
||||
language: "" # optional ISO-639-1 hint (e.g. "en"); blank = auto-detect
|
||||
language: "" # optional ISO-639-1 hint; blank = use HERMES_LOCAL_STT_LANGUAGE if set, else auto-detect
|
||||
groq:
|
||||
language: "" # optional ISO-639-1 hint (e.g. "en"); blank = auto-detect
|
||||
language: "" # optional ISO-639-1 hint; blank = use HERMES_LOCAL_STT_LANGUAGE if set, else auto-detect
|
||||
openai:
|
||||
model: "whisper-1" # whisper-1, gpt-4o-mini-transcribe, gpt-4o-transcribe
|
||||
mistral:
|
||||
model: "voxtral-mini-latest" # voxtral-mini-latest, voxtral-mini-2602
|
||||
xai:
|
||||
model: "grok-stt" # xAI Grok STT
|
||||
language: "" # optional ISO-639-1 hint
|
||||
language: "" # optional ISO-639-1 hint; blank = use HERMES_LOCAL_STT_LANGUAGE if set, else "en"
|
||||
```
|
||||
|
||||
### Provider Details
|
||||
|
|
|
|||
|
|
@ -414,9 +414,9 @@ stt:
|
|||
provider: "local" # "local" (free) | "groq" | "openai" | "mistral" | "xai"
|
||||
local:
|
||||
model: "base" # tiny, base, small, medium, large-v3
|
||||
language: "" # optional ISO-639-1 hint (e.g. "en"); blank = auto-detect
|
||||
language: "" # optional ISO-639-1 hint; blank = use HERMES_LOCAL_STT_LANGUAGE if set, else auto-detect
|
||||
groq:
|
||||
language: "" # optional ISO-639-1 hint (e.g. "en"); blank = auto-detect
|
||||
language: "" # optional ISO-639-1 hint; blank = use HERMES_LOCAL_STT_LANGUAGE if set, else auto-detect
|
||||
# model: "whisper-1" # Legacy: used when provider is not set
|
||||
|
||||
# Text-to-Speech
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue