0
votes

I followed Google's Quick-Start documentation for the Speech API to enable billing and API for an account. This account has authorized a service account to create Compute instances on its behalf. After creating an instance on the child account, hosting a binary to use the Speech API, I am unable to successfully use the example C# code provided by Google in the C# speech example:

try
        {
            var speech = SpeechClient.Create();                
            var response = speech.Recognize(new RecognitionConfig()
            {
                Encoding = RecognitionConfig.Types.AudioEncoding.Linear16,
                LanguageCode = "en"
            }, RecognitionAudio.FromFile(audioFiles[0]));
            foreach (var result in response.Results)
            {
                foreach (var alternative in result.Alternatives)
                {
                    Debug.WriteLine(alternative.Transcript);
                }
            }
      } catch (Exception ex)
      // ...
      }

Requests fail on the SpeechClient.Create() line with the following error:


--------------------------- Grpc.Core.RpcException: Status(StatusCode=Unauthenticated, Detail="Exception occured in metadata credentials plugin.")

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

at Grpc.Core.Internal.AsyncCall`2.UnaryCall(TRequest msg)

at Grpc.Core.Calls.BlockingUnaryCall[TRequest,TResponse](CallInvocationDetails`2 call, TRequest req)

at Grpc.Core.DefaultCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request)

at Grpc.Core.Internal.InterceptingCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request)

at Google.Cloud.Speech.V1.Speech.SpeechClient.Recognize(RecognizeRequest request, CallOptions options)

at Google.Api.Gax.Grpc.ApiCall.<>c__DisplayClass0_0`2.b__1(TRequest req, CallSettings cs)

at Google.Api.Gax.Grpc.ApiCallRetryExtensions.<>c__DisplayClass1_0`2.b__0(TRequest request, CallSettings callSettings)

at Google.Api.Gax.Grpc.ApiCall`2.Sync(TRequest request, CallSettings perCallCallSettings)

at Google.Cloud.Speech.V1.SpeechClientImpl.Recognize(RecognizeRequest request, CallSettings callSettings)

at Google.Cloud.Speech.V1.SpeechClient.Recognize(RecognitionConfig config, RecognitionAudio audio, CallSettings callSettings)

at Rc2Solver.frmMain.RecognizeWordsGoogleSpeechApi() in C:\Users\jorda\Google Drive\VSProjects\Rc2Solver\Rc2Solver\frmMain.cs:line 1770

--------------------------- OK

I have verified that the Speech API is activated. Here is the scope that the service account uses when creating the Compute instances:

credential = new ServiceAccountCredential(
                new ServiceAccountCredential.Initializer(me)
                {
                    Scopes = new[] { ComputeService.Scope.Compute, ComputeService.Scope.CloudPlatform }
                }.FromPrivateKey(yk)

                );

I have found no information or code online about specifically authorizing or authenticating the Speech API for service account actors. Any help is appreciated.

1

1 Answers

0
votes

It turns out the issue was that the Cloud Compute instances needed to be created with a ServiceAccount parameter specified. Otherwise the Cloud instances were not part of a ServiceAccount default credential, which is referenced by the SpeechClient.Create() call. Here is the proper way to create an instance attached to a service account, and it will use the SA tied to the project ID:

service = new ComputeService(new BaseClientService.Initializer() {
 HttpClientInitializer = credential,
  ApplicationName = "YourAppName"
});

string MyProjectId = "example-project-27172";
var project = await service.Projects.Get(MyProjectId).ExecuteAsync();
ServiceAccount servAcct = new ServiceAccount() {
 Email = project.DefaultServiceAccount,
  Scopes = new [] {
   "https://www.googleapis.com/auth/cloud-platform"
  }
};


Instance instance = new Instance() {
 MachineType = service.BaseUri + MyProjectId + "/zones/" + targetZone + "/machineTypes/" + "g1-small",
  Name = name,
  Description = name,
  Disks = attachedDisks,
  NetworkInterfaces = networkInterfaces,
  ServiceAccounts = new [] {
   servAcct
  },
  Metadata = md
};

batchRequest.Queue < Instance > (service.Instances.Insert(instance, MyProjectId, targetZone),
 (content, error, i, message) => {
  if (error != null) {
   AddEventMsg("Error creating instance " + name + ": " + error.ToString());
  } else {
   AddEventMsg("Instance " + name + " created");
  }
 });