Классификация эмоций в аудио¶
Emotion API анализирует голосовую окраску записи моделью DUSHA и возвращает
вероятности пяти классов: angry, neutral, other, positive, sad.
Штатно используется локальный ONNX ensemble; сервер можно переключить на
Triton-провайдер настройкой EMOTION_BACKEND.
Модель валидирована для русской речи: API принимает lang=ru и lang=ru-RU.
Поддержка эмоций для казахской, кыргызской,
узбекской и таджикской речи не заявляется, даже если выбранная STT-модель умеет
распознавать эти языки.
Доступны два эквивалентных пути:
Запрос — multipart/form-data; требуется обычная
аутентификация API-ключом или portal-сессией.
Параметры¶
| Параметр | По умолчанию | Описание |
|---|---|---|
audio |
— | Обязательный аудио- или видеофайл, до MAX_AUDIO_UPLOAD_BYTES |
aggregate |
серверный EMOTION_TRITON_AGGREGATE, штатно mean |
mean усредняет вероятности всех окон; max_confidence выбирает окно с самой уверенной меткой |
includeSegments |
false |
Вернуть результат каждого временного окна в segments; принимается также include_segments |
negativeEmotionThreshold |
серверный EMOTION_NEGATIVE_THRESHOLD, штатно 0.5 |
Порог от 0 до 1 для суммы вероятностей angry + sad; принимается также negative_emotion_threshold |
lang |
ru-RU |
После BCP-47-нормализации допустимы только ru и ru-RU; другой locale отклоняется с 400 |
format |
oggopus |
Подсказка формата, если контейнер нельзя определить по байтам |
sampleRateHertz |
16000 |
Частота только для headerless format=lpcm |
Параметры можно передавать в query string или форму; для дублирующихся значений
форма имеет приоритет. WAV читается напрямую, остальные контейнеры
конвертируются в mono WAV 16 кГц. В отличие от файлового STT v1, здесь
headerless PCM поддержан явно через format=lpcm&sampleRateHertz=....
В этом случае ожидается signed little-endian PCM16 mono.
Ответ¶
{
"result": "neutral",
"audio": "call.wav",
"source_sample_rate": 48000,
"model_sample_rate": 16000,
"duration_sec": 12.4,
"model": "dusha_emotion_ensemble_wav2vec_conformer_calibrated",
"model_version": "1",
"calibration_version": "sha256:...",
"prediction": "neutral",
"confidence": 0.71,
"dominantEmotion": {
"label": "neutral",
"score": 0.71,
"negative": false
},
"emotions": [
{"label": "angry", "score": 0.05, "negative": true},
{"label": "neutral", "score": 0.71, "negative": false},
{"label": "other", "score": 0.08, "negative": false},
{"label": "positive", "score": 0.12, "negative": false},
{"label": "sad", "score": 0.04, "negative": true}
],
"negative_emotion": false,
"negative_emotion_score": 0.09,
"negative_emotion_threshold": 0.5,
"negativeEmotion": {
"detected": false,
"score": 0.09,
"threshold": 0.5,
"labels": ["angry", "sad"]
},
"probs": {
"angry": 0.05,
"neutral": 0.71,
"other": 0.08,
"positive": 0.12,
"sad": 0.04
},
"top": [
{"label": "neutral", "prob": 0.71},
{"label": "positive", "prob": 0.12},
{"label": "other", "prob": 0.08},
{"label": "angry", "prob": 0.05},
{"label": "sad", "prob": 0.04}
],
"window_seconds": 3.0,
"hop_seconds": 1.0,
"num_windows": 11,
"aggregate": "mean",
"segments": null
}
top содержит все пять классов по убыванию вероятности. negativeEmotion
дублирует snake_case-поля в удобной для совместимых клиентов форме.
negative_emotion_score равен P(angry) + P(sad). Класс other следует
интерпретировать только как другую или неопределённую акустическую окраску:
контракт не называет его отдельным психологическим состоянием и не выдаёт за
механизм достоверного определения намерений.
model_version фиксирует версию модели в Triton-style repository, а
calibration_version — SHA-256 fingerprint фактически развёрнутого файла
метаданных калибровки. Если этот файл недоступен приложению при удалённом
Triton, calibration_version возвращается как null.
При includeSegments=true каждый элемент segments содержит start_sec,
end_sec, prediction, confidence, negative_emotion,
negative_emotion_score, dominantEmotion, emotions и probs. Штатно модель
использует окна 3 секунды с шагом 1 секунда; точные значения возвращаются в
ответе и могут меняться настройками сервера. В отдельном Emotion API это окна
аудио без привязки к словам, репликам или спикерам STT. Для готовой связи
«эпизод → таймкод → реплика → аудио» используйте интегрированный анализ в
STT v1.
Интеграция со STT v1¶
POST /api/stt/v1 и POST /api/stt/v1:recognizeAsync могут запустить DUSHA
параллельно с распознаванием того же канонического WAV. Повторно отправлять
аудио в отдельный Emotion API не нужно:
Принимаются также snake_case-формы emotion_analysis,
emotion_include_segments, emotion_negative_threshold. В ответ добавляются
emotion_analysis и emotion_analysis_status. Сервер сглаживает оконный
negative-score с помощью EMA, выделяет устойчивые негативные, позитивные и
неопределённые эпизоды, объединяет короткие разрывы и связывает эпизод с
пересекающимися utterances или segments. После сведения физических stereo-
каналов модель не приписывает сигнал конкретному спикеру; персональная
атрибуция требует отдельного per-channel анализа.
В session доступны:
negative_share— доля исходной временной шкалы, где сглаженный сигнал выше порога;peak_negative_score— максимум сглаженного negative-score; полеpeak_negative_emaсодержит тот же показатель как явный alias;peak_negative_raw_score— максимум исходного, несглаженногоP(angry) + P(sad);peak_at_ms— положение максимума сглаженного сигнала;deescalation_score— среднее сглаженное значение на первых 20% окон минус среднее на последних 20%; положительное значение означает снижение сигнала;- каждый эпизод хранит
mean_confidenceиmax_confidence, а совместимое полеconfidenceповторяет среднее значение; deescalation_trend—improved,stableилиworsenedс опубликованным вmetadataпорогом изменения.
negative_share взвешен по времени исходной записи, а positive_share и
uncertain_share показывают долю окон соответствующего производного состояния.
Каждое окно и каждый эпизод сохраняют все пять raw probabilities. Порог,
параметр EMA и правила объединения эпизодов возвращаются вместе с результатом,
поэтому клиенту не нужно угадывать серверные настройки. Если emotion backend
временно недоступен, успешный STT не теряется: статус становится unavailable
или failed, а транскрипт возвращается как обычно.
Независимый сигнал по тексту¶
Для lang=ru-RU тот же emotionAnalysis=true дополнительно анализирует
финальные utterances или segments локальной моделью
cointegrated/rubert-tiny2-cedr-emotion-detection, закреплённой на revision
453ae93ca895c98cda29522c72b6fbc5a08067b9. Отдельный контейнер не нужен.
Результаты не смешиваются с акустическими вероятностями и возвращаются в
соседних полях text_emotion_analysis и text_emotion_analysis_status.
Модель многометочная: сервер применяет sigmoid отдельно к joy, sadness,
surprise, fear, anger и no_emotion. Штатный порог показа равен 0.7 и
настраивается через TEXT_EMOTION_SIGNAL_THRESHOLD. Каждый сигнал содержит
model_score, все raw scores, исходную цитату, проанализированную clause,
таймкоды, speaker и индексы исходной реплики/сегмента. model_score — выход
модели, а не калиброванная вероятность истинной эмоции.
Перед inference длинные реплики делятся по границам предложений и контрастным
союзам. Контексты с отрицанием, возможным сарказмом, вопросом, косвенной речью
или несколькими активными метками не подавляются, а получают warnings и
review_required=true. Ошибка загрузки модели даёт текстовый статус
unavailable, ошибка inference — failed; акустический анализ и готовая
транскрипция при этом сохраняются.
Пример¶
curl -X POST \
"https://api.speech.example.com/api/stt/v1:recognizeEmotion?aggregate=mean&includeSegments=true" \
-H "Authorization: Api-Key $API_KEY" \
-F "audio=@call.wav" \
-F "negativeEmotionThreshold=0.5"
Связь со STT v3¶
Классификатор recognitionClassifier.classifiers[].classifier="negative" в
STT v3 использует тот же emotion backend, но возвращает
SpeechKit-совместимый classifierUpdate. Сейчас v3 вычисляет одну классификацию
по полному файлу. Отдельный Emotion API удобнее, если нужны все вероятности и
временные окна.
Интерпретация и ограничения¶
Модель оценивает вероятностную акустическую окраску русской речи. Это сигнал для навигации и ручной проверки исходного аудио, а не объективное определение внутреннего состояния человека. Безопасная последовательность использования:
Не используйте score как единственное основание для оценки сотрудника, штрафа, найма, медицинского вывода, оценки честности, кредитного или страхового решения. Для контакт-центра порог и качество следует отдельно проверить на своей телефонии, шуме, кодеках и составе спикеров.
Inference выполняется вне event loop. Единый process-wide лимит для отдельного
Emotion API, интегрированных STT v1/v3 вызовов и ONNX/Triton задаётся
EMOTION_MAX_CONCURRENCY (штатно 1).
Ошибки¶
| Код | Когда возникает |
|---|---|
400 |
Пустой файл, неподдерживаемый язык, невалидный порог, частота LPCM, WAV или ошибка конвертации |
401 |
Нет действующей аутентификации |
413 |
Файл превышает серверный лимит |
422 |
aggregate или другой параметр не прошёл проверку схемы |
500 |
Неожиданная внутренняя ошибка |
503 |
ONNX/Triton emotion backend недоступен или вернул ошибку |