应用程序默认凭据不可用

时间:2019-04-03 13:48:45

标签: android google-cloud-platform speech-to-text

我正在尝试为我的Android应用程序使用Google Cloud Platform的语音转文本API。我已经通过了一个录制的音频文件以转换为文本。 我无法解决被描述为“ 的应用程序默认凭据”的IOException。如果在Google Compute Engine中运行,则它们是可用的。否则,必须定义环境变量GOOGLE_APPLICATION_CREDENTIALS指向定义凭据的文件。有关更多信息,请参见https://developers.google.com/accounts/docs/application-default-credentials

我已经创建了一个服务帐户,启用了特定的API,创建了一个帐户密钥(cred.json)。 将环境变量“ GOOGLE_APPLICATION_CREDENTIALS”设置为文件的路径(上面的cred.json)。这是在Mac上的.bash_profile文件中完成的。

这是问题所在: 当我检查环境。使用

从终端获取变量

回显$ GOOGLE_APPLICATION_CREDENTIALS

结果是cred.json文件的[路径]

但是,如果我尝试检查“ GOOGLE_APPLICATION_CREDENTIALS”,则在为该应用进行调试时,它显示为空。我使用

进行了检查
Log.d("@sttenv", System.getenv("GOOGLE_APPLICATION_CREDENTIALS"));

这就是为什么我得到上面提到的IOException的原因。该行引发IOException。

SpeechClient speechClient = SpeechClient.create();

SpeechClient(它是代码本身的开始)给出了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();
}

我该如何解决?我尝试设置环境。来自终端的变量,无用。 我也想知道,如果我们将此应用程序安装在Android手机中(而不是在模拟器上),是否需要cred.json文件出现在手机本身中?因为cred.josn(帐户密钥)在我的Mac上。我正在尝试通过Android手机访问API?因此,我应该将cred.json保存在手机上,并提供给env的路径。变量?

1 个答案:

答案 0 :(得分:0)

GOOGLE_APPLICATION_CREDENTIALS是一个编译时间变量。 您会注意到build.gradle中有一个任务,可以将凭证从变量指向的位置复制到原始目录中的credential.json文件:

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"
}

然后应使用代码对这个文件进行寻址,以产生用于API服务的访问令牌:

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));
        }
    }
}