UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

129 lines (128 loc) 4.33 kB
import { s as asFiniteNumber } from "./number-coercion-CLj0HTDM.js"; import { m as readProviderJsonResponse, n as assertOkOrThrowHttpError } from "./provider-http-errors-U-nhuk_f.js"; import { d as requireTranscriptionText, l as postJsonRequest, p as resolveProviderHttpRequestConfig } from "./shared-DCDpYrmy.js"; import "./string-coerce-runtime-GQa0ehRA.js"; import "./provider-http-k9RMI7iG.js"; import { t as OPENROUTER_BASE_URL } from "./provider-defaults-ilQX6q3J.js"; import "./provider-catalog-DuNWmWj-.js"; import path from "node:path"; //#region extensions/openrouter/media-understanding-provider.ts const DEFAULT_OPENROUTER_AUDIO_TRANSCRIPTION_MODEL = "openai/whisper-large-v3-turbo"; const SUPPORTED_AUDIO_FORMATS = /* @__PURE__ */ new Set([ "wav", "mp3", "flac", "m4a", "ogg", "webm", "aac" ]); function normalizeMimeType(mime) { const normalized = mime?.trim().toLowerCase(); if (!normalized) return; const [type] = normalized.split(";"); return type?.trim() || void 0; } function resolveFormatFromMime(mime) { const normalized = normalizeMimeType(mime); if (!normalized) return; switch (normalized) { case "audio/wav": case "audio/x-wav": return "wav"; case "audio/mpeg": case "audio/mp3": return "mp3"; case "audio/flac": return "flac"; case "audio/mp4": case "audio/m4a": case "audio/x-m4a": return "m4a"; case "audio/ogg": case "audio/oga": case "audio/opus": return "ogg"; case "audio/webm": return "webm"; case "audio/aac": return "aac"; default: return; } } function resolveFormatFromFileName(fileName) { const ext = path.extname(fileName ?? "").trim().toLowerCase().replace(/^\./, ""); if (!ext) return; if (ext === "mpeg") return "mp3"; if (ext === "mp4") return "m4a"; if (ext === "oga" || ext === "opus") return "ogg"; return SUPPORTED_AUDIO_FORMATS.has(ext) ? ext : void 0; } function resolveOpenRouterAudioFormat(params) { const fromMime = resolveFormatFromMime(params.mime); if (fromMime) return fromMime; const fromFileName = resolveFormatFromFileName(params.fileName); if (fromFileName) return fromFileName; throw new Error(`OpenRouter STT could not resolve audio format from mime "${params.mime ?? ""}" and file "${params.fileName ?? ""}"`); } async function transcribeOpenRouterAudio(params) { const model = params.model?.trim() || DEFAULT_OPENROUTER_AUDIO_TRANSCRIPTION_MODEL; const format = resolveOpenRouterAudioFormat({ mime: params.mime, fileName: params.fileName }); const fetchFn = params.fetchFn ?? fetch; const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } = resolveProviderHttpRequestConfig({ baseUrl: params.baseUrl, defaultBaseUrl: OPENROUTER_BASE_URL, headers: params.headers, request: params.request, defaultHeaders: { Authorization: `Bearer ${params.apiKey}`, "Content-Type": "application/json", "HTTP-Referer": "https://openclaw.ai", "X-OpenRouter-Title": "OpenClaw" }, provider: "openrouter", api: "openrouter-stt", capability: "audio", transport: "media-understanding" }); const temperature = asFiniteNumber(params.query?.temperature); const { response, release } = await postJsonRequest({ url: `${baseUrl}/audio/transcriptions`, headers, body: { model, input_audio: { data: params.buffer.toString("base64"), format }, ...params.language?.trim() ? { language: params.language.trim() } : {}, ...temperature !== void 0 ? { temperature } : {} }, timeoutMs: params.timeoutMs, ...params.signal ? { signal: params.signal } : {}, fetchFn, allowPrivateNetwork, dispatcherPolicy, auditContext: "openrouter stt" }); try { await assertOkOrThrowHttpError(response, "OpenRouter audio transcription failed"); const payload = await readProviderJsonResponse(response, "openrouter.stt"); return { text: requireTranscriptionText(payload.text, "OpenRouter transcription response missing text"), model }; } finally { await release(); } } const openrouterMediaUnderstandingProvider = { id: "openrouter", capabilities: ["image", "audio"], defaultModels: { image: "auto", audio: DEFAULT_OPENROUTER_AUDIO_TRANSCRIPTION_MODEL }, autoPriority: { audio: 35 }, describeImage: void 0, describeImages: void 0, transcribeAudio: transcribeOpenRouterAudio }; //#endregion export { openrouterMediaUnderstandingProvider as t };