Twilio 功能可将未接电话或在办公时间以外接听的电话转移到语音信箱,否则拨打 sip
Twilio Function to divert unanswered calls or calls received outside office hours to voicemail, otherwise dial sip
我的 Twilio 函数部分已经有了这个函数,虽然我不确定我是从某个地方复制粘贴这个函数还是默认:
var moment = require('moment-timezone')
exports.handler = function(context, event, callback) {
let now = moment().tz('Australia/Brisbane');
let isWorkday = (now.isoWeekday() < 6);
let isWorkingHour = (now.hour() > 7 && now.hour() < 17);
let response = {};
if(isWorkday && isWorkingHour) {
callback(null, response);
} else {
callback("Service is closed");
}
};
我还发现了另一个 SO post,其中有人包含一个基本功能,可以在无人接听电话时转移到语音信箱:
exports.handler = function(context, event, callback) {
const twiml = new Twilio.twiml.VoiceResponse();
if (event.DialCallStatus === 'completed' || event.DialCallStatus === 'answered') {
twiml.hangup();
} else {
twiml.say("Service is closed");
twiml.record({
transcribe: true,
transcribeCallback: "http://twimlets.com/voicemail?Email=example@domain.com",
action: "/hangup"
});
}
callback(null, twiml);
};
我想做的基本上是将这两者结合起来:
- 如果在
!isWorkday || !isWorkingHour
处接到电话,则直接发送至语音信箱。根本不要按 phone。
- 如果在
isWorkday && isWorkingHour
处接听电话,那么 运行 像这样的 Twiml bin:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Sip>
me@myuniqueid.sip.us1.twilio.com;region=au1
</Sip>
</Dial>
</Response>
- 如果呼叫在 20 秒内未接听,则发送至语音信箱(使用与步骤 1 不同的问候语)。
奖金问题:我显然还需要能够收听语音邮件,因为我怀疑转录是否会非常准确。在创建新语音邮件时,有什么方法可以在我收到的电子邮件中向语音邮件(或语音邮件 mp3 本身)添加 link 吗?或者我可以为拨出电话创建一个 function/twiml 垃圾箱,让我可以拨打号码并收听我的语音邮件,就像普通语音邮件的工作方式一样吗??
嘿哟,这里是 Twilio 开发者布道师。
我刚刚在单个函数中设置并构建了您的用例。这个函数内部有很多事情要做(我可能建议将工作分成几个函数)。
我也很乐意回答您的额外问题,但请单独打开它以保持此答案的重点。 :)
让我们看一个工作示例!
const moment = require('moment-timezone');
function isServiceOpen() {
let now = moment().tz('Australia/Brisbane');
let isWorkday = now.isoWeekday() < 6;
let isWorkingHour = now.hour() > 7 && now.hour() < 17;
return isWorkday && isWorkingHour;
}
exports.handler = function(context, event, callback) {
const twiml = new Twilio.twiml.VoiceResponse();
console.log(event);
const callIncludesRecording = !!event.RecordingUrl;
const callWasAnswered = event.DialCallStatus === 'completed';
const callWasNotAnswered = event.DialCallStatus === 'no-answer';
const serviceIsOpen = isServiceOpen();
if (callWasAnswered) {
twiml.hangup();
} else if (callIncludesRecording) {
console.log('Call includes recording!');
// do something with the recording URL here
console.log(event.RecordingUrl);
twiml.say("Thank you! We'll come back to you shortly.");
twiml.hangup();
} else if (callWasNotAnswered) {
console.log('Call was not answered...');
twiml.say(
'Unfortunately no one can answer right now. But you can leave a message.'
);
twiml.record({
action: '/handle-call'
});
} else if (!serviceIsOpen) {
console.log('Service is closed...');
twiml.say('Service is closed but you can leave a message');
twiml.record({
action: '/handle-call'
});
} else {
twiml.dial(
{
action: '/handle-call',
method: 'POST',
timeout: 5
},
'+4915...'
);
}
callback(null, twiml);
};
您在上面看到的功能在 /handle-call
端点下可用,并应答所有 webhooks 的调用。
场景 1 - 无人接听电话
在函数末尾,您会看到 dial
function call. The important piece for this case is that dial
supports a timeout
and an action
属性。
twiml.dial(
{
action: '/handle-call',
method: 'POST',
timeout: 30
},
'+49157...'
);
以上内容告诉 Twilio 尝试拨打号码 +49157...
30 秒(实际上接近 35 - 您可以在 the docs 中阅读详细信息)。如果通话结束或在达到超时之前没有人接听电话,Twilio 将要求定义的 action
URL 进行额外的 TwiML 配置。
action
属性中的URL引用相同的函数路径(/handle-call
),同样的函数将再次执行,但这次event
对象将包括 no-answer
的 DialCallStatus
(查看变量 callWasNotAnswered
)。如果电话无人接听,您可以 return TwiML 说一条消息并告诉 API 开始通话录音。
// no one answered – let's record
twiml.say(
'Unfortunately, no one can answer right now. But you can leave a message.'
);
twiml.record({
action: '/handle-call'
});
record
verb also allows an action
attribute 可让您定义录制完成后应请求的 URL(我们将在相同的 /handle-call
端点下再次使用相同的函数)。
对同一个 URL 的调用将在 event
对象中包含一个 RecordingUrl
。如果此 属性 存在,您就知道这是录音的结果。在这个阶段,是时候对录音 URL 做一些事情了(发送一条消息,记录它,......),在说 "goodbye" 之后结束通话并挂断电话。
// do something with the recording URL here
console.log(event.RecordingUrl);
twiml.say("Thank you! We'll come back to you shortly.");
twiml.hangup();
webhook流程如下:
POST
/handle-call
(初始 webhook)-> 拨打 +49157...
POST
/handle-call
(超时后呼叫) -> 说 "unfortunately, ..." & 录音
POST
/handle-call
(录音完成) -> say "thank you" & hangup
场景 2 - 电话在工作时间以外
对于这种情况,我采用了您已经提供的逻辑并创建了一个 isServiceOpen
辅助函数。当在工作时间以外打来电话时,该功能会使用定义消息和录音的 TwiML 进行响应。
twiml.say('Service is closed but you can leave a message');
twiml.record({
action: '/handle-call'
});
录制完成后调用我们的函数(/handle-call
)。这次,请求将包含 RecordingUrl
,处理方式与场景 1 相同(记录录音 URL 和挂断)。
webhook流程如下:
POST
/handle-call
(初始 webhook)-> 说 "service is closed" 并记录
POST
/handle-call
(录音完成) -> say "thank you" & hangup
场景 3 – 电话已接听
如果电话发生在工作时间并且得到足够快的应答,则不需要录音。因为拨号动词包含一个 action
属性(我们在场景 1 中使用了它),所以在通话结束后将发送另一个 webhook。
此 webhook 将包含一个 DialCallStatus
参数和 completed
值。然后是时候结束通话挂断了。
twiml.hangup();
POST
/handle-call
(初始 webhook)-> 拨“+49157...”
POST
/handle-call
(通话结束)-> 挂断
希望以上内容对您有所帮助。正如最初提到的,将功能拆分为 /handle-call
、/handle-recording
和其他功能可能是个好主意。
让我知道这是否有帮助,如果您有任何其他问题。 :)
我的 Twilio 函数部分已经有了这个函数,虽然我不确定我是从某个地方复制粘贴这个函数还是默认:
var moment = require('moment-timezone')
exports.handler = function(context, event, callback) {
let now = moment().tz('Australia/Brisbane');
let isWorkday = (now.isoWeekday() < 6);
let isWorkingHour = (now.hour() > 7 && now.hour() < 17);
let response = {};
if(isWorkday && isWorkingHour) {
callback(null, response);
} else {
callback("Service is closed");
}
};
我还发现了另一个 SO post,其中有人包含一个基本功能,可以在无人接听电话时转移到语音信箱:
exports.handler = function(context, event, callback) {
const twiml = new Twilio.twiml.VoiceResponse();
if (event.DialCallStatus === 'completed' || event.DialCallStatus === 'answered') {
twiml.hangup();
} else {
twiml.say("Service is closed");
twiml.record({
transcribe: true,
transcribeCallback: "http://twimlets.com/voicemail?Email=example@domain.com",
action: "/hangup"
});
}
callback(null, twiml);
};
我想做的基本上是将这两者结合起来:
- 如果在
!isWorkday || !isWorkingHour
处接到电话,则直接发送至语音信箱。根本不要按 phone。 - 如果在
isWorkday && isWorkingHour
处接听电话,那么 运行 像这样的 Twiml bin:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Sip>
me@myuniqueid.sip.us1.twilio.com;region=au1
</Sip>
</Dial>
</Response>
- 如果呼叫在 20 秒内未接听,则发送至语音信箱(使用与步骤 1 不同的问候语)。
奖金问题:我显然还需要能够收听语音邮件,因为我怀疑转录是否会非常准确。在创建新语音邮件时,有什么方法可以在我收到的电子邮件中向语音邮件(或语音邮件 mp3 本身)添加 link 吗?或者我可以为拨出电话创建一个 function/twiml 垃圾箱,让我可以拨打号码并收听我的语音邮件,就像普通语音邮件的工作方式一样吗??
嘿哟,这里是 Twilio 开发者布道师。
我刚刚在单个函数中设置并构建了您的用例。这个函数内部有很多事情要做(我可能建议将工作分成几个函数)。
我也很乐意回答您的额外问题,但请单独打开它以保持此答案的重点。 :)
让我们看一个工作示例!
const moment = require('moment-timezone');
function isServiceOpen() {
let now = moment().tz('Australia/Brisbane');
let isWorkday = now.isoWeekday() < 6;
let isWorkingHour = now.hour() > 7 && now.hour() < 17;
return isWorkday && isWorkingHour;
}
exports.handler = function(context, event, callback) {
const twiml = new Twilio.twiml.VoiceResponse();
console.log(event);
const callIncludesRecording = !!event.RecordingUrl;
const callWasAnswered = event.DialCallStatus === 'completed';
const callWasNotAnswered = event.DialCallStatus === 'no-answer';
const serviceIsOpen = isServiceOpen();
if (callWasAnswered) {
twiml.hangup();
} else if (callIncludesRecording) {
console.log('Call includes recording!');
// do something with the recording URL here
console.log(event.RecordingUrl);
twiml.say("Thank you! We'll come back to you shortly.");
twiml.hangup();
} else if (callWasNotAnswered) {
console.log('Call was not answered...');
twiml.say(
'Unfortunately no one can answer right now. But you can leave a message.'
);
twiml.record({
action: '/handle-call'
});
} else if (!serviceIsOpen) {
console.log('Service is closed...');
twiml.say('Service is closed but you can leave a message');
twiml.record({
action: '/handle-call'
});
} else {
twiml.dial(
{
action: '/handle-call',
method: 'POST',
timeout: 5
},
'+4915...'
);
}
callback(null, twiml);
};
您在上面看到的功能在 /handle-call
端点下可用,并应答所有 webhooks 的调用。
场景 1 - 无人接听电话
在函数末尾,您会看到 dial
function call. The important piece for this case is that dial
supports a timeout
and an action
属性。
twiml.dial(
{
action: '/handle-call',
method: 'POST',
timeout: 30
},
'+49157...'
);
以上内容告诉 Twilio 尝试拨打号码 +49157...
30 秒(实际上接近 35 - 您可以在 the docs 中阅读详细信息)。如果通话结束或在达到超时之前没有人接听电话,Twilio 将要求定义的 action
URL 进行额外的 TwiML 配置。
action
属性中的URL引用相同的函数路径(/handle-call
),同样的函数将再次执行,但这次event
对象将包括 no-answer
的 DialCallStatus
(查看变量 callWasNotAnswered
)。如果电话无人接听,您可以 return TwiML 说一条消息并告诉 API 开始通话录音。
// no one answered – let's record
twiml.say(
'Unfortunately, no one can answer right now. But you can leave a message.'
);
twiml.record({
action: '/handle-call'
});
record
verb also allows an action
attribute 可让您定义录制完成后应请求的 URL(我们将在相同的 /handle-call
端点下再次使用相同的函数)。
对同一个 URL 的调用将在 event
对象中包含一个 RecordingUrl
。如果此 属性 存在,您就知道这是录音的结果。在这个阶段,是时候对录音 URL 做一些事情了(发送一条消息,记录它,......),在说 "goodbye" 之后结束通话并挂断电话。
// do something with the recording URL here
console.log(event.RecordingUrl);
twiml.say("Thank you! We'll come back to you shortly.");
twiml.hangup();
webhook流程如下:
POST
/handle-call
(初始 webhook)-> 拨打 +49157...POST
/handle-call
(超时后呼叫) -> 说 "unfortunately, ..." & 录音POST
/handle-call
(录音完成) -> say "thank you" & hangup
场景 2 - 电话在工作时间以外
对于这种情况,我采用了您已经提供的逻辑并创建了一个 isServiceOpen
辅助函数。当在工作时间以外打来电话时,该功能会使用定义消息和录音的 TwiML 进行响应。
twiml.say('Service is closed but you can leave a message');
twiml.record({
action: '/handle-call'
});
录制完成后调用我们的函数(/handle-call
)。这次,请求将包含 RecordingUrl
,处理方式与场景 1 相同(记录录音 URL 和挂断)。
webhook流程如下:
POST
/handle-call
(初始 webhook)-> 说 "service is closed" 并记录POST
/handle-call
(录音完成) -> say "thank you" & hangup
场景 3 – 电话已接听
如果电话发生在工作时间并且得到足够快的应答,则不需要录音。因为拨号动词包含一个 action
属性(我们在场景 1 中使用了它),所以在通话结束后将发送另一个 webhook。
此 webhook 将包含一个 DialCallStatus
参数和 completed
值。然后是时候结束通话挂断了。
twiml.hangup();
POST
/handle-call
(初始 webhook)-> 拨“+49157...”POST
/handle-call
(通话结束)-> 挂断
希望以上内容对您有所帮助。正如最初提到的,将功能拆分为 /handle-call
、/handle-recording
和其他功能可能是个好主意。
让我知道这是否有帮助,如果您有任何其他问题。 :)