Постоянная высокая задержка 21 с при первом запросе к диалоговому потоку - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть настройка диалогового потока на Raspberry Pi для голосового помощника, и пока вся система работает, я сталкиваюсь с необычной проблемой.

Детали среды
  • ОС: Raspbian Stretch - Raspberry Pi 3B +
  • Node.js версия: 8.15.0
  • npm версия: 5.6.0
  • dialogflow версия: 0.8.0

Когда я изначальнозагрузите систему и отправьте аудиопоток с микрофона в диалоговое окно для обработки в реальном времени; результат возвращается через ~ 21 секунду.Последующие аудио-запросы возвращаются правильно в течение 1-2 секунд.Это поведение также появляется после определенного периода бездействия, т. Е. Если система уже запущена, и я не делаю голосовой запрос в течение ~ 3-5 минут.

Кроме того, задержка первого ответа последовательно воспроизводится вплоть домиллисекунда почти!Я добавил время, чтобы убедиться в этом.Изображение показывает, что первый ответ (красные стрелки) последовательно занимает 21.xx секунд, чтобы вернуться.Последующие ответы находятся в диапазоне 1-2 с.

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

Я принудительно закрываю поток через 4000 мс.Интересно то, что во время моей регистрации, когда поток принудительно отключен, событие unpipe запускается, но событие finish не запускается сразу, даже если .end() правильно вызывается в потоке в событии unpipeобработчик.Это происходит только при первом запросе или после периода бездействия, а событие финиша срабатывает только после того, как диалоговое окно отправит результат обратно через ~ 21 секунду.Это как если бы поток принудительно оставался открытым и вызов .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)

Примечание: это поведение болеепроизносится на пи.21-секундная задержка, кажется, происходит на Пи.Хотя на моем Mac такое же поведение, задержка ответа после первого запроса намного меньше (~ 7 секунд).Нет проблем с сетевым подключением, потому что результат всегда возвращается, сразу после огромного разрыва.Я также пытался с другим подключением к Интернету.Эта проблема также возникает, когда я просто использую облачную речь Google.

Чтобы проверить, была ли это какая-то проблема с потоками, я создал фиктивный поток, в котором просто выводил запись с микрофона в файл .wav.Это работало нормально, и на этот раз .end () вызывается немедленно и правильно из события unpipe.Я пошел на шаг дальше и направил этот WAV-файл в диалоговый поток, а не из микрофона, и затем поведение вернулось!21.xx секунд !!!

Я также прилагаю GIF журнала.Если вы посмотрите все это (в середине длинный промежуток, продолжайте смотреть :)), вы увидите проблему, о которой я говорю.Как вы увидите, первый результат занимает много времени, а последующие запросы возвращаются мгновенно.

dialogflow

Любая помощь будет принята с благодарностью!Это сводит меня с ума!

...