Error : "permission denied on resources" Trying to implement @google-cloud/speech Verison 5.4.1(i.e V2) in Node JS
I am writing to request assistance with an issue I have encountered while implementing the Google Speech-to-Text gRPC API in my project. Specifically, I am receiving an error message indicating "permission denied on resources" when attempting to use the API.
I have followed the API documentation and have ensured that my credentials are valid and have the appropriate permissions. However, despite my best efforts, I have been unable to resolve this issue and am currently unable to proceed with my project.
I would greatly appreciate any assistance or guidance you can provide in resolving this issue. Please let me know if there is any additional information I can provide to help diagnose the problem.
Thank you in advance for your help.
OS Verison : Ubuntu 20 Node Verison : 19.8.1 Google Cloud Speech API Veriosn : gRPC 5.4.1 (i.e Verison 2)
ERROR SHOWN BELOW
0|ASR | Error: 7 PERMISSION_DENIED: Permission 'speech.recognizers.list' denied on resource '//speech.googleapis.com/projects/gifted-airway-380611/locations/global' (or it may not exist).
0|ASR | at callErrorFromStatus (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@grpc/grpc-js/build/src/call.js:31:19)
0|ASR | at Object.onReceiveStatus (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@grpc/grpc-js/build/src/client.js:192:76)
0|ASR | at Object.onReceiveStatus (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:360:141)
0|ASR | at Object.onReceiveStatus (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:323:181)
0|ASR | at /home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@grpc/grpc-js/build/src/resolving-call.js:94:78
0|ASR | at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
0|ASR | for call at
0|ASR | at ServiceClientImpl.makeUnaryRequest (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@grpc/grpc-js/build/src/client.js:160:34)
0|ASR | at ServiceClientImpl.
Hi @DixitMalia, would you mind providing your code to reproduce as well? Thank you!
Hi @sofisl this is the complete code from where i made the request and hit the gRPC API and get the response `const { Writable } = require('stream'); const {SpeechClient} = require('@google-cloud/speech').v2; /*
- For speech provider implementer.
- Basic Provider public interface:
- function setConfig(config) - sets configuration used by recognize stream
- function start(config) - starts the recognize stream
- function restart(config) - restarts the recognize stream
- function end() - stops recognize and writable stream
- function write(data) - writes data to the writable stream
- event result(result) - triggered when a result is received from provider
- field results[] - cache of received results (oldest to newest)
- Basic result object public interface:
- result = {
-
text: <the recognized string value> -
score: <percent based accuracy/confidence score> - }; */
/*
- Google Speech API:
-
https://googleapis.dev/nodejs/speech/latest/ - Google infinite streaming speech example:
- https://cloud.google.com/speech-to-text/docs/samples/speech-transcribe-infinite-streaming
- Nodejs stream API:
- https://nodejs.org/api/stream.html */ // const encoding = 'Encoding of the audio file, e.g. ProviderAR16'; // const sampleRateHertz = 16000; // const languageCode = 'BCP-47 language code with regional subtags, e.g. en-US'; // const limit = 10000; // ms - set to low number for demo purposes
const DEFAULT_ENCODING = "MULAW"; const DEFAULT_SAMPLE_RATE = 8000; const DEFAULT_LANGUAGE = "en-US"; //en-US const DEFAULT_RESTART_TIME = 60; // in seconds const DEFAULT_MAX_RESULTS = 100; const DEFAULT_MODEL = "phone_call";
/**
-
@class GoogleProvider.
-
Start, restart, and stop Google speech to text recognition. Results are
-
emitted via a "result" event that is passed the following object:
-
result = {
-
text:
-
score: <percent based accuracy/confidence score>
-
};
-
@extends Writable */ class GoogleProvider extends Writable {
/* Mapped encodings supported by Google */ static encodings = { ulaw: "MULAW", slin: "LINEAR16", opus: "OGG Opus", speex:"SPEEX_WITH_HEADER_BYTE", };
/* Languages this provider supports */ static languages = [ "en-US","en-IN","hi-IN","en-INT","hi-INT","es-US" ];
/* Models this provider supports*/ static models =[ "default","phone_call","medical_conversation","latest_long" ]; /**
- Creates an instance of a Google provider stream.
- @param {Object} [options] - provider specific options
- @param {Object} [options.restartTime=10] - If specified auto-restart
-
recognition stream after a given interval (in seconds) - @param {Object} [options.maxResults=100] - The maximum number of results
-
to cache before results are dropped (oldest dropped first)
*/ constructor(options) { super(); //FOR V1 this.config = { encoding: DEFAULT_ENCODING, sampleRateHertz: DEFAULT_SAMPLE_RATE, languageCode: DEFAULT_LANGUAGE, model:DEFAULT_MODEL, //Extra----- useEnhanced: true, maxAlternatives:5, //Daibieties Sis Changes //single_utterance: false, // metadata: { // interactionType: 'PHONE_CALL', // microphoneDistance: 'MIDFIELD', // originalMediaType: 'AUDIO', // recordingDeviceName: 'PHONE_LINE', //update 1 from pc to phone line // } }; this.restartTimer = null; this.restartTimeout = options && options.restartTime || DEFAULT_RESTART_TIME; this.maxResults = options && options.maxResults || DEFAULT_MAX_RESULTS;
this.results = []; this.recognizeStream = null;}
_construct(callback) { this.client =new SpeechClient();
callback();}
_write(chunk, encoding, callback) { if (this.recognizeStream) { this.recognizeStream.write(chunk); }
callback();}
_writev(chunks, callback) { for (let chunk in chunks) { this._write(chunk, null, callback); }
callback();}
_final(callback) { this.stop(); this.client.close();
callback();}
/**
-
Sets the configuration to use on the recognition stream.
-
@param {Object} [config] - configuration to set
-
@param {Object} [config.codec] - the codec to map to an encoding
-
@param {string} [config.language] - the language to use
-
@param {string} [config.model] - the model to use */ setConfig(config) { if (!config) { return; }
let update = {}; if (config.codec) { if (!(config.codec.name in GoogleProvider.encodings)) { throw new Error("Codec '" + config.codec.name + " 'not supported"); } console.log('Line 201 provider',config.codec.name,config.codec.sampleRate) update.encoding = GoogleProvider.encodings[config.codec.name]; update.sampleRateHertz = config.codec.sampleRate; }
if (config.language) { if(config.language == "en-INT"){ config.language = "en-IN" this.restartTimeout = "20" }else if(config.language == "hi-INT"){ config.language = "hi-IN" this.restartTimeout = "20" } console.log("Restart Timeout and language selected :: ",this.restartTimeout,config.language)
if (!GoogleProvider.languages.includes(config.language)) { throw new Error("Language '" + config.language + " 'not supported"); } update.languageCode = config.language;} if (config.model) { if (!GoogleProvider.models.includes(config.model)) { throw new Error("Model '" + config.model + " 'not supported"); } update.model = config.model; } //SPEECH CONTEXT SELECTION console.log("Selected language (For Speech Context)::::",config.language) if (config.language == "en-US"){ update['speechContext']={ "phrases" : ["$OOV_CLASS_DIGIT_SEQUENCE", "$OOV_CLASS_FULLPHONENUM", "$DAY", "$FULLPHONENUM", "$MONTH", "$OPERAND", "$POSTALCODE", "$TIME", "$YEAR"], "boost" : 10.0 //Db SIS 10.0 } }else if(config.language == "en-IN"){ update['speechContext']={ "phrases": ["$OOV_CLASS_ALPHANUMERIC_SEQUENCE","$OOV_CLASS_ALPHA_SEQUENCE","$OOV_CLASS_AM_RADIO_FREQUENCY","$OOV_CLASS_DIGIT_SEQUENCE","$OOV_CLASS_FM_RADIO_FREQUENCY","$OOV_CLASS_FULLPHONENUM","$OOV_CLASS_PERCENT","$OOV_CLASS_TEMPERATURE","$ADDRESSNUM","$DAY","$MONEY","$MONTH","$OPERAND","$POSTALCODE","$TIME","$YEAR"], "boost" : 4.0 } }else if(config.language == "hi-IN"){ update['speechContext']={ "phrases": ["$OOV_CLASS_ALPHANUMERIC_SEQUENCE","$OOV_CLASS_ALPHA_SEQUENCE","$OOV_CLASS_DIGIT_SEQUENCE","$OOV_CLASS_POSTALCODE","$ADDRESSNUM","$DAY","$MONEY","$MONTH","$OPERAND","$POSTALCODE","$TIME","$YEAR"], "boost" : 4.0 } }else{ console.log("NO SPEECH CONTEXT SELECTED"); } this.config = {...this.config, ...update}; }
/**
-
Starts the recognition stream.
-
@param {Object} [config] - configuration to use
-
@param {Object} [config.codec] - the codec to map to an encoding
-
@param {string} [config.language] - the language to use
-
@param {string} [config.model] - the model to use */ async start(config) { if (this.recognizeStream) { return; // Already started } this.setConfig(config); config = this.config; //FOR V1 // const voice_activity_timeout = { // speech_start_timeout: 5, // speech_end_timeout: 5, // };
// const request = { // config: this.config, // interimResults: true, // //features as per v1p1beta1 // enable_voice_activity_events: true, // voice_activity_timeout : voice_activity_timeout, // };
//FOR V2 // const adaptation = { // "phrases": ["$OOV_CLASS_ALPHANUMERIC_SEQUENCE","$OOV_CLASS_ALPHA_SEQUENCE","$OOV_CLASS_DIGIT_SEQUENCE","$OOV_CLASS_POSTALCODE","$ADDRESSNUM","$DAY","$MONEY","$MONTH","$OPERAND","$POSTALCODE","$TIME","$YEAR"] // }; // const AutoDetectDecodingConfig = { // auto_decoding_config: {}, // }; // const RecognitionConfig = { // // features:, // // adaptation: adaptation, // decoding_config: AutoDetectDecodingConfig, // } ; // const voice_activity_timeout = { // speech_start_timeout: 5, // speech_end_timeout: 5, // }; // const streaming_features = { // enable_voice_activity_events: true, // interim_results: true, // voice_activity_timeout: voice_activity_timeout, // };
const request = { parent: 'projects/{project-id}/locations/global', // // recognizer: 'default', // // config: RecognitionConfig, // // config_mask: , // // streaming_features: streaming_features, }; // Run request v2 var recog = await this.client.listRecognizers(request); console.log('================================',(iterable)); // for (const response of iterable) { // console.log(response); // } console.log("=====NEW REQUEST=====") // console.log("Selected ASR ENGINE LANGUGAE::",request.config.languageCode); console.log("REQUEST TIME::",new Date()); console.log("FINAL CONFIGURATION::",request); // console.log("-------------------RECOGNIZE-STREAM-API-----------",this.client) this.recognizeStream = this.client ._streamingRecognize(request) .on('error', (e) => { console.log(e); console.error("GoogleProvider: " + e + " - ending stream"); this.end(); }) .on('data', (response) => { console.log('================Response From G-API==================',response.results) if (response.results[0] && response.results[0].alternatives[0]) { if (response.results[0].alternatives[0].confidence == 0) { return; } let result = { text : response.results[0].alternatives[0].transcript, score: Math.round(response.results[0].alternatives[0].confidence * 100), }; console.debug("GoogleProvider: result: " + JSON.stringify(result)); this.emit('result', result); if (this.results.length == this.maxResults) { //max result case console.log("Reached Max Results Case(MAX=100) :: ",this.results.length) this.results.shift(); } this.results.push(result); } else { // stream limit reached restart? console.debug("GoogleProvider: received but no response"); } }); if (this.restartTimeout) { /* * Google's speech engine may stop transcribing after a while, * so restart the recognize stream after a specified interval. */ console.log('Restart the stream after this.restartTimeout sec') this.restartTimer = setTimeout(() => this.restart(), this.restartTimeout * 1000); // console.log(this.restartTimer) } while (this.writableCorked) { this.uncork(); }}
/**
-
Stops the recognition stream. */ stop() { if (this.restartTimer) { clearInterval(this.restartTimer); this.restartTimer = null; }
if (!this.recognizeStream) { return; }
this.cork(); // Buffer any incoming data` this.recognizeStream.end(); this.recognizeStream = null; }
/**
- Restarts the recognition stream.
- @param {Object} [config] - configuration to use
- @param {Object} [config.codec] - the codec to map to an encoding
- @param {string} [config.language] - the language to use
- @param {string} [config.model] - the model to use */ restart(config) { this.stop(); this.start(config); } }
/**
-
Gets a speech provider
-
@param {string} name - A speech provider name
-
@param {Object} options - Provider specific options
-
@return A speech provider. */ function getProvider(name, options) { if (name == "google") { return new GoogleProvider(options); }
throw new Error("Unsupported speech provider '" + name + "'"); }
module.exports = { getProvider, } `
@DixitMalia
Following this doc: https://cloud.google.com/speech-to-text/v2/docs/transcribe-client-libraries
You must add Cloud Speech Administrator role to get list recognizers.
@lvxduck Thank you for your reply Speech to Text key used here is already having an admin role and IAM Permission