实现Twilio掩码号码呼叫未接听时的语音留言功能


实现Twilio掩码号码呼叫未接听时的语音留言功能

本文详细介绍了如何为twilio掩码号码的呼叫转发功能实现语音留言回退机制。当客户拨打掩码号码,而转发至用户真实号码的呼叫未能接通(如无人接听、占线或不可达)时,系统将引导客户录制语音留言。教程涵盖了twiml dial 动词的超时配置、record 动词的使用,以及如何通过webhook回调处理录音,实现语音留言的存储、转文本和邮件通知。

Twilio掩码号码呼叫转发与语音留言回退机制

在构建基于Twilio的通信应用时,为用户提供掩码号码并实现呼叫转发是常见需求。然而,当被转发的用户无法接听电话时,提供一个语音留言选项能显著提升用户体验。本教程将指导您如何结合Twilio的TwiML(Twilio Markup Language)动词,实现这一高级功能:当客户拨打掩码号码,且呼叫转发至用户真实号码失败时,自动引导客户录制语音留言。

核心概念与Twilio TwiML动词

实现此功能主要依赖于Twilio的两个TwiML动词:

  1. 动词与 timeout 属性:用于将当前呼叫连接到另一个电话号码。timeout 属性定义了Twilio在放弃尝试连接被叫方之前等待的时间(秒)。如果在此时间内被叫方未接听,Twilio将继续执行TwiML响应中的下一个动词。
  2. 动词与 recordingStatusCallback 属性:用于录制呼叫方的语音。recordingStatusCallback 属性指定一个URL,Twilio会在录音完成后向该URL发送HTTP请求,其中包含录音的详细信息和URL。

实现步骤

我们将基于现有的Express应用和Twilio Webhook配置进行扩展。

1. 配置呼叫转发与超时

首先,修改处理入站语音呼叫的/webhook/voice路由。在case "ringing"逻辑中,使用动词尝试将呼叫转发到用户的真实号码。关键在于为设置一个timeout属性。如果用户未在指定时间内接听,Twilio将执行TwiML响应中的下一个动词。

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

// 假设这些是您的数据库和邮件发送工具函数
const { getNumberWithoutUser, updateQuota } = require("../db/dbOperations");
const { sendMessageNotificationEmail } = require("../emailing/email");
const { sendSms, client } = require("../twilioFunctions");
const { appendMessage } = require("../db/messagingCollectionUtils");
const { appendCall } = require("../db/callsCollectionUtils");

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

  const [numbers] = await getNumberWithoutUser(To);
  if (!numbers) {
    console.warn(`User does not own number: ${To}`);
    return res.status(400).send("User does not own this number");
  }

  const activeSubscription = numbers.numbers.subscriptions.find(
    (subscription) => subscription.active
  );
  if (!activeSubscription) {
    console.warn(`No active subscription for number: ${To}`);
    return res.send("Call Forwarding is disabled or package has finished");
  }

  const type = activeSubscription.type;
  const isToPrimaryPhone = numbers?.numbers?.settings?.forwarding?.toPrimaryPhone;
  const primaryPhoneNumber = numbers?.numbers?.settings?.forwarding?.primaryPhoneNumber;

  console.log("CallStatus", CallStatus);

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

    switch (CallStatus) {
      case "ringing":
        // 尝试拨打用户主号码,设置15秒超时
        // 如果在15秒内未接听,Twilio将继续执行TwiML响应中的下一个动词
        twiml.dial({ timeout: 15 }, primaryPhoneNumber);

        // 如果呼叫未接通(超时、占线、无人接听),则播放提示音并开始录音
        twiml.say("您拨打的用户当前无法接听,请在哔声后留言,按星号键结束。");
        twiml.record({
          recordingStatusCallback: "https://your-ngrok-url/webhook/voicemail-callback", // 替换为您的Webhook URL
          maxLength: 60, // 最长录音时间60秒
          finishOnKey: '*' // 按星号键结束录音
        });
        twiml.say("感谢您的留言,再见。"); // 录音结束后播放
        twiml.hangup(); // 结束通话

        await updateQuota(numbers._id, To, "callForwarding", type);
        res.type("text/xml");
        return res.send(twiml.toString());

      case "completed":
        // 呼叫成功完成,记录通话信息
        await appendCall(numbers._id, To, From, req.body);
        return res.send("success");

      // 可以根据需要处理其他CallStatus,例如 "no-answer", "busy", "failed"
      // 但对于语音留言回退,主要逻辑已在 'ringing' 状态的TwiML中处理
    }
  } else {
    console.log("Call Forwarding is disabled or primaryPhoneNumber is not set.");
  }
  res.send("Call Forwarding is disabled or package has finished");
});

// 导出router以供主应用使用
module.exports = router;

代码解释:

风声雨声 风声雨声

基于 gpt-3.5 的翻译服务、内容学习服务

风声雨声 124 查看详情 风声雨声
  • 在twiml.dial之后,我们紧接着添加了twiml.say和twiml.record。这是Twilio TwiML的关键行为:如果dial动词未能成功连接呼叫(例如,超时、占线、无人接听),Twilio会自动执行TwiML响应中的下一个动词。
  • timeout: 15:设置拨号超时为15秒。
  • recordingStatusCallback:这是最重要的部分,它指定了一个URL,Twilio会在录音完成后向该URL发送POST请求,包含录音文件的URL和其他元数据。请务必将其替换为您的实际Webhook地址。
  • maxLength:限制录音的最长时间。
  • finishOnKey:允许呼叫者通过按特定键(例如*)提前结束录音。

2. 处理语音留言回调

当客户完成录音或达到maxLength限制时,Twilio会向recordingStatusCallback指定的URL发送一个POST请求。您需要创建一个新的路由来处理这个回调。在这个路由中,您可以获取录音文件的URL,将其存储到数据库,并进一步处理(例如,使用Twilio的Speech-to-Text API进行转录,然后通过邮件发送给用户)。

// ... (其他引入和router定义) ...

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

  console.log("Voicemail Callback Received:");
  console.log(`Recording URL: ${RecordingUrl}`);
  console.log(`Call SID: ${CallSid}`);
  console.log(`From: ${From}, To: ${To}`);
  console.log(`Duration: ${RecordingDuration} seconds`);
  console.log(`Transcription: ${TranscriptionText || "Not *ailable or not requested"}`);

  try {
    // 1. 获取掩码号码对应的用户信息
    const [numbers] = await getNumberWithoutUser(To);
    if (!numbers) {
      console.error(`Voicemail: User does not own number: ${To}`);
      return res.status(400).send("User does not own this number");
    }

    // 2. 将语音留言信息存储到数据库
    // 假设您有一个 appendVoicemail 函数来处理此逻辑
    await appendVoicemail(numbers._id, To, From, {
      recordingUrl: RecordingUrl,
      duration: RecordingDuration,
      callSid: CallSid,
      // 如果您在Record动词中启用了转录,TranscriptionText 会在这里
      transcription: TranscriptionText || null,
      timestamp: new Date(),
    });

    // 3. 将语音留言转录为文本(如果未在Record动词中启用)并发送邮件
    // Twilio的Record动词可以直接进行转录,但如果需要更高级的转录或后续处理,可以在这里调用Twilio的Transcription API
    let finalTranscription = TranscriptionText;
    if (!finalTranscription && RecordingUrl) {
      // 示例:手动调用Twilio API进行转录 (需要配置client)
      // const transcription = await client.transcriptions.create({
      //   recordingSid: RecordingUrl.split('/').pop().split('.')[0] // 从URL中提取Recording SID
      // });
      // finalTranscription = transcription.transcriptionText;
      // console.log("Manual Transcription:", finalTranscription);
    }

    // 4. 将语音留言(或其转录文本)通过邮件发送给用户
    const userEmail = numbers?.numbers?.settings?.emailForVoicemail || numbers?.user?.email; // 假设用户邮箱配置在这里
    if (userEmail) {
      await sendMessageNotificationEmail(
        userEmail,
        `您有一个来自 ${From} 的新语音留言`,
        `您收到一个新语音留言。时长:${RecordingDuration}秒。\n\n` +
        `语音链接:${RecordingUrl}.mp3\n\n` + // Twilio录音URL通常支持.mp3扩展
        (finalTranscription ? `转录文本:\n${finalTranscription}` : "无转录文本。")
      );
      console.log(`Voicemail sent to user email: ${userEmail}`);
    } else {
      console.warn(`No email configured for user associated with number: ${To}`);
    }

    res.status(200).send("Voicemail callback processed successfully");
  } catch (error) {
    console.error("Error processing voicemail callback:", error);
    res.status(500).send("Error processing voicemail callback");
  }
});

// 辅助函数,需要您在 dbOperations.js 中实现
async function appendVoicemail(userId, maskedNumber, fromNumber, voicemailData) {
  // 实际的数据库操作,将语音留言数据存储到您的DB中
  console.log(`Storing voicemail for user ${userId} from ${fromNumber} on ${maskedNumber}:`, voicemailData);
  // 示例: await db.collection('voicemails').insertOne({ userId, maskedNumber, fromNumber, ...voicemailData });
  return Promise.resolve(); // 模拟成功
}

// ... (导出router) ...

代码解释:

  • RecordingUrl:这是录音文件的URL,您可以直接播放或下载。Twilio通常提供多种格式,添加.mp3后缀可以直接获取MP3格式。
  • TranscriptionText:如果您的Record动词配置了转录功能(通过设置transcribe: true),转录的文本会直接包含在此参数中。
  • appendVoicemail:这是一个占位函数,您需要根据您的数据库结构实现将录音信息(URL、时长、来电号码等)存储到数据库的逻辑。
  • sendMessageNotificationEmail:这是一个占位函数,用于向用户发送包含语音留言链接和转录文本的邮件通知。

注意事项与最佳实践

  1. Webhook URL安全性:您的Webhook URL应该通过HTTPS进行保护,以防止中间人攻击。Twilio还提供了Webhook请求签名验证功能,强烈建议您实现它来确保请求确实来自Twilio。
  2. 错误处理:在您的Webhook路由中,务必实现健壮的错误处理机制,以应对数据库操作失败、邮件发送失败等情况。
  3. 用户体验
    • twiml.say的提示语应该清晰明了,告知客户当前情况以及如何留言和结束录音。
    • maxLength和finishOnKey的设置应合理,平衡用户留言的需求和系统资源的消耗。
  4. Speech-to-Text API:Twilio的Record动词可以直接进行语音转文本。您可以在twiml.record中添加transcribe: true和transcribeCallback属性来启用和处理转录。如果需要更高级的转录模型或语言支持,也可以在voicemail-callback中手动调用Twilio的Transcription API或集成第三方服务。
  5. 配额管理:确保您在updateQuota函数中正确更新了用户的呼叫和语音留言配额。
  6. 可扩展性:随着用户量的增长,确保您的数据库和邮件服务能够处理增加的负载。

总结

通过以上步骤,您已经成功为您的Twilio掩码号码呼叫转发系统添加了语音留言回退功能。这不仅提升了用户体验,也确保了客户在无法直接联系到用户时,仍能有效地传达信息。结合Twilio强大的TwiML和Webhook机制,您可以构建出高度灵活和功能丰富的通信应用。

以上就是实现Twilio掩码号码呼叫未接听时的语音留言功能的详细内容,更多请关注其它相关文章!


# 如何实现  # 芜湖谷歌seo哪家好  # 宠物用品店如何进行线上营销推广  # 品牌的seo怎么做  # 大网站如何优化营销方案  # 网络营销推广培训那家好  # 网站内容优化策略是什么  # 中关村网站建设美丽中国  # 建设网站的技术步骤  # 关键词挖掘排名怎么写  # 乌海关键词排名采购  # 回调  # 您在  # 可以直接  # js  # 会在  # 这是  # 您可以  # 掩码  # 您的  # 转录  # red  # 邮箱  # 路由  # switch  # ai  # 工具  # app 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: CodeIgniter 3 中基于 MySQL 数据高效生成动态图表教程  《爱笔思画x》魔棒工具抠图教程  电子白板帮助菜单使用指南  Chart.js 教程:自定义插件实现图表与图例间距调整  Win10如何查看已安装的更新补丁 Win10卸载指定更新教程【教程】  如何用mysql开发用户注册登录功能_mysql用户注册登录数据库设计  Go Goroutine调度与并发执行深度解析  Flexbox布局:实现粘性导航与底部页脚的完美结合  抖音火山版如何进行提现  2025SNH48年度青春盛典门票价格及购买方式  SQLAlchemy 2.0 与 Pydantic 模型类型安全集成指南  房产|直播|视频号怎么认证开通?|直播|需要什么资质?  c++类和对象到底是什么_c++面向对象编程基础  猫眼app抢票快还是小程序快  windows10怎么关闭自动安装应用_windows10禁止推广应用下载  无人机考证官网 中国民航无人机考证官网登录入口  创客贴登录页面入口 创客贴网页版最新网址链接  Win10如何关闭开机锁屏界面_Windows10跳过锁屏直接登录设置  AngularJS动态内容中DOM元素查找的时序问题及$timeout解决方案  《环球网校》设置报考省市方法  WooCommerce 新客户订单自动添加管理员备注教程  阿里旺旺电脑网页版入口 阿里旺旺电脑版网页登录入口  如何快速去除厨房重油污? 2025年最好用的厨房清洁剂推荐  MongoDB聚合管道:高效统计列表中各项的文档数量  Word 2003字体大小设置方法  家里的小飞虫总是不断,用什么方法可以彻底根除?  在VS Code中利用AI辅助进行代码迁移  使用 .htaccess 正确配置 WordPress 子目录重定向与路径保留  抖音官网入口快速访问 抖音网页版账号注册解析  AO3中文版手机快速通道_AO3最新稳定链接更新  PHP 4 函数中引用参数的默认值限制与解决方案  Dash应用中自定义HTML页面标题与网站图标(F*icon)的实用指南  DeepSeek超全面指南:入门必看  微博网页版访问入口 微博网页版网页端使用指南  可米酷漫画在线阅读入口_ 可米酷漫画官网直达链接  PHP utf8_encode 字符编码转换疑难解析与最佳实践  百度识图图像分析 百度识图识别平台  狙击外星人小游戏在线链接_狙击外星人小游戏网页链接  批改网官网首页登录 批改网学生用户登录入口  服装短视频如何起号推广?服装短视频起号推广有什么要求?  顺丰官方查单号入口 顺丰快递单号查询官网入口  如何修改Windows截图的默认保存位置_告别C盘让桌面更整洁【教程】  如何通过settings.json个性化您的VS Code体验  《雷电模拟器》自动点击设置方法  《杖剑传说》食谱大全  海棠阅读网页版_进入海棠网页版在线阅读中心  谷歌浏览器怎么把网页翻译成中文_Chrome网页翻译功能使用方法  Retrofit根路径POST请求:@POST("/") 的应用与解析  悟空浏览器网页版在线工具 悟空浏览器网页版在线平台入口  漫蛙manwa漫画官网链接_漫蛙manwa最新可用网址推荐 

 2025-12-13

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.