gRPC 给定 PHP 的错误元数据
Posted
技术标签:
【中文标题】gRPC 给定 PHP 的错误元数据【英文标题】:gRPC Bad metadata given PHP 【发布时间】:2019-03-01 08:42:28 【问题描述】:目前我正准备将一个简单的代码从 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: Bad metadata value given:
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;
【问题讨论】:
【参考方案1】:似乎元数据是数组(键=>数组())。例子: https://github.com/grpc/grpc/blob/master/src/php/tests/interop/interop_client.php#L416-L419
$res = $service->StreamingRecognize(["authorization" => ["Bearer $iam"]], $raw_req);
【讨论】:
上面的链接不再指向正确的地方。这是一些元数据声明的永久链接:github.com/grpc/grpc/blob/…以上是关于gRPC 给定 PHP 的错误元数据的主要内容,如果未能解决你的问题,请参考以下文章