The Application Default Credentials are not available

僤鯓⒐⒋嵵緔 提交于 2021-01-05 10:56:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!