英文:
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
,如上所述的文档中所述:
正如上述文档所述,您可以从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
:
As described in the aforementioned documentation you can do it from the GCP Console or using the command line.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论