0

0

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

花韻仙語

花韻仙語

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

|

435人浏览过

|

来源于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智能翻译浏览器插件,支持多语种对照式翻译

下载

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动词的灵活运用是实现此类复杂通信逻辑的关键。

相关专题

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

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

355

2023.06.29

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

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

2076

2023.08.14

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

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

348

2023.08.31

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

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

255

2023.09.05

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

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

324

2023.10.09

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

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

411

2023.10.16

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

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

407

2023.10.16

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

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

221

2023.10.19

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 50.1万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号