问题
I am trying to use speech-to-text API of Google Cloud Platform for my Android App. I have passed it a recorded audio file for conversion to text. I can't solve an IOException which is described as "The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information."
I've created a service account, enabled the particular API, created a account key(cred.json). Set the environment variable "GOOGLE_APPLICATION_CREDENTIALS" to the [path] of the file(cred.json from above). This was done in .bash_profile file on mac.
Here is the problem: When I check for the env. variable from terminal using
echo $GOOGLE_APPLICATION_CREDENTIALS
the result is [path] of the cred.json file
But while deubgging the app if I try to check "GOOGLE_APPLICATION_CREDENTIALS" it shows null. I checked it using
Log.d("@sttenv", System.getenv("GOOGLE_APPLICATION_CREDENTIALS"));
This is the reason why I get the IOException mentioned above. This line throws the IOException.
SpeechClient speechClient = SpeechClient.create();
The SpeechClient which is the very start of the code itself gives an IOException.
try {
SpeechClient speechClient = SpeechClient.create();
// Reads the audio file into memory
Path path = Paths.get(tempFileName);
byte[] data = Files.readAllBytes(path);
ByteString audioBytes = ByteString.copyFrom(data);
// Builds the sync recognize request
RecognitionConfig config = RecognitionConfig.newBuilder()
.setEncoding(AudioEncoding.LINEAR16)
.setSampleRateHertz(44100)
.setLanguageCode("en-US")
.build();
RecognitionAudio audio = RecognitionAudio.newBuilder()
.setContent(audioBytes)
.build();
// Performs speech recognition on the audio file
RecognizeResponse response = speechClient.recognize(config, audio);
List<SpeechRecognitionResult> results = response.getResultsList();
for (SpeechRecognitionResult result : results) {
// There can be several alternative transcripts for a given chunk of speech. Just use the
// first (most likely) one here.
SpeechRecognitionAlternative alternative = result.getAlternativesList().get(0);
//System.out.printf("Transcription: %s%n", alternative.getTranscript());
log.debug("Transcription: %s%n", alternative.getTranscript());
}
}
catch (IOException e){
e.printStackTrace();
}
How should I tackle this? I tried setting the env. variable from the terminal, no use. Also I wanted to know, if we install this app in a android phone(not on emulator), does it require the cred.json file to be present in the phone itself? Because the cred.josn (account key) is on my mac. And I'm trying to access the API through a Android phone? So should I save the cred.json on my phone and give it's path to the env. variable?
回答1:
GOOGLE_APPLICATION_CREDENTIALS is a compile time variable. you can notice there is task in the build.gradle that copies the credentials from where ever the variable points to to the credential.json file in the raw directory:
task copySecretKey(type: Copy) {
def File secretKey = file "$System.env.GOOGLE_APPLICATION_CREDENTIALS"
from secretKey.getParent()
include secretKey.getName()
into 'src/main/res/raw'
rename secretKey.getName(), "credential.json"
}
this file should then be addressed in code to produce an access token for the API services:
private class AccessTokenTask extends AsyncTask<Void, Void, AccessToken> {
@Override
protected AccessToken doInBackground(Void... voids) {
final SharedPreferences prefs =
getSharedPreferences(PREFS, Context.MODE_PRIVATE);
String tokenValue = prefs.getString(PREF_ACCESS_TOKEN_VALUE, null);
long expirationTime = prefs.getLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, -1);
// Check if the current token is still valid for a while
if (tokenValue != null && expirationTime > 0) {
if (expirationTime
> System.currentTimeMillis() + ACCESS_TOKEN_EXPIRATION_TOLERANCE) {
return new AccessToken(tokenValue, new Date(expirationTime));
}
}
// ***** WARNING *****
// In this sample, we load the credential from a JSON file stored in a raw resource
// folder of this client app. You should never do this in your app. Instead, store
// the file in your server and obtain an access token from there.
// *******************
final InputStream stream = getResources().openRawResource(R.raw.credential);
try {
final GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
.createScoped(SCOPE);
final AccessToken token = credentials.refreshAccessToken();
prefs.edit()
.putString(PREF_ACCESS_TOKEN_VALUE, token.getTokenValue())
.putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME,
token.getExpirationTime().getTime())
.apply();
return token;
} catch (IOException e) {
Log.e(TAG, "Failed to obtain access token.", e);
}
return null;
}
@Override
protected void onPostExecute(AccessToken accessToken) {
mAccessTokenTask = null;
final ManagedChannel channel = new OkHttpChannelProvider()
.builderForAddress(HOSTNAME, PORT)
.nameResolverFactory(new DnsNameResolverProvider())
.intercept(new GoogleCredentialsInterceptor(new GoogleCredentials(accessToken)
.createScoped(SCOPE)))
.build();
mApi = SpeechGrpc.newStub(channel);
// Schedule access token refresh before it expires
if (mHandler != null) {
mHandler.postDelayed(mFetchAccessTokenRunnable,
Math.max(accessToken.getExpirationTime().getTime()
- System.currentTimeMillis()
- ACCESS_TOKEN_FETCH_MARGIN, ACCESS_TOKEN_EXPIRATION_TOLERANCE));
}
}
}
来源:https://stackoverflow.com/questions/55496769/the-application-default-credentials-are-not-available