讲师中心 微信公众号
AI工具推荐 视频效率加速

Twilio实现呼叫转发与未接来电语音留言功能详解

梦明小哥_5466

梦明小哥_5466

发布时间:2025-12-14 10:01:33

|

475人浏览过

|

来源于php中文网

原创

twilio实现呼叫转发与未接来电语音留言功能详解

本教程详细介绍了如何使用Twilio构建一个具备呼叫转发功能的系统,并在此基础上实现未接来电自动转接语音留言。文章将涵盖Twilio TwiML中的`Dial`和`Record`动词的使用,包括设置呼叫超时、录制语音留言,以及通过Webhook处理录音回调和转录,最终实现将语音留言通过邮件通知用户。

在现代通信应用中,为用户提供一个隐私保护的虚拟号码(即掩码号码)并将其呼叫转发至真实号码是一项常见需求。然而,当用户真实号码无法接通、占线或未及时应答时,如何确保客户能够留下语音留言,并及时通知用户,是提升用户体验的关键。本教程将详细阐述如何利用Twilio的强大功能,构建一个完整的呼叫转发与未接来电语音留言系统。

1. 核心需求分析

我们的目标是实现以下功能:

  1. 客户拨打用户的掩码号码。
  2. Twilio将呼叫转发至用户的真实号码。
  3. 如果用户真实号码未接通、占线或未应答,客户可以录制语音留言。
  4. 语音留言将被存储,并通过Twilio的语音转文本API进行转录。
  5. 转录文本和语音文件链接将通过电子邮件发送给用户。

2. Twilio TwiML动词:Dial与Record

Twilio通过TwiML(Twilio Markup Language)来控制呼叫流程。实现上述功能主要依赖于Dial和Record这两个核心动词。

2.1 使用 Dial 动词进行呼叫转发与超时设置

Dial动词用于将当前呼叫连接到另一个电话号码或Twilio客户端。为了处理未接来电,我们需要利用Dial动词的timeout和action属性。

  • timeout:指定Twilio等待被叫方接听的时间(秒)。如果在此时间内未接听,Twilio将停止尝试连接。
  • action:当Dial动词执行结束时(例如,被叫方未接听、占线或失败),Twilio会向此URL发起一个HTTP请求。这个URL将用于处理呼叫的后续逻辑,例如转接至语音留言。

示例代码:主呼叫Webhook (/webhook/voice)

const twilio = require("twilio");
const express = require("express");
const router = express.Router();

// 假设 getNumberWithoutUser 和 updateQuota 是你的数据库操作函数
// const { getNumberWithoutUser, updateQuota } = require("../db/dbOperations");

router.post("/webhook/voice", async (req, res) => {
  const { To, From, CallStatus } = req.body;

  // 假设根据 'To' 掩码号码获取用户信息和真实号码
  // const [numbers] = await getNumberWithoutUser(To);
  // if (!numbers) return res.status(400).send("User does not own this number");

  // 假设这些信息从数据库中获取
  const primaryPhoneNumber = "+8613800138000"; // 示例:用户的真实号码
  const isToPrimaryPhone = true; // 示例:是否开启了呼叫转发

  if (isToPrimaryPhone) {
    const twiml = new twilio.twiml.VoiceResponse();

    // 可选:在转接前播放欢迎语
    twiml.say({ voice: 'alice', language: 'zh-CN' }, "请稍候,我们正在为您转接。");

    // 使用Dial动词将呼叫转发到用户的真实号码
    // 设置15秒超时,如果未接听,则将控制权转交给 /webhook/handle_dial_outcome
    twiml.dial({
      timeout: 15, // 等待被叫方接听的秒数
      action: '/webhook/handle_dial_outcome', // 如果未接听,Twilio将请求此URL
      hangupOnStar: true // 允许呼叫者按 * 键跳过语音留言
    }, primaryPhoneNumber);

    // 假设更新呼叫配额
    // await updateQuota(numbers._id, To, "callForwarding", type);

    res.type("text/xml");
    return res.send(twiml.toString());
  }

  // 如果呼叫转发未启用或套餐已过期
  res.send("Call Forwarding is disabled or package has finished");
});

module.exports = router;

2.2 使用 Record 动词录制语音留言

当Dial动词因超时而结束时,Twilio会调用action指定的URL。在这个新的Webhook中,我们将使用Record动词来提示客户录制语音留言。

AI舌诊面诊问诊医疗系统+诊疗商城系统源码
AI舌诊面诊问诊医疗系统+诊疗商城系统源码

AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。

下载

Record动词的关键属性:

  • maxLength:录音的最大时长(秒)。
  • finishOnKey:当呼叫者按下此键时,录音结束。
  • action:录音完成后,Twilio会向此URL发起HTTP请求,并附带录音的URL和其他信息。
  • transcribe:设置为true可以启用Twilio的语音转文本服务。
  • transcribeCallback:如果启用了转录,转录完成后Twilio会向此URL发起请求,并附带转录文本。

示例代码:处理Dial动词结果的Webhook (/webhook/handle_dial_outcome)

// ... (之前的require和router定义)

router.post("/webhook/handle_dial_outcome", async (req, res) => {
  const { DialCallStatus, To, From } = req.body; // DialCallStatus 表示Dial动词的执行结果
  const twiml = new twilio.twiml.VoiceResponse();

  // 检查Dial动词的执行状态
  if (DialCallStatus === 'no-answer' || DialCallStatus === 'busy' || DialCallStatus === 'failed') {
    // 如果呼叫未接听、占线或失败,则提示客户留言
    twiml.say({ voice: 'alice', language: 'zh-CN' }, "您拨打的用户暂时无法接听,请在哔声后留言。");
    twiml.record({
      maxLength: 60, // 最大录音时长60秒
      finishOnKey: '#', // 呼叫者按 # 键结束录音
      action: '/webhook/recording_status', // 录音完成后,Twilio将请求此URL
      transcribe: true, // 启用语音转文本
      transcribeCallback: '/webhook/transcription_status' // 转录完成后,Twilio将请求此URL
    });
    twiml.say({ voice: 'alice', language: 'zh-CN' }, "留言结束,感谢您的来电。");
  } else {
    // 其他状态,例如呼叫已完成(通常不会进入此分支,因为如果接听,Dial动词会直接连接,不会触发action)
    // 或者可以播放一个结束语
    twiml.say({ voice: 'alice', language: 'zh-CN' }, "感谢您的来电。");
  }

  res.type("text/xml");
  return res.send(twiml.toString());
});

// module.exports = router; // 如果是单独的文件,需要导出

3. 处理录音与转录回调

当录音完成或转录完成时,Twilio会分别向action和transcribeCallback指定的URL发送POST请求,其中包含录音或转录的详细信息。

3.1 录音状态回调 (/webhook/recording_status)

这个Webhook会接收到录音的URL、时长等信息。你可以在这里将这些信息存储到数据库,并触发邮件通知。

// ... (之前的require和router定义)

router.post("/webhook/recording_status", async (req, res) => {
  const { RecordingUrl, RecordingDuration, CallSid, From, To } = req.body;

  console.log(`收到新的语音留言:${RecordingUrl},时长:${RecordingDuration}秒`);

  // 1. 将录音信息存储到数据库
  // const [numbers] = await getNumberWithoutUser(To); // 根据'To'掩码号码获取用户数据
  // if (numbers) {
  //   await appendMessage(numbers._id, To, From, {
  //     type: 'voicemail',
  //     url: RecordingUrl,
  //     duration: RecordingDuration,
  //     callSid: CallSid
  //   });
  //   // 2. 如果不需要等待转录结果,可以直接发送邮件通知
  //   // await sendMessageNotificationEmail(numbers.userEmail, "您有新的语音留言", `请访问:${RecordingUrl}`);
  // }

  // Twilio期望收到一个200 OK响应
  res.send("Voicemail recording processed.");
});

3.2 转录状态回调 (/webhook/transcription_status)

如果启用了transcribe: true,当Twilio完成语音转文本后,会调用此Webhook。这里可以获取转录文本,并将其与录音链接一同通过邮件发送给用户。

// ... (之前的require和router定义)

router.post("/webhook/transcription_status", async (req, res) => {
  const { TranscriptionStatus, TranscriptionText, RecordingUrl, CallSid, From, To } = req.body;

  if (TranscriptionStatus === 'completed') {
    console.log(`语音留言转录完成。录音:${RecordingUrl},转录文本:${TranscriptionText}`);

    // 1. 更新数据库中对应的语音留言记录,添加转录文本
    // const [numbers] = await getNumberWithoutUser(To);
    // if (numbers) {
    //   // 假设有一个函数可以更新留言记录
    //   // await updateVoicemailTranscription(CallSid, TranscriptionText);

    //   // 2. 发送包含语音链接和转录文本的邮件通知
    //   // const emailBody = `您有一个新的语音留言:\n语音链接:${RecordingUrl}\n转录内容:${TranscriptionText}`;
    //   // await sendMessageNotificationEmail(numbers.userEmail, "您有新的语音留言及转录", emailBody);
    // }
  } else {
    console.log(`语音转录失败或进行中,状态:${TranscriptionStatus}`);
  }

  res.send("Voicemail transcription processed.");
});

4. 注意事项与最佳实践

  • Webhook安全性:所有Twilio Webhook都应该验证请求的签名,以确保请求确实来自Twilio,防止恶意攻击。Twilio官方提供了SDK来帮助进行签名验证。
  • 错误处理:在Webhook中,始终要考虑各种异常情况,例如数据库连接失败、邮件发送失败等,并实现相应的错误日志记录和重试机制。
  • 用户体验:
    • 在转接语音留言前播放清晰的提示音,告知客户即将进入留言环节。
    • 明确告知客户如何结束留言(例如“请在哔声后留言,留言结束后请按#号键”)。
    • 提供合适的maxLength,避免留言过长或过短。
  • 异步处理:邮件发送、数据库更新等操作可能耗时较长。为了不阻塞Twilio的Webhook响应,可以考虑将这些任务放入消息队列进行异步处理。Twilio期望Webhook在几秒内返回TwiML。
  • Twilio控制台配置:确保你的Twilio掩码号码已正确配置了主呼叫Webhook URL(例如 https://your-ngrok-url.com/webhook/voice)。
  • 开发调试:使用ngrok等工具可以方便地将本地开发环境暴露给Twilio的Webhook请求,进行实时调试。
  • 国际化:在twiml.say中使用language属性可以指定语音提示的语言,例如zh-CN代表中文普通话,提升不同地区用户的体验。

总结

通过本教程,我们学习了如何利用Twilio的Dial和Record TwiML动词,结合多个Webhook回调,构建一个功能完善的呼叫转发和未接来电语音留言系统。这不仅提升了用户在无法接听电话时的服务连续性,也为客户提供了便捷的沟通渠道。理解Twilio的Webhook机制和TwiML动词的灵活运用是实现此类复杂通信逻辑的关键。

热门AI工具

更多
蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

2945

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

4081

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

3291

2023.08.31

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

1047

2023.09.05

vb中怎么连接access数据库
vb中怎么连接access数据库

vb中连接access数据库的步骤包括引用必要的命名空间、创建连接字符串、创建连接对象、打开连接、执行SQL语句和关闭连接。本专题为大家提供连接access数据库相关的文章、下载、课程内容,供大家免费下载体验。

2887

2023.10.09

数据库对象名无效怎么解决
数据库对象名无效怎么解决

数据库对象名无效解决办法:1、检查使用的对象名是否正确,确保没有拼写错误;2、检查数据库中是否已存在具有相同名称的对象,如果是,请更改对象名为一个不同的名称,然后重新创建;3、确保在连接数据库时使用了正确的用户名、密码和数据库名称;4、尝试重启数据库服务,然后再次尝试创建或使用对象;5、尝试更新驱动程序,然后再次尝试创建或使用对象。

2887

2023.10.16

vb连接access数据库的方法
vb连接access数据库的方法

vb连接access数据库方法:1、使用ADO连接,首先导入System.Data.OleDb模块,然后定义一个连接字符串,接着创建一个OleDbConnection对象并使用Open() 方法打开连接;2、使用DAO连接,首先导入 Microsoft.Jet.OLEDB模块,然后定义一个连接字符串,接着创建一个JetConnection对象并使用Open()方法打开连接即可。

2933

2023.10.16

vb连接数据库的方法
vb连接数据库的方法

vb连接数据库的方法有使用ADO对象库、使用OLEDB数据提供程序、使用ODBC数据源等。详细介绍:1、使用ADO对象库方法,ADO是一种用于访问数据库的COM组件,可以通过ADO连接数据库并执行SQL语句。可以使用ADODB.Connection对象来建立与数据库的连接,然后使用ADODB.Recordset对象来执行查询和操作数据;2、使用OLEDB数据提供程序方法等等。

2681

2023.10.19

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

100

2026.10.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
uni-app从入门到实战教程
uni-app从入门到实战教程

共0课时 | 0人学习

uni-app x harmony开发指南
uni-app x harmony开发指南

共0课时 | 0人学习

uni-app鸿蒙运行和发行
uni-app鸿蒙运行和发行

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn