服务定位
emotion-analysis-server 是一个本地 C++ HTTP 情绪分析服务,对外呼通话做通话后情绪判断:
文本走 BERT 多语种情感模型,音频走 wav2vec2 情绪识别,两路结果统一归一为极性
(positive / neutral / negative)+ 0–100 分后融合输出,供外呼平台按”客户情绪”筛选线索、
质检与重试决策。
与 ASR / TTS 两个服务不同,本服务直接调用 ONNX Runtime(C++ API)跑模型,不依赖
sherpa-onnx。它不在通话媒体主链路上,而是被 智能外呼 的后台工作线程在通话结束后调用。
一句话:ASR/TTS 负责”听见、说出”,情绪分析负责”听完之后,判断客户是正面还是负面”。
它和其它组件的关系
1 | ┌────────────────────┐ 通话结束后排队 ┌─────────────────────────┐ |
- 启用方式在消费方 callout-server:
emotionAnalysis.enabled=true并配置本服务端点(详见 智能外呼); - callout-server 把
attemptId、尽力提取的转写文本、recordingUrl、transcriptUrl发到POST /analyze; - 返回结果写回
call_attempts.emotion_*字段,前端可按情绪极性筛选与展示。
端点
服务监听默认 127.0.0.1:9090,对外暴露两个端点:
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /health |
返回模型就绪状态(textReady / audioReady)与模型文件探测结果 |
| POST | /analyze |
分析单条通话,返回融合后的情绪极性与分数 |
POST /analyze
请求体:
1 | { |
text、recordingUrl至少提供一个;- 两者都有时融合输出(文本权重
0.6、音频0.4)。
响应体:
1 | { |
| 字段 | 说明 |
|---|---|
label / score |
顶层 / fused 的归一极性与极性分(0–100,50 为中性),供业务直接使用 |
confidence |
融合结果置信度 |
reason |
人类可读的判定依据(文本 / 音频 / 融合各自结论) |
text |
文本模型原始输出:raw 如 "4 stars",stars 为期望星级 1–5 |
audio |
音频模型原始输出:raw 如 "happy",confidence 为该类置信度 |
risks |
命中的风险标记(如有) |
- 某一模态不可用时该子对象
available:false,并在reason中说明原因; - 两路都不可用时返回
ok:false、label:"unavailable"。
推理细节
文本(emotion-text)
模型为 bert-base-multilingual-uncased-sentiment。内置 BERT WordPiece 分词器
(清理 → CJK 按字切分 → 空白切分 → 小写 → 标点切分 → 贪心 WordPiece),输出 5 类星级 logits,
softmax 后取期望星级 E,score = round((E-1)/4*100),再按分数映射极性(<40 负、>60 正、其余中性)。
注意
分词仅做 ASCII 小写,未做全 Unicode 大小写 / 去音标——对中文、英文无影响,
带音标的拉丁文本可能略有偏差。
音频(emotion-audio)
模型为 wav2vec2-emotion-recognition。拉取 recordingUrl → 解码 WAV → 按配置选择声道或混音 →
重采样到 16k → 静音过滤(默认开启)→ 最多截取 30s → 归一化 → 7 类情绪 logits → argmax + 置信度 →
情绪映射到极性基准分,并按置信度向中性收缩。
- 声道选择:
audioChannel支持mix/left/right/channel0/channel1/customer/agent。left≡channel0、right≡channel1;customer/agent通过audioChannelRoles映射到实际声道。
会议 WAV 几个声道、客户 / 坐席各在哪个声道取决于 FreeSWITCH 录音方式,上线前务必用真实录音听音确认;
若录音只有单声道却配置成right/channel1,音频模态会失败并在reason说明,不会静默回退; - 静音过滤:按 20ms 短帧 RMS 判断并保留语音段前后约 200ms,可用
audioTrimSilence:false关闭; - 仅支持
http://(无 TLS;https://会被拒绝并在reason说明); - WAV 支持 PCM 8/16/24/32-bit 与 IEEE float32;压缩格式(MP3 / Opus 等)不支持;
- 重采样为线性插值;静音过滤后的录音超过 30s 截断。
模型目录结构
模型放在仓库 onnx-platform/models/ 下:
1 | onnx-platform/models/emotion-text/ |
配置
onnx-platform/emotion-analysis-server/config.json:
1 | { |
| 字段 | 默认 | 说明 |
|---|---|---|
listenHost / listenPort |
127.0.0.1 / 9090 |
HTTP 监听地址 |
workerThreads |
2 |
HTTP 处理线程数 |
maxQueuedRequests |
32 |
等待队列上限,超出立即 503 |
maxRequestBodyBytes |
2097152 |
单请求体最大字节数 |
logDir |
logs |
日志目录,相对路径按运行目录解析,日志按天滚动 |
textModelDir / audioModelDir |
emotion-text / emotion-audio |
相对 onnx-platform/models/ 的模型目录 |
audioChannel |
customer |
音频分析使用的声道:mix/left/right/channel0/channel1/customer/agent |
audioChannelRoles |
{customer:right, agent:left} |
customer / agent 角色到实际声道的映射 |
audioTrimSilence / audioSilenceThreshold |
true / 0.01 |
静音过滤开关与 RMS 阈值 |
依赖与构建
ONNX Runtime 发行版置于
onnx-platform/onnxruntime/<平台>/(含include/与lib/);
CMake 变量ONNXRUNTIME_ROOT可覆盖默认路径。这一点与 ASR/TTS 服务使用仓库内sherpa-onnx预编译包不同——本服务直接依赖 ONNX Runtime。构建(Windows):
1
2cd onnx-platform\emotion-analysis-server
.\build.ps1产物安装到
target\win_x64\(含onnxruntime.dll)。bun run dev/bun run dev:emotion
即从这里启动它。运行时需能定位
onnx-platform/models/(按工作目录向上查找models/),例如从target\win_x64\启动。
验证
启动后查看健康状态:
1 | curl http://127.0.0.1:9090/health |
分析一条文本:
1 | curl -s -X POST http://127.0.0.1:9090/analyze \ |
仓库内还提供了 request-emotion.js(兼容 Node 18+ / Bun),可跑内置中英文正负样本套件、
单条文本分析、文本 + 录音融合:
1 | node .\request-emotion.js # 内置样本套件(/health + 样本) |
局限
注意
- 仅做通话后离线分析,不是实时情绪(不在媒体主链路上);
- 音频侧只接受
http://的未压缩 WAV,录音超过 30s 截断; - 与 ASR/TTS 服务一样无鉴权、无限流(除
maxQueuedRequests),建议仅在内网 / 可信网络运行; - 文本极性基于多语种情感星级模型,属于”情感倾向”而非细粒度情绪标签。