Транскрипция в реальном времени
Непрерывно отправляйте аудио PCM через WebSocket Muse Voice Transcribe и получайте события транскрипции в реальном времени.
Muse Voice Transcribe в реальном времени принимает необработанное аудио PCM через постоянное соединение WebSocket и непрерывно возвращает события прогресса, речевых реплик и транскрипции. Этот интерфейс генерирует только текст, но не речевые ответы.
wss://api.agtcloud.cn/v1/asr/realtimeАутентификация и подключение
После установления WebSocket отправьте первый текстовый кадр JSON в течение 10 секунд. Bearer-ключ API передаётся в authorization.accessToken, а не в Header рукопожатия WebSocket.
| Параметр | Значение |
|---|---|
| Адрес подключения | wss://api.agtcloud.cn/v1/asr/realtime |
| Расположение аутентификации | authorization.accessToken первого текстового кадра JSON |
| Модель | muse-voice-transcribe-1.0 |
| Необязательные параметры запроса | sessionId, только для передачи ID сеанса; не означает поддержку восстановления соединения или получения истории сеансов |
Первый кадр не содержит type и не должен превышать 64 KiB. Начинайте отправку аудио только после получения успешного ответа с sessionId; успешное обновление соединения до WebSocket ещё не означает успешную аутентификацию первого кадра.
Порядок работы сеанса
- Установите соединение WebSocket.
- Отправьте первый кадр с аутентификацией, моделью и настройками аудио.
- Дождитесь
sessionIdот сервера. - Отправляйте необработанные двоичные кадры PCM с частотой, соответствующей реальному времени, и одновременно непрерывно принимайте события.
- После окончания аудио отправьте
{"type":"endStream"}. - Продолжайте принимать завершающую транскрипцию и сообщения закрытия.
speechComplete означает завершение одной речевой реплики, а не всего сеанса. После отправки endStream продолжайте читать события сервера до закрытия соединения.
Параметры первого кадра
| Поле | Тип | Описание |
|---|---|---|
authorization.accessToken | string | Обязательно, в формате Bearer your-api-key |
model | string | Обязательно, используйте muse-voice-transcribe-1.0 |
audioEncoding | string | Обязательно, для аудио в реальном времени используйте PCM_16KHZ или PCM_24KHZ |
mode | string | Необязательно: PUSH_TO_TALK, ENDPOINTING, DIARIZATION |
partialMode | string | Необязательно: CUMULATIVE возвращает накопленный текст, DELTA — новый текст |
keywords | string[] | Необязательно, подсказки терминов или имён собственных |
languageBias | string[] | Необязательно, подсказка ожидаемых языков |
emitAudioProgress | boolean | Необязательно, возвращать ли события прогресса обработки аудио |
zdrOverride | boolean | Необязательная настройка обработки данных; её действие зависит от текущего сервиса и разрешений аккаунта |
Входное аудио
Аудио должно быть монофоническим PCM16 little-endian без заголовка WAV и соответствовать частоте дискретизации 16 kHz или 24 kHz, указанной в первом кадре. Каждый аудиокадр не должен превышать 1 MiB, а количество байтов должно быть чётным.
Рекомендуется отправлять аудио блоками по 100 ms с частотой реального времени: 4800 байтов для 24 kHz и 3200 байтов для 16 kHz. Если в тишине необходимо сохранять непрерывную временную шкалу, отправляйте данные тишины PCM в том же формате.
# Создать монофоническое необработанное аудио PCM16 с частотой 24 kHz
ffmpeg -i input.mp3 -ac 1 -ar 24000 -c:a pcm_s16le -f s16le audio.pcmПример Python
Установите клиент WebSocket, подготовьте audio.pcm и запустите пример. Отправка и получение выполняются в разных потоках, чтобы загрузка аудио не блокировала обработку событий сервера.
python -m pip install websocket-clientimport json
import sys
import threading
import websocket
url = "wss://api.agtcloud.cn/v1/asr/realtime"
stop = threading.Event()
sender = None
ws = websocket.create_connection(url, timeout=40, enable_multithread=True)
def send_audio():
try:
with open(sys.argv[1], "rb") as audio:
while not stop.is_set():
chunk = audio.read(4800)
if not chunk:
break
if len(chunk) % 2:
raise ValueError("Количество байтов PCM должно быть чётным")
ws.send_binary(chunk)
if stop.wait(len(chunk) / 48000):
return
if not stop.is_set():
silence = bytes(4800)
for _ in range(10):
ws.send_binary(silence)
if stop.wait(0.1):
return
ws.send(json.dumps({"type": "endStream"}))
except Exception as exc:
print("Отправка прервана:", exc)
stop.set()
ws.close()
try:
ws.send(json.dumps({
"authorization": {"accessToken": "Bearer your-api-key"},
"model": "muse-voice-transcribe-1.0",
"audioEncoding": "PCM_24KHZ",
"mode": "ENDPOINTING",
"partialMode": "CUMULATIVE",
"languageBias": ["Mandarin Chinese"],
"emitAudioProgress": True
}))
ack = json.loads(ws.recv())
if ack.get("type") == "error" or not ack.get("sessionId"):
raise RuntimeError("Ошибка инициализации подключения: " + json.dumps(ack, ensure_ascii=False))
print("sessionId:", ack["sessionId"])
sender = threading.Thread(target=send_audio, daemon=True)
sender.start()
while not stop.is_set():
message = ws.recv()
if not message:
break
event = json.loads(message)
print(json.dumps(event, ensure_ascii=False))
if event.get("type") == "error":
break
finally:
stop.set()
ws.close()
if sender is not None:
sender.join(timeout=2)Справочник событий
audioProcessedMs показывает накопленный прогресс обработки; значения разных событий не следует складывать. В режиме CUMULATIVE новый частичный текст заменяет предыдущий накопленный результат; в режиме DELTA новый текст добавляется к предыдущему.
audioProgress
Возвращает текущий накопленный прогресс обработки аудио.
| Поле | Тип | Обязательно | Описание | Пример |
|---|---|---|---|---|
type | string | Да | Всегда `audioProgress`. | audioProgress |
audioProcessedMs | integer | Да | Накопленная длительность обработанного аудио в миллисекундах. | 1600 |
{
"type": "audioProgress",
"audioProcessedMs": 1600
}speechComplete.transcript содержит полную транскрипцию текущей речевой реплики. При завершении сеанса событие transcript с final: true может не содержать текста; клиент не должен заменять уже сохранённый накопленный текст или speechComplete.transcript пустой строкой.
Ограничения сеанса и обработка ошибок
Сеанс длится до примерно 60 минут. Отсутствие сообщений клиента в течение 15 секунд может привести к завершению ввода; сеть или состояние сервера также могут завершить соединение раньше. Клиент должен задавать общую длительность, тайм-аут чтения и стратегию ограниченного количества повторных попыток.
| Код закрытия | Значение | Рекомендация |
|---|---|---|
1008 | Ошибка политики или протокола | Проверьте структуру первого кадра, аутентификацию, параметры и последующие управляющие сообщения |
1011 | Прерывание на сервере или в вышестоящем сервисе | Сохраните sessionId, событие ошибки и причину закрытия перед решением о повторной попытке |
1013 | Сервис временно недоступен или ограничивает частоту запросов | Выполняйте ограниченное количество повторных попыток с увеличивающейся задержкой |
Оплата
Транскрипция в реальном времени оплачивается по длительности обработанного аудио. Актуальные цены указаны в каталоге моделей текущего сайта. Значения в миллисекундах из событий прогресса показывают временную шкалу обработки; их не следует суммировать как отдельные начисления.