我通过从 Twilio 下载文件作为 PCM 并稍微更改我的参数来解决这个问题。另外,由于 Twilio 处理记录动词的方式,我需要在等待记录状态回调 POST 时将呼叫转移到保持状态。我还向呼叫者发送一条短信,其中包含 Lex 的最终状态。
我用来下载文件的代码:
app.post('/processRecording', (request, response) => {
var https = require('https');
var fs = require('fs');
let callSID = request.body.CallSid;
let url = request.body.RecordingUrl;
var saveFile = new Promise(function(resolve, reject) {
let fileName = callSID+ ".pcm";
var file = fs.createWriteStream(fileName);
var request = https.get(url, function(response) {
response.pipe(file);
resolve();
});
});
});
const accountSid = 'YOUR ACCOUNT SID';
const authToken = 'YOUR AUTH TOKEN';
const client = require('twilio')(accountSid, authToken);
//Once the file is downloaded, I then fetch the call from the hold state using this code:
saveFile.then(function(){
client.calls(callSID)
.update({method: 'POST', url: '/updateCall'})
.then(call => console.log(call.to))
.done();
});
我的 updateCall 端点如下所示:
app.post('/updateCall', (request, response) => {
let lexruntime = new AWS.LexRuntime();
let recordedFileName = request.body.CallSid + '.pcm';
let toNumber = request.body.To;
let fromNumber = request.body.From;
let twiml = new Twilio.twiml.VoiceResponse();
let lexFileStream = fs.createReadStream(recordedFileName);
let sid = request.body.CallSid;
var params = {
botAlias: 'prod', /* required */
botName: 'OrderFlowers', /* required */
contentType: 'audio/lpcm; sample-rate=8000; sample-size-bits=16; channel-count=1; is-big-endian=false',
accept: 'text/plain; charset=utf-8',
userId: sid /* required */
};
params.inputStream = lexFileStream;
lexruntime.postContent(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
if (data.dialogState == "ElicitSlot" || data.dialogState == "ConfirmIntent" || data.dialogState == "ElicitIntent" ){
twiml.say(data.message);
twiml.redirect({
method: 'POST'
}, '/recordVoice');
response.type('text/xml');
response.send(twiml.toString());
}
else if (data.dialogState == "Fulfilled" ){
twiml.say(data.message);
response.type('text/xml');
response.send(twiml.toString());
client.messages.create({
to: toNumber,
from: fromNumber,
body: data.message
}).then(msg => {
}).catch(err => console.log(err));
}
else{
twiml.say(data.message);
response.type('text/xml');
response.send(twiml.toString());
}
});
});
recordVoice 端点实际上是一个 Twilio Serverless 函数,但我认为这就是它作为快速端点的样子:
app.post('/recordVoice', (request, response) => {
let twiml = new Twilio.twiml.VoiceResponse();
twiml.record({
action: '/deadAir',
recordingStatusCallback: '/processRecording',
trim: true,
maxLength: 10,
finishOnKey: '*'
});
twiml.say('I did not receive a recording');
response.type('text/xml');
response.send(twiml.toString());
});
/deadAir 端点也是一个 Twilio Serverless Function,但它看起来像这样:
app.post('/deadAir', (request, response) => {
let twiml = new Twilio.twiml.VoiceResponse();
twiml.pause({
length: 60
});
response.type('text/xml');
response.send(twiml.toString());
});