{"version":3,"file":"audio-input.mjs","names":[],"sources":["../../../../../../../ai/src/transcribe/audio-input.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { basename, extname } from \"node:path\";\nimport type { AudioInput } from \"../contracts/transcription-model.contract\";\n\n/**\n * File-extension → IANA audio media type map covering the formats the\n * common STT providers accept — including the **WhatsApp voice-note**\n * formats (`.ogg` / `.opus`, Opus-in-Ogg on Android; `.m4a` on iOS).\n */\nconst AUDIO_MEDIA_TYPES: Record<string, string> = {\n  \".mp3\": \"audio/mpeg\",\n  \".mpeg\": \"audio/mpeg\",\n  \".mpga\": \"audio/mpeg\",\n  \".m4a\": \"audio/mp4\",\n  \".mp4\": \"audio/mp4\",\n  \".wav\": \"audio/wav\",\n  \".webm\": \"audio/webm\",\n  \".weba\": \"audio/webm\",\n  \".ogg\": \"audio/ogg\",\n  \".oga\": \"audio/ogg\",\n  \".opus\": \"audio/ogg\",\n  \".flac\": \"audio/flac\",\n  \".aac\": \"audio/aac\",\n};\n\n/**\n * Resolve the audio media type from a filename's extension, or\n * `undefined` when the extension is unknown. Case-insensitive.\n *\n * @example\n * audioMediaTypeForFilename(\"voice-note.opus\"); // \"audio/ogg\"\n */\nexport function audioMediaTypeForFilename(filename: string): string | undefined {\n  return AUDIO_MEDIA_TYPES[extname(filename).toLowerCase()];\n}\n\n/**\n * Package raw audio bytes as an {@link AudioInput} for `ai.transcribe()`.\n * Pure plumbing — no AI, no I/O. Use when you already hold the bytes\n * (an upload buffer, a downloaded blob).\n *\n * @example\n * const audio = audioFromBuffer(uploadBuffer, \"audio/ogg\", \"note.ogg\");\n * const { data } = await ai.transcribe({ model: openai.transcribe({ name: \"whisper-1\" }), audio });\n */\nexport function audioFromBuffer(\n  data: Uint8Array,\n  mediaType: string,\n  filename?: string,\n): AudioInput {\n  return {\n    base64: Buffer.from(data).toString(\"base64\"),\n    mediaType,\n    ...(filename ? { filename } : {}),\n  };\n}\n\n/**\n * Read an audio file from disk and package it as an {@link AudioInput}\n * for `ai.transcribe()` — the one-line bridge from a file on disk\n * (WhatsApp `.ogg`/`.opus`, a meeting `.m4a`, a `.wav`) to the\n * transcription verb. **Pure utility — no AI here**; the actual text\n * extraction is the AI step (`ai.transcribe`).\n *\n * The media type is inferred from the file extension (override via\n * `options.mediaType` for extensionless or mislabeled files).\n *\n * @example\n * // WhatsApp voice note → text, end to end:\n * const audio = await audioFromFile(\"./voice-note.ogg\");\n * const { data, error } = await ai.transcribe({\n *   model: openai.transcribe({ name: \"whisper-1\" }),\n *   audio,\n *   language: \"en\",\n * });\n * if (!error) console.log(data.text);\n */\nexport async function audioFromFile(\n  filePath: string,\n  options?: { mediaType?: string },\n): Promise<AudioInput> {\n  const buffer = await readFile(filePath);\n  const filename = basename(filePath);\n  const mediaType = options?.mediaType ?? audioMediaTypeForFilename(filename) ?? \"audio/mpeg\";\n\n  return { base64: buffer.toString(\"base64\"), mediaType, filename };\n}\n"],"mappings":";;;;;;;;;AASA,MAAM,oBAA4C;CAChD,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;AACV;;;;;;;;AASA,SAAgB,0BAA0B,UAAsC;CAC9E,OAAO,kBAAkB,QAAQ,QAAQ,CAAC,CAAC,YAAY;AACzD;;;;;;;;;;AAWA,SAAgB,gBACd,MACA,WACA,UACY;CACZ,OAAO;EACL,QAAQ,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,QAAQ;EAC3C;EACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;CACjC;AACF;;;;;;;;;;;;;;;;;;;;;AAsBA,eAAsB,cACpB,UACA,SACqB;CACrB,MAAM,SAAS,MAAM,SAAS,QAAQ;CACtC,MAAM,WAAW,SAAS,QAAQ;CAClC,MAAM,YAAY,SAAS,aAAa,0BAA0B,QAAQ,KAAK;CAE/E,OAAO;EAAE,QAAQ,OAAO,SAAS,QAAQ;EAAG;EAAW;CAAS;AAClE"}