0

0

Twilio匿名呼叫转接:未接来电自动转语音留言实现指南

聖光之護

聖光之護

发布时间:2025-12-07 23:52:02

|

234人浏览过

|

来源于php中文网

原创

twilio匿名呼叫转接:未接来电自动转语音留言实现指南

本教程详细指导如何利用Twilio构建一个匿名电话呼叫转接系统,并实现未接来电自动转语音留言功能。当客户拨打匿名号码,呼叫被转接至用户真实号码后,若用户未接听,系统将引导客户录制语音留言。文章将涵盖Twilio TwiML的Dial动词超时配置、Record动词的使用,以及如何处理录音回调、存储留言并进行语音转文本处理及邮件通知。

1. 引言

在构建基于Twilio的通信应用时,实现匿名呼叫转接是常见的需求。例如,当客户拨打一个由平台提供的匿名号码时,该呼叫会被转接到用户真实的手机号码。然而,如果用户因各种原因(如忙线、未接听、无法接通)未能接听电话,如何确保客户能够留下重要的信息?本教程将详细介绍如何利用Twilio的TwiML(Twilio Markup Language)功能,为未接来电自动启用语音留言系统,并将留言内容(包括语音文件和转录文本)通过邮件发送给用户。

2. 理解Twilio TwiML与呼叫流程

Twilio TwiML是一种XML方言,用于指示Twilio如何处理呼叫和短信。通过在您的服务器上响应Twilio Webhook请求时返回TwiML指令,您可以完全控制呼叫流程。

实现匿名呼叫转接和语音留言的理想流程如下:

Chaos® Vantage
Chaos® Vantage

用实时光线追踪探索您的最复杂的3D场景。

下载
  1. 客户拨打匿名号码: 客户拨打由Twilio分配给用户的匿名号码。
  2. Twilio发送Webhook请求: Twilio向您预先配置的Webhook URL发送HTTP请求,告知有新的来电。
  3. 应用处理请求: 您的应用程序接收请求,识别匿名号码对应的用户及其真实号码。
  4. 呼叫转接: 应用程序生成包含Dial(拨号)动词的TwiML响应,尝试将呼叫转接到用户的真实号码。
  5. 超时或未接听处理: 如果用户在预设时间内未接听,或者电话忙线/无法接通,Dial动词将超时。
  6. 语音留言引导: 应用程序在Dial动词之后,通过Say(说话)和Record(录音)动词引导客户录制语音留言。
  7. 录音完成回调: 客户完成录音后,Twilio将录音文件存储起来,并向您配置的recordingStatusCallback URL发送另一个Webhook请求。
  8. 存储与通知: 您的应用程序接收录音回调,将录音信息(如URL)存储到数据库,并利用Twilio的语音转文本API(或已转录文本)通过邮件通知用户。

3. 实现呼叫转接与语音留言逻辑

我们将基于一个现有的Node.js Express应用示例进行修改,重点关注webhook/voice端点和新增的webhook/voicemail-callback端点。

3.1 配置呼叫转接与超时处理

Dial动词是Twilio TwiML中用于将当前呼叫连接到另一个号码的关键。其timeout属性允许您指定Twilio在放弃尝试连接被叫方之前等待的最大秒数。关键在于,如果Dial动词在未指定action属性的情况下超时或失败,Twilio会继续执行其TwiML响应中的下一个指令。这正是我们实现语音留言的入口点。

示例代码:修改 /webhook/voice 端点

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

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

// 模拟数据库操作和邮件发送函数
async function getNumberWithoutUser(maskedNumber) {
    // 模拟从数据库获取号码信息
    if (maskedNumber === "+1234567890") { // 假设这是匿名号码
        return [{
            _id: "user123",
            numbers: {
                subscriptions: [{ active: true, type: "premium" }],
                settings: {
                    forwarding: { toPrimaryPhone: true, primaryPhoneNumber: "+1987654321" }, // 真实号码
                    emailForVoicemail: "user@example.com" // 接收语音留言的邮箱
                }
            }
        }];
    }
    return [null];
}

async function updateQuota(userId, maskedNumber, type, subscriptionType) {
    console.log(`Updating quota for user ${userId} for masked number ${maskedNumber}, type: ${type}, subscription: ${subscriptionType}`);
    // 实际的配额更新逻辑
}

async function appendCall(userId, to, from, callDetails) {
    console.log(`Appending call record for user ${userId}: From ${from} to ${to}`);
    // 实际的通话记录存储逻辑
}

async function sendMessageNotificationEmail(toEmail, subject, body) {
    console.log(`Sending email to ${toEmail} with subject: "${subject}"`);
    // 实际的邮件发送逻辑
}


router.post("/webhook/voice", async (req, res) => {
    const { To, From, CallStatus } = req.body;
    console.log(`Incoming call status: ${CallStatus}, From: ${From}, To: ${To}`);

    const [numbers] = await getNumberWithoutUser(To);

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

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

    if (isToPrimaryPhone && primaryPhoneNumber) {
        const twiml = new twilio.twiml.VoiceResponse();
        if (CallStatus === "ringing") {
            // 播放欢迎语(可选),使用中文女声
            twiml.say({ voice: 'woman', language: 'zh-CN' }, "您好,正在为您转接,请稍候。");

            // 尝试拨打用户真实号码,设置7

相关专题

更多
pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1885

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2087

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

1017

2024.11.28

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

510

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

244

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

258

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5282

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

477

2023.09.01

PHP WebSocket 实时通信开发
PHP WebSocket 实时通信开发

本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

10

2026.01.19

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.4万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

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

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