fix(stt): configure OpenAI client timeout and retries
(cherry picked from commit 2158ee474af441821517da37e724821f46ec2ed5)
This commit is contained in:
@@ -1625,6 +1625,8 @@ stt:
|
||||
openai:
|
||||
model: "whisper-1" # whisper-1 | gpt-4o-mini-transcribe | gpt-4o-transcribe | gpt-transcribe
|
||||
language: "" # auto-detect; set to "en", "es", "fr", etc. to force
|
||||
timeout: 60 # request timeout in seconds; increase for self-hosted model cold starts
|
||||
max_retries: 1 # OpenAI SDK transport retries; set 0 to disable
|
||||
# mistral:
|
||||
# model: "voxtral-mini-latest" # voxtral-mini-latest | voxtral-mini-2602
|
||||
# deepinfra:
|
||||
|
||||
@@ -1129,6 +1129,8 @@ DEFAULT_CONFIG = {
|
||||
# whisper-1, gpt-4o-mini-transcribe, gpt-4o-transcribe, gpt-transcribe
|
||||
"model": "whisper-1",
|
||||
"language": "", # auto-detect; set "en", "es", ... to force
|
||||
"timeout": 60, # seconds; allow self-hosted backends time to cold-start
|
||||
"max_retries": 1, # OpenAI SDK transport retries
|
||||
},
|
||||
"mistral": {
|
||||
"model": "voxtral-mini-latest", # voxtral-mini-latest, voxtral-mini-2602
|
||||
|
||||
@@ -226,6 +226,32 @@ class TestTranscribeGroq:
|
||||
assert "openai package" in result["error"]
|
||||
|
||||
|
||||
class TestOpenAIClientConfig:
|
||||
@pytest.mark.parametrize(
|
||||
("openai_config", "expected_timeout", "expected_retries"),
|
||||
[({}, 60, 1), ({"timeout": 95, "max_retries": 3}, 95, 3)],
|
||||
)
|
||||
def test_stt_openai_config_controls_sdk_client(
|
||||
self, monkeypatch, tmp_path, sample_wav, openai_config, expected_timeout, expected_retries
|
||||
):
|
||||
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
config_lines = ["stt:", " openai:"]
|
||||
config_lines.extend(f" {key}: {value}" for key, value in openai_config.items())
|
||||
(tmp_path / "config.yaml").write_text("\n".join(config_lines) + "\n", encoding="utf-8")
|
||||
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) as openai_client:
|
||||
from tools.transcription_tools import _transcribe_groq
|
||||
result = _transcribe_groq(sample_wav, "whisper-large-v3-turbo")
|
||||
|
||||
assert result["success"] is True
|
||||
assert openai_client.call_args.kwargs["timeout"] == expected_timeout
|
||||
assert openai_client.call_args.kwargs["max_retries"] == expected_retries
|
||||
|
||||
|
||||
def test_null_groq_subsection_is_safe(self, monkeypatch, sample_wav):
|
||||
"""`stt.groq: null` in YAML yields None; must not raise, auto-detect stays intact."""
|
||||
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
|
||||
|
||||
@@ -37,12 +37,19 @@ def _has_xai_stt_credentials() -> bool:
|
||||
|
||||
|
||||
def _with_openai_client(api_key: str, base_url: Optional[str], file_path: str, log_label: str, body):
|
||||
"""Run ``body(client)`` on a fresh OpenAI SDK client (30s timeout, no retries); always closed.
|
||||
"""Run ``body(client)`` on a fresh, configured OpenAI SDK client; always closed.
|
||||
Errors map to the shared envelope. APIConnectionError is checked before APITimeoutError (its
|
||||
subclass) so timeouts report as connection errors, as they always have."""
|
||||
try:
|
||||
from openai import OpenAI
|
||||
client = OpenAI(api_key=api_key, base_url=base_url, timeout=30, max_retries=0)
|
||||
from tools.transcription_tools import _load_stt_config
|
||||
openai_config = _get_stt_section(_load_stt_config(), "openai")
|
||||
client = OpenAI(
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
timeout=openai_config.get("timeout", 60),
|
||||
max_retries=openai_config.get("max_retries", 1),
|
||||
)
|
||||
try:
|
||||
return body(client)
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user