speechmatics / speechmatics-js-sdk

Javascript and Typescript SDK for Speechmatics
MIT License
40 stars 7 forks source link

Concurrent Quota Exceeded #59

Open rahulserver opened 2 months ago

rahulserver commented 2 months ago

Describe the bug Randomly getting this error

{
  message: 'Error',
  type: 'quota_exceeded',
  reason: 'Concurrent Quota Exceeded'
}

Here is my code

  ws.on('message', async (data) => {

    if (Buffer.isBuffer(data)) {
      // Handle binary data (audio)
      console.log('buffer');
      const res = await AIresponse(JSON.parse(data).text)

      // console.log({ type: 'server', text: res.text })
      ws.send(JSON.stringify({type: 'server', text: res.text}));

    } else {
      console.log("no buffer");
      const generateRandomId = () => {
        const timestamp = Date.now();
        const randomNum = Math.floor(Math.random() * 1000);
        return `${timestamp}-${randomNum}`;
      };
      const randomId = generateRandomId();
      const uniqueFilename = `audio_${randomId}.wav`;
      const filePath = path.join(__dirname, uniqueFilename);

      fs.writeFile(filePath, Buffer.from(data), (err) => {
        if (err) {
          console.error('Error writing file:', err);
        } else {
          const fileStream = fs.createReadStream(filePath);

          fileStream.on('data', (sample) => {
            session.sendAudio(sample);
          });

          fileStream.on('end', async () => {
            await session.stop();
            fs.unlink(filePath, (err) => {
              if (err) {
                console.error('Error deleting file:', err);
              } else {
                // console.log('Temporary audio file deleted:', filePath);
              }
              startSession();
            });
          });
        }
      });
    }
  });

My event handlers:

session.addListener('Error', (error) => {
  console.log('Session error:', error);
});

let accumulatedTranscript = '';

// Listen for new transcript messages and accumulate them
session.addListener('AddTranscript', (message) => {
  console.log("transcript received", message.metadata.transcript);
  accumulatedTranscript += message.metadata.transcript;
});

session.addListener('EndOfTranscript', async () => {
  console.log('End of transcript:', accumulatedTranscript);

  // Clear the transcript accumulator for the next session
  accumulatedTranscript = '';
});

startSession method:

const startSession = () => {
  session
    .start({
      transcription_config: {
        language: 'en',
        operating_point: 'enhanced',
        enable_partials: false,
        max_delay: 2,
      },
      audio_format: {type: 'file'},
    })
    .then(() => {
      console.log('Speechmatics session started');
    })
    .catch((error) => {
      console.log('Error starting session:', error.message, error);
    });
};

Perhaps the error could be due to repeatedly calling await session.stop()? But if i don't call it, then it never calls the 'endOfTranscription' function. So how do I fix it? Also I just wonder why is the audio format 'file'? I am streaming audio from a react app to a node js proxy server because I don't want to expose my speechmatics credentials to the front end(isn't this the standard practice?)

mnemitz commented 4 weeks ago

Thanks for filing an issue. Apologies for the delayed response.

I haven't tried running your code yet, but this error does indeed sometimes happen when stopping and starting sessions very quickly. This is because we track and limit how many open connections there are per account at a given time, and this process isn't instant.

Is using a proxy server standard practice?

It is an option, but you may find generating JWTs to be a more flexible option for your use case: https://docs.speechmatics.com/introduction/authentication#temporary-keys

Short-lived JWTs for our real-time API can be generated by a backend server or serverless function. These tokens are safe to send to the browser, as they can expire as soon as you like.

In the next few days we will be revamping the SDK, and we will have plenty of examples for real-time transcription and more. For now, to solve your problem I would recommend looking into generating JWTs (which would eliminate the need for a proxy server), or adding some delay when restarting sessions in your proxy server.