google-cloud-node icon indicating copy to clipboard operation
google-cloud-node copied to clipboard

Error : "permission denied on resources" Trying to implement @google-cloud/speech Verison 5.4.1(i.e V2) in Node JS

Open DixitMalia opened this issue 2 years ago • 4 comments

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. (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19) 0|ASR | at /home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/@google-cloud/speech/build/src/v2/speech_client.js:318:29 0|ASR | at wrappedCall (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/google-gax/build/src/paginationCalls/pagedApiCaller.js:86:20) 0|ASR | at /home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/google-gax/build/src/normalCalls/timeout.js:44:16 0|ASR | at repeat (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/google-gax/build/src/normalCalls/retries.js:80:25) 0|ASR | at Immediate. (/home/ubuntu/telephony/call_ai_asr_main/call_ai_asr/node_modules/google-gax/build/src/normalCalls/retries.js:118:13) 0|ASR | at process.processImmediate (node:internal/timers:480:21) { 0|ASR | code: 7, 0|ASR | details: "Permission 'speech.recognizers.list' denied on resource '//speech.googleapis.com/projects/gifted-airway-380611/locations/global' (or it may not exist).", 0|ASR | metadata: Metadata { 0|ASR | internalRepr: Map(2) { 0|ASR | 'google.rpc.errorinfo-bin' => [Array], 0|ASR | 'grpc-status-details-bin' => [Array] 0|ASR | }, 0|ASR | options: {} 0|ASR | }, 0|ASR | note: 'Exception occurred in retry method that was not classified as transient', 0|ASR | statusDetails: [ 0|ASR | ErrorInfo { 0|ASR | metadata: [Object], 0|ASR | reason: 'IAM_PERMISSION_DENIED', 0|ASR | domain: 'speech.googleapis.com' 0|ASR | } 0|ASR | ], 0|ASR | reason: 'IAM_PERMISSION_DENIED', 0|ASR | domain: 'speech.googleapis.com', 0|ASR | errorInfoMetadata: { 0|ASR | resource: 'projects/gifted-airway-380611/locations/global', 0|ASR | permission: 'speech.recognizers.list' 0|ASR | } 0|ASR | }

DixitMalia avatar May 01 '23 05:05 DixitMalia

Hi @DixitMalia, would you mind providing your code to reproduce as well? Thank you!

sofisl avatar May 01 '23 22:05 sofisl

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 avatar May 03 '23 04:05 DixitMalia

@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.

image

lvxduck avatar May 22 '23 09:05 lvxduck

@lvxduck Thank you for your reply Speech to Text key used here is already having an admin role and IAM Permission

DixitMalia avatar May 22 '23 11:05 DixitMalia