基于桌面 UI 自动化的 QQ 电话通知 Skill:通过模拟鼠标点击 PC 版 QQ 的「语音通话」按钮,自动向指定 QQ 好友拨打语音电话,为本地运行的各类 Agent 提供「任务完成 / 异常中断」时的强提醒能力。电话铃声能触达已离开电脑的用户——这是弹窗、消息推送做不到的。
牛马铃:给「牛马」打工人准备的铃。一次封装、多 Agent 复用。
- 三种接入方式:Python SDK / HTTP REST(18600)/ CLI,共用同一核心流程
- 图片匹配拨打:定位语音按钮,置信度可配置,失败自动重试 2 次
- 并发安全:全局互斥锁,同一时间仅一路拨打,并发返回「占线」(503)
- 防抖:同一目标默认 5 分钟内仅拨一次(可配置)
- 用户在位检测:键鼠空闲阈值,人在电脑前自动跳过拨打(仅自动化触发生效),离开后自动恢复
- 无人接听自动重拨:对方接听或拒绝均视为触达成功;无应答自动间隔重拨,直至接听或拒绝(次数可设上限或不限)
- 接听后语音提醒(可选):对方接听后自动播放固定语音(如「任务有新进展,请前往电脑查看」),播完自动挂断
- 全配置化:快捷键、等待时长、置信度、防抖、端口全部进配置文件,无硬编码
- 合规:仅模拟手动操作,无注入、无破解、不调用 QQ 私有接口、不存账号密码
- Windows 10/11(仅支持 PC 版 QQ,不支持网页版 / Mac / 移动端)
- Python 3.10+
- PC 版 QQ 已登录,桌面已解锁(锁屏无法工作)
方式一:一键安装器(推荐)——在仓库/技能目录内运行:
python install.py # 建 .venv → pip install -e . → 生成 config.yaml → doctor 自检
python install.py --dry-run # 演练模式:只探测与打印计划,不做任何改动
python install.py --yes # 非交互(Agent 场景);默认不注册 hook,仅打印可复制的命令幂等可重复执行:已完成的步骤自动跳过,不覆盖你已校准的 config.yaml 与模板;hook/看门狗注册默认只作用于当前宿主(由安装路径自动判定)。
方式二:手动安装:
# 1. 获取项目后进入目录
cd numalarm
# 2. 安装依赖(区分见文件内注释;pywin32 仅 Windows 自动安装)
pip install -r requirements.txt
# 3.(可选)安装为命令行工具,获得 numalarm 命令
pip install -e .
# 不安装也可用等价写法:python -m numalarm.interfaces.cli <命令>本仓库符合开放的 Agent Skill 规范(根目录 SKILL.md),放入宿主的技能目录即可被自动发现。各宿主的目录路径不同,通常形如 ~/.<宿主>/skills/numalarm,以宿主文档为准:
git clone https://github.com/magicapple123/numalarm.git ~/.workbuddy/skills/numalarm # 示例:某工作台类宿主
git clone https://github.com/magicapple123/numalarm.git ~/.claude/skills/numalarm # 示例:Claude Code安装后 Agent 自动遵循 SKILL.md「Agent 集成约定」——任务中断/等待决策前先拨打电话。 命令行拨打能力仍需完成上方依赖安装与下方校准步骤。
配置自动发现:把
config.yaml放在技能目录根即可,无需设置环境变量。 查找优先级:环境变量NUMALARM_CONFIG→ 当前工作目录 → 技能/安装目录。
分四种情况,总有能用的:
- 宿主支持 Agent Skill 规范(凡是读 SKILL.md 的都算):查该宿主文档找到技能目录,
把仓库放进
skills/numalarm即可——规范开放,不限定宿主; - 任何能执行命令行/脚本的 Agent:其实不需要「安装 skill」——
装好依赖(
pip install -r requirements.txt)、配好config.yaml, 直接调 CLI / Python SDK / HTTP 三种接口即可,与宿主无关; - 想让打断自动提醒的约定长期生效:把 SKILL.md 中「Agent 集成约定」一节 粘贴进该 Agent 的系统提示 / 长期记忆 / 规则文件(如 AGENTS.md、CLAUDE.md、自定义指令), 效果等同技能安装;
- 打断自动拨打的 Hook 兜底:任何使用 Claude Code hooks 兼容配置
(
settings.json)的宿主都能注册,指定配置路径即可:numalarm hook install --settings "D:/我的Agent/settings.json"; 完全不支持 hooks 的宿主则依赖第 3 点的约定层(Agent 主动拨打)。
Codex 没有 Claude Code 的 hooks 体系,numalarm hook install 不适用;
它读取 AGENTS.md 指令文件,因此走约定层接入(Agent 主动调用 CLI)。
- 打开 codex 的指令文件:全局
C:\Users\<你>\.codex\AGENTS.md(不存在则新建;只对单个项目生效就放项目根目录); - 复制 examples/AGENTS-codex.md 的约定正文粘贴到文件末尾,
把
<numalarm 安装目录>替换为你机器上的实际路径(需含.venv); - 保存后重开 codex 会话(AGENTS.md 启动时读取);
- 验证:对 codex 说「测试拨打一次电话」——离开电脑再测更直观。
约定内含 hold 免打扰与心跳协议:看门狗对 codex 同样生效(硬崩溃兜底)。 该模板也适用于其他读取 AGENTS.md 的 Agent,替换路径即可。
牛马铃包含若干宿主级 / 全机级注册项,安装前请知悉——install.py 默认只触碰与当前宿主相关的项:
| 组件 | 位置 | 默认范围 | 移除方式 |
|---|---|---|---|
安装目录(含 .venv、config.yaml、模板) |
你克隆/安装的目录 | 单目录,本地 | 直接删除目录 |
| 拨打 hook(Notification/PermissionRequest/Stop) | 各宿主 settings.json |
hook install 默认写全部已探测宿主;install.py 与 --host/--settings 只写当前/指定宿主 |
numalarm hook uninstall(只删拨打类) |
| 心跳 hook(PreToolUse/SessionEnd) | 各宿主 settings.json |
同上 | numalarm watchdog uninstall(只删心跳类) |
| 看门狗计划任务 | Windows 计划任务 / crontab | 全机唯一(--host 只影响心跳 hook 写入范围,不影响任务本身) |
numalarm watchdog uninstall |
| 运行时状态(锁/防抖/hold/心跳/更新备份) | ~/.numalarm |
全机共享,多副本共用 | numalarm uninstall |
pip 包(pip install -e .) |
对应 Python 环境 | 仅该环境(install.py 使用目录内 .venv) |
pip uninstall numalarm |
| 虚拟声卡 VB-Cable(可选) | 系统驱动 | 全机 | Windows「设置 → 应用」卸载 |
默认作用域可用环境变量切换:设置 NUMALARM_HOOK_SCOPE=current 后,hook install / watchdog install 的默认目标仅为当前安装所在宿主。
不熟悉命令行?把下面整段提示词复制、发送给你电脑里的 Agent(任何能执行命令行与读写文件的 Agent 均可)。流程完全幂等:无论是全新安装、上次装到一半中断,还是想顺便更新,重复发送都安全——每一步都会先检查当前状态,已完成的自动跳过,不会重复安装文件、不会覆盖你已校准的配置:
请帮我安装(或修复/续装)numalarm(牛马铃)技能——这是一个在任务中断或需要我决策时自动给我打 QQ 电话提醒的工具。本流程可安全重复执行:每一步都先检查我的设备当前状态,已完成的自动跳过,不会重复安装文件,也不会覆盖我已校准的配置。请按以下步骤执行:
1. 技能目录:
- 检查我的宿主技能目录(常见为 ~/.<宿主名>/skills/numalarm,不确定时查看宿主文档或询问我)下是否已存在 numalarm
- 已存在且是 git 仓库:进入目录执行 git pull 更新到最新版(保留我的配置与校准文件)
- 不存在:从 https://github.com/magicapple123/numalarm 克隆
- 将该路径与 SKILL.md 的「Agent 集成约定」登记到我的长期记忆(已有则更新)
2. 依赖(全部隔离在技能目录的 .venv 内,不写系统 Python):
- 快捷方式:若目录内有 install.py,可直接运行 python install.py --yes 一步完成建 venv + 装依赖 + 生成配置 + 自检(幂等;非交互默认不注册 hook,后续步骤照常)
- .venv 已存在:直接复用,不重建
- 不存在:python -m venv .venv 创建
- 运行 .venv 的 python -m pip install -r requirements.txt(pip 对已满足的依赖自动跳过),然后运行 numalarm doctor 自检,有 FAIL 项修复后重跑
3. 配置文件 config.yaml:
- 已存在:读取它,只补缺失的配置项(如 media/presence 等),不要覆盖我已校准的值
- 不存在:基于 config.example.yaml 生成,并向我询问:default_target(提醒电话打给哪个 QQ 好友)、是否配置别名、响铃时长与重拨上限(默认 45 秒/不限次)、是否启用用户在位检测(默认开启)
4. 两张模板截图(先用 git status/diff 检查 assets 下两个文件是否已被修改:已修改=我已校准,跳过对应步骤):
- assets/voice_button_sample.png 未校准:指导我打开与目标好友的聊天窗口,截取「语音通话」按钮图标覆盖它
- assets/call_ringing_sample.png 未校准:指导我发起一次语音通话(先征得我同意),在响铃界面截取顶部「等待对方接听」文字覆盖它
5. 虚拟声卡(仅当我要启用「接听后语音提醒」时执行):
- 先枚举系统音频输出设备,检查是否已存在 CABLE 设备(可用几行 Python 调 Windows SAPI 枚举,或让我看 mmsys.cpl 的播放设备列表)——已存在则跳过下载与安装
- 未安装:从 https://vb-audio.com/Cable/ 下载 VB-Cable 安装包解压,运行 VBCABLE_Setup_x64.exe(需要我在 UAC 授权,安装后可能需重启),完成后检查默认扬声器是否被抢占、被抢占则切回我的真实扬声器
6. 麦克风指向(QQ 新版没有设备选择项,走系统默认录音设备):
- 检查当前默认录音设备:已是 CABLE Output 则跳过;否则设为「CABLE Output」(可用 PowerShell 模块 AudioDeviceCmdlets,或指导我在 mmsys.cpl 手动设置),并提醒我真人语音通话时说一声即可切回
7. 若第 5 步启用了语音提醒:确认 config.yaml 中 media.speak_on_answer 为 true(已是则跳过)
8. 校准:运行 numalarm test <我的目标>,四步全部 PASS 即完成;有 FAIL 按提示协助修正(常见为重新截图或调整偏移)
9. 询问我是否需要(均幂等,重复执行无害):
- 注册打断自动拨打 hook(numalarm hook install,重复运行只刷新命令不重复注册)
10. 告知我卸载方式:numalarm uninstall 一站式清理 + 删除技能目录;若装过虚拟声卡需在 Windows「设置-应用」卸载;卸载后请把我长期记忆里登记的 numalarm 约定与路径删除(这是你的记忆系统,只能由你清理)
11. 以后任何时候我说「更新 numalarm」,运行 numalarm update:先检查远端有无新版本——没有就告诉我当前已是最新、不需要更新;有则更新(自动保留我的 config.yaml 与校准模板),完成后运行 doctor 与 test 验证
要求:每一步执行前先报告检查结果与将要做的事;涉及真实拨打的测试必须先征得我同意;所有安装隔离在技能目录内,不得写入系统 Python 或改动我的其他软件。
# 一键安装(建 .venv + 依赖 + 配置,幂等;也可手动执行下方 1-2 步)
python install.py
# 0. 环境自检(新用户先跑这个:依赖/配置/素材/QQ 逐项体检 + 修复提示)
numalarm doctor
# 1. 生成配置
copy config.example.yaml config.yaml # 或运行交互式向导:numalarm init
# 2. 替换两张模板截图(重要!按 assets/README.md 的步骤)
# 截取你 QQ 聊天窗口的「语音通话」按钮覆盖 assets/voice_button_sample.png
# 以及通话窗口「等待对方接听」文字覆盖 assets/call_ringing_sample.png
# 3. 校准验证(搜索好友 + 打开聊天窗 + 识别按钮,不拨打)
# 校准前建议先关闭该好友的聊天窗口(避免误命中已打开的旧会话)
numalarm test 张三
# 第 3 步 detail 出现「未确认会话」= 搜索可能未命中,需检查偏移或昵称
# 全部 PASS 后即可正式拨打:
numalarm call 张三from numalarm import call_qq
result = call_qq(target="张三", timeout=30, silent=False)
# {"code": 200, "message": "拨打成功", "data": {"target": "张三", "attempts": 1, ...}}
call_qq(target="老板") # 使用别名(target_alias: {老板: 张三})
call_qq() # 使用 default_target
call_qq(reason="任务中断:需要你选择方案") # Agent 打断提醒场景(默认受在位检测控制)numalarm serve # 默认 127.0.0.1:18600
curl -X POST http://127.0.0.1:18600/api/call \
-H "Content-Type: application/json" \
-d '{"target": "张三", "timeout": 30, "silent": false}'
curl http://127.0.0.1:18600/api/status # 查询是否空闲numalarm doctor # 环境自检(新用户第一步)
numalarm call [目标] [-m "原因"] [--auto] [--silent/-s] [--timeout 30]
numalarm test [目标] # 校准:不点击拨打,逐步输出检测项
numalarm init # 交互式生成 config.yaml
numalarm serve [--host H] [--port P] # 启动 HTTP 服务
numalarm hook install / status / uninstall # 打断自动拨打钩子(见下文)
numalarm installs [--apply] # 多副本体检与收拢(见下文)
numalarm hold [-m 60] / --clear # 暂停/恢复自动提醒(自动继续回合用)| 状态码 | 含义 |
|---|---|
| 200 | 拨打成功 |
| 400 | 参数错误 |
| 429 | 请求过于频繁(防抖触发) |
| 503 | 服务占线(正在拨打中) |
| 1001 | QQ 进程未启动 |
| 1002 | 目标好友未找到 |
| 1003 | 语音按钮匹配失败 |
| 1004 | 拨打超时 |
| 1005 | 未知错误 |
所有接口统一返回 {"code": int, "message": str, "data": object}。成功时 data 含 target(实际拨打目标)、attempts(实际拨打次数)、outcome(触达结果说明)、elapsed_seconds、reason(触发原因,传入时);启用语音提醒时含 voice_played;用户在电脑前跳过时 code=200 且 data.skipped=true。
完整项与注释见 config.example.yaml,复制为 config.yaml 后修改(放在运行目录或技能/安装目录均可,自动发现)。主要参数:
| 配置项 | 默认值 | 说明 |
|---|---|---|
| default_target | null | 默认拨打目标(昵称/备注) |
| target_alias | {} | 别名映射:别名 -> 真实昵称/备注 |
| qq_process_name / qq_window_title | QQ.exe / QQ | 进程名与主面板标题关键字 |
| call_window_hint / verify_call_window | 通话 / true | 通话窗口检测关键字与开关 |
| hotkey.wake_panel | ctrl+alt+z | 唤起主面板全局快捷键(与 QQ 设置一致) |
| hotkey.search | ctrl+f | 搜索框快捷键(search_method: hotkey 时使用) |
| search_method | click | 搜索框打开方式:click=点击搜索框(QQ NT 不响应 Ctrl+F)/ hotkey |
| search_box_offset | [225, 81] | click 模式搜索框点击点相对主面板左上角的像素偏移(换分辨率/DPI 后需校准) |
| search_select | click | 搜索结果选中方式:click=点击第一条(部分 QQ 版本回车无效)/ enter |
| search_result_offset | [178, 184] | click 选中模式:第一条搜索结果点击点相对主面板左上角的像素偏移 |
| timing.* | 见示例 | 各步骤等待时长(秒) |
| match.confidence / max_retry / grayscale | 0.8 / 2 / true | 图片匹配置信度、重试次数、灰度加速 |
| debounce.enabled / window_seconds | true / 300 | 防抖开关与窗口(秒) |
| retry.enabled | true | 无人接听自动重拨开关(需 verify_call_window: true) |
| retry.max_attempts | 0 | 总拨打次数上限(含首次);0=不限次,直至接听或拒绝 |
| retry.interval_seconds | 10 | 无人接听重拨间隔(秒) |
| retry.ring_seconds | 45 | 单次响铃上限(秒),超时主动挂断重拨;0=等 QQ 自然结束(可能数分钟) |
| retry.natural_ringout_seconds | 120 | 自然响铃超时下限(秒):窗口存活低于该值即关闭视为已接听/拒绝,防止秒拒被误判无人接听 |
| presence.enabled / idle_seconds | true / 180 | 用户在位检测:键鼠空闲超过该秒数才拨打(仅 auto 触发路径生效,手动命令不受限) |
| media.speak_on_answer | false | 接听后自动播放语音提醒(需虚拟声卡) |
| media.message | 任务有新进展,请前往电脑查看 | 提醒文本(SAPI 离线合成) |
| media.output_device_hint | CABLE | 语音输出设备名关键字 |
| media.hangup_after_speak | true | 播放完成后自动挂断 |
| retry.no_answer_seconds | 25 | 兜底判定阈值(秒);有响铃模板时改用状态文本判定(推荐) |
| log.level / file | INFO / logs/numalarm.log | 日志级别与文件 |
| server.host / port | 127.0.0.1 / 18600 | HTTP 服务监听 |
想让对方接听后听到一段固定语音(如「任务有新进展,请前往电脑查看」)?原理:QQ 语音通话只传麦克风的声音,因此用虚拟声卡把离线合成的语音注入 QQ 的麦克风输入。
一次性准备:
- 安装免费虚拟声卡驱动 VB-Audio Virtual Cable(安装后重启);
⚠️ 安装器可能把系统默认扬声器抢占为虚拟声卡,装完在声音设置里把默认扬声器切回真实设备; - 让 QQ 的麦克风指向虚拟声卡。注意:新版 QQ 内置设置里没有设备选择项,需将系统默认录音设备设为「CABLE Output (VB-Audio Virtual Cable)」——
- 手动:
Win+R输入mmsys.cpl→ 「录制」选项卡 → 右键 CABLE Output → 设为默认设备; - 或用 PowerShell:
Install-Module AudioDeviceCmdlets后执行Get-AudioDevice -List | Where-Object Name -like "*CABLE Output*" | Set-AudioDevice; ⚠️ 此后其他应用的录音也会走虚拟声卡,真人语音通话前需切回真实麦克风 (Get-AudioDevice -List | Where-Object Name -like "*麦克风*" | Set-AudioDevice); 进阶可用 VoiceMeeter 把真实麦克风与虚拟声卡混音,两者兼顾。
- 手动:
启用:config.yaml 中设置
media:
speak_on_answer: true
message: 任务有新进展,请前往电脑查看
output_device_hint: CABLE
hangup_after_speak: true # 播完自动挂断之后的拨打流程变为:对方接听 → 自动播放提醒语音 → 自动挂断(无人接听仍自动重拨)。语音由 Windows 自带 SAPI 离线合成(支持中文),无需联网、无需额外依赖;未安装虚拟声卡时该功能自动降级为普通拨打(如实记录播放失败)。
让「Agent 停下等待用户时自动打电话」在平台层生效,不依赖 Agent 自觉遵守 skill 约定:
numalarm hook install # 自动探测已安装的兼容宿主并注册(幂等,先备份)
numalarm hook status # 查看注册状态
numalarm hook uninstall # 移除拨打类 hook(心跳 hook 与其余配置保留)
numalarm hook install --host claude # 只注册到指定宿主(workbuddy / claude / codebuddy)
numalarm hook install --settings "D:/我的Agent/settings.json" # 任意兼容宿主:手动指定配置路径- 支持宿主:任何兼容 Claude Code hooks 配置规范(
settings.json)的 Agent 宿主;hook install自动探测本机常见宿主,其他兼容宿主用--settings <路径>指定,不限于内置名单 - 作用域:不传参数时默认写全部已探测宿主;
--host <名>/--settings <路径>可限定;设置环境变量NUMALARM_HOOK_SCOPE=current可把默认切换为「仅当前安装所在宿主」 - 注册事件:
Notification(Agent 需要用户注意)+PermissionRequest(等待用户批准)+Stop(Agent 回合结束=任务交付时刻)——配合在位检测,实现「人离开电脑后任务完成自动响铃;人在电脑前零打扰」 - hook 命令:
NUMALARM_CONFIG=... pythonw -m numalarm.interfaces.cli call --silent --auto(async 异步不阻塞,无黑框,受用户在位检测控制) - 自带防轰炸:防抖窗口内重复触发只拨一次;重拨会话持锁期间后续触发直接返回 503 静默退出
- 注册后重启对应宿主会话生效;配合
numalarm call -m "原因"可在日志中追溯触发原因
Stop/Notification 等 hook 由宿主进程执行——Agent 进程硬崩溃(强杀/无响应被杀/OOM)时它们全部失效。看门狗用外部观察者补上这个盲区:
任务运行期间:每次工具调用 → PreToolUse hook 刷新心跳文件(~/.numalarm/heartbeat.json)
任务正常结束:SessionEnd hook 清除心跳
看门狗(计划任务每分钟一次):
心跳超过 watchdog.stale_seconds(默认 300s)未刷新
且 QQ 在运行 → 判定 Agent 异常 → 自动拨打(auto,人在电脑前自动跳过)
numalarm watchdog install # 注册计划任务 + 心跳 hook(跨宿主通用)
numalarm watchdog status # 查看注册状态
numalarm watchdog uninstall # 移除心跳 hook 与计划任务(拨打类 hook 不受影响)
numalarm watchdog install --host claude # 心跳 hook 只写指定宿主(计划任务本身始终全机唯一)跨宿主通用:兼容 hooks 的宿主由 PreToolUse hook 自动刷新心跳;无 hook 机制的宿主(任何能跑命令的 Agent)按 SKILL.md 约定在长任务中定期运行 numalarm heartbeat 即可接入同一个看门狗。
调优:watchdog.stale_seconds 需大于 Agent 纯思考(不调工具)的最长间隙,否则可能误报(误报时人在电脑前会被在位检测拦截,人不在则多打一通提醒——方向正确,频率可用阈值调节)。
团队/编排类 Agent 常有「回合结束但将自动继续」的时刻(等待子代理汇报、CI 完成、定时恢复)——这类回合不需要用户操作,Stop hook 却会照常触发。为此提供 hold 机制:
numalarm hold # 暂停自动提醒 30 分钟(默认,可 -m 自定义)
numalarm hold -m 60 # 暂停 60 分钟
numalarm hold --clear # 立即恢复(需要用户操作/最终交付时)使用约定(已写入 SKILL.md):Agent 回合结束后将自动继续时,结束前运行 numalarm hold;需要用户操作或最终交付时先 numalarm hold --clear 再拨打。hold 到期自动恢复——即使 Agent 忘记摘牌也不会永久漏提醒。
numalarm update先检查、后更新:
- 没有新版本:提示「已是最新版本,无需更新」,不做任何改动;
- 有新版本:自动备份你的
config.yaml与校准模板 → 拉取最新代码 → 同步虚拟环境依赖 → 刷新 hook 注册 → 恢复你的配置与校准模板(上游若带来新模板会另存于备份目录供对比)。
完成后建议运行 numalarm test 校准,并重启宿主会话使技能更新生效。手动方式(备选):进入技能目录 git stash && git pull && git stash pop,再同步 .venv 依赖与 numalarm hook install。
同一台电脑可能存在多份 numalarm(不同宿主的技能目录、开发目录、历史克隆),它们共享 ~/.numalarm 状态并可能互相覆盖 hook 指向。体检与收拢:
numalarm installs # 列出全部副本:版本 / git HEAD / 是否有配置 / 模板是否已校准 / 被哪些宿主 hook 引用
numalarm installs --json # 机器可读输出(供 Agent 解析)
numalarm installs --apply --dir <目录> # 把各宿主 hook 统一改指到指定安装(先备份 .numalarm-bak)install.py安装时自动体检:发现其他副本会打印清单,并在交互模式下询问是否复用其 config.yaml 与已校准模板(覆盖前自动备份到~/.numalarm/backups);numalarm doctor同样给出[提示]级的多副本报告,并检查 hook 命令指向的目录是否存在——指向缺失目录的 hook 会静默失效,doctor 会将其标为 FAIL;- 多份安装并存「能用但状态散乱」(共享的锁/防抖/hold/心跳会互相影响),建议最终收拢到一份。
所有组件均可完全移除——依赖隔离在技能目录的独立虚拟环境中,不写入系统 Python,卸载后设备无任何残留:
| 组件 | 清理方式 |
|---|---|
| 宿主 Hook 注册(拨打类) | numalarm hook uninstall(只删拨打类;numalarm uninstall 全量处理) |
| 看门狗计划任务与心跳 hook(若装过) | numalarm watchdog uninstall(只删心跳类) |
| 桌面快捷方式(旧版本创建的) | numalarm uninstall 逐个确认删除(shortcut 功能已在 v1.0.3 移除) |
运行时状态(~/.numalarm:防抖记录与锁文件) |
numalarm uninstall 自动清理 |
| Agent 长期记忆中的约定登记 | 由 Agent 自行删除(numalarm uninstall 结束时会提醒;numalarm 无法访问宿主的记忆系统) |
技能/仓库目录(含 .venv 虚拟环境、config.yaml、模板) |
直接删除整个目录即可(建议最后删) |
pip 安装的 numalarm 包(若用过 pip install -e .) |
pip uninstall numalarm |
| 虚拟声卡 VB-Cable(可选装) | 先切回真实麦克风/扬声器,再到 Windows「设置 → 应用」卸载 VB-Audio Virtual Cable |
一站式命令:numalarm uninstall(-y 跳过确认)。
Q:提示 1003 语音按钮匹配失败?
重新按 assets/README.md 截图(分辨率/DPI 必须与运行时一致);或调低 match.confidence(如 0.75);确认聊天窗口未被遮挡。
Q:提示 1001 但 QQ 明明开着?
检查 qq_process_name(新版 QQ 进程可能不同)与 qq_window_title;确认 QQ 已登录(仅登录后主面板才可唤起)。
Q:拨打成功但报 1004 超时?
你的 QQ 版本拨打后可能不弹独立通话窗口,把 verify_call_window 改为 false 即可。
Q:中文昵称能输入吗? 能。搜索框输入通过剪贴板粘贴(Ctrl+V)实现,天然支持中文。
Q:搜索框打不开 / 回车不选中结果?
QQ NT 版本不响应 Ctrl+F,且部分版本回车不选中搜索结果。保持默认 search_method: click + search_select: click(点击搜索框 + 点击第一条结果);更换分辨率/DPI 后需重新校准 search_box_offset 与 search_result_offset 两个偏移值(用 numalarm test 配合截图逐步校准)。
Q:QQ 面板已经开着,会被热键藏起来吗? 不会。程序会先探测面板是否可见,可见则直接前置,仅在其不可见时才按「提取消息」热键(该热键是开关切换)。
Q:快捷键唤不起主面板?
进入 QQ 设置 -> 热键,把「提取消息/主面板」快捷键改为与 hotkey.wake_panel 一致(默认 Ctrl+Alt+Z)。
Q:无人接听会重拨吗?
会。拨打后通话窗口头部显示「等待对方接听」,程序据此判定状态:文案变化(变为计时器=已接听 / 拒绝提示=已拒绝)即触达成功,立即停止;窗口关闭且全程仍在响铃(QQ 响铃超时自动挂断)即无人接听,按 retry.interval_seconds 间隔自动重拨。retry.max_attempts: 0(默认)不限次直至触达,设正整数可限次。重拨全程持锁,期间其他调用返回 503;HTTP 调用方需设置足够的客户端超时(QQ 响铃超时可达 1 分钟以上)。响铃文案模板见 assets/README.md,QQ 更新改变文案后需重新截取。
Q:人在电脑前时不想被打扰怎么办?
默认就帮你考虑了:hook 与 agent 的拨打都带 --auto(自动化触发)标记,受用户在位检测控制——键鼠空闲超过 presence.idle_seconds(默认 180s)才真正拨打,你动一下鼠标它就静默跳过,离开电脑后自动恢复。重拨会话进行中你回到电脑前,下一轮也会自动停止。人工手动敲的 numalarm call(不带 --auto)不受此限制——你手动要打的电话总会打。另可用 numalarm hook uninstall 摘掉平台钩子,或在对话里直接告诉 agent「这次不用打电话」(skill 约定层会遵循)。
Q:误触发怎么办? 拨打过程中把鼠标快速移到屏幕左上角可强制中断(pyautogui failsafe)。
Q:电脑上装过好几份 numalarm,会互相打架吗?
不会双拨:全局互斥锁 + 共享防抖状态兜底。但状态会互相影响(心跳/防抖/hold 位于全机共享的 ~/.numalarm)。运行 numalarm installs 查看全部副本,numalarm installs --apply --dir <目录> 可把各宿主 hook 统一指向一份安装;install.py 也会在安装时自动体检并提示。
numalarm/
├── SKILL.md # Skill 元数据(Agent Skill 规范)
├── README.md # 本文档
├── TESTS.md # 测试用例说明
├── CHANGELOG.md # 更新日志
├── LICENSE # MIT 许可证
├── requirements.txt # 依赖清单(必选/可选区分)
├── pyproject.toml # 打包配置(numalarm 命令入口 + ruff 规范)
├── config.example.yaml # 配置示例(复制为 config.yaml 使用)
├── conftest.py # pytest 根目录导入支持
├── install.py # 一键安装器(仅标准库,幂等;见「安装」)
├── tests/ # 单元测试(纯逻辑,跨平台可跑)
│ ├── test_numalarm.py
│ ├── test_installations.py # 安装副本探测与 hook 命令解析
│ ├── test_cli_hooks.py # hook 分类/卸载/作用域回归
│ └── test_installer.py # 安装器步骤计算与参数
├── .github/workflows/ # CI(Ubuntu 测试矩阵 + Windows 冒烟)
├── assets/
│ ├── voice_button_sample.png # 语音按钮模板
│ ├── call_ringing_sample.png # 响铃状态判定模板
│ └── README.md # 素材截取与替换说明
└── numalarm/ # 核心代码包
├── __init__.py # 对外暴露 call_qq / test_call
├── core/ # 核心拨打逻辑层
│ ├── qq_controller.py # QQ 窗口唤起、搜索、聊天窗控制
│ ├── call_executor.py # 拨打流程编排与执行
│ ├── state_detector.py # 进程、窗口、用户在位检测
│ └── voice.py # 语音提醒:SAPI 离线合成与输出设备路由
├── interfaces/ # 对外接入层
│ ├── sdk.py # Python SDK
│ ├── api.py # HTTP REST
│ └── cli.py # CLI + 宿主 Hook 管理
└── common/ # 通用基础组件
├── config.py # 配置加载与管理
├── installations.py # 安装副本探测与 hook 命令解析(仅标准库)
├── lock.py # 全局互斥锁(进程内 + 跨进程文件锁)
├── logger.py # 统一日志(支持静默)
└── exceptions.py # 自定义异常与状态码
- 仅支持 Windows 平台 PC 版 QQ;仅在桌面解锁、QQ 已登录时可用
- 不提供 QQ 自动登录、不存储账号密码
- 仅 UI 模拟点击,不注入进程、不破解协议、不调用 QQ 私有接口
- 无联网上报、无后台隐藏功能
core 与 interfaces 已解耦,预留:视频通话(替换点击目标图)、自动挂断(检测通话窗口后模拟点击)、附带消息(拨打前模拟输入发送)。详见 SKILL.md「扩展预留」。