跳到正文

配置参考

配置

config.json 字段:

json
{
  "esl-server": {
    "host": "0.0.0.0",
    "port": 9911,
    "commandTimeoutMs": 15000,
    "asrTimeoutMs": 30000,
    "settleDelayMs": 1000
  },
  "logging": {
    "dir": "./logs",
    "level": "info",
    "maxSize": "20m",
    "maxFiles": "14d"
  },
  "http-server": {
    "host": "0.0.0.0",
    "port": 9912,
    "authToken": ["esl-0x21"]
  },
  "freeswitch": {
    "host": "192.168.2.184",
    "port": 8021,
    "password": "ClueCon",
    "callbackHost": "192.168.2.246",
    "callbackPort": 9911,
    "originateDialStringTemplate": "user/{{destinationNumber}}"
  },
  "audioFork": {
    "wsUrl": "ws://192.168.2.246:10096/audio",
    "bugName": "callflow_asr",
    "mixType": "mono",
    "sampleRate": "16k",
    "bidirectionalAudioEnabled": false,
    "bidirectionalAudioStreamEnabled": false,
    "bidirectionalAudioStreamSampleRate": 16000,
    "connectTimeoutMs": 5000,
    "eventSubscriptionMode": "all"
  },
  "tts": {
    "defaults": {
      "speakerId": 0,
      "speed": 1,
      "requestTimeoutMs": 10000
    },
    "use": {
      "call": "shout",
      "conference": "wav"
    },
    "profiles": {
      "wav": {
        "endpoint": "http://127.0.0.1:9080/tts",
        "playbackTarget": "wav-url",
        "fsPlaybackBaseDir": ""
      },
      "shout": {
        "endpoint": "http://127.0.0.1:9080/tts-stream",
        "playbackPrefix": "shout://"
      }
    }
  },
  "businessConfig": {
    "ollama-chat-business": {
      "endpoint": "http://127.0.0.1:11434/api/chat",
      "model": "qwen3.5:2b",
      "requestTimeoutMs": 60000
    },
    "kb-audio-chat-business": {
      "endpoint": "http://127.0.0.1:9931/api/v1/conversation",
      "strategy": "kb-mock",
      "token": "chat-token",
      "requestTimeoutMs": 10000
    }
  },
  "recording": {
    "directory": "/usr/local/freeswitch/record"
  },
  "callout": {
    "calloutServer": {
      "baseUrl": "http://127.0.0.1:9920",
      "token": "callout-token",
      "requestTimeoutMs": 10000
    },
    "nlu": {
      "baseUrl": "http://127.0.0.1:9930",
      "token": "nlu-token",
      "requestTimeoutMs": 30000
    },
    "chat": {
      "baseUrl": "http://127.0.0.1:9931",
      "token": "chat-token",
      "requestTimeoutMs": 60000
    }
  },
  "db": {
    "url": "postgres://postgres:postgres@localhost:5432/freeswitch"
  },
  "redis": {
    "host": "127.0.0.1",
    "port": 6379,
    "username": "default",
    "password": "redis",
    "db": 0,
    "keyPrefix": "callflow",
    "ttlMs": 600000
  }
}

esl-server

  • host / port:ESL outbound 监听地址与端口
  • commandTimeoutMs:ESL 命令等待 reply 的超时
  • asrTimeoutMs:单轮 hear 的默认等待超时(业务可在 hear() 入参覆盖)
  • settleDelayMs:手动 answer 后建议的等待,给信令稳定

http-server

  • host / port:HTTP 监听地址,承载 /outbound-calls 与运行时配置端点
  • authToken:HTTP 接口共享令牌数组。未配置或为空时不启用鉴权;配置一个或多个 非空值时,请求必须在 token 请求头中携带其中一个匹配值,否则返回 401

freeswitch

  • host / port / password:inbound ESL(用于 originate)
  • callbackHost / callbackPort:FreeSWITCH 在外呼接通后回拨当前 ESL 服务 使用的地址,必须可以从 FreeSWITCH 进程访问到
  • originateDialStringTemplate:所有外呼场景的默认拨号串模板,必须包含 占位符;业务可在调用入参中传 dialStringTemplate 覆盖(同样需包含占位符)

audioFork

  • wsUrl:mod_audio_fork 要连接的 ASR WebSocket 地址(即 sherpa-asr-online-server
  • bugName:media bug 名称,用于 uuid_audio_fork stop 精确定位
  • mixType / sampleRate:上行音频通道与采样率,mono/16k 适合大多数 ASR
  • bidirectionalAudioEnabled / bidirectionalAudioStreamEnabled:下行音频通 道,hear-only 模式保持关闭
  • connectTimeoutMs:等待 WebSocket 连接成功事件的超时
  • eventSubscriptionMode:ESL 事件订阅策略
    • "all"event plain ALL,再在应用侧按 UUID 过滤;最稳但高并发下 事件量较大
    • "channel-plus-custom"myevents + CUSTOM,保留当前通道基础事件并额外 订阅 audio_fork / conference 相关 CUSTOM 事件

tts

采用 defaults / use / profiles 三段结构:defaults 是业务未指定时的合成默认值 (speakerId / speed / requestTimeoutMs);use.call / use.conference 分别选择 单呼与会议使用的 profile("wav""shout");profiles.wav.endpoint 对应 sherpa-tts-server 的 POST /ttsprofiles.shout.endpoint 对应 POST /tts-streamprofiles.shout.playbackPrefix 在启用 mod_shout 时通常为 "shout://"。 逐字段说明与播放目标映射(wav-url / file-path)见 TTS 对接

businessConfig

按 registry / 数据库中的稳定业务编码保存各业务的文件层默认配置。容器和每个子项都必须是 JSON 对象;出现未注册业务编码会在启动期直接报错,避免拼写错误被静默忽略。

ollama-chat-business 子项包含:

  • endpoint:完整 Ollama POST /api/chat 地址
  • model:单阶段流式对话模型名称
  • requestTimeoutMs:单轮请求超时(正整数毫秒)

该配置为必填项并在进程启动期校验。字段缺失、URL 非法或不是 /api/chat、模型为空、 超时非正整数时进程直接退出,不会静默回退到 localhost。启动日志 esl_server_started 会记录实际 endpoint、model 和 timeout。

ollama-chat-business 还支持数据库覆盖,call_businesses.businessConfigcall_business_number_mappings.mappingConfig 直接填写上述三个字段,不额外包业务编码。 最终配置按 config.json.businessConfig["ollama-chat-business"] < call_businesses.businessConfig < call_business_number_mappings.mappingConfig 深合并:普通对象递归合并,数组、标量和 null 由高层整体覆盖。显式 business_code 路由不会读取号码映射层。最终值无效时记录 business_config_invalid、播放“系统错误”并结束,且不会请求 Ollama。

kb-audio-chat-business 子项可省略;一旦填写,endpointstrategy 和正整数 requestTimeoutMs 必须有效,token 可选且不会写入启动日志。路由命中该业务时仍会 对三层合并结果再次校验;若文件层缺省且数据库层不能补齐,通话按 business_config_invalid 结束,不发送知识库请求。

recording

  • directory:FreeSWITCH 进程可写的录音目录
  • ctx.startRecording() 只返回 FreeSWITCH 落盘路径 filePath 和短文件名 fileName;完整播放 URL 由调用方媒体配置拼接

callout

外部依赖按 calloutServernluchat 三个服务边界配置。每组统一包含:

  • baseUrl:服务基地址,只允许 HTTP(S),可带反向代理路径前缀;启动时去除尾斜杠, 不允许用户名、密码、query 或 fragment
  • token:该服务独立共享令牌;非空时请求携带 X-Callout-Internal-Token,为空则不发
  • requestTimeoutMs:该服务独立的正整数请求超时

API 路径由代码固定维护,不再写入配置。callout-server 使用 /api/call-results/api/call-progress/api/transfers/route/api/transfers/end/api/v1/scripts/{id}/runtime;NLU 使用 /api/v1/nlu;Chat 使用 /api/v1/chat/stream。三个服务之间不会回退或混用 token、超时。

旧版 resultCallbackEndpointnluEndpointchatEndpoint 等扁平字段不再兼容, 启动时会给出迁移错误。示例 token 仅用于本地联调;生产环境必须逐服务替换为高强度凭证, 并限制配置文件读取权限。

db

  • url:PostgreSQL 连接串(当前配置只使用该字段)。业务路由会查 call_businessescall_business_number_mappings,schema 见 src/db/schema.ts

redis

Redis 跨实例协调配置,是 callflow-esl 的必选依赖:会议协调、坐席实时盯屏 会话注册表、运行时配置重载广播都建立在它之上。缺配置或启动时连不上会阻止服务启动 (进程以非零码退出,交给 systemd/k8s 重启),不再有进程内 Map 降级模式:

  • host / port / username / password / db:连接参数
  • keyPrefix:会议运行态、实例心跳、盯屏会话、reload 频道等 key/channel 的统一前缀
  • ttlMs:会议运行态、实例心跳、盯屏会话等 key 的 TTL(毫秒)

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。