对对话框流的第一次查询始终保持21秒的高延迟

时间:2019-02-26 14:42:56

标签: node.js raspberry-pi dialogflow google-cloud-speech

我在树莓派上为语音助手设置了对话流,而在整个系统运行时,我遇到了一个异常问题。

环境细节
  • 操作系统:Raspbian Stretch-Raspberry Pi 3B +
  • Node.js版本:8.15.0
  • npm版本:5.6.0
  • dialogflow版本:0.8.0

当我最初启动系统并将音频流从麦克风发送到dialogflow进行实时处理时,它会在约21秒后返回结果。发送的后续音频请求将在1-2秒内正确返回。一段时间不活动后,即系统已经在运行,并且在大约3-5分钟内我没有发出语音请求,这种现象也会再次出现。

第一个响应的延迟几乎一直持续到毫秒!我添加了一些时间来确定这一点。该图像显示第一个响应(红色箭头)始终需要21.xx秒才能返回。随后的响应在1-2秒范围内。

screen shot 2019-02-26 at 12 07 49 am

我在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图像。如果您观看整个内容(中间有很长的空隙,请继续观看:)),您会看到我在说的问题。如您所见,第一个结果需要很长时间才能返回,而随后的查询会立即返回。

dialogflow

任何帮助将不胜感激!这让我发疯了!

0 个答案:

没有答案