呼叫记录推送接口

适用于: 挂机话单落库后,由 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.offonfalse推送总开关
calllog.post.urlhttp://127.0.0.1/api.php?m=opencalllog&openkey=...&a=daoru第三方接收地址(http/https)
calllog.post.batch.size40每批推送条数
calllog.post.busy.interval10有数据时的轮询间隔(秒,下限 1)
calllog.post.idle.interval60空闲/推送失败时的轮询间隔(秒,下限 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内部分机侧 / 对端号码(自动判别主被叫哪侧是分机)
beginTimeyyyy-MM-dd HH:mm:ss(注意与标准格式的毫秒时间戳不同)
duration / ringDuration / queueDuration / ivrAnwerDuration通话/振铃/排队/IVR 放音时长(秒)
isrecord1 有录音 / 0 无(仅 STATE_RECEIVED 时置 1)
hungupside挂机方归位到本视角:extnum / telnum / third
ivrvoicemail留言文件路径 Base64(有留言时 business 强制为 VOICE_MAIL)
stttxtAI 通话摘要(内容/格式由提示词模板决定,可为 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.urlbegin(排队开始)、duration(排队秒数)、waittimeout(true 超时/false 客户挂机)
ivrIVR 流程结束挂机ivr.hungup.notify.urlivrid、pointname(挂机前最后节点名)、begin
voicemailIVR 留言完成voicemail.hungup.notify.urlivrid、留言文件路径参数(参数名默认 VMailFilePath,可由 IVR 流程配置)
robotAI 机器人通话结束ai.hungup.notify.urlrobotid

通用参数: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