Google Cloud Speech to Text API 在 Android 上由于无效的身份验证凭据而失败。

huangapple go评论62阅读模式
英文:

Google Cloud Speech to text API call fails due to invalid authentication credentials on Android

问题

我正在尝试在我的Android客户端中使用Google Cloud语音转文字API。我已经在Google Cloud中启用了API,并在控制台中生成了一个新的密钥,步骤如下: "创建凭据" -> "服务帐户"(添加详细信息) -> "创建并继续"。这将生成一个包含以下参数的JSON文件:

{
  "type": "service_account",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": "",
  "universe_domain": ""
}

我已将此JSON文件添加到我的Android项目的raw目录中(这只是一个概念验证,所以目前不太担心安全性)。

接下来是Android代码:

val req = RecognizeRequest.newBuilder()
               .setConfig(RecognitionConfig.newBuilder()
                        .setEncoding(RecognitionConfig.AudioEncoding.AMR_WB)
                        .setLanguageCode("en-US")
                        .setSampleRateHertz(16000)
                        .build())
                    .setAudio(RecognitionAudio.newBuilder()
                        .setContent(fileByteString))
                        .build()

val speechClient = SpeechClient.create(SpeechSettings.newBuilder()
              .setCredentialsProvider{GoogleCredentials.fromStream(this.resources.openRawResource(R.raw.credentials)) }

val response = speechClient.recognize(req)

Log.d(TAG, "we have a count of ${response.resultsCount} hits on the audio file")

val results = response.resultsList

当调用speechClient.recognize(req)函数时,API返回以下错误消息:

com.google.api.gax.rpc.UnauthenticatedException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.

有没有人知道如何在调用此API时正确进行身份验证?

我还尝试在Google Cloud控制台中生成OAuth和Service Key类型的凭据,但是我得到了一个不同的错误,大致说“凭据不包含字段type”。

英文:

I'm trying to use the google cloud speech to text API in my android client. I have enabled the API in the Google Cloud and in the console I have generate a new key like this: "Create credentials" -> "Service account" (added details) -> "Create and Continue". This has generated a JSON file that contains this params:

{
  "type": "service_account",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": "",
  "universe_domain": ""
}

I have added this JSON file in the raw dir in my android project (this is just a POC so not to worried about security at this point)

Next is the android code:

val req = RecognizeRequest.newBuilder()
               .setConfig(RecognitionConfig.newBuilder()
                        .setEncoding(RecognitionConfig.AudioEncoding.AMR_WB)
                        .setLanguageCode("en-US")
                        .setSampleRateHertz(16000)
                        .build())
                    .setAudio(RecognitionAudio.newBuilder()
                        .setContent(fileByteString))
                        .build()


            val speechClient = SpeechClient.create(SpeechSettings.newBuilder()              .setCredentialsProvider{GoogleCredentials.fromStream(this.resources.openRawResource(R.raw.credentials)) }


            val response = speechClient.recognize(req)

Log.d(TAG, "we have a count of ${response.resultsCount} hits on the  audio file")

            val results = response.resultsList

When the speechClient.recognize(req) fun is called, the API sends back this error message:

com.google.api.gax.rpc.UnauthenticatedException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.
        at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:116)
        at com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:98)
        at com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:66)
        at com.google.api.gax.grpc.GrpcExceptionCallable$ExceptionTransformingFuture.onFailure(GrpcExceptionCallable.java:97)
        at com.google.api.core.ApiFutures$1.onFailure(ApiFutures.java:84)
        at com.google.common.util.concurrent.Futures$CallbackListener.run(Futures.java:1127)
        at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:31)
        at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1286)
        at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:1055)
        at com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:807)
        at io.grpc.stub.ClientCalls$GrpcFuture.setException(ClientCalls.java:574)
        at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:544)
        at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
        at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
        at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
        at com.google.api.gax.grpc.ChannelPool$ReleasingClientCall$1.onClose(ChannelPool.java:541)
        at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java:489)
        at io.grpc.internal.DelayedClientCall$DelayedListener.delayOrExecute(DelayedClientCall.java:453)
        at io.grpc.internal.DelayedClientCall$DelayedListener.onClose(DelayedClientCall.java:486)
        at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:567)
        at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:71)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:735)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:716)
        at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
        at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
     Suppressed: com.google.api.gax.rpc.AsyncTaskException: Asynchronous task failed
        at com.google.api.gax.rpc.ApiExceptions.callAndTranslateApiException(ApiExceptions.java:57)
        at com.google.api.gax.rpc.UnaryCallable.call(UnaryCallable.java:112)
        at com.google.cloud.speech.v1.SpeechClient.recognize(SpeechClient.java:252)

Does anyone know how to auth correctly when calling this API please?

I have also tried to generate OAuth & Service Key type of credentials in the Google Cloud Console but I was getting a different error saying something like "Credentials don't contain field `type`"

答案1

得分: 1

请查看此相关的SO问题,它是为TextToSpeechSettings定义的,但我认为提供的解决方案在这里也适用。

如建议的,基本上您需要从您的服务帐户JSON文件的内容创建一个有效的GoogleCredentials对象:

// R.raw.credential指向下载的credential.json文件
InputStream stream = getResources().openRawResource(R.raw.credential); 
GoogleCredentials credentials = GoogleCredentials.fromStream(stream);

然后,使用获取的凭据初始化您的SpeechClient

例如,适应我的原始答案的代码:

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import com.google.api.gax.core.CredentialsProvider;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.speech.v1.RecognitionAudio;
import com.google.cloud.speech.v1.RecognitionConfig;
import com.google.cloud.speech.v1.RecognizeRequest;
import com.google.cloud.speech.v1.RecognizeResponse;
import com.google.cloud.speech.v1.SpeechClient;
import com.google.cloud.speech.v1.SpeechRecognitionResult;
import com.google.cloud.speech.v1.SpeechSettings;
import com.google.protobuf.ByteString;

public class RecognitionActivity extends Activity {

  // 您的活动定义

  private void performRecognition(ByteString fileByteString) throws IOException {
    // R.raw.credential指向下载的credential.json文件
    // 我在笔记本电脑上本地测试了我的代码,使用了
    // GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("/path/to/credentials.json"));
    InputStream stream = getResources().openRawResource(R.raw.credential);
    GoogleCredentials credentials = GoogleCredentials.fromStream(stream);
    // 您也可以使用ServiceAccountCredentials而不是上面的行:
    // ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream(stream);
    CredentialsProvider credentialsProvider = FixedCredentialsProvider.create(credentials);
    SpeechSettings speechSettings = SpeechSettings.newBuilder()
        .setCredentialsProvider(credentialsProvider)
        .build();

    SpeechClient speechClient = SpeechClient.create(speechSettings);

    // 您代码的其余部分

    RecognizeRequest req = RecognizeRequest.newBuilder()
        .setConfig(RecognitionConfig.newBuilder()
            .setEncoding(RecognitionConfig.AudioEncoding.AMR_WB)
            .setLanguageCode("en-US")
            .setSampleRateHertz(16000)
            .build())
        .setAudio(RecognitionAudio.newBuilder()
            .setContent(fileByteString))
        .build();

    RecognizeResponse response = speechClient.recognize(req);

    Log.d(TAG, "我们在音频文件上有 ${response.getResultsCount()} 个命中")

    List<SpeechRecognitionResult> results = response.getResultsList();
    
    // 处理结果
  }
}

在Kotlin中(请原谅我可能存在的不准确性),它看起来是这样的:

private fun performRecognition(fileByteString: ByteString) {
    // R.raw.credential指向下载的credential.json文件
    val stream: InputStream = getResources().openRawResource(R.raw.credential)
    val credentials = GoogleCredentials.fromStream(stream);
    // val credentials = ServiceAccountCredentials.fromStream(stream)
    val credentialsProvider = FixedCredentialsProvider.create(credentials)
    val speechSettings = SpeechSettings.newBuilder()
            .setCredentialsProvider(credentialsProvider)
            .build()

    val speechClient = SpeechClient.create(speechSettings)

    // 您代码的其余部分
    val req = RecognizeRequest.newBuilder()
            .setConfig(RecognitionConfig.newBuilder()
                    .setEncoding(RecognitionConfig.AudioEncoding.AMR_WB)
                    .setLanguageCode("en-US")
                    .setSampleRateHertz(16000)
                    .build())
            .setAudio(RecognitionAudio.newBuilder()
                    .setContent(fileByteString))
            .build()

    val response = speechClient.recognize(req)

    Log.d(TAG, "我们在音频文件上有 ${response.resultsCount} 个命中")

    val results = response.resultsList

    // 处理结果
}

请确保您已按照必要步骤设置了Speech API,特别是与配置服务帐户相关的步骤。

服务帐户必须能够与Speech API互动,为其分配一个方便的角色,如Cloud Speech Client,如上所述的文档中所述:

Google Cloud Speech to Text API 在 Android 上由于无效的身份验证凭据而失败。

正如上述文档所述,您可以从GCP控制台或使用命令行来执行此操作。

英文:

Please, consider review this related SO question, it is defined for TextToSpeechSettings but I think that the solution provided could be of application here as well.

As suggested, basically you need to create a valid GoogleCredentials object from the content of your service account json file:

// R.raw.credential points to the downloaded credential.json file
InputStream stream = getResources().openRawResource(R.raw.credential); 
GoogleCredentials credentials = GoogleCredentials.fromStream(stream);

And then, use the obtained credentials to initialize your SpeechClient.

For instance, adapting the code from my original answer:

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import com.google.api.gax.core.CredentialsProvider;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.speech.v1.RecognitionAudio;
import com.google.cloud.speech.v1.RecognitionConfig;
import com.google.cloud.speech.v1.RecognizeRequest;
import com.google.cloud.speech.v1.RecognizeResponse;
import com.google.cloud.speech.v1.SpeechClient;
import com.google.cloud.speech.v1.SpeechRecognitionResult;
import com.google.cloud.speech.v1.SpeechSettings;
import com.google.protobuf.ByteString;

public class RecognitionActivity extends Activity {

  // Your activity definition

  private void performRecognition(ByteString fileByteString) throws IOException {
    // R.raw.credential points to the downloaded credential.json file
    // I tested my code locally in a laptop using
    // GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("/path/to/credentials.json"));
    InputStream stream = getResources().openRawResource(R.raw.credential);
    GoogleCredentials credentials = GoogleCredentials.fromStream(stream);
    // You can use ServiceAccountCredentials as well instead of the line above:
    // ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream(stream);
    CredentialsProvider credentialsProvider = FixedCredentialsProvider.create(credentials);
    SpeechSettings speechSettings = SpeechSettings.newBuilder()
        .setCredentialsProvider(credentialsProvider)
        .build();

    SpeechClient speechClient = SpeechClient.create(speechSettings);

    // The rest of your code

    RecognizeRequest req = RecognizeRequest.newBuilder()
        .setConfig(RecognitionConfig.newBuilder()
            .setEncoding(RecognitionConfig.AudioEncoding.AMR_WB)
            .setLanguageCode("en-US")
            .setSampleRateHertz(16000)
            .build())
        .setAudio(RecognitionAudio.newBuilder()
            .setContent(fileByteString))
        .build();

    RecognizeResponse response = speechClient.recognize(req);

    Log.d(TAG, "we have a count of " + response.getResultsCount() + " hits on the  audio file")

    List<SpeechRecognitionResult> results = response.getResultsList();
    
    // Handle results
  }
}

In kotlin (please, forgive me for any inaccuracy) it would look like this:

private fun performRecognition(fileByteString: ByteString) {
    // R.raw.credential points to the downloaded credential.json file
    val stream: InputStream = getResources().openRawResource(R.raw.credential)
    val credentials = GoogleCredentials.fromStream(stream);
    // val credentials = ServiceAccountCredentials.fromStream(stream)
    val credentialsProvider = FixedCredentialsProvider.create(credentials)
    val speechSettings = SpeechSettings.newBuilder()
            .setCredentialsProvider(credentialsProvider)
            .build()

    val speechClient = SpeechClient.create(speechSettings)

    // The rest of your code
    val req = RecognizeRequest.newBuilder()
            .setConfig(RecognitionConfig.newBuilder()
                    .setEncoding(RecognitionConfig.AudioEncoding.AMR_WB)
                    .setLanguageCode("en-US")
                    .setSampleRateHertz(16000)
                    .build())
            .setAudio(RecognitionAudio.newBuilder()
                    .setContent(fileByteString))
            .build()

    val response = speechClient.recognize(req)

    Log.d(TAG, "we have a count of ${response.resultsCount} hits on the  audio file")

    val results = response.resultsList

    // Handle results
}

Please, be sure that you followed the necessary steps for setting up the Speech API, especially those related to configuring the service account.

The service account must be able to interact with the Speech API, assigning a convenient role to it such as Cloud Speech Client:

Google Cloud Speech to Text API 在 Android 上由于无效的身份验证凭据而失败。

As described in the aforementioned documentation you can do it from the GCP Console or using the command line.

huangapple
  • 本文由 发表于 2023年7月6日 22:44:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76630026.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定