Потоковое распознавание и синтез (gRPC)¶
Помимо HTTP REST API, сервис предоставляет gRPC-интерфейс для высокопроизводительных интеграций и потоковой обработки. Источником звука может быть микрофон или готовая длинная запись: клиент передаёт аудио частями и получает текст по мере распознавания. Это совместимый поднабор Yandex SpeechKit API v3, а не полная реализация всех сообщений STT v3.
Подключение¶
В примерах используется публичный порт 50052.
Аутентификация¶
gRPC требует аутентификации: передавайте действующий API-ключ в metadata. Запросы без валидного ключа отклоняются с кодом UNAUTHENTICATED. Принимаются обе схемы — Bearer (как в клиентах в стиле Yandex) и Api-Key:
Сервисы¶
Recognizer — потоковое распознавание (STT v3)¶
Сервис speechkit.stt.v3.Recognizer реализует основной потоковый контракт
Yandex SpeechKit STT v3.
| Метод | Описание |
|---|---|
RecognizeStreaming |
Двунаправленный поток: клиент отправляет аудио (StreamingRequest), сервер возвращает промежуточные и итоговые результаты (StreamingResponse) |
Первый кадр от клиента должен содержать session_options; только после него
отправляйте аудио. Конфигурация задаётся ровно один раз: повторный
session_options, даже с теми же значениями, отклоняется с INVALID_ARGUMENT.
Для смены режима распознавания, языка или формата откройте новый RPC. Поток без конфигурации
сессии отклоняется. Поддерживаются
следующие параметры:
| Поле | Поведение |
|---|---|
recognition_model.model |
Для русского по умолчанию SpeechExpert-STT-RU: T-One preview и Riva final после EOF; можно явно выбрать прямой SpeechExpert-STT-RU-stream или другую совместимую модель |
recognition_model.language_restriction.language_code[0] |
Языковая подсказка; остальные коды и restriction_type не применяются |
recognition_model.audio_format.raw_audio.sample_rate_hertz |
Частота входного PCM |
recognition_model.audio_format.raw_audio.audio_channel_count |
Число interleaved-каналов, от 1 до 32 |
recognition_model.text_normalization |
Нормализация, profanity filter, литературный текст/пунктуация и форматирование телефонов |
recognition_model.text_normalization.literature_text |
true включает восстановление пунктуации в финальном тексте, если оно поддерживается выбранной моделью; по умолчанию false |
recognition_model.audio_processing_type |
REAL_TIME по умолчанию; FULL_DATA выдаёт только финалы после успешного завершения всего ввода |
speaker_labeling.speaker_labeling |
SPEAKER_LABELING_ENABLED включает потоковую диаризацию Nemotron для mono; по умолчанию выключена |
eou_classifier.default_classifier.max_pause_between_words_hint_ms |
Пауза, после которой фраза считается завершённой |
eou_classifier.external_classifier принимается protobuf-схемой, но
игнорируется. Параметры HTTP v3 recognitionClassifier, speechAnalysis и
summarization в потоковую gRPC-сессию не входят. Неизвестные значения enum
audio_processing_type и speaker_labeling отклоняются с INVALID_ARGUMENT.
После конфигурации клиент отправляет little-endian PCM16 в chunk.data. Для
нескольких каналов сэмплы должны быть interleaved; сервер разделяет каналы и
распознаёт их параллельно. Поток, оборванный посередине многоканального PCM-фрейма,
отклоняется с INVALID_ARGUMENT.
Для готовой записи преобразуйте аудио в PCM16 на стороне клиента и отправляйте
его последовательно, одновременно читая ответы. Загружать исходный файл
целиком перед получением текста не требуется. В режимах пофразового
распознавания для русского, английского, казахского, кыргызского, узбекского и таджикского языков клиент
получает partial текущей фразы и её final по мере обработки. После последнего
фрагмента завершите отправку запросов и дочитайте ответы до CLOSED. Русский
режим по умолчанию SpeechExpert-STT-RU выдаёт накопительный T-One preview во время передачи,
а окончательный результат Riva для всей записи — после завершения ввода.
Каждый такой partial заменяет весь предварительный транскрипт сессии. Подробнее —
распознавание длинных записей.
Многоканальный поток применяет обратное давление: когда распознаватель или
получатель ответов не успевает, чтение аудио приостанавливается. Если доставка
данных каналам или помещение результата в очередь не продвигается 30 секунд,
весь RPC завершается с UNAVAILABLE; его дочерние распознаватели закрываются.
Аудио и ответы не отбрасываются для обхода заполненной очереди.
Баланс проверяется до выдачи результатов. При успешном EOF оплачивается
принятая длительность аудио. При ошибке или отключении после выдачи partial
или final оплачивается проверенная граница последнего отправленного ответа;
позднее аудио без нового ответа не отменяет это списание. Запрос, отклонённый до
выдачи результата, не создаёт такое списание. Исходный код ошибки сохраняется,
а повторная отмена RPC не запускает второе списание.
Вместо байтов можно отправить silence_chunk.duration_ms. Допустимая длительность
одного события — от 1 до 300000 мс. Для тишины частота должна быть задана в
raw_audio либо использовать значение по умолчанию.
Минимальный клиент для mono PCM16 16 кГц:
import os
import grpc
from speechkit.stt.v3 import stt_pb2, stt_service_pb2_grpc
def requests():
options = stt_pb2.StreamingOptions()
model = options.recognition_model
model.model = "SpeechExpert-STT-RU"
model.audio_format.raw_audio.sample_rate_hertz = 16_000
model.audio_format.raw_audio.audio_channel_count = 1
model.language_restriction.language_code.append("ru-RU")
yield stt_pb2.StreamingRequest(session_options=options)
with open("audio.pcm", "rb") as source:
while chunk := source.read(3200): # около 100 мс
yield stt_pb2.StreamingRequest(
chunk=stt_pb2.AudioChunk(data=chunk)
)
channel = grpc.insecure_channel("api.speech.example.com:50052")
stub = stt_service_pb2_grpc.RecognizerStub(channel)
metadata = (("authorization", f"Bearer {os.environ['API_KEY']}"),)
for response in stub.RecognizeStreaming(requests(), metadata=metadata):
event = response.WhichOneof("Event")
if event in {"partial", "final"}:
update = getattr(response, event)
print(event, response.channel_tag, update.alternatives[0].text)
elif event == "status_code":
print("closed", response.status_code.code_type)
Импорт в клиенте зависит от package path, который использовался при генерации
кода из stt.proto; имена protobuf-сообщений остаются теми же.
Пример использует русский режим по умолчанию: SpeechExpert-STT-RU возвращает preview
T-One, затем один окончательный текст Riva после EOF. Чтобы получать прямые
пофразовые T-One finals во время передачи, явно задайте
options.recognition_model.model = "SpeechExpert-STT-RU-stream".
Автоматическое восстановление пунктуации сервисом выключено по умолчанию.
Чтобы включить его, добавьте настройку до отправки первого session_options:
Восстановление применяется только к final; partial не проходит этот шаг.
Знаки препинания, уже выданные выбранной моделью, не удаляются. В protobuf
эта настройка называется literature_text.
ElevenLabs Scribe v2 Realtime¶
Для Scribe Realtime замените настройку модели в приведённом клиенте:
options = stt_pb2.StreamingOptions()
model = options.recognition_model
model.model = "ElevenLabs-Scribe-v2-Realtime" # также принимается scribe_v2_realtime
model.language_restriction.language_code.append("ru-RU")
model.audio_format.raw_audio.sample_rate_hertz = 16_000
model.audio_format.raw_audio.audio_channel_count = 1
model.audio_processing_type = stt_pb2.RecognitionModelOptions.REAL_TIME
Отправьте эти session_options первыми, затем передавайте PCM и одновременно
читайте ответы, как в полном примере. Модель принимает 75 языков сервиса,
включая ru-RU, en-US, kk-KZ, ky-KG, uz-UZ, tg-TJ и fr-FR.
Для многоканального PCM каждый канал распознаётся своим соединением с ElevenLabs.
Сервер преобразует звук каждого канала в mono PCM16 16 кГц для провайдера.
Промежуточные гипотезы приходят в стандартном partial, окончательные фразы —
в final. Пословные таймкоды провайдера публикуются в Alternative.words,
границы фразы — в start_time_ms и end_time_ms; все значения отсчитываются
от начала входного аудио. Финал выдаётся один раз после получения таймкодов.
Если таймкоды не пришли вовремя, публикуются оценённые границы фразы без слов.
Текст Scribe Realtime сохраняется вместе с его пословной разметкой:
параметры recognition_model.text_normalization, включая литературный текст,
не изменяют результат этой модели.
После последнего чанка закройте клиентский поток и дочитайте ответы до CLOSED.
При стандартной настройке дочитывание ElevenLabs после EOF может занять до
15 секунд. В этом режиме не вызываются файловые Scribe v2 или Medical для
уточнения текста. FULL_DATA только откладывает выдачу финалов до успешного
EOF; отдельного распознавания полной записи нет.
У провайдера нет нативной диаризации Realtime; для mono можно включить
потоковую диаризацию Nemotron. Аудио передаётся внешнему
сервису ElevenLabs; на сервере требуется ELEVENLABS_API_KEY, webhook не нужен.
Стоимость и поведение при ошибках описаны в обзоре Realtime.
Потоковая диаризация¶
Для mono-аудио добавьте в начальные session_options стандартные поля
SpeechKit v3. Их имена, номера и значения enum совместимы с официальными
protobuf-клиентами:
options = stt_pb2.StreamingOptions()
options.recognition_model.model = "SpeechExpert-STT-RU-stream"
options.recognition_model.language_restriction.language_code.append("ru-RU")
options.recognition_model.audio_format.raw_audio.sample_rate_hertz = 16_000
options.recognition_model.audio_format.raw_audio.audio_channel_count = 1
options.recognition_model.audio_processing_type = stt_pb2.RecognitionModelOptions.REAL_TIME
options.speaker_labeling.speaker_labeling = (
stt_pb2.SpeakerLabelingOptions.SPEAKER_LABELING_ENABLED
)
# Отправьте StreamingRequest(session_options=options) первым сообщением,
# затем chunk.data с PCM16, как в полном примере выше.
В этом примере явно выбран прямой SpeechExpert-STT-RU-stream, чтобы финальные
фрагменты появлялись во время записи. В SpeechExpert-STT-RU окончательный
текст ASR появляется после EOF, поэтому диаризованные финалы также ждут EOF.
partial приходит без метки диктора. Выдача final ждёт, пока диаризация
зафиксирует соответствующий участок аудио. В ответе StreamingResponse.channel_tag
содержит строковый ID диктора от "0" до "7"; для старых клиентов то же значение
дублируется в final.channel_tag. Если принадлежность речи определить не удалось,
метка остаётся пустой, в том числе у непустого final. Идентификаторы сохраняются
в пределах одной сессии и не обозначают личность человека между подключениями.
Многоканальный вход с включённой диаризацией отклоняется с INVALID_ARGUMENT.
При наличии согласованных пословных таймкодов одна ASR-фраза может стать несколькими
final с разными дикторами; каждый увеличивает audio_cursors.final_index.
Если доступны только границы фразы, ей назначается преобладающий диктор целиком.
При одновременной речи нескольких людей разделение их слов не гарантируется.
speaker_analysis — отдельная статистика речи и этим режимом не добавляется.
REAL_TIME с диаризацией — расширение нашего сервера: Yandex описывает
определение дикторов
только для FULL_DATA, mono и не более двух дикторов. Для отложенной выдачи
укажите stt_pb2.RecognitionModelOptions.FULL_DATA. Аудио обрабатывается
последовательно, финалы временно сохраняются и отправляются только после
успешного EOF; partial в этом режиме не выдаются. Это не запускает дополнительное
офлайн-распознавание или уточнение текста. При ошибке до завершения обработки
накопленные финалы не отправляются. Режим действует и без диаризации.
Подробнее о задержке и доступных таймкодах — в обзоре диаризации.
Поддерживаемые языки и результаты¶
Локальное потоковое распознавание с промежуточным текстом доступно
для русского, английского, казахского, кыргызского, узбекского и таджикского языков. Укажите язык в
recognition_model.language_restriction.language_code и соответствующее
значение recognition_model.model:
| Язык | Код языка | Значение model |
|---|---|---|
| Русский, по умолчанию: итог после EOF | ru-RU |
SpeechExpert-STT-RU |
| Русский, прямой пофразовый поток | ru-RU |
SpeechExpert-STT-RU-stream |
| Английский | en-US |
Parakeet-EN |
| Казахский | kk-KZ или kk |
SpeechExpert-STT-KK-stream |
| Кыргызский | ky-KG или ky |
GigaAM-Multilingual-Large-CTC |
| Узбекский | uz-UZ или uz |
SpeechExpert-STT-UZ-stream |
| Таджикский | tg-TJ или tg |
SpeechExpert-STT-TG-stream |
Для всех этих языков и остальных языков курируемого набора можно явно выбрать
ElevenLabs-Scribe-v2-Realtime; пример приведён выше.
Идентификаторы в таблице нужны для настройки запроса. Несовместимые сочетания
языка и значения model отклоняются до распознавания. Подробнее о выборе
интерфейса — в обзоре потокового распознавания.
В русском SpeechExpert-STT-RU каждый partial заменяет preview всей сессии;
Riva final после EOF заменяет его окончательным текстом. Если Riva не вернул
текст, итогом становится последний preview. В остальных пофразовых режимах,
включая SpeechExpert-STT-RU-stream, каждый новый partial заменяет
предварительный текст текущей фразы. final
завершает её: добавьте его текст к итоговому транскрипту и очистите
предварительный текст этой фразы. Финальный текст может отличаться от промежуточного.
Локальный таджикский поток возвращает итог без автоматической пунктуации и нормализации
текста независимо от настроек recognition_model.text_normalization.
Успешный пустой final также завершает фразу. После отправки всего аудио
закройте клиентский поток запросов и продолжайте читать ответы до CLOSED:
сервер завершит оставшуюся фразу.
Без диаризации в локальном кыргызском потоке итог каждой фразы уточняется отдельно. Пока готовится
предыдущий final, уже могут приходить partial следующей фразы. Храните
гипотезы по паре channel_tag и Alternative.start_time_ms; финал очищает
только гипотезу с этим ключом. Финалы приходят в исходном порядке. Нового
поля phrase_id в protobuf нет.
При диаризации channel_tag обозначает диктора, а у partial остаётся пустым;
не используйте его как единственный ключ предварительной фразы. Сопоставляйте
финальные фрагменты с гипотезами по диапазону времени и учитывайте, что одна
фраза может содержать несколько финальных фрагментов разных дикторов.
Для локальных казахского, кыргызского, узбекского и таджикского потоков границы фраз определяются автоматически;
параметр max_pause_between_words_hint_ms на них не влияет.
Для этих языков многоканальный запрос принимается целиком: при нехватке доступной ёмкости
сервер отклоняет весь запрос.
Доступны также режимы с уточнением предварительного текста:
| Язык | Значение model |
Поведение |
|---|---|---|
| Русский, по умолчанию | SpeechExpert-STT-RU |
Накопительный T-One preview всей записи и окончательный текст Riva после EOF |
| Русский | GigaAM-Multilingual-Large-CTC |
Накопительный partial для всей записи и один уточнённый final после завершения ввода |
| Казахский | GigaAM-Multilingual-Large-CTC |
partial текущей фразы и уточнённый final каждой завершённой фразы, в исходном порядке |
В режимах с единственным итогом после завершения ввода partial заменяет весь
предварительный транскрипт. Если уточнение не дало текста, итогом становится
последний предварительный результат. Для казахского режима с уточнением
действуют правила пофразовой обработки, описанные выше.
В узбекском потоке SpeechExpert-STT-UZ-stream возвращает предварительный
текст по мере поступления аудио и уточняет каждую завершённую фразу,
включая оставшийся фрагмент при завершении ввода.
Ответы и таймстемпы¶
Сервер возвращает только partial, final и завершающий status_code.
События HTTP v3 finalRefinement, eouUpdate, classifierUpdate, аналитика
спикеров/разговора и суммаризация в этом gRPC-контракте не реализованы.
Для русского и английского пофразового распознавания поля
Alternative.start_time_ms, Alternative.end_time_ms и Alternative.words[]
содержат доступные границы речи на шкале исходного потока. Это время речи, а не
момент получения сетевого чанка. Нулевой start_time_ms валиден.
В русских режимах с единственным итогом после завершения ввода промежуточные
и итоговый результаты получают накопленный диапазон аудио. Если итоговый текст
отличается от предварительного, words у финала остаётся пустым, поскольку
точное пословное выравнивание неизвестно.
Для локальных казахского, кыргызского, узбекского и таджикского потоков start_time_ms и end_time_ms обозначают границы
обработанного аудиофрагмента, включая паузы. Это не точное время произнесения
слов, поэтому words[] остаётся пустым.
При отсутствии доступного тайминга scalar-поля protobuf остаются со значением 0,
а words пуст.
AudioCursors — отдельная шкала прогресса транспорта:
| Поле | Семантика |
|---|---|
received_data_ms |
Объём принятых PCM-данных, включая silence_chunk |
partial_time_ms |
Монотонная граница обработанного аудио; не меньше final_time_ms |
final_time_ms |
Монотонный максимум границ отправленных финалов |
eou_time_ms |
Совпадает с final_time_ms |
final_index |
Число отправленных final в сессии |
Границы речи в Alternative не подменяются курсорами: уточнённый финал может
заканчиваться раньше предыдущего partial, тогда как partial_time_ms всё равно
движется только вперёд. Без диаризации для многоканального аудио
StreamingResponse.channel_tag и AlternativeUpdate.channel_tag равны
строковому номеру физического канала, начиная с "1"; для mono они пусты.
После обработки всего ввода
сервер отправляет отдельный status_code с code_type=CLOSED.
response_wall_time_ms в gRPC содержит Unix-время формирования ответа в
миллисекундах. Это отличается от одноимённого JSON-поля HTTP v3, где хранится
прошедшее время обработки операции.
Если нормализация доступна для языка и включена, она применяется к каждому
partial и final; отдельного finalRefinement нет. Правила преобразования
чисел, телефонов и фильтрации ненормативной лексики применяются только к
русскому. Таджикский текст возвращается без такой постобработки. Если объект text_normalization передан с
PHONE_FORMATTING_MODE_UNSPECIFIED, форматирование телефонов считается
включённым. words[] сохраняют исходные распознанные слова и поэтому после пунктуации,
фильтрации или нормализации могут уже не совпадать с итоговым text.
WebSocket STT¶
Для браузерных клиентов и более простого JSON-протокола используйте отдельный WebSocket STT. Он принимает mono PCM16 16 кГц и не требует генерации клиентского кода из protobuf.
Synthesizer — потоковый синтез (TTS v3)¶
Сервис speechkit.tts.v3.Synthesizer поддерживает синтез речи через методы UtteranceSynthesis и StreamSynthesis.
Server Reflection¶
Сервер поддерживает gRPC Server Reflection — API можно исследовать через grpcurl:
# Список доступных сервисов
grpcurl -plaintext -H "authorization: Bearer ${API_KEY}" api.speech.example.com:50052 list
# Описание доступных методов
grpcurl -plaintext -H "authorization: Bearer ${API_KEY}" api.speech.example.com:50052 describe
Для изучения доступных сервисов и генерации клиента можно использовать Server Reflection.