一页纸说明代码怎么组织、一通电话经过哪些模块,帮助贡献者快速定位要改的文件。 (用户视角的功能介绍见 README;演进计划见 roadmap。)
电话网 (PSTN / VoLTE)
│
▼
┌─────────────────┐ AT 串口 (RING/ATA/ATD/CLCC/短信/DTMF)
│ EC20/EG25 模组 │◄───────────────────────────► modem.py
│ (USB) │ │ 事件回调
│ │ 8kHz PCM 语音 ▼
└─────────────────┘◄──────────► audio_bridge.py ◄─ call_agent.py (CallSession)
▲ (重采样) │ │
│ macOS 无原生驱动: │ │ wss (realtime)
│ scripts/ec20_usb_pty.py │ ▼
│ USB→PTY 桥出 /tmp/ec20-at │ agents/ (Qwen Omni /
│ │ Doubao / OpenAI)
│ │ │
│ prompts.py ──────────────────►│ │ 云端语音模型
│ call_tools.py(AI 工具)──────►│
│ summarizer.py(通话后摘要)◄───┤
│ call_log.py(录音/事件落盘)◄──┤
│ remote_dialer.py(远程真人外呼)◄┤
│ ▲ LiveKit 音频/数据通道 │
│ │ │
│ 手机浏览器 Web Dialer ─────────────┘
│ dial_queue.py(批量外呼)─────►│
│ sms_email_forwarder.py ◄─ 新短信回调
│ ▼
│ events.py (EventHub)
│ │ WebSocket 广播
│ ▼
│ web/server.py (aiohttp)
│ │
│ web/static/index.html(仪表盘单页)
│ ▲
└── app.py(入口/常驻编排,把上面全部装配起来) │
desktop_app.py(pywebview 薄壳)────────┘ 或直接浏览器访问
一通来电的路径:模组上报 RING → modem.py 回调 → call_agent.py 建立
CallSession(ATA 接听)→ audio_bridge.py 把 8kHz PCM 与云端模型的
16k/24k 音频互转 → agents/ 经 WebSocket 与 realtime 模型对话(可调
call_tools.py 里的工具)→ 全程事件经 events.py 推给网页 → 挂断后
summarizer.py 出摘要、call_log.py 落盘。
首次启动时,app.py 仍负责装配服务;Web 端会通过 /api/meta 与 /api/config
驱动首启向导,完成硬件检查、provider 凭证、机主/人设和测试短信配置后写回 .env。
| 模块 | 职责 |
|---|---|
app.py |
进程入口与常驻编排:韧性启动(模组不在也起 Web)、后台 supervisor 重连、装配以下所有模块 |
main.py |
精简命令行入口:仅来电自动接入(无 Web、无常驻编排),用于最小化 headless 运行 |
src/agentcall/modem.py |
EC20/EG25 AT 指令封装:接听/拨号/挂断/CLCC 轮询/短信 (UCS2)/DTMF,串口断线自动重连,通话丢失判定 |
src/agentcall/audio_bridge.py |
模组 8kHz PCM ↔ AI 采样率的双向音频桥;三种模式:uac_ffmpeg(macOS 已验证)/ uac(PortAudio/WASAPI,Windows 主路径)/ nmea(勿在 macOS 用) |
src/agentcall/call_agent.py |
CallSession 会话编排:来电/外呼生命周期、模组↔音频桥↔Agent 接线、延迟挂断与世代号防护 |
src/agentcall/remote_dialer.py |
#31 远程网页拨号状态机:短期邀请、媒体就绪后才 ATD、单通幂等、全双工 PCM、DTMF、断线宽限与录音审计 |
src/agentcall/livekit_media.py |
LiveKit programmatic participant:浏览器音轨 ↔ 8k PCM、有界媒体队列、身份/主题受限的控制数据通道 |
src/agentcall/remote_pairing.py |
#31.1 本地手机配对库:一次性短期配对码、最多 5 台设备、长期凭证仅存哈希、原子落盘与撤销 |
src/agentcall/web/remote_gateway.py |
独立公网最小权限网关:固定 PWA 页面、HttpOnly 配对 Cookie、单通短期会话签发;不挂载管理 API |
src/agentcall/cloud_credentials.py |
#42 云端 Edge 凭证与 Ed25519 设备密钥的系统钥匙串存储 |
src/agentcall/cloud_control.py |
#42 Edge 主动 WSS、心跳、严格命令校验、会话启动 ACK 与云端 enrollment/配对 API 客户端 |
cloud/ |
公司托管 Beta 控制面:Worker API、Durable Object Edge 路由、D1 数据、LiveKit 短期 token broker 与固定 PWA |
src/agentcall/number_profiles.py |
本地预设任务库:JSON 兼容加载、稳定 ID、分层匹配、CRUD 校验与原子写入 |
src/agentcall/prompts.py |
通话提示词构造,纯函数、可独立测试 |
src/agentcall/call_tools.py |
通话中 AI 工具(发短信/挂断/读验证码/按 DTMF)的注册与执行 |
src/agentcall/agents/ |
base.py VoiceAgent 抽象接口 + 各云端 realtime 实现 + factory.py 按 AGENT_PROVIDER 创建。加新语音 provider 从这里入手 |
src/agentcall/web/ |
aiohttp 服务(server.py):仪表盘页面、WebSocket 实时推送、短信/外呼/历史/配置 REST API;前端是 static/index.html 单文件 |
src/agentcall/config.py |
集中配置注册表:所有环境变量的默认值只在这里注册(.env.example 有防脱节测试绑定),凭证校验与 .env 持久化 |
src/agentcall/platforms.py |
平台差异唯一出处:Windows/macOS/Linux 的默认端口、路径、venv 位置。业务代码不直接判 sys.platform |
src/agentcall/port_detect.py |
MODEM_PORT=auto 时按 Quectel VID (0x2C7C) 自动扫描 AT 串口(Windows 主要用) |
src/agentcall/events.py |
EventHub:把模组/Agent 线程的事件线程安全地广播给网页 WebSocket |
src/agentcall/sms_email_forwarder.py |
新短信邮件转发:可靠 OTP 提取、UTF-8 邮件构造、TLS-only SMTP、有限重试与有界后台队列;默认关闭且不重放历史短信 |
src/agentcall/call_log.py |
通话记录:按通话建目录,保存事件打点 (events.jsonl)、双向录音 WAV、元数据 |
src/agentcall/dial_queue.py |
批量外呼队列 + 号码白名单 |
src/agentcall/rate_limit.py |
进程内滑动窗口频控,用于短信发送闸与远程网页外呼闸 |
src/agentcall/repeat_suppression.py |
文本相似度判重,抑制 IVR 场景里 AI 近似重复应答 |
src/agentcall/contacts.py |
已联系号码策略:从短信历史、来电记录和当前通话对端判定短信回复目标是否允许 |
src/agentcall/summarizer.py |
通话后把整通转写交给文本模型,产出结构化摘要 |
src/agentcall/monitor_playback.py |
通话音频镜像到本机扬声器(监听旁路,仅 macOS,其他平台优雅降级) |
src/agentcall/coreaudio.py |
macOS CoreAudio 设备枚举(ctypes 直调,无第三方依赖) |
src/agentcall/macos_launchd.py |
打包版 macOS App 的 launchd agent 生成、安装、卸载与重启管理 |
scripts/ec20_usb_pty.py |
macOS USB→PTY 桥:Quectel 无 mac 驱动,用 libusb 把 AT 口暴露为 /tmp/ec20-at |
scripts/launchd/、scripts/windows/ |
常驻安装:macOS launchd 双单元 / Windows 计划任务 (install.ps1) |
desktop_app.py |
桌面形态:pywebview 薄窗口包住本地 Web |
tray_app.py |
macOS 菜单栏托盘常驻形态:顶栏电话图标(绿=运行/灰=停止)+ 打开控制台/重启服务/退出菜单,产品化默认形态 |
packaging/ |
PyInstaller 打包(macOS .app / Windows .exe) |
- 接新的语音模型:
agents/下实现VoiceAgent子类 →factory.py注册 → 配置项进config.py。 - 加配置项:只在
config.py注册表登记默认值,并同步.env.example(有测试强制两者一致)。 - 平台相关行为:改
platforms.py,不要在业务代码里散落sys.platform判断。 - 网页 UI / API:
web/server.py(路由)+web/static/index.html(前端单文件,内置 EN/中文 i18n 字典)。 - 预设任务库:存储、匹配或 CRUD 规则改
number_profiles.py;管理 API/UI 分别在web/server.py与web/static/index.html。 - AT 指令 / 模组行为:
modem.py;注意串口操作要走_serial_lock原子块(与 CLCC 轮询并发)。 - 单独学习/验证某个模组能力:
examples/modem/有每个原子能力(原始 AT、设备探测、 拨号、接听、发短信、收短信、DTMF)的最小独立 demo,基于Eg25Modem,见其 README。 - 每步改动跑对应单测(
tests/unit/),提交前全量.venv/bin/pytest -q。