Refs #121 — живая проверка ждёт ключ SaluteSpeech, поэтому задача остаётся открытой.
Что сделано
SaluteSTT (app/llm/stt.py) за протоколом SpeechToText: синхронный REST speech:recognize, из WAV браузера снимается заголовок, уходит PCM 16 бит mono (audio/x-pcm;bit=16;rate=…), language=ru-RU. Без gRPC и protobuf.
OAuth-токен кешируется на процесс, обновляется за минуту до истечения и один раз по 401. Ретраи на 429/5xx как у OpenRouter.
Guard:STT_PROVIDER=openrouter при DEMO_CLOCK=false — ошибка настроек, приложение не стартует. auto выбирает Salute при наличии кредов; вне демо без них голос выключен (не OpenRouter и не mock).
Не-PCM/не-mono WAV → 415 вместо 500.
ADR-016.
Проверка
Новые тесты с httpx.MockTransport: формат запроса, кеш токена и обновление по 401, пустой результат → «нет речи», ошибки, отказ от стерео, выбор провайдера, guard вне демо, несуществующий CA.
Полный прогон: 1092 passed, 1 skipped; ruff чисто.
Дев-сервер работает с DEMO_CLOCK=true — на нём ничего не меняется.
Refs #121 — живая проверка ждёт ключ SaluteSpeech, поэтому задача остаётся открытой.
## Что сделано
- `SaluteSTT` (`app/llm/stt.py`) за протоколом `SpeechToText`: синхронный REST `speech:recognize`, из WAV браузера снимается заголовок, уходит PCM 16 бит mono (`audio/x-pcm;bit=16;rate=…`), `language=ru-RU`. Без gRPC и protobuf.
- OAuth-токен кешируется на процесс, обновляется за минуту до истечения и один раз по 401. Ретраи на 429/5xx как у OpenRouter.
- Настройки: `STT_PROVIDER=salute`, `SALUTE_SPEECH_CREDENTIALS` (SecretStr), `SALUTE_SPEECH_SCOPE`, `SALUTE_SPEECH_CA` (корневой сертификат Минцифры, TLS проверяется всегда).
- **Guard:** `STT_PROVIDER=openrouter` при `DEMO_CLOCK=false` — ошибка настроек, приложение не стартует. `auto` выбирает Salute при наличии кредов; вне демо без них голос выключен (не OpenRouter и не mock).
- Не-PCM/не-mono WAV → 415 вместо 500.
- ADR-016.
## Проверка
- Новые тесты с `httpx.MockTransport`: формат запроса, кеш токена и обновление по 401, пустой результат → «нет речи», ошибки, отказ от стерео, выбор провайдера, guard вне демо, несуществующий CA.
- Полный прогон: 1092 passed, 1 skipped; `ruff` чисто.
- Дев-сервер работает с `DEMO_CLOCK=true` — на нём ничего не меняется.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Eleboba
added this to the Грант ВШЭ · пилот «Династия» milestone 2026-10-31 17:11:45 +03:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Refs #121 — живая проверка ждёт ключ SaluteSpeech, поэтому задача остаётся открытой.
Что сделано
SaluteSTT(app/llm/stt.py) за протоколомSpeechToText: синхронный RESTspeech:recognize, из WAV браузера снимается заголовок, уходит PCM 16 бит mono (audio/x-pcm;bit=16;rate=…),language=ru-RU. Без gRPC и protobuf.STT_PROVIDER=salute,SALUTE_SPEECH_CREDENTIALS(SecretStr),SALUTE_SPEECH_SCOPE,SALUTE_SPEECH_CA(корневой сертификат Минцифры, TLS проверяется всегда).STT_PROVIDER=openrouterприDEMO_CLOCK=false— ошибка настроек, приложение не стартует.autoвыбирает Salute при наличии кредов; вне демо без них голос выключен (не OpenRouter и не mock).Проверка
httpx.MockTransport: формат запроса, кеш токена и обновление по 401, пустой результат → «нет речи», ошибки, отказ от стерео, выбор провайдера, guard вне демо, несуществующий CA.ruffчисто.DEMO_CLOCK=true— на нём ничего не меняется.🤖 Generated with Claude Code