1006 Код ошибки в текстовом API IBM Watson - PullRequest
0 голосов
/ 18 марта 2019

Я использую Ratchet для подключения к веб-сокетам IBM Watson, и кажется, что он всегда работает нормально для небольших файлов (я тестировал до 66-минутного файла MP3 размером 23 МБ), но он всегда терпит неудачу для большие файлы (например, 2 часа 56 МБ mp3).

Это мой журнал:

[2019-03-17 21:43:23] local.DEBUG: \Ratchet\Client\connect bf4e38983775f6e53b392666138b5a3a50e9c9c8  
[2019-03-17 21:43:24] local.DEBUG: startWatsonStream options = {"content-type":"audio\/mpeg","timestamps":true,"speaker_labels":true,"smart_formatting":true,"inactivity_timeout":-1,"interim_results":false,"max_alternatives":1,"word_confidence":false,"action":"start"}  
[2019-03-17 21:43:24] local.DEBUG: Split audio into this many frames: 570222  
[2019-03-17 21:43:42] local.DEBUG: send action stop  
[2019-03-17 21:43:42] local.DEBUG: Received: {
   "state": "listening"
}  
[2019-03-17 21:43:42] local.DEBUG: Received first 'listening' message.  
[2019-03-17 22:56:31] local.DEBUG: Connection closed (1006 - Underlying connection closed)  

Обратите внимание на 1 ч 13 м между получением первого «прослушивающего» сообщения и последующим закрытием соединения с ошибкой.

Ватсон говорит: «1006 указывает, что соединение закрыто ненормально».

https://tools.ietf.org/html/rfc6455 говорит:

1006 является зарезервированным значением и НЕ ДОЛЖНО быть установлено конечным пунктом как код состояния в кадре управления Close. Он предназначен для использования в приложениях, ожидающих, что код состояния указывает на ненормальное закрытие соединения, например, без отправки или получения кадра управления Close.

Какую часть моего кода я могу настроить, чтобы он мог обрабатывать более длинные mp3-файлы, не выдавая ошибку 1006?

\Ratchet\Client\connect($url, [], $headers)->then(function(\Ratchet\Client\WebSocket $conn) use($contentType, $audioFileContents, $callback) {
    $conn->on('message', function($msg) use ($conn, $callback) {
        $this->handleIncomingWebSocketMessage($msg, $conn, $callback);
    });
    $conn->on('close', function($code = null, $reason = null) {
        Log::debug("Connection closed ({$code} - {$reason})");
    });
    $this->startWatsonStream($conn, $contentType);
    $this->sendBinaryMessage($conn, $audioFileContents); 
    Log::debug('send action stop');
    $conn->send(json_encode(['action' => 'stop']));
}, function (\Exception $e) {
    Log::error("Could not connect: {$e->getMessage()} " . $e->getTraceAsString());
});

...

public function handleIncomingWebSocketMessage($msg, $conn, $callback) {
    Log::debug("Received: " . str_limit($msg, 100));
    $msgArray = json_decode($msg, true);
    $state = $msgArray['state'] ?? null;
    if ($state == 'listening') {
        if ($this->listening) {//then this is the 2nd time listening, which means audio processing has finished and has already been sent by server and received by this client.
            Log::debug("FINAL RESPONSE: " . str_limit($this->responseJson, 500));
            $conn->close(\Ratchet\RFC6455\Messaging\Frame::CLOSE_NORMAL, 'Finished.'); 
            $callback($this->responseJson);
        } else {
            $this->listening = true;
            Log::debug("Received first 'listening' message.");
        }
    } else {
        $this->responseJson = $msg;
    }
}

public function sendBinaryMessage($conn, $fileContents) {
    $chunkSizeInBytes = 100; //probably just needs to be <= 4 MB according to Watson's rules
    $chunks = str_split($fileContents, $chunkSizeInBytes);
    Log::debug('Split audio into this many frames: ' . count($chunks));
    $final = true;
    foreach ($chunks as $key => $chunk) {
        $frame = new \Ratchet\RFC6455\Messaging\Frame($chunk, $final, \Ratchet\RFC6455\Messaging\Frame::OP_BINARY);
        $conn->send($frame);
    }

}

1 Ответ

1 голос
/ 30 марта 2019

Как общая рекомендация, распознавание файлов, особенно если файлы имеют размер более нескольких МБ, должно выполняться с использованием API Watson /recognitions (подробнее здесь: https://cloud.ibm.com/apidocs/speech-to-text),, который является асинхронным. Вы не нужно держать соединение открытым в течение нескольких часов, это не очень хорошая практика, так как вы можете столкнуться с тайм-аутом чтения, вы можете потерять сетевое соединение и т. д. Делая это асинхронно, вы POST-файл и затем соединение заканчивается, затем вы можете получать статус каждые X минут или получать уведомления с помощью обратного вызова, что бы вам ни помогло.

curl -X POST -u "apikey:{apikey}" --header "Content-Type: audio/flac" --data-binary @audio-file.flac "https://stream.watsonplatform.net/speech-to-text/api/v1/recognitions?callback_url=http://{user_callback_path}/job_results&user_token=job25&timestamps=true"

кстати. Ваш клиент веб-сокетов использует фреймы для пинг-понга, чтобы поддерживать живые соединения? Я заметил, что вы не запрашиваете промежуточные результаты ({"content-type":"audio\/mpeg","timestamps":true,"speaker_labels":true,"smart_formatting":true,"inactivity_timeout":-1,"interim_results":false,"max_alternatives":1,"word_confidence":false,"action":"start"}), это еще один способ сохранить соединение открытым, но менее надежный. Пожалуйста, проверьте рамки для пинг-понга.

...