目前我要重写一个从Python到PHP的简单代码。此代码用于使用ProtoBuf和gRPC向Yandex Cloud(语音工具包)发出请求。
在Python(v3)上一切正常。
然后,我想在PHP(MacOS上的7.1.23)中使用相同的内容。我使用protoc
编译Protobuf和grpc php插件来获取服务客户端。
我面临的第一个复杂因素是客户端的方法接口是SttServiceClient->StreamingRecognize(array metadata[], array options=[])
,这是相当混乱的,因为我认为它应该接受StreamingRecognitionRequest
。
第二个是我收到异常InvalidArgumentException:给出错误的元数据值:
PHP Fatal error: Uncaught InvalidArgumentException: Bad metadata value given in /Users/cyberpug/Documents/repos/php/yaskit/vendor/grpc/grpc/src/lib/BidiStreamingCall.php:37
Stack trace:
#0 /Users/cyberpug/Documents/repos/php/yaskit/vendor/grpc/grpc/src/lib/BidiStreamingCall.php(37): Grpc\Call->startBatch(Array)
#1 /Users/cyberpug/Documents/repos/php/yaskit/vendor/grpc/grpc/src/lib/BaseStub.php(384): Grpc\BidiStreamingCall->start(Array)
#2 /Users/cyberpug/Documents/repos/php/yaskit/vendor/grpc/grpc/src/lib/BaseStub.php(595): Grpc\BaseStub->Grpc\{closure}('/yandex.cloud.a...', Array, Array, Array)
#3 /Users/cyberpug/Documents/repos/php/yaskit/STT/proto/Yandex/Cloud/Ai/Stt/V2/SttServiceClient.php(26): Grpc\BaseStub->_bidiRequest('/yandex.cloud.a...', Array, Array, Array)
#4 /Users/cyberpug/Documents/repos/php/yaskit/test.php(83): Yandex\Cloud\Ai\Stt\V2\SttServiceClient->StreamingRecognize(Array, Array)
#5 {main}
thrown in /Users/cyberpug/Documents/repos/php/yaskit/vendor/grpc/grpc/src/lib/BidiStreamingCall.php on line 37
好吧,我在这里无能为力。我无法理解为什么会这样(一个不期望的客户端界面)以及为什么会发生这样的错误?今天我读了很多关于Protobuf和gRPC的事情都无济于事!
这是Python上的代码(v3):
class Yandex:
def __init__(self, **kwargs):
self._host = kwargs["url"]
self._credentials = grpc.ssl_channel_credentials()
self._iamToken = kwargs["iamToken"]
spec = stt_service_pb2.RecognitionSpec(
language_code=kwargs["lang"],
profanity_filter=kwargs["profanityFilter"],
model=kwargs["model"],
partial_results=kwargs["partialResults"],
audio_encoding=kwargs["audioEncoding"],
sample_rate_hertz=kwargs["sampleRateHertz"]
)
self._config = stt_service_pb2.RecognitionConfig(
specification=spec,
folder_id=kwargs["folderId"]
)
def _createStub(self):
return stt_service_pb2_grpc.SttServiceStub(
channel=grpc.secure_channel(
self._host,
self._credentials
)
)
def _createHandshake(self):
return stt_service_pb2.StreamingRecognitionRequest(
config=self._config
)
def _createRequest(self, data):
return stt_service_pb2.StreamingRecognitionRequest(
audio_content=data
)
def _wrap(self, method):
yield self._createHandshake()
for chunk in method():
yield self._createRequest(chunk)
def stream(self, method):
stub = self._createStub()
return stub.StreamingRecognize(
self._wrap(method),
metadata=(('authorization', 'Bearer %s' %
self._iamToken),)
)
这是我的PHP代码,我尝试过:
#!/usr/bin/env php
<?php
namespace yaskit;
require "Configuration.php";
use Yaskit\Settings;
use Yaskit\TokenManager;
use \Yandex\Cloud\Ai\Stt\V2\RecognitionConfig;
use \Yandex\Cloud\Ai\Stt\V2\RecognitionSpec;
use \Yandex\Cloud\Ai\Stt\V2\RecognitionSpec\AudioEncoding;
use \Yandex\Cloud\Ai\Stt\V2\StreamingRecognitionRequest;
use \Yandex\Cloud\Ai\Stt\V2\SttServiceClient;
$auth_set = new Settings();
$app_set = new Settings();
$auth_set->load("settings.auth.json");
$app_set->load("settings.speech-to-text.json");
$mgr = new TokenManager("private-test.pem");
$mgr->useLogger($app->createLogger(TokenManager::class));
$mgr->validate($auth_set);
$url = "stt.api.cloud.yandex.net:443";
$iam = $auth_set["iam-token"];
$raw_req = array(
"config" => array(
"specification" => array(
"sample_rate_hertz" => $app_set["sample-rate-hertz"],
"language_code" => $app_set["lang"],
"profanity_filter" => $app_set["profanity-filter"],
"model" => $app_set["model"],
"partial_results" => $app_set["partial-results"],
"audio_encoding" => AudioEncoding::LINEAR16_PCM,
),
"folder_id" => $auth_set["folder-id"],
),
);
$spec = new RecognitionSpec(array(
"sample_rate_hertz" => $app_set["sample-rate-hertz"],
"language_code" => $app_set["lang"],
"profanity_filter" => $app_set["profanity-filter"],
"model" => $app_set["model"],
"partial_results" => $app_set["partial-results"],
"audio_encoding" => AudioEncoding::LINEAR16_PCM,
));
$config = new RecognitionConfig(array(
"specification" => $spec,
"folder_id" => $auth_set["folder-id"],
));
$req = new StreamingRecognitionRequest(array(
"config" => $config,
));
$service = new SttServiceClient($url, [
"credentials" => \Grpc\ChannelCredentials::createSsl(),
]);
$res = $service->StreamingRecognize(["authorization" => "Bearer $iam"], $raw_req);
我不知道我应该在这里发布哪些编译文件(因为有很多),所以我只发布Service Client和raw protobuf本身。如果需要我会发布更多。
SttServiceClient:
<?php
// GENERATED CODE -- DO NOT EDIT!
namespace Yandex\Cloud\Ai\Stt\V2;
/**
*/
class SttServiceClient extends \Grpc\BaseStub {
/**
* @param string $hostname hostname
* @param array $opts channel options
* @param \Grpc\Channel $channel (optional) re-use channel object
*/
public function __construct($hostname, $opts, $channel = null) {
parent::__construct($hostname, $opts, $channel);
}
/**
* @param array $metadata metadata
* @param array $options call options
*/
public function StreamingRecognize($metadata = [], $options = []) {
return $this->_bidiRequest('/yandex.cloud.ai.stt.v2.SttService/StreamingRecognize',
['\Yandex\Cloud\Ai\Stt\V2\StreamingRecognitionResponse','decode'],
$metadata, $options);
}
}
原始protobuf:
syntax = "proto3";
package yandex.cloud.ai.stt.v2;
option go_package = "github.com/yandex-cloud/go-genproto/yandex/cloud/ai/stt/v2;stt";
service SttService {
rpc StreamingRecognize (stream StreamingRecognitionRequest) returns (stream StreamingRecognitionResponse) {
}
}
message StreamingRecognitionRequest {
oneof streaming_request {
RecognitionConfig config = 1;
bytes audio_content = 2;
}
}
message RecognitionConfig {
RecognitionSpec specification = 1;
string folder_id = 2;
}
message RecognitionSpec {
enum AudioEncoding {
AUDIO_ENCODING_UNSPECIFIED = 0;
// 16-bit signed little-endian (Linear PCM)
LINEAR16_PCM = 1;
OGG_OPUS = 2;
}
AudioEncoding audio_encoding = 1;
// 8000, 16000, 48000 only for pcm
int64 sample_rate_hertz = 2;
// code in BCP-47
string language_code = 3;
bool profanity_filter = 4;
string model = 5;
// If set true, tentative hypotheses may be returned as they become available (final=false flag)
// If false or omitted, only final=true result(s) are returned.
bool partial_results = 7;
bool single_utterance = 8;
}
message StreamingRecognitionResponse {
repeated SpeechRecognitionChunk chunks = 1;
bool end_of_single_utterance = 2;
}
message SpeechRecognitionChunk {
repeated SpeechRecognitionAlternative alternatives = 1;
bool final = 2;
}
message SpeechRecognitionAlternative {
string text = 1;
float confidence = 2;
}
似乎元数据是数组(key => array())。示例:https://github.com/grpc/grpc/blob/master/src/php/tests/interop/interop_client.php#L416-L419
$res = $service->StreamingRecognize(["authorization" => ["Bearer $iam"]], $raw_req);