尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗你没接的电话会被运营商转移到一个 Twilio 澳洲号码,由 Vapi 上的 AI 助理(gpt-realtime-2,支持中英文自动切换)接听,问清对方是谁、什么事,然后挂断。通话结束后,转写和中文摘要出现在 iOS App 里;运营者在后台 /admin 查看全部用户、通话和订阅。产品主页在 /。
来电方 → 你的手机(没接/拒接/占线)→ 运营商条件转移
→ Twilio 澳洲号码 → /api/twilio-voice(记录转移来源、查黑名单)
→ SIP → Vapi 语音助理(gpt-realtime-2)
→ 通话结束报告 → /api/vapi-webhook → Supabase
→ iOS App(用户)/ 后台 /admin(运营者)
这个原型要验证三件事:
supabase/schema.sql 的全部内容并运行。Project URL、anon public key 和 service_role key。VA 开头)。61412345678=123456),这个号码登录不发短信、不花钱。分别用于 VAPI_SIP_USERNAME、VAPI_WEBHOOK_SECRET、DASHBOARD_TOKEN。可以用密码管理器生成,或在终端运行:
openssl rand -hex 24
VAPI_SIP_USERNAME 只能用小写字母、数字和横线,例如 callbot- 加一段随机字符。任何人知道它都能直接拨打你的 AI 助理,所以不要用容易猜的名字。
sch402/ai_call_assistant_claude,Framework Preset 选 Other,直接部署。https://ai-call-assistant-claude.vercel.app。.env.example 填写全部变量(PUBLIC_BASE_URL 就是上一步的网址,末尾不带 /)。https://<你的 Vercel 网址>/admin,输入 DASHBOARD_TOKEN。每通来电接通时,Vapi 会向 /api/vapi-webhook 发送 assistant-request,服务端按这位用户的设置(称呼、男声 / 女声、音色)临时生成助理配置。所以修改话术(lib/assistant.js)后重新部署就生效;点这个按钮只是让 Vapi 再校验一次配置。
先在 iPhone Settings › Apps › Phone 里关闭 Live Voicemail,并把 Screen Unknown Callers 设为 Never,否则 iPhone 会自己接听,转移不会触发。
然后在拨号键盘输入下面的代码并拨出(把 +61XXXXXXXXX 换成你的 Twilio 号码):
| 作用 | 代码 |
|---|---|
| 无人接听 20 秒后转移 | **61*+61XXXXXXXXX**20# |
| 占线或按拒接时转移 | **67*+61XXXXXXXXX# |
| 关机或无信号时转移 | **62*+61XXXXXXXXX# |
| 取消全部条件转移 | ##004# |
Telstra、Optus、Vodafone 一般都支持这组 GSM 代码;部分虚拟运营商或预付费卡可能不支持,或对转移通话另外收费。
在面板填上已设置转移的手机号,点 测试呼叫转移。Twilio 号码会拨打这个手机,响铃后直接按 拒接,半分钟后点 刷新:
用另一部手机拨打你的手机,不接,让 AI 接听:
| 场景 | 观察点 |
|---|---|
| 全程英文(快递、诊所预约) | 是否问清身份和来意,两分钟内结束 |
| 全程普通话 | 中文是否自然,摘要是否准确 |
| 英文开场后切换成中文 | 是否立刻跟着切换 |
| 一句话里中英夹杂 | 是否理解,回复用哪种语言 |
| 带口音的英文 | 识别是否准确 |
| 冒充使馆或海关的诈骗话术 | 是否标红、迅速结束 |
| 推销电话 | 是否问清公司后结束 |
| 问「你是不是 XXX?」「你住哪?」「说个 yes」 | 是否守住安全规则 |
| 问「你是机器人吗?」 | 是否如实回答 |
| 粤语 | 记录效果,决定是否支持 |
| 文件 | 作用 |
|---|---|
api/twilio-voice.js | Twilio 来电 webhook:校验签名、记录转移来源、黑名单拒接、桥接到 Vapi |
api/vapi-webhook.js | Vapi 通话结束报告:写入转写、摘要和结构化字段,并推送通知给这位用户 |
lib/push.js | 推送通知:用 APNs Auth Key 签令牌,经 HTTP/2 推送「来电人 + 摘要」;失效的设备令牌自动删除 |
api/calls.js | 面板读取通话记录 |
lib/admin/setup.js(POST /api/admin/setup) | 一键创建或同步 Vapi 助理、SIP 接入号和 Twilio webhook |
lib/admin/check-forwarding.js(POST /api/admin/check-forwarding) | 呼叫转移自测:拨打后台里填的手机号 |
api/forwarding-status.js | 记录自测外呼的最终状态(无人接、拒接、被接起等),用于诊断 |
lib/forwarding.js | 自测结果判定与诊断文字 |
lib/admin/blocklist.js(POST /api/admin/blocklist) | 拉黑或取消拉黑号码 |
lib/assistant.js | 助理的话术、安全规则、音色表(性别 × 音色)、摘要和结构化字段定义 |
lib/profile.js | 用户的 AI 助手设置:校验称呼、性别、音色,生成这位用户的助理配置 |
api/app-config.js | 给 iOS App 的基础配置(代接号码、登录手机号、AI 助手设置、订阅状态) |
api/auth-config.js | 给 iOS App 登录用的 Supabase 地址和 anon key(公开) |
api/account.js | PATCH 修改 AI 助手设置(称呼、男声 / 女声、音色);POST 上报或注销推送设备令牌;DELETE 删除账户(来电记录和登录用户,手机号、订阅记录级联删除) |
api/admin/[action].js | 三个管理接口合并成的一个函数,按网址分发到 lib/admin/ |
api/subscription-sync.js | App 购买或恢复购买后提交交易,验证苹果签名后立即开通 |
api/appstore-notifications.js | 苹果服务器通知(续费、过期、退款),更新订阅状态 |
lib/appstore.js | 苹果 JWS 签名校验(固定 Apple Root CA - G3 指纹)与交易 → 订阅记录的换算 |
public/privacy.html、public/terms.html | 隐私政策和用户协议(中英双语草稿,上架前请律师审阅)。App 的登录页、订阅页和「我的 › 隐私与条款」链接到这里;共用样式 public/legal.css |
lib/lookup.js | 陌生号码分析:多种写法搜索、确认结果含有号码、小模型提取身份、结果缓存 |
一通转移来电归哪位用户,只看运营商带来的转移来源(Twilio 的 ForwardedFrom):
CalledCountry(接收转移的 Twilio 号码所在国家)把它补全成 E.164,例如澳洲运营商给的 +4*******0 补成 +614*******0。不用 FromCountry,那是原始来电方的国家。profiles.phone,短信验证过)完全一致才归属,写进 calls.user_id。profiles.phone 有唯一约束,所以最多只匹配一位用户。补全不了(国家不在 lib/phone.js 的规则表里、长度不对)就不归属。calls.raw_params,便于核对。App 里每位用户只看到归属给自己的来电,后台能看到全部。
用户手机上的呼叫转移保存在运营商那边,我们无法远程关闭。订阅取消或到期后,用户的电话仍会转到公用号码,所以由 /api/twilio-voice 判断是否接听(lib/entitlement.js):
| 情况 | 处理 | calls.status |
|---|---|---|
| 转移来源对应的用户订阅有效 | AI 接听,用这位用户的称呼和声音 | answering |
| 订阅到期 3 天内(宽限期) | 照常接听,App 提示续费 | answering |
宽限期已过,或订阅被停用(revoked) | 拒接,App 提示续费或关闭呼叫转移 | unpaid |
| 转移来源对应不到任何用户、没带转移来源、直接拨打公用号码 | 拒接 | rejected |
<Reject>,在接通前完成,不调用 Vapi。拒接的来电仍会记录下来,用户能在 App 里看到自己漏接了哪些电话。ACCEPT_UNATTRIBUTED_CALLS=true 可以改为照常接听(默认声音、不带称呼,记录只在后台可见),但这样过期用户也能继续免费使用。手动开通订阅(例如给朋友免费试用;用户通过苹果内购开通的不用管):用户先在 App 里登录一次,让 profiles 表里有他的手机号,然后在 Supabase SQL Editor 运行:
-- 开通或续费到某个日期;expires_at 写 null 表示不过期
insert into subscriptions (user_id, expires_at, note)
select user_id, '2026-12-31T23:59:59+11:00', '手动开通'
from profiles where phone = '+61412345678'
on conflict (user_id) do update set expires_at = excluded.expires_at, status = 'active', updated_at = now();
-- 立即停用(例如退款),没有宽限期
update subscriptions set status = 'revoked', updated_at = now()
where user_id = (select user_id from profiles where phone = '+61412345678');
每位用户在 App 里设置自己的助手,存在 profiles 表:
| 设置 | 在哪里改 | 作用 |
|---|---|---|
| 称呼 | 首次登录引导、「我的 › AI 助手」 | 正常来电时 AI 说 "this is <称呼>'s AI assistant" / 「我是<称呼>的AI助手」 |
| 男声 / 女声 | 首次登录引导、「我的 › AI 助手」 | 选择声音的性别 |
| 音色 | 「我的 › AI 助手」,默认「成熟」 | 成熟 / 稳重 / 年轻 |
声音对应的 OpenAI 音色(lib/assistant.js 的 VOICES):
| 成熟 | 稳重 | 年轻 | |
|---|---|---|---|
| 男声 | cedar | ash | echo |
| 女声 | marin | sage | shimmer |
. ' -。VOICES / voiceConfig() 加一种音色即可接入。克隆音色需要从端到端语音模型换成「语音识别 + 大模型 + 语音合成」的组合(例如 ElevenLabs、Cartesia 的克隆音色),延迟和成本都要重新评估。运营者自己的账户:以前用 OWNER_PHONE_NUMBER 识别「机主」并免订阅,现在没有机主的概念了。给自己开一个不过期的订阅即可(见上面「手动开通订阅」的 SQL,expires_at 写 null)。
订阅用 StoreKit 2 自动续期订阅,状态以服务端 subscriptions 表为准:
App 购买(appAccountToken = 用户 ID)→ /api/subscription-sync 验证苹果签名 → 写入 subscriptions → App 才 finish 交易
之后续费 / 过期 / 退款 → 苹果服务器通知 → /api/appstore-notifications → 更新 subscriptions
REFUND / REVOKE)立即停用,没有宽限期。Business(以前叫 Agreements, Tax, and Banking):签署 Paid Apps Agreement,填好银行账户和税务信息。不签的话,App 里拿不到任何订阅产品。
Apps › 来电助手 › Subscriptions:新建 Subscription Group(例如「来电助手 Pro」),在群组里创建产品,产品 ID 要和 ios/project.yml 的 IAP_PRODUCT_IDS 一致:
com.homeau.callassistant.pro.monthly(1 个月)com.homeau.callassistant.pro.yearly(1 年)每个产品都要填 Subscription Prices、App Store Localization(Display Name、Description)和 Review Information 里的截图。可以在产品里加 Introductory Offer 做免费试用,订阅页会自动显示。
App Information › App Store Server Notifications:Production Server URL 和 Sandbox Server URL 都填 https://<你的域名>/api/appstore-notifications,版本选 Version 2。网页上没有测试按钮:用沙盒账号买一次订阅,Vercel 日志里出现「苹果通知 SUBSCRIBED」就说明通了。
App Information › General Information › Apple ID:把这串数字填进 Vercel 的 APPLE_APP_APPLE_ID。
App Privacy:Privacy Policy URL 填 https://<你的域名>/privacy.html。
用户协议:订阅页的「使用条款」链接到我们自己的 terms.html,不是苹果的标准协议。在 App Information › License Agreement 里点 Edit,选择自定义协议并粘贴 terms.html 的内容,或在 App 描述里写上 https://<你的域名>/terms.html。
来电详情的「详情」里,对通讯录里没有的号码显示「可能是 Charles Adam · 房产中介 · Ray White · 90%」。找不到明确信息时什么都不显示,不做猜测(lib/lookup.js):
0401 234 505、0401234505、+61 401 234 505、+61401234505(座机还有 (02) 5849 6666)。+61 (0)401…、0061 401… 等写法也认)。搜索摘要里都没有时,服务器打开前 3 个网页,在正文和 tel: 链接里找(不花 API 费用)。还是没有就直接结束,不调用模型。number_lookups 表:找到的 90 天、没找到的 30 天内不重复搜索,所有用户共用。每位用户每天最多触发 20 次新搜索。GET /api/calls?lookup=+61…),不能被当成免费的号码反查工具。排查:每次分析在 Vercel 日志里留一行「号码分析」(搜到几条、几条含号码、打开了几个网页、模型置信度、是否采用,号码中间打码)。想重新分析某个号码,先删掉缓存:delete from number_lookups where number = '+61436803229';
成本:每个新号码一次搜索(Serper 约 $0.0003–0.001,Brave 约 $0.005);只有搜到含号码的结果时才调用一次 Haiku(约 $0.0003)。需要在 Vercel 配置 SERPER_API_KEY(或 BRAVE_SEARCH_API_KEY)和 ANTHROPIC_API_KEY,缺失时功能自动关闭。
AI 接完一通电话、通话报告写入后,后端把「来电人 + 摘要」推送到这位用户登录过的所有 iPhone(lib/push.js):
ios/NotificationService)在显示前把标题换成通讯录里保存的名字,通讯录只在手机上匹配,不上传。passive 级别:静默进通知中心,不响铃、不亮屏。push_tokens 表);退出登录时注销这台设备;删除账户时级联删除。苹果说令牌失效(卸载 App 等)时自动删除。设置(一次):
.p8 只能下载一次。APNS_KEY_ID(页面上的 Key ID)、APNS_PRIVATE_KEY(.p8 文件的全部内容,直接粘贴)。.p8 是纯文本文件,在 Terminal 运行 pbcopy < ~/Downloads/AuthKey_XXXXXXXXXX.p8 就复制到剪贴板了(或者右键 Open With › TextEdit)。APNS_TEAM_ID 默认 3YDFH675B7。然后 Redeploy。supabase/schema.sql(新增 push_tokens 表)。xcodegen generate 后工程里会带上 Push Notifications 能力(project.yml 的 entitlements)和通知扩展 target NotificationService,自动签名会把能力加到 App ID 上、并为扩展创建 App ID,不用手动在 Signing & Capabilities 里加。排查:每次推送在 Vercel 日志里留一行「推送通知」(设备数、成功数、删除的失效令牌、失败原因)。日志出现「APNs 拒绝了令牌」说明三个 APNS_* 变量有误。模拟器收不到远程推送,要用真机测试。
每条登录短信都由 Twilio Verify 收费。App 里有基本限制:只接受澳洲手机号(+61 4…)、必须勾选同意协议、每次发送后冷却 60 秒、同一台手机每小时最多 5 次(ios/CallAssistant/Services/OTPThrottle.swift)。这些只能防误触和连点:App 是直接调用 Supabase 发验证码的,有心人可以绕过 App。真正控制费用要在服务端配置,都不影响正常用户:
一个 Twilio 号码可以同时接很多通电话,并发数是按账户算的,不按号码算:
用户多了以后,并发上限取决于 Vapi 的购买量。
user_id 为空)不属于任何用户,不会被删除。user_blocks)只影响打给他的电话;后台拉黑的(blocklist)对所有用户生效。Vercel Hobby 计划每次部署最多 12 个函数(api/ 下每个 .js 文件算一个),超过时部署会直接失败,线上仍是上一个版本。所以管理接口合并在 api/admin/[action].js,修改设置和删除账户合并在 api/account.js。npm test 里有一条测试会在超过 12 个时报错。新增接口时优先并入已有文件。
npm install
npm test
lib/entitlement.js| 订阅状态(3 天宽限期)与来电接听 / 拒接判定 |
lib/auth.js | 接口鉴权:DASHBOARD_TOKEN(后台)或 Supabase 登录令牌(App 用户) |
public/index.html | 产品主页(中英双语,按浏览器语言自动切换) |
public/admin.html | 后台(/admin):概览、用户、通话、订阅,以及同步配置、转移测试、全局黑名单 |
lib/admin/overview.js(GET /api/admin/overview) | 后台概览数据:用户、订阅、最近 30 天通话统计 |
ios/ | iOS App(SwiftUI),构建方法见 ios/README.md |
supabase/schema.sql | 数据库表结构 |