UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

143 lines (142 loc) 5.49 kB
import { m as readProviderJsonResponse, n as assertOkOrThrowHttpError, p as readProviderJsonObjectResponse } from "./provider-http-errors-U-nhuk_f.js"; import "./image-runtime-BOIoCq-0.js"; import { d as requireTranscriptionText, l as postJsonRequest, n as buildOpenAiCompatibleAuthHeaders, p as resolveProviderHttpRequestConfig, t as buildAudioTranscriptionFormData, u as postMultipartRequest } from "./shared-DCDpYrmy.js"; import { t as OPENAI_AUDIO_TRANSCRIPTIONS_API } from "./openai-audio-api-CZK5TvIV.js"; //#region packages/media-understanding-common/src/openai-compatible-video.ts /** Trim optional strings, falling back when empty. */ function resolveMediaUnderstandingString(value, fallback) { return value?.trim() || fallback; } /** Coerce text from OpenAI-compatible content or reasoning fields. */ function coerceOpenAiCompatibleVideoText(payload) { const message = payload.choices?.[0]?.message; if (!message) return null; if (typeof message.content === "string" && message.content.trim()) return message.content.trim(); if (Array.isArray(message.content)) { const text = message.content.map((part) => part.text?.trim() ?? "").filter(Boolean).join("\n"); if (text) return text; } if (typeof message.reasoning_content === "string" && message.reasoning_content.trim()) return message.reasoning_content.trim(); return null; } /** Build an OpenAI-compatible request body with an inline data URL video. */ function buildOpenAiCompatibleVideoRequestBody(params) { return { model: params.model, messages: [{ role: "user", content: [{ type: "text", text: params.prompt }, { type: "video_url", video_url: { url: `data:${params.mime};base64,${params.buffer.toString("base64")}` } }] }] }; } //#endregion //#region src/media-understanding/openai-compatible-video.ts /** Describe a video through an OpenAI-compatible chat-completions endpoint. */ async function describeOpenAiCompatibleVideo(params) { const fetchFn = params.fetchFn ?? fetch; const model = resolveMediaUnderstandingString(params.model, params.defaultModel); const mime = resolveMediaUnderstandingString(params.mime, "video/mp4"); const prompt = resolveMediaUnderstandingString(params.prompt, params.defaultPrompt); const errorPrefix = `${params.providerLabel} video description`; const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } = resolveProviderHttpRequestConfig({ baseUrl: params.baseUrl, defaultBaseUrl: params.defaultBaseUrl, headers: params.headers, request: params.request, defaultHeaders: { "content-type": "application/json", ...buildOpenAiCompatibleAuthHeaders(params) }, provider: params.provider, api: "openai-completions", capability: "video", transport: "media-understanding" }); const { response, release } = await postJsonRequest({ url: `${baseUrl}/chat/completions`, headers, body: buildOpenAiCompatibleVideoRequestBody({ model, prompt, mime, buffer: params.buffer }), timeoutMs: params.timeoutMs, ...params.signal ? { signal: params.signal } : {}, fetchFn, allowPrivateNetwork, dispatcherPolicy }); try { await assertOkOrThrowHttpError(response, `${errorPrefix} failed`, { requestHeaders: headers }); const text = coerceOpenAiCompatibleVideoText(await readProviderJsonResponse(response, `${errorPrefix} failed`, { requestHeaders: headers })); if (!text) throw new Error(`${errorPrefix} response missing content`); return { text, model }; } finally { await release(); } } //#endregion //#region src/media-understanding/openai-compatible-audio.ts function resolveModel(model, fallback) { return model?.trim() || fallback; } /** Sends an OpenAI-compatible audio transcription request and returns validated text output. */ async function transcribeOpenAiCompatibleAudio(params) { const fetchFn = params.fetchFn ?? fetch; const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } = resolveProviderHttpRequestConfig({ baseUrl: params.baseUrl, defaultBaseUrl: params.defaultBaseUrl, headers: params.headers, request: params.request, defaultHeaders: buildOpenAiCompatibleAuthHeaders(params), provider: params.provider, api: OPENAI_AUDIO_TRANSCRIPTIONS_API, capability: "audio", transport: "media-understanding" }); const url = `${baseUrl}/audio/transcriptions`; const model = resolveModel(params.model, params.defaultModel); const form = buildAudioTranscriptionFormData({ buffer: params.buffer, fileName: params.fileName, mime: params.mime, fields: { model, language: params.language, prompt: params.prompt } }); const { response: res, release } = await postMultipartRequest({ url, headers, body: form, timeoutMs: params.timeoutMs, ...params.signal ? { signal: params.signal } : {}, fetchFn, pinDns: false, allowPrivateNetwork, dispatcherPolicy }); try { await assertOkOrThrowHttpError(res, "Audio transcription failed", { requestHeaders: headers }); const payload = await readProviderJsonObjectResponse(res, "Audio transcription failed", { requestHeaders: headers }); return { text: requireTranscriptionText(typeof payload.text === "string" ? payload.text : void 0, "Audio transcription response missing text"), model }; } finally { await release(); } } //#endregion export { resolveMediaUnderstandingString as a, coerceOpenAiCompatibleVideoText as i, describeOpenAiCompatibleVideo as n, buildOpenAiCompatibleVideoRequestBody as r, transcribeOpenAiCompatibleAudio as t };