Формат ответа
GET /v1/jobs/{id}/result возвращает JSON. Пример для стерео-звонка со всеми опциями, сокращённый:
{
"schema_version": "gapi_task_result.v0",
"audio_seconds": 282.7,
"speech_seconds": 230.4,
"channels": 2,
"stereo_parties": true,
"speakers": 2,
"vocabulary_terms": 4,
"vocabulary_dropped": false,
"text": "Assalomu alaykum, Metasell kompaniyasi. …",
"language": {"code": "uz", "confidence": 0.97, "speech_seconds": 230.4, "share": {"uz": 0.91, "ru": 0.09}, "posterior": {"uz": 0.97, "ru": 0.03}},
"call_outcome": {"outcome": "conversation", "reached": true, "confidence": 0.99, "probabilities": {"conversation": 0.99, "no_answer": 0.004, "operator_message": 0.003, "ivr": 0.003}, "answer_at": 11.4, "seconds": 180.0},
"segments": [
{
"index": 0,
"start": 0.42,
"end": 3.9,
"speaker": 1,
"text": "Assalomu alaykum, Metasell kompaniyasi.",
"raw_asr_text": "assalomu alaykum metasell kompaniyasi",
"formatted_text": "Assalomu alaykum, Metasell kompaniyasi.",
"pii": {"entities": [], "redacted_text": "Assalomu alaykum, Metasell kompaniyasi."},
"language": {"code": "uz", "confidence": 0.99}
}
],
"speaker_info": [
{
"index": 0,
"speech_seconds": 149.2,
"gender": {"label": "male", "confidence": 0.97},
"role": "client",
"identity": {"status": "new", "voice_id": 100, "speaker_id": "e3db…", "name": null},
"has_voiceprint": true,
"clarity": {"scored_words": 412, "low_confidence_share": 0.071, "estimated_error_share": 0.118, "speech_rate": 5.6,
"line_quality": {"snr_db": 31.5, "clipping_share": 0.0, "bandwidth_hz": 3850, "band": "telephone"}}
}
],
"voices": [
{"label": "SPEAKER_1", "speaker": 0, "voice_id": 100, "name": null, "status": "new"},
{"label": "SPEAKER_2", "speaker": 1, "voice_id": 101, "name": "Азимбек", "status": "matched", "score": 0.97}
],
"options_report": {"requested": ["gender", "speaker_roles", "speaker_identification", "pii", "language_detection", "call_outcome"], "errors": {}, "seconds": 1.8},
"timing": {"decode_seconds": 0.3, "vad_seconds": 0.4, "stt_seconds": 2.1, "total_seconds": 4.9}
}Текст приходит латиницей: модель обучена на латинской записи узбекского, и все опции (пунктуация, числа, персональные данные) работают с ней. Кириллицы на выходе нет.
Верхний уровень
| Поле | Что это |
|---|---|
audio_seconds | Длина записи; из неё считается списание в g |
speech_seconds | Сколько в ней речи |
channels, stereo_parties | Каналов в файле; true, если стороны разделены по каналам |
speakers | Сколько голосов нашло разделение по спикерам |
text | Весь текст подряд |
segments | Реплики по порядку |
speaker_info | Сводка по каждому спикеру записи: что нашли опции, и clarity, когда спикеры известны |
language | Основной язык речи записи и доля каждого языка, при «Языке речи»; см. Опции |
call_outcome | Был ли живой разговор, а если нет, что играло вместо него; секунда, когда ответили. При «Дозвоне»; см. Опции |
voice_events | Смех, недовольство и энергия голоса: `[{"type": "laughter" |
summary | Краткое резюме звонка: {"text", "lines", "read_lines"}, при «Кратком резюме звонка»; см. Опции |
voices | Постоянные номера голосов проекта, при «Узнавать по голосу» |
options | Настройки, с которыми запись реально считалась: проект плюс settings запроса. Здесь все ключи со страницы Опции — включая stereo_channels_as_speakers, max_speakers, call_direction и fuzzy_itn (нестрогая нормализация чисел; по умолчанию выключена) |
tenant | Бизнес интегратора, к которому относится запись, если задание его назвало; см. Тенанты |
vocabulary_terms, vocabulary_dropped | Сколько терминов словаря взяла задача; true во втором, если после чистки не осталось ни одного |
diarization_error | true, если разделение по спикерам не отработало: номеров спикеров в записи не будет. При удачном разделении поле есть и равно null |
options_report | Какие опции запрашивались, какие не посчитались и почему |
segment_voiceprints | У каких реплик есть голосовой отпечаток: {"dims", "format", "min_seconds", "segments": [индексы]}. Сами отпечатки наружу не отдаются — это список реплик, из которых можно завести голос через POST /v1/speakers/{id}/enroll с segment_indexes |
timing | Сколько секунд заняла обработка: decode_seconds, vad_seconds, stt_seconds, format_seconds, diarization_seconds, total_seconds. Считаем по ним себя, а не вас |
options_report показывает, что запрашивалось (requested), что не посчиталось и почему (errors), и сколько секунд ушло на опции (seconds). Если запрашивались роли, там же лежит roles: status, откалиброванный score (вероятность, что роли распределены верно) и остальные поля, описанные в разделе Клиент и менеджер. Роль каждого спикера берите из speaker_info[].role.
Рядом лежат служебные поля — word_timing, formatting, partial. Они для разбора наших же обращений: состав может поменяться, не стройте на них логику.
Реплика
| Поле | Что это |
|---|---|
index | Порядковый номер, с 0 |
start, end | Секунды от начала записи |
speaker | Номер спикера записи или null |
text | Итоговый текст с включёнными опциями |
raw_asr_text | Как услышала модель: строчные, без знаков |
formatted_text | С пунктуацией и заглавными |
words | Слова с временем, при word_timestamps; см. ниже |
speaker_share | Какая доля речи реплики размечена самим разделением по спикерам, от 0 до 1; остальное унаследовано от соседних слов. Есть только там, где спикеры считались |
contextual_text | Текст после словаря, до пунктуации и чисел; между raw_asr_text и formatted_text |
duration_bucket_seconds | Служебная корзина длительности для нашей телеметрии |
emotion | Только если запрос присылает убранный ключ emotion: всегда {"label": null, "reason": "removed"}; см. Эмоции (убраны) |
pii | {"entities", "redacted_text"}, при «Персональных данных» |
language | {"code", "confidence"}, при «Языке речи»; у реплики короче секунды — {"code": null, "reason": "too_short"} |
Метки pii: NAME, PHONE, ADDRESS, DATE, DOCUMENT_ID, CARD_NUMBER.
Слово
{"text": "kredit", "raw": "kredit", "formatted": "kredit", "start": 12.40, "end": 12.81, "speaker": 0, "aligned": "exact", "confidence": 0.93}
{"text": "Uzum", "raw": "uzim", "formatted": "Uzum", "start": 4.12, "end": 4.51, "speaker": 1, "aligned": "term", "confidence": null}| Поле | Что это |
|---|---|
text | Слово после словаря, до пунктуации |
raw | Что услышала модель на этом месте; у вставленного слова поля нет |
formatted | Оно же с заглавными и знаками, когда реплика отформатирована |
start, end | Секунды от начала записи |
speaker | Номер спикера, если спикеры считались |
aligned | Откуда взято время слова |
confidence | Вероятность от 0 до 1, что слово распознано верно; null, если это не собственное слово модели (см. ниже) |
aligned стоит читать: exact — кадры самой модели на этом слове; term — слово пришло из словаря и размечено по кадрам поисковика терминов, то есть это прямое доказательство, что термин применился; span — доля от переписанного куска; chunk — на этот кусок модель не дала слов, время у всего куска общее; none — слово вставлено без акустического подтверждения, длина нулевая.
Уверенность в слове. confidence — вероятность от 0 до 1, что слово распознано правильно. Она откалибрована на звонках, проверенных людьми: из всех слов с отметкой 0.8 верны примерно восемь из десяти. Число есть только у собственных слов модели (aligned: exact). У слова, которое корректор или ваш словарь поставили вместо услышанного (span, term), у вставленного без акустического подтверждения (none) и у куска без пригодных слов (chunk) — confidence: null: акустической оценки у них нет. Слова, переписанные корректором, верны заметно реже собственных слов модели, так что на null тоже стоит взглянуть.
Что измеряет уверенность. Она показывает, насколько распознаватель был уверен в услышанном, а не насколько хорошо человек говорил. Узкая телефонная линия, шум, тихий или перегруженный микрофон, наложение голосов, редкие имена и вставки на русском или английском снижают её так же, как неразборчивая речь. Большая доля слов с низкой уверенностью на одном звонке значит, что расшифровке этого спикера меньше стоит доверять. Сама по себе это не доказательство плохой дикции.
Спикер записи
| Поле | Что это |
|---|---|
index | Номер спикера, тот же, что в репликах |
speech_seconds | Сколько он говорил |
gender | {"label": "female" | "male" | "unknown", "confidence", "reason", "windows", "speech_seconds", "probabilities"}. У unknown поле confidence равно null, а reason говорит почему |
role | "client", "manager", "machine" (голос, звучавший только до ответа живого человека: голосовое меню, сообщение оператора связи), "other" (живой голос сверх двух собеседников) или "unknown". См. Клиент и менеджер |
identity | {"status", "voice_id", "speaker_id", "name", "score", "threshold", "runner_up", "kind"} |
has_voiceprint | У спикера хватило речи на голосовой отпечаток: его можно назвать через Голоса и спикеры. Сам отпечаток наружу не отдаётся |
emotion | Только с убранным ключом emotion: {"dominant_mood": null, "mood_share": {}, "valence": null, "arousal": null, "dominance": null, "reason": "removed"} |
language | {"code", "confidence", "seconds"} — язык по всей речи спикера; меньше двух секунд речи — {"code": null, "reason": "insufficient_speech"} |
clarity | Насколько распознаватель был уверен в словах этого спикера, рядом с качеством линии, по которой они пришли; см. Clarity |
identity.status отвечает на один вопрос: узнали ли этого человека и, если нет, почему.
| Статус | Что произошло | Есть ли voice_id |
|---|---|---|
matched | Отпечаток совпал с голосом проекта | да, номер знакомого голоса |
new | Не совпал, но речи хватило: голос заведён этой записью и дальше будет узнаваться | да, новый номер |
unknown | Не совпал, и речи меньше 10 секунд — заводить голос по такому отпечатку ненадёжно | нет |
insufficient_speech | Отпечаток не удалось посчитать вовсе: речи почти нет | нет |
no_enrolled_voices | В проекте ещё нет ни одного голоса, сравнивать не с чем | нет |
Разница между unknown и insufficient_speech в том, что в первом случае отпечаток есть и сравнение прошло, просто человек незнаком и речи мало для регистрации; во втором считать было нечего.
У matched и unknown рядом лежат score, близость к ближайшему голосу от 0 до 1, и threshold, порог, начиная с которого совпадение засчитывается. Если score регулярно чуть ниже порога, голосу не хватает отпечатков: добавьте ещё один из хорошей записи.
С known_speakers (только сотрудники) identity говорит о линиях сотрудников тенанта: status это matched, not_matched, not_enrolled (у названной линии ещё нет голоса) или insufficient_speech; совпадение несёт external_id, role, voice (кто из людей линии, 1–4) и expected, threshold равен 0,65, а runner_up это другой спикер звонка против той же линии. voice_id получают только сотрудники, а has_voiceprint нет: отпечатков такой записи не хранится.
Там же runner_up — близость ко второму по похожести голосу (-1, если сравнивать было не с чем). Совпадение засчитывается, только если первый обошёл второго с запасом: два похожих голоса не должны выигрывать друг у друга случайно. У matched и new есть ещё kind — какой это голос в проекте: candidate, recurring или named, см. Голоса и спикеры.
Clarity: уверенность распознавания по спикеру
speaker_info[].clarity считается для каждой записи, где известны спикеры, — стереозвонка со сторонами на разных каналах или моно-записи с разделением по спикерам, — при любых опциях и без доплаты.
"clarity": {
"scored_words": 412,
"low_confidence_share": 0.071,
"estimated_error_share": 0.118,
"speech_rate": 5.6,
"line_quality": {"snr_db": 31.5, "clipping_share": 0.0, "bandwidth_hz": 3850, "band": "telephone"}
}| Поле | Что это |
|---|---|
scored_words | Слова спикера, у которых есть confidence |
low_confidence_share | Доля из них ниже 0.5, то есть скорее неверных, чем верных |
estimated_error_share | Среднее 1 - confidence по ним: какая доля из них, по ожиданию, неверна |
reason | insufficient_words, когда таких слов меньше 40; обе доли тогда null |
speech_rate | Слоги (гласные буквы) в секунду собственной речи спикера |
line_quality.snr_db | Насколько пики речи громче пауз между словами внутри реплик спикера, в дБ |
line_quality.clipping_share | Доля речи спикера с отсчётами на пределе шкалы: перегруженный микрофон или линия |
line_quality.bandwidth_hz | До какой частоты голос спикера доходит по этой линии |
line_quality.band | narrow — ниже 3 800 Гц, telephone — от 3 800 до 4 500 Гц, wide — от 4 500 Гц |
Всё считается по собственным репликам спикера за всю запись, без моментов, когда одновременно говорит кто-то другой. На стереозвонке линия каждой стороны — её собственный канал. Если такой речи меньше секунды, line_quality и speech_rate равны null.
Линия отдельно от спикера. Доли стоят рядом с line_quality, измеренным по голосу того же спикера. Линию мы из них не вычитаем: по нашим измерениям она объясняет в них немногое. Сильнее всего сказывалась ширина полосы: у спикеров на narrow линии доля слов с низкой уверенностью почти вдвое выше, чем у остальных. В пределах шума обычных звонков уровень шума заметной разницы не давал. Почти половина разницы между спикерами общая для обоих участников одного звонка, то есть принадлежит звонку, а не человеку. Сравнивайте людей в одной band. Судите о человеке по многим звонкам, а не по одному, и в сравнении с собеседником на тех же звонках. Внимания стоит тот, кто звонок за звонком заметно выше своего собеседника на линии того же типа.
Ограничения. Доли не даются, если слов с оценкой меньше 40, и остаются шумными примерно до 100: плюс-минус 4 пункта при 40 словах, 2,5 при 100. В моно-записях разделение по спикерам относит примерно одно слово из двадцати не тому человеку; у стереозаписей со стороной на каждом канале этой проблемы нет. Темп речи считается по распознанным словам, поэтому там, где распознавание не справилось, он занижен. Калибровка сделана для узбекских звонков и текущей версии распознавателя и пересчитывается при каждой её смене.
Эмоции (убраны)
Опция «Эмоции» убрана 10 октября 2026 года: спрос на неё был невелик, а надёжно определять эмоции в звонках оказалось трудно. Ключ emotion по-прежнему принимается, чтобы интеграции не сломались, и ничего не стоит. Запрос, который его присылает, получает в прежних полях заглушку: {"label": null, "reason": "removed"} у каждой реплики, сводку спикера со значениями null и пустым mood_share в speaker_info[].emotion и options_report.emotion = {"status": "removed"}. Позже ключ будет удалён; см. Опции.
Пока задача не готова
GET /v1/jobs/{id}/result отдаёт результат только у готовой задачи; пока она идёт, приходит 409 result_not_ready. Реплики по мере готовности берутся из GET /v1/jobs/{id}/events: см. API.