我在树莓派上为语音助手设置了对话流,而在整个系统运行时,我遇到了一个异常问题。
环境细节dialogflow
版本:0.8.0 当我最初启动系统并将音频流从麦克风发送到dialogflow进行实时处理时,它会在约21秒后返回结果。发送的后续音频请求将在1-2秒内正确返回。一段时间不活动后,即系统已经在运行,并且在大约3-5分钟内我没有发出语音请求,这种现象也会再次出现。
第一个响应的延迟几乎一直持续到毫秒!我添加了一些时间来确定这一点。该图像显示第一个响应(红色箭头)始终需要21.xx秒才能返回。随后的响应在1-2秒范围内。
我在4000毫秒后强行关闭流。有趣的是,在日志记录期间,当强行取消流传输时,会触发unpipe
事件,但是即使在流上正确调用finish
也会立即触发.end()
事件在unpipe
事件处理程序中。这仅在第一个请求上发生,或者在一段时间不活动之后发生,并且仅当dialogflow在约21秒后将结果发送回时才触发finish事件。好像流被强制保持打开状态并对其调用.end()毫无作用。
这是我的代码:
const record = require('node-record-lpcm16')
const path = require('path')
const os = require('os')
const config = require(path.join(process.cwd(),"app","config","config"))
var FileWriter = require('wav').FileWriter
// SNOWBOY WAKEWORD DETECTOR
const Detector = require('snowboy').Detector;
const Models = require('snowboy').Models;
const through2 = require('through2')
const models = new Models();
var fs = require('fs')
models.add({
file: path.join(process.cwd(), 'app','config', config.speech.model),
sensitivity: config.speech.sensitivity,
hotwords: 'peeqo'
})
const snowboyDetector = new Detector({
resource: path.join(process.cwd(), 'app','config', 'common.res'),
models: models,
audioGain: 2.0
})
const snowboyOn = true
// NODE RECORD
var recorder = (os.arch()=='arm')?'arecord':'rec'
const opts = {
verbose: false,
threshold: 0,
recordProgram: recorder,
sampleRateHertz: 16000
}
const dialogflow = require('dialogflow')
const speech = new dialogflow.SessionsClient({
projectId: config.speech.projectId,
keyFilename: path.join(process.cwd(), 'app','config', config.speech.dialogflowKey)
})
const sessionPath = speech.sessionPath(config.speech.projectId, "test-app")
const request = {
session: sessionPath,
queryParams: {
session: speech.sessionPath(config.speech.projectId, "test-app")
},
queryInput:{
audioConfig:{
audioEncoding: "AUDIO_ENCODING_LINEAR_16",
sampleRateHertz: 16000,
languageCode: 'en-US'
}
},
singleUtterance: true,
interimResults: true
}
// DIALOGFLOW CLASS
class GoogleSpeech {
constructor(request){
this.request = request
this.stream = speech.streamingDetectIntent()
this.result = ''
this.unpipeTimeout = null
this.listenFor = 4000 //cut off stream after this duration
this.stream.write(this.request)
}
startStream(){
var self = this
this.stream.on('pipe', function(){
console.log('PIPING > GOOGLE')
self.unpipeTimeout = setTimeout(()=>{
// cut off listening since time limit exceeded
console.log("UNPIPING GOOGLE MYSELF")
self.unpipeTimeout = null
tstream.unpipe(self.stream)
mic.unpipe(tstream)
}, self.listenFor)
})
this.stream.on('error', function(err){
console.error('ERROR > GOOGLE', err)
})
this.stream.on('close', function(){
console.log('GOOGLE PIPE > CLOSED')
})
this.stream.on('data', function(data){
if(data.recognitionResult){
console.log(`Interim result: ${data.recognitionResult.transcript}`)
}
if(data.queryResult != null){
self.result = data.queryResult.queryText
tstream.unpipe(self.stream)
mic.unpipe(tstream)
}
})
this.stream.on('unpipe', function(src){
console.log('UNPIPING > GOOGLE')
tstream.end()
self.stream.end()
})
this.stream.on('finish', function(){
console.log('FINISHED > GOOGLE')
if(self.unpipeTimeout != null){
// clear timer if it is running but result has returned already
clearTimeout(self.unpipeTimeout)
self.unpipeTimeout = null
console.log("CLEARING TIMEOUT > RESULT RETURNED")
}
if(self.result){
console.log(`RESULT: ${self.result}`)
}
// pipe back to snowboy for hotword detection
mic.pipe(snowboyDetector)
})
var tstream = through2.obj((obj,_,next) => {
next(null, {inputAudio: obj})
})
// pipe to dialogflow
mic
.pipe(tstream)
.pipe(this.stream)
}
}
// SNOWBOY EVENTS
snowboyDetector.on('unpipe', function(src){
console.log('STOPPED PIPING > SNOWBOY')
})
snowboyDetector.on('pipe', function(src){
console.log('PIPING > SNOWBOY')
})
// EVENT ON WAKEWORD DETECTION
snowboyDetector.on('hotword', function(index, hotword){
// unpipe stream from hotword detection
// and pipe to dialogflow
mic.unpipe(snowboyDetector)
// pass in request config
const gNew = new GoogleSpeech(request)
gNew.startStream()
})
const mic = record.start(opts)
// START LISTENING FOR HOTWORD
mic.pipe(snowboyDetector)
请注意:这种行为在pi上更为明显。 Pi似乎正在发生21秒的延迟。尽管我的Mac上表现出相同的行为,但第一个查询后的响应延迟要少得多(〜7秒)。没有网络连接问题,因为总是在巨大的差距之后才返回结果。我也尝试过使用其他互联网连接。当我只使用Google Cloud Speech时也会发生此问题。
要检查流是否存在某种问题,我创建了一个虚拟流,在其中我只将麦克风录音输出到.wav文件。这工作正常,这次从unpipe事件中立即正确调用了.end()。我又走了一步,将这个.wav文件流式传输到了dialogflow,而不是从麦克风流式传输,然后行为返回了! 21.xx秒!
我还附上了日志记录的gif图像。如果您观看整个内容(中间有很长的空隙,请继续观看:)),您会看到我在说的问题。如您所见,第一个结果需要很长时间才能返回,而随后的查询会立即返回。
任何帮助将不胜感激!这让我发疯了!