Работа с ASR осуществляется протоколу WebSocket. Для корректной работы с сервисом требуется пройти авторизацию. Подробно этот механизм описан в главе Authorization API. В процессе авторизации будет сформирован JWT содержащий UUID Ключа (key_uuid) и время жизни токена (exp).
После успешной авторизации требуется установить подключение к сервису ASR. Ссылка для подключения содержится в параметре endpoint_asr Ключа.
Пример URL сервиса:
wss://asr-asraas-stage.neuro.net/v2/recognize
Для старта сессии распознавания на сервер необходимо отправить запрос с JSON-объектом следующего формата:
{
'command': 'start_recognizer',
'call_uuid': 'uuid', # уникальный uuid
'token': 'jwt_token', # токен аутентификации
'params': {} # параметры сессии в виде словаря
}
Если авторизация проходит успешно, открывается соединение WebSocket, которое на вход ожидает поток аудиоданных в бинарном формате. Поддерживаемый формат аудио: PCM 16bit le без WAV-заголовка, частота дискретизации 8000 Гц.
Пример кода на Python для открытия соединения:
async def process(self, url: str, file_stream, jwt_token):
async with session.ws_connect(url, timeout=5) as ws:
await ws.send_json({'command': 'start_recognizer',
'token': jwt_token,
'call_uuid': '68fce9af-16e2-4208-8ea7-214d3c65477c',
'params': {
'decode_numbers': True,
'replace_yo': True,
'normalization': None
}
})
ok = await ws.receive_str()
if 'ok' not in status:
raise Exception(status)
full_prediction, _ = await asyncio.gather(
self._data_reader(ws), # реализация вывода результата распознавания
self._data_writer(ws, file_stream) # реализация отправки аудио потока в бинарном формате
)
logging.info(f'{full_prediction = }') # full_prediction – распознанный текст
В случае, если jwt_token
указан неверно, ASR вернет сообщение об ошибке и закроет WS-соединение.
Описание параметров сессии распознавания
Доступные параметры:
Параметр |
Описание |
replace_yo |
bool Включить замену «ё» на «е». Если Если Значение по умолчанию: Допустимые значения: |
decode_numbers |
bool Включить декодирование числительных в цифры. Если Если Значение по умолчанию: Допустимые значения: |
chunk_size |
int Размер чанка в байтах. Значение по умолчанию: 4160 байт (260 мс). |
vad_finalize_time |
int Время ожидания финализации в миллисекундах. Значение по умолчанию: 1000 мс. |
normalization |
string Включить ограничение нормализации. Если Если Значение по умолчанию: Допустимые значения: |
enable_automatic_punctuation |
bool Включить автоматическую расстановку пунктуации по паузам в речи. Если Если Значение по умолчанию: Допустимые значения: |
detect_gender |
bool Включить распознавание пола говорящего. Если Если Значение по умолчанию: Допустимые значения: |
detect_answerphone |
bool Включить распознавание наличия сигнала автоответчика в аудио. Если Если Значение по умолчанию: Допустимые значения: |
detect_speaker |
bool Включить распознавание диктора в аудио. Распознавание диктора происходит на основе известного набора дикторов (голоса автоответчиков и голосовых помощников). Если Если Значение по умолчанию: Допустимые значения: |
significant_words |
list Список значащих слов, на которые необходимо обратить особое внимание при распознавании. Все слова из списка будут использоваться в результатах распознавания с большей вероятность, чем похожие по звучанию на них. Если слово подразумевает изменений словоформы (например, изменение окончания при склонении по падежам), то необходимо указать все требуемые словоформы в списке. Значение по умолчанию: Допустимые значения: |
Отправка данных на ASR Server производится через WebSocket
соединение, открытое на предыдущем шаге. Поддерживаемый формат аудио: PCM 16bit le без WAV-заголовка, частота дискретизации 8000 Гц. Отправка данных производится по частям (чанкам). Размер чанка по умолчанию составляет 4160 байт (260 мс).
Ниже приведен пример функции _data_writer
на Python, принимающей на вход объект WS-подключения и поток аудио данных. Внутри самой функции реализуется простая отправка данных на сервер в цикле по чанкам. Вызов метода sleep нужен для имитации потокового режима. После отправки всех данных на сервер отправляется команда close_recognizer для закрытия подключения.
async def _data_writer(self, ws: aiohttp.ClientWebSocketResponse, stream):
for data in stream:
await ws.send_bytes(data)
await asyncio.sleep(0.260)
await ws.send_json({
'command': 'close_recognizer',
'call_uuid': '68fce9af-16e2-4208-8ea7-214d3c65477c'
})
Ниже приведен пример функции _data_reader
на Python, принимающей на вход объект WS-подключения. В асинхронном цикле по WS-сообщениям происходит проверка содержимого. В случае получения данных распознавания функция копит их в список до тех пор, пока не будет закрыто соединение. После закрытия соединения все полученные результаты собираются в одну текстовую строку и передаются на выход функции.
Код на Python:
async def _data_reader(self, ws: aiohttp.ClientWebSocketResponse):
predict_list = []
prediction = ''
try:
async for msg in ws:
if not isinstance(msg, aiohttp.WSMessage):
continue
if msg.type == aiohttp.WSMsgType.CLOSE:
logging.warning(f'websocket is closed')
break
elif msg.type == aiohttp.WSMsgType.CLOSED:
logging.warning(f'websocket is closed')
break
elif msg.type == aiohttp.WSMsgType.TEXT:
if msg.data == 'ok':
await ws.close()
full_prediction = ' '.join(predict_list)
return full_prediction
try:
json_data = json.loads(msg.data)
except Exception as err:
json_data = {}
is_final = json_data.get('is_final')
prediction = json_data.get('text')
if is_final and not (prediction == ''):
predict_list.append(prediction)
finally:
if (len(predict_list) == 0) or predict_list[-1] != prediction:
predict_list.append(prediction)
full_prediction = ' '.join(predict_list)
return full_prediction
Структура ответа
ASR возвращает ответ в JSON формате. Ответ содержит в себе следующие поля:
Параметр | Тип | Значение по умолчанию | Условие |
---|---|---|---|
text |
str | '' | Поле с итоговым текстом. |
greedy_text |
str | '' | «Сырой» текст, без обработки языковой моделью. |
rd_text |
str | '' | Текст после обработки словарями. |
is_final |
bool | False |
Флаг финализации. Показывает, что возникла пауза в речи. |
voiced |
bool | False |
Флаг наличия речи во входном аудиопотоке. |
timestamps |
list | [] |
Массив временных меток начала и конца слов в аудиопотоке. Пример: "timestamps": [{"word": "распознаное_слово1", "start": 12.16, "end": 12.4}, {"word": "распознаное_слово2", "start": 12.48, "end": 12.56}, {"word": "распознаное_слово3", "start": 12.56, "end": 12.88}] |
timeline |
float | 0.0 |
Время с начала сессии распознавания. |
confidence |
float | 0.1 |
Уверенность ASR в результате распознавания. Изменяется в пределах [0..1]. |
gender |
dict |
|
Результат распознавания пола говорящего, где 'label ' - метка пола ( 'male' , 'female' , '' ), 'confidence' - уверенность в результате. |
answerphone |
dict |
|
Результат распознавания сигнала автоответчика, где
|
speaker |
dict |
|
Результат распознавания диктора, где
|
В коде на Python структуру ответа можно описать следующим классом:
class ASRResponse(defaultdict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__dict__ = self
self.text: str = ''
self.greedy_text: str = ''
self.rd_text: str = ''
self.is_final: bool = False
self.paused_text: str = ''
self.voiced: bool = False
self.timestamps: list = []
self.alternatives: list = []
self.timeline: float = time.time() - kwargs.get('start_time', 0.0)
self.confidence: float = 1.0
self.gender: dict = {'label': '', 'confidence': 1.0}
self.answerphone: dict = {'label': False, 'confidence': 1.0}
self.speaker: dict = {'label': False, 'name': 'undefined','confidence': 1.0}
Пример JSON-объекта с ответом:
{
'start_time': 1704971858.117291,
'text': 'ой молодой человек',
'greedy_text': '',
'rd_text': 'ой молодой человек',
'is_final': False,
'paused_text': 'ой молодой человек',
'voiced': True,
'timestamps':
[
{
'word': 'ой',
'start': 0.28,
'end': 0.44
},
{
'word': 'молодой',
'start': 0.8,
'end': 1.16
},
{
'word': 'человек',
'start': 1.2,
'end': 1.6
}
],
'alternatives':
[
{
'text': 'ой молодой человек',
'confidence': 0.0
}
],
'timeline': 1.9199999570846558,
'confidence': 1.0,
'gender':
{
'label': '',
'confidence': 1.0
},
'answerphone':
{
'label': False,
'confidence': 1.0
},
'speaker':
{
'label': False,
'name': 'undefined',
'confidence': 1.0
},
'logits': None,
'predict_runtime': 0.03794360160827637
}
После отправки аудио потока необходимо отправить команду завершения распознавания в формате JSON:
{
'command': 'close_recognizer',
'call_uuid': 'uuid' # uuid который передавался при инициализации подключения
}
В ответ сервер отправляет закрывающий пакет, и функция чтения результата распознавания завершается.
Пример кода на Python:
await ws.send_json({
'command': 'close_recognizer',
'call_uuid': '68fce9af-16e2-4208-8ea7-214d3c65477c'
})