呼叫记录推送接口
适用于: 挂机话单落库后,由 CTI 批量 POST 推送到第三方服务器,实现 OA/CRM 话单同步、BI 入库。 配套: 话单字段含义见 call-log-query(推送
datas即完整话单实体);录音按recordVoice/callid走 recording-download。 呼叫状态推送(振铃/接通实时事件流)不在本文档范围,见 websocket-call-state 与官方说明书"HTTP 来电弹屏推送"章节。
实现: HibernateService/src/com/mediapbx/hibernate/calllog/post/CallLogPostManager.java(对应官方说明书《HTTP呼叫记录推送接口》章节)。
1. 机制概述
- 定时器周期扫描
calllog表,把增量话单(id >= lastCallLogId且posted != 1)按批 POST 到配置的 URL; - 第三方接收成功(见 §4 响应约定)后服务端置
posted=1,失败则下一轮自动重推,不丢数据; - 有数据时按忙时间隔轮询,空闲/失败时自动降频(见 §5);
- 系统启动完成后延迟 3 分钟才开始推送(等待各组件初始化)。
2. 开通与配置(软参)
在 OMS 配置管理"高级参数"(confview 软参)中配置,HibernateService/conf/service.properties 默认值:
| 软参 key | 默认值 | 说明 |
|---|---|---|
calllog.post.offon | false | 推送总开关 |
calllog.post.url | http://127.0.0.1/api.php?m=opencalllog&openkey=...&a=daoru | 第三方接收地址(http/https) |
calllog.post.batch.size | 40 | 每批推送条数 |
calllog.post.busy.interval | 10 | 有数据时的轮询间隔(秒,下限 1) |
calllog.post.idle.interval | 60 | 空闲/推送失败时的轮询间隔(秒,下限 30) |
calllog.post.start.id | -1 | 推送起始话单 id:-1 从当前最大 id 起(只推增量);0 清空全部 posted 标记全量重推;也可指定某个 id 从那里补推 |
要点:
- 软参修改热生效(开关/间隔变更会自动重启推送定时器);
calllog.post.start.id改为0会触发全量重推,对接初期可用它回灌历史数据,正式运行后改回-1。 - 推送报文中的
client_ip取自软参internal.ip(服务器内网 IP),第三方可据此区分多台 CTI。 - AI 摘要联动: 开启
calllog.save.stttxt.offon后,话单的stttxt字段是 CTI 在挂机后用大模型对整通沟通内容生成的摘要总结(不是原始转写文本)——内容与格式由提示词模板决定,可让模型输出 JSON 等结构化结果(通话摘要、沟通结果等)。摘要生成前话单暂不推送,生成后立即经直推通道推送——即第三方拿到的一定是摘要完成后的stttxt。提示词模板与配置见 §3.1 的stttxt字段说明。
3. 推送报文(CTI → 第三方,HTTP POST JSON)
Content-Type 为 JSON,UTF-8 编码。按接收 URL 自动二选一:
3.1 标准格式(URL 不含 opencalllog&openkey)
{
"client_ip": "192.168.3.86",
"datas": [
{
"id": 1476510,
"caller": "806",
"callee": "1000",
"beginTime": 1691059681306,
"duration": 41,
"state": "STATE_RECEIVED",
"callType": "LOCAL_CALL",
"callid": "105652437424950-326581766720130@192.168.3.9",
"recordVoice": "/opt/data/records/2023-08-03/xxx.wav",
"business": "INCOMING",
"stttxt": "{\"summary\":\"客户咨询设备维修...\",\"result\":\"需返厂\",\"followup\":\"3天内回访\"}",
"...": "其余字段与 CALL_LOG_QUERY 返回一致"
}
]
}
datas 数组元素即完整话单实体,字段含义与枚举(state/callType/business 等)同 call-log-query §1/§4,不再重复。注意 beginTime/ivrAnwerTime 等为毫秒时间戳;recordVoice 非空表示有录音。
stttxt 字段(AI 通话摘要): 开启 calllog.save.stttxt.offon 后,由 CTI 在挂机后调用大模型对整通沟通内容生成摘要总结——不是逐句转写文本。输出内容与格式由提示词模板决定,按需生成纯文本或 JSON 结构(通话摘要、沟通结果、待办事项等)。模板配置:
| 项 | 说明 |
|---|---|
| 模板文件 | 配置目录 ai.qa.template/ 下的 .md 文件:ai_qa.md(全局)/ ai_qa_<business>.md(按业务类型)/ ai_qa_<business>_<accessnum>.md(业务+接入号),查找优先级从后者到前者;参考样例 ai_qa_example.md |
| 占位符 | 模板中的 __conversation_list__ 会被替换为对话文本后发给大模型 |
| 编辑接口 | GET /bridge/jsoncfg?opt=ai_qa_template_get&json={"business":"...","accessnum":"..."} 读取;opt=ai_qa_template_update 更新(json 增加 content 字段;传空 content 删除该层模板)(OMS 话单页的摘要模板编辑即走此接口) |
| 长度限制 | 生成结果超长截断至 4000 字符 |
3.2 兼容格式(URL 含 opencalllog&openkey,国信 PHP 对接历史格式)
推送精简字段数组,extnum/telnum 已按"哪一侧是内部分机"自动归位:
[
{
"callid": "105652437424950-326581766720130@192.168.3.9",
"extnum": "806",
"telnum": "13512340001",
"business": "INCOMING",
"forward": "",
"state": "STATE_RECEIVED",
"beginTime": "2023-08-03 14:48:01",
"ivrAnwerDuration": 1,
"queueDuration": 0,
"ringDuration": 5,
"duration": 41,
"estimate": 0,
"isrecord": 1,
"hungupside": "extnum",
"ivrvoicemail": "",
"stttxt": ""
}
]
| 字段 | 说明 |
|---|---|
| extnum / telnum | 内部分机侧 / 对端号码(自动判别主被叫哪侧是分机) |
| beginTime | yyyy-MM-dd HH:mm:ss(注意与标准格式的毫秒时间戳不同) |
| duration / ringDuration / queueDuration / ivrAnwerDuration | 通话/振铃/排队/IVR 放音时长(秒) |
| isrecord | 1 有录音 / 0 无(仅 STATE_RECEIVED 时置 1) |
| hungupside | 挂机方归位到本视角:extnum / telnum / third |
| ivrvoicemail | 留言文件路径 Base64(有留言时 business 强制为 VOICE_MAIL) |
| stttxt | AI 通话摘要(内容/格式由提示词模板决定,可为 JSON;未开启摘要时为空) |
4. 响应约定(第三方必读)
接收端处理完成后返回纯文本:
| 响应体 | CTI 侧行为 |
|---|---|
200 | 视为保存成功,置 posted 标记,继续推下一批 |
400 | 保存失败,不置标记,下一轮重推同一批 |
(空) / 503 | 同上,按失败处理 |
| 其他任意非空文本 | 源码实际按成功处理(建议严格按 200/400 约定返回) |
注意:一批数据是一起重推的——某条记录持续 400 会导致整批滞留。第三方解析失败时应返回 400 并人工介入,而非无限重试。
5. 推送节奏与可靠性
| 特性 | 行为 |
|---|---|
| 增量断点 | lastCallLogId 内存跟踪,每 32 批才落盘一次;服务停止时保存。异常宕机最多重复推送约 32 批×批量条数(接收端按 id 幂等去重即可) |
| 失败处理 | 不置 posted 标记自动重推;同时切换到 idle 间隔降频,并上报 WARN_POST_CALL_LOG_FAILED 告警(恢复后自动撤销) |
| 顺序 | 每批按 id 升序推送;忙时 1~10 秒一轮,基本近实时 |
| 启动 | 系统启动完成后再等 3 分钟才开始 |
| 全量重推 | calllog.post.start.id=0 清空所有 posted 标记从头推(数据量大时第三方需限速入库) |
6. 接收端最小示例
// Spring Boot 示例:收到即落队列,快速返回
@PostMapping(value = "/telcrm/calllog")
@ResponseBody
public String receive(@RequestBody CallLogPushBody body) {
try {
queue.offer(body); // 异步处理,不要在本请求内做慢操作
return "200";
} catch (Exception e) {
return "400";
}
}
接收端要求:HTTP 服务快速应答(超时按失败处理会反复重推);按 id(标准格式)或 callid(兼容格式)做幂等。
7. 挂机事件推送(辅助通道)
另一族轻量 GET 推送在挂机瞬间发出(挂机信息推送,HungupNotifyUtils 家族),与 §1 的批量话单推送互补——实时性更高但只有摘要字段:
| business | 触发 | 配置软参 | 附加参数 |
|---|---|---|---|
queue | 排队中客户挂机/等待超时 | queue.hungup.notify.url | begin(排队开始)、duration(排队秒数)、waittimeout(true 超时/false 客户挂机) |
ivr | IVR 流程结束挂机 | ivr.hungup.notify.url | ivrid、pointname(挂机前最后节点名)、begin |
voicemail | IVR 留言完成 | voicemail.hungup.notify.url | ivrid、留言文件路径参数(参数名默认 VMailFilePath,可由 IVR 流程配置) |
robot | AI 机器人通话结束 | ai.hungup.notify.url | robotid |
通用参数:callid、caller、callee、business,拼在 URL query 上(同步 GET 直发,无重试)。callid 与话单一致,可联动查询完整记录。
8. 常见问题排查
| 现象 | 原因与处理 |
|---|---|
| 完全收不到推送 | calllog.post.offon 未开;calllog.post.url 为空/不以 http(s) 开头;系统刚启动未满 3 分钟 |
| 只推了一批就停 | 第三方返回了空/400/503,整批滞留:看接收端日志,处理后返回 200 |
| 同批数据反复收到 | 幂等去重按 id 处理即可(重推是设计行为) |
| 推送比通话晚很多 | 处于 idle 间隔(60 秒);或开启了 AI 摘要(calllog.save.stttxt.offon),话单等摘要生成后才推 |
| 想重推历史数据 | calllog.post.start.id 置 0 全量重推,或置某个 id 从该处补推 |
client_ip 不对 | 该字段取软参 internal.ip,非请求方看到的真实网卡 IP |
