给出PHP的gRPC Bad元数据

问题描述 投票:1回答:1

目前我要重写一个从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;
}
php protocol-buffers grpc yandex
1个回答
3
投票

似乎元数据是数组(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);
© www.soinside.com 2019 - 2024. All rights reserved.