问题
I'm learning to use the Watson Speech JS SDK. In particular I like Transcribe from Microphone, with Alternatives. I'm generating my token with a Firebase Cloud Function. I'm using AngularJS, not JQuery. The first problem I'm running into is
var stream = WatsonSpeech.SpeechToText.recognizeMicrophone(Object.assign(token, {
objectMode: true,
format: false,
wordConfidence: true
}));
I got this error message:
WatsonSpeechToText: missing required parameter: opts.token
(Using $scope.token
or token
makes no difference.)
Looking up this error in the documentation:
module.exports = function recognizeMicrophone(options) {
if (!options || !options.token) {
throw new Error('WatsonSpeechToText: missing required parameter: opts.token');
}
OK, it's looking for an options
object. I fixed the error with this code:
const options = {
token: $scope.token,
objectMode: true,
format: false,
wordConfidence: true
};
console.log(options);
var stream = WatsonSpeech.SpeechToText.recognizeMicrophone(options);
Now I get this error:
WebSocket connection to 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?model=en-US_BroadbandModel&watson-token=[object%20Object]' failed: HTTP Authentication failed; no valid credentials available
The options
object logs this:
token:
access_token: "eyJraWQiOiIyMDIwMDIyNTE4MjgiLCJhbGciOiJSUzI1NiJ9.eyJpYW1faWQiOiJp0tU2..."
expiration: 1585332575
expires_in: 3600
refresh_token: "OKC8z8ebLMzZcrAt6YgInnJJn0UIx1P3NTeDvdEC3kJqIQ7Yn9J9iu6-DF..."
scope: "ibm openid"
token_type: "Bearer"
objectMode: true
format: false
wordConfidence: true
smart_formatting: false
The token is a JSON object, which includes the access_token
. Is this what the SDK wants? The RecognizeStream documentation doesn't say whether it wants the JSON token or just the naked access_token
.
Adding 000
to the expiration
field shows that I have 53 minutes left on this token.
I'm using the API key that's specific to my Speech-to-Text service.
Any other suggestions?
回答1:
Version 0.37.0 of the SDK introduced breaking changes:
All options parameters for all methods are coverted to be lowerCamelCase
For example: access_token is now accessToken and content-type is now contentType
This is related to IBM's move from Cloud Foundry services with username/password auth to Services with IAM auth and api keys. The SDK documentation says:
NOTE: The token parameter only works for CF instances of services. For RC services using IAM for authentication, the accessToken parameter must be used.
The options
object looks like this if you use an api key:
const options = {
accessToken: $scope.token,
objectMode: true,
format: false,
wordConfidence: true
};
If you leave out the token property you get this error message:
WatsonSpeechToText: missing required parameter: opts.token (CF) or opts.accessToken (RC)
What that means is, if you're getting your token from Cloud Foundry (CF) the property must be opts.token
(or options.token
); but if you're getting your token from IAM auth and an api-key, which is called RC
for no reason I know of, then the property must be opts.accessToken
(or options.accessToken
).
Confusing the matter, the demo source code implies that access_token
is the property name:
var stream = WatsonSpeech.SpeechToText.recognizeMicrophone(Object.assign(token, {
objectMode: true,
format: false,
wordConfidence: true
}));
Object.assign
is taking the target
token object as it comes from IBM and then adding or replacing the properties and values in the source
object. Because the property is access_token
in the IAM token you'd think that, because the demo runs, access_token
is the property. But apparently the demo is running on a Cloud Foundry token, which can use either token
or access_token
as the property name.
If you get this error message:
WatsonSpeechToText: missing required parameter: opts.token (CF) or opts.accessToken (RC)
then you're using neither token
nor accessToken
as the property name.
If you get this error message:
WebSocket connection to 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?model=en-US_BroadbandModel&watson-token=[object%20Object]' failed: HTTP Authentication failed; no valid credentials available
then you're using token
with a token generated with an IAM api-key. Or your token is expired. You can check that easily by putting this code in your app to tell you how many minutes are left on your token:
// shows time to token expiration
var expiry = new Date($scope.token.expiration * 1000);
var now = Date.now();
var duration = -(now - expiry);
function msToTime(duration) {
var milliseconds = parseInt((duration % 1000) / 100),
seconds = Math.floor((duration / 1000) % 60),
minutes = Math.floor((duration / (1000 * 60)) % 60),
hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
return "Token expires in " + minutes + ":" + seconds + " minutes:seconds";
}
console.log(msToTime(duration))
You can test if your token is valid from the CLI. First get a new token:
curl -k -X POST \
--header "Content-Type: application/x-www-form-urlencoded" \
--header "Accept: application/json" \
--data-urlencode "grant_type=urn:ibm:params:oauth:grant-type:apikey" \
--data-urlencode "apikey=s00pers3cret" \
"https://iam.cloud.ibm.com/identity/token"
then request the language models:
curl -X GET "https://stream.watsonplatform.net/speech-to-text/api/v1/models?access_token=eyJraWQiO...."
I had another problem in my code. I was updating the IBM Speech-to-Text SDK but my code was linking to an old SDK I'd installed with bower three years ago. I didn't realize that I was using 0.33.1 when 0.38.0 is the latest version. Add this to your code to catch this problem:
console.log (WatsonSpeech.version);
With the old SDK I was getting an old error message that didn't even mention the new property name:
WatsonSpeechToText: missing required parameter: opts.token
My blog post has more about IBM Cloud Speech-to-Text.
来源:https://stackoverflow.com/questions/60891348/ibm-cloud-speech-to-text-sdk-auth-failures-with-bearer-token