{"version":3,"sources":["../src/stt.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {\n  type APIConnectOptions,\n  type AudioBuffer,\n  AudioByteStream,\n  AudioEnergyFilter,\n  Future,\n  Task,\n  createTimedString,\n  getBaseLanguage,\n  log,\n  normalizeLanguage,\n  stt,\n  waitForAbort,\n} from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { WebSocket } from 'ws';\nimport { PeriodicCollector } from './_utils.js';\nimport type { STTLanguages, STTModels } from './models.js';\n\nexport interface STTOptions {\n  apiKey?: string;\n  language?: STTLanguages | string;\n  detectLanguage: boolean;\n  interimResults: boolean;\n  punctuate: boolean;\n  model: STTModels;\n  smartFormat: boolean;\n  noDelay: boolean;\n  endpointing: number;\n  fillerWords: boolean;\n  sampleRate: number;\n  numChannels: number;\n  keywords: [string, number][];\n  keyterm: string[];\n  profanityFilter: boolean;\n  /**\n   * Redact sensitive information from the transcription. Accepts a single value or list of\n   * values. Supported values: \"pci\", \"numbers\", \"ssn\", \"true\" (redact all).\n   * See https://developers.deepgram.com/docs/redaction for details.\n   */\n  redact: string | string[];\n  dictation: boolean;\n  diarize: boolean;\n  numerals: boolean;\n  mipOptOut: boolean;\n  baseUrl: string;\n}\n\nconst defaultSTTOptions: STTOptions = {\n  apiKey: process.env.DEEPGRAM_API_KEY,\n  language: 'en-US',\n  detectLanguage: false,\n  interimResults: true,\n  punctuate: true,\n  model: 'nova-3',\n  smartFormat: true,\n  noDelay: true,\n  endpointing: 25,\n  fillerWords: false,\n  sampleRate: 16000,\n  numChannels: 1,\n  keywords: [],\n  keyterm: [],\n  profanityFilter: false,\n  redact: [],\n  dictation: false,\n  diarize: false,\n  numerals: false,\n  mipOptOut: false,\n  baseUrl: 'wss://api.deepgram.com',\n};\n\nexport class STT extends stt.STT {\n  #opts: STTOptions;\n  #logger = log();\n  label = 'deepgram.STT';\n  private abortController = new AbortController();\n\n  get model(): string {\n    return this.#opts.model;\n  }\n\n  get provider(): string {\n    return 'Deepgram';\n  }\n\n  constructor(opts: Partial<STTOptions> = defaultSTTOptions) {\n    super({\n      streaming: true,\n      interimResults: opts.interimResults ?? defaultSTTOptions.interimResults,\n      alignedTranscript: 'word',\n    });\n    if (opts.apiKey === undefined && defaultSTTOptions.apiKey === undefined) {\n      throw new Error(\n        'Deepgram API key is required, whether as an argument or as $DEEPGRAM_API_KEY',\n      );\n    }\n\n    this.#opts = {\n      ...defaultSTTOptions,\n      ...opts,\n      language: opts.language ? normalizeLanguage(opts.language) : defaultSTTOptions.language,\n    };\n\n    if (this.#opts.detectLanguage) {\n      this.#opts.language = undefined;\n    } else if (\n      this.#opts.language &&\n      getBaseLanguage(this.#opts.language) !== 'en' &&\n      [\n        'nova-2-meeting',\n        'nova-2-phonecall',\n        'nova-2-finance',\n        'nova-2-conversationalai',\n        'nova-2-voicemail',\n        'nova-2-video',\n        'nova-2-medical',\n        'nova-2-drivethru',\n        'nova-2-automotive',\n        'nova-3-general',\n      ].includes(this.#opts.model)\n    ) {\n      this.#logger.warn(\n        `${this.#opts.model} does not support language ${this.#opts.language}, falling back to nova-2-general`,\n      );\n      this.#opts.model = 'nova-2-general';\n    }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  async _recognize(_: AudioBuffer): Promise<stt.SpeechEvent> {\n    throw new Error('Recognize is not supported on Deepgram STT');\n  }\n\n  updateOptions(opts: Partial<STTOptions>) {\n    this.#opts = {\n      ...this.#opts,\n      ...opts,\n      language:\n        opts.language !== undefined ? normalizeLanguage(opts.language) : this.#opts.language,\n    };\n  }\n\n  stream(options?: { connOptions?: APIConnectOptions }): SpeechStream {\n    return new SpeechStream(this, this.#opts, options?.connOptions);\n  }\n\n  async close() {\n    this.abortController.abort();\n  }\n}\n\nexport class SpeechStream extends stt.SpeechStream {\n  #opts: STTOptions;\n  #audioEnergyFilter: AudioEnergyFilter;\n  #logger = log();\n  #speaking = false;\n  #resetWS = new Future();\n  #requestId = '';\n  #audioDurationCollector: PeriodicCollector<number>;\n  label = 'deepgram.SpeechStream';\n\n  constructor(stt: STT, opts: STTOptions, connOptions?: APIConnectOptions) {\n    super(stt, opts.sampleRate, connOptions);\n    this.#opts = opts;\n    this.closed = false;\n    this.#audioEnergyFilter = new AudioEnergyFilter();\n    this.#audioDurationCollector = new PeriodicCollector(\n      (duration) => this.onAudioDurationReport(duration),\n      { duration: 5.0 },\n    );\n  }\n\n  protected async run() {\n    const maxRetry = 32;\n    let retries = 0;\n    let ws: WebSocket;\n\n    while (!this.input.closed && !this.closed) {\n      const streamURL = new URL(`${this.#opts.baseUrl}/v1/listen`);\n      const params = {\n        model: this.#opts.model,\n        punctuate: this.#opts.punctuate,\n        smart_format: this.#opts.smartFormat,\n        dictation: this.#opts.dictation,\n        diarize: this.#opts.diarize,\n        numerals: this.#opts.numerals,\n        no_delay: this.#opts.noDelay,\n        interim_results: this.#opts.interimResults,\n        encoding: 'linear16',\n        vad_events: true,\n        sample_rate: this.#opts.sampleRate,\n        channels: this.#opts.numChannels,\n        endpointing: this.#opts.endpointing || false,\n        filler_words: this.#opts.fillerWords,\n        keywords: this.#opts.keywords.map((x) => x.join(':')),\n        keyterm: this.#opts.keyterm,\n        profanity_filter: this.#opts.profanityFilter,\n        redact: this.#opts.redact,\n        language: this.#opts.language,\n        mip_opt_out: this.#opts.mipOptOut,\n      };\n      Object.entries(params).forEach(([k, v]) => {\n        if (v !== undefined) {\n          if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n            streamURL.searchParams.append(k, String(v));\n          } else {\n            v.forEach((x) => streamURL.searchParams.append(k, String(x)));\n          }\n        }\n      });\n\n      ws = new WebSocket(streamURL, {\n        headers: { Authorization: `Token ${this.#opts.apiKey}` },\n      });\n\n      try {\n        await new Promise((resolve, reject) => {\n          ws.on('open', resolve);\n          ws.on('error', (error) => reject(error));\n          ws.on('close', (code) => reject(`WebSocket returned ${code}`));\n        });\n\n        await this.#runWS(ws);\n      } catch (e) {\n        if (!this.closed && !this.input.closed) {\n          if (retries >= maxRetry) {\n            throw new Error(`failed to connect to Deepgram after ${retries} attempts: ${e}`);\n          }\n\n          const delay = Math.min(retries * 5, 10);\n          retries++;\n\n          this.#logger.warn(\n            `failed to connect to Deepgram, retrying in ${delay} seconds: ${e} (${retries}/${maxRetry})`,\n          );\n          await new Promise((resolve) => setTimeout(resolve, delay * 1000));\n        } else {\n          this.#logger.warn(\n            `Deepgram disconnected, connection is closed: ${e} (inputClosed: ${this.input.closed}, isClosed: ${this.closed})`,\n          );\n        }\n      }\n    }\n\n    this.closed = true;\n  }\n\n  updateOptions(opts: Partial<STTOptions>) {\n    this.#opts = { ...this.#opts, ...opts };\n    this.#resetWS.resolve();\n  }\n\n  async #runWS(ws: WebSocket) {\n    this.#resetWS = new Future();\n    let closing = false;\n\n    const keepalive = setInterval(() => {\n      try {\n        ws.send(JSON.stringify({ type: 'KeepAlive' }));\n      } catch {\n        clearInterval(keepalive);\n        return;\n      }\n    }, 5000);\n\n    // gets cancelled also when sendTask is complete\n    const wsMonitor = Task.from(async (controller) => {\n      const closed = new Promise<void>(async (_, reject) => {\n        ws.once('close', (code, reason) => {\n          if (!closing) {\n            this.#logger.error(`WebSocket closed with code ${code}: ${reason}`);\n            reject(new Error('WebSocket closed'));\n          }\n        });\n      });\n\n      await Promise.race([closed, waitForAbort(controller.signal)]);\n    });\n\n    const sendTask = async () => {\n      const samples100Ms = Math.floor(this.#opts.sampleRate / 10);\n      const stream = new AudioByteStream(\n        this.#opts.sampleRate,\n        this.#opts.numChannels,\n        samples100Ms,\n      );\n\n      // waitForAbort internally sets up an abort listener on the abort signal\n      // we need to put it outside loop to avoid constant re-registration of the listener\n      const abortPromise = waitForAbort(this.abortSignal);\n\n      try {\n        while (!this.closed) {\n          const result = await Promise.race([this.input.next(), abortPromise]);\n\n          if (result === undefined) return; // aborted\n          if (result.done) {\n            break;\n          }\n\n          const data = result.value;\n\n          let frames: AudioFrame[];\n          if (data === SpeechStream.FLUSH_SENTINEL) {\n            frames = stream.flush();\n            this.#audioDurationCollector.flush();\n          } else if (\n            data.sampleRate === this.#opts.sampleRate &&\n            data.channels === this.#opts.numChannels\n          ) {\n            frames = stream.write(data.data.buffer as ArrayBuffer);\n          } else {\n            throw new Error(`sample rate or channel count of frame does not match`);\n          }\n\n          for await (const frame of frames) {\n            if (this.#audioEnergyFilter.pushFrame(frame)) {\n              const frameDuration = frame.samplesPerChannel / frame.sampleRate;\n              this.#audioDurationCollector.push(frameDuration);\n              ws.send(frame.data.buffer);\n            }\n          }\n        }\n      } finally {\n        closing = true;\n        ws.send(JSON.stringify({ type: 'CloseStream' }));\n        wsMonitor.cancel();\n      }\n    };\n\n    const listenTask = Task.from(async (controller) => {\n      const putMessage = (message: stt.SpeechEvent) => {\n        if (!this.queue.closed) {\n          try {\n            this.queue.put(message);\n          } catch (e) {\n            // ignore\n          }\n        }\n      };\n\n      const listenMessage = new Promise<void>((resolve, reject) => {\n        ws.on('message', (msg) => {\n          try {\n            const json = JSON.parse(msg.toString());\n            switch (json['type']) {\n              case 'SpeechStarted': {\n                // This is a normal case. Deepgram's SpeechStarted events\n                // are not correlated with speech_final or utterance end.\n                // It's possible that we receive two in a row without an endpoint\n                // It's also possible we receive a transcript without a SpeechStarted event.\n                if (this.#speaking) return;\n                this.#speaking = true;\n                putMessage({ type: stt.SpeechEventType.START_OF_SPEECH });\n                break;\n              }\n              // see this page:\n              // https://developers.deepgram.com/docs/understand-endpointing-interim-results#using-endpointing-speech_final\n              // for more information about the different types of events\n              case 'Results': {\n                const metadata = json['metadata'];\n                const requestId = metadata['request_id'];\n                const isFinal = json['is_final'];\n                const isEndpoint = json['speech_final'];\n                this.#requestId = requestId;\n\n                const alternatives = liveTranscriptionToSpeechData(\n                  this.#opts.language!,\n                  json,\n                  this.startTimeOffset,\n                );\n\n                // If, for some reason, we didn't get a SpeechStarted event but we got\n                // a transcript with text, we should start speaking. It's rare but has\n                // been observed.\n                if (alternatives[0] && alternatives[0].text) {\n                  if (!this.#speaking) {\n                    this.#speaking = true;\n                    putMessage({\n                      type: stt.SpeechEventType.START_OF_SPEECH,\n                    });\n                  }\n\n                  if (isFinal) {\n                    putMessage({\n                      type: stt.SpeechEventType.FINAL_TRANSCRIPT,\n                      alternatives: [alternatives[0], ...alternatives.slice(1)],\n                    });\n                  } else {\n                    putMessage({\n                      type: stt.SpeechEventType.INTERIM_TRANSCRIPT,\n                      alternatives: [alternatives[0], ...alternatives.slice(1)],\n                    });\n                  }\n                }\n\n                // if we receive an endpoint, only end the speech if\n                // we either had a SpeechStarted event or we have a seen\n                // a non-empty transcript (deepgram doesn't have a SpeechEnded event)\n                if (isEndpoint && this.#speaking) {\n                  this.#speaking = false;\n                  putMessage({ type: stt.SpeechEventType.END_OF_SPEECH });\n                }\n\n                break;\n              }\n              case 'Metadata': {\n                break;\n              }\n              default: {\n                this.#logger.child({ msg: json }).warn('received unexpected message from Deepgram');\n                break;\n              }\n            }\n\n            if (this.closed || closing) {\n              resolve();\n            }\n          } catch (err) {\n            this.#logger.error(`STT: Error processing message: ${msg}`);\n            reject(err);\n          }\n        });\n      });\n\n      await Promise.race([listenMessage, waitForAbort(controller.signal)]);\n    }, this.abortController);\n\n    await Promise.race([\n      this.#resetWS.await,\n      Promise.all([sendTask(), listenTask.result, wsMonitor]),\n    ]);\n    closing = true;\n    ws.close();\n    clearInterval(keepalive);\n  }\n\n  private onAudioDurationReport(duration: number) {\n    const usageEvent: stt.SpeechEvent = {\n      type: stt.SpeechEventType.RECOGNITION_USAGE,\n      requestId: this.#requestId,\n      recognitionUsage: {\n        audioDuration: duration,\n      },\n    };\n    this.queue.put(usageEvent);\n  }\n}\n\nconst liveTranscriptionToSpeechData = (\n  language: STTLanguages | string,\n  data: { [id: string]: any },\n  startTimeOffset: number = 0,\n): stt.SpeechData[] => {\n  const alts: any[] = data['channel']['alternatives'];\n\n  return alts.map((alt) => {\n    const wordsData: any[] = alt['words'] ?? [];\n    const detectedLanguage =\n      language === 'multi' ? alt['languages']?.[0] ?? language : alt['language'] ?? language;\n\n    return {\n      language: normalizeLanguage(detectedLanguage),\n      startTime: wordsData.length ? wordsData[0]['start'] + startTimeOffset : startTimeOffset,\n      endTime: wordsData.length\n        ? wordsData[wordsData.length - 1]['end'] + startTimeOffset\n        : startTimeOffset,\n      confidence: alt['confidence'],\n      text: alt['transcript'],\n      words: wordsData.map((word) =>\n        createTimedString({\n          text: word['word'] ?? '',\n          startTime: (word['start'] ?? 0) + startTimeOffset,\n          endTime: (word['end'] ?? 0) + startTimeOffset,\n          confidence: word['confidence'] ?? 0.0,\n          startTimeOffset,\n        }),\n      ),\n    };\n  });\n};\n"],"mappings":"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","names":["stt"]}