IBM Watson语音到文本API中的1006错误代码

时间:2019-03-18 14:47:52

标签: websocket ibm-watson ratchet

我正在使用Ratchet连接到IBM Watson Websocket,并且对于较小的文件,它似乎总是可以正常工作(我已经测试了长达66分钟的23 MB mp3文件),但是对于较大的文件(例如2小时56 MB 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)  

请注意,在收到第一条“正在监听”消息与关闭连接并出现错误之间的1h13m。

Watson说:“ 1006表示连接异常关闭。”

https://tools.ietf.org/html/rfc6455说:

  

1006是保留值,端点不得在“关闭”控制帧中将其设置为状态代码。它指定用于需要状态代码以指示连接异常关闭的应用程序,例如,没有发送或接收关闭控制帧。

我可以调整代码的哪一部分,以便它可以处理更长的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 个答案:

答案 0 :(得分:1)

作为一般建议,基于文件的识别,尤其是如果文件大于几个MB,应该使用Watson /recognitions API(此处为更多详细信息:https://cloud.ibm.com/apidocs/speech-to-text)来完成,这是异步。您无需将连接保持几个小时的开放时间,这不是一个好习惯,因为您可能会遇到读取超时,网络连接断开等问题。通过异步执行该操作,您可以发布文件,然后连接结束,那么您可以每隔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"

顺便说一句。您的websockets客户端是否使用乒乓框架保持连接活动?我注意到您不要求获得临时结果({"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"}),这是保持连接开放的另一种方法,但可靠性较低。请检查乒乓球框。