deepgram / deepgram-js-sdk

Official JavaScript SDK for Deepgram's automated speech recognition APIs.
https://developers.deepgram.com
MIT License
139 stars 52 forks source link

Fetch timeout #330

Open xtrinch opened 2 weeks ago

xtrinch commented 2 weeks ago

What is the current behavior?

Speech to text is returning DeepgramUnknownError: Failed to construct 'Request': member signal is not of type AbortSignal when attempting to use signal to abort the request after some time

Steps to reproduce

  const client = createClient(
    "API_KEY",
    {
          global: {
            fetch: {
              options: {
                url: "SOME_URL",
                signal: AbortSignal.timeout(config.timeoutSeconds * 1000),
              },
            },
          }
    },
  );

Expected behavior

I would have presumed it wouldn't throw an error, unless I'm doing something wrong, but the types seem to allow this? Is there another way to add the timeout?

Environment

Node 18

lukeocodes commented 2 weeks ago

Can you give me a little more info about your environment?

xtrinch commented 2 weeks ago

Node 18-alpine docker image, "@deepgram/sdk": "^3.5.0", anything else that could be relevant?

lukeocodes commented 2 weeks ago

We use cross-fetch... I've not seen your method of timeout, but this is what someone else had been using.

  const controller = new AbortController();
  const { signal } = controller;

  // set up your timeout

  const client = createClient(
    "API_KEY",
    {
      global: {
        fetch: {
          options: {
            url: "SOME_URL",
            signal,
          },
        },
      }
    },
  );

You can also provide an entirely custom fetch and configure your requirements that way

xtrinch commented 2 weeks ago

Thanks for the tips, I converted it to a custom fetch and it now works. It most likely appears to be a lifetime issue because if I pass it into global options I guess the same signal tries to be used multiple times. For anyone interested in the future, this worked:

const customFetch = async (
  timeoutSeconds: number,
  input: string | URL | globalThis.Request,
  init?: RequestInit,
): Promise<Response> => {
  return fetch(input, {
    ...init,
    signal: AbortSignal.timeout(timeoutSeconds * 1000),
  });
};

export const configureDeepgram = (config: DeepgramConfig): DeepgramClient => {
  const client = createClient(
    config.apiKey,
     {
          global: {
            fetch: {
              client: (
                input: string | URL | globalThis.Request,
                init?: RequestInit,
              ): Promise<Response> =>
                customFetch(config.timeoutSeconds, input, init),
              options: {
                url: config.url,
              },
            },
          },
        }
  );

  return client;
};