openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
153 lines (152 loc) • 6.06 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import { m as readProviderJsonResponse, n as assertOkOrThrowHttpError } from "./provider-http-errors-U-nhuk_f.js";
import { t as isProviderApiKeyConfigured } from "./provider-auth-availability-BUrlw84-.js";
import { n as resolveGeneratedMediaMaxBytes } from "./configured-max-bytes-CTSUbFDK.js";
import "./provider-auth-BeZ7NZUU.js";
import { l as postJsonRequest } from "./shared-DCDpYrmy.js";
import "./string-coerce-runtime-GQa0ehRA.js";
import "./media-generation-runtime-Dd81xPqM.js";
import "./provider-http-k9RMI7iG.js";
import { n as extractGeneratedMusicFileCandidates, t as downloadGeneratedMusicAsset } from "./music-generation-CAe8vdz7.js";
import { t as resolveFalHttpRequestConfig } from "./http-config-DNPnj6OD.js";
//#region extensions/fal/music-generation-provider.ts
const DEFAULT_FAL_MUSIC_MODEL = "fal-ai/minimax-music/v2.6";
const FAL_ACE_STEP_MODEL = "fal-ai/ace-step/prompt-to-audio";
const FAL_STABLE_AUDIO_MODEL = "fal-ai/stable-audio-25/text-to-audio";
const DEFAULT_TIMEOUT_MS = 18e4;
const FAL_MUSIC_MODELS = [
DEFAULT_FAL_MUSIC_MODEL,
FAL_ACE_STEP_MODEL,
FAL_STABLE_AUDIO_MODEL
];
function resolveFalMusicModel(model) {
return normalizeOptionalString(model) ?? DEFAULT_FAL_MUSIC_MODEL;
}
function buildFalMinimaxBody(req) {
const lyrics = normalizeOptionalString(req.lyrics);
if (lyrics && req.instrumental === true) throw new Error("fal MiniMax music generation cannot use lyrics when instrumental=true.");
return {
prompt: req.prompt,
...lyrics ? { lyrics } : {},
...req.instrumental === true ? { is_instrumental: true } : {},
...!lyrics && req.instrumental !== true ? { lyrics_optimizer: true } : {},
...typeof req.durationSeconds === "number" ? { duration: req.durationSeconds } : {},
audio_setting: {
sample_rate: 44100,
bitrate: 256e3,
format: req.format ?? "mp3"
}
};
}
function buildFalAceStepBody(req) {
if (normalizeOptionalString(req.lyrics)) throw new Error("fal ACE-Step music generation does not support explicit lyrics.");
return {
prompt: req.prompt,
...req.instrumental === true ? { instrumental: true } : {},
...typeof req.durationSeconds === "number" ? { duration: req.durationSeconds } : {}
};
}
function buildFalStableAudioBody(req) {
if (normalizeOptionalString(req.lyrics)) throw new Error("fal Stable Audio music generation does not support explicit lyrics.");
if (req.instrumental === true) throw new Error("fal Stable Audio music generation does not support instrumental mode.");
return {
prompt: req.prompt,
...typeof req.durationSeconds === "number" ? { seconds_total: req.durationSeconds } : {}
};
}
function buildFalMusicRequestBody(req, model) {
if (model === FAL_ACE_STEP_MODEL) return buildFalAceStepBody(req);
if (model === FAL_STABLE_AUDIO_MODEL) return buildFalStableAudioBody(req);
return buildFalMinimaxBody(req);
}
function resolveFalMusicMetadata(payload) {
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return;
const metadata = {};
for (const key of ["seed", "tags"]) {
const value = payload[key];
if (value !== void 0 && value !== null) metadata[key] = value;
}
return Object.keys(metadata).length > 0 ? metadata : void 0;
}
function buildFalMusicGenerationProvider() {
return {
id: "fal",
label: "fal",
defaultModel: DEFAULT_FAL_MUSIC_MODEL,
models: [...FAL_MUSIC_MODELS],
isConfigured: (ctx) => isProviderApiKeyConfigured({
provider: "fal",
...ctx
}),
capabilities: {
generate: {
maxTracks: 1,
maxDurationSeconds: 240,
supportsLyrics: true,
supportsLyricsByModel: {
[FAL_ACE_STEP_MODEL]: false,
[FAL_STABLE_AUDIO_MODEL]: false
},
supportsInstrumental: true,
supportsInstrumentalByModel: { [FAL_STABLE_AUDIO_MODEL]: false },
supportsDuration: true,
supportsFormat: true,
supportedFormats: ["mp3", "wav"],
supportedFormatsByModel: {
[DEFAULT_FAL_MUSIC_MODEL]: ["mp3"],
[FAL_ACE_STEP_MODEL]: ["wav"],
[FAL_STABLE_AUDIO_MODEL]: ["wav"]
}
},
edit: { enabled: false }
},
async generateMusic(req) {
if ((req.inputImages?.length ?? 0) > 0) throw new Error("fal music generation does not support image reference inputs.");
const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } = await resolveFalHttpRequestConfig({
req,
capability: "audio"
});
const model = resolveFalMusicModel(req.model);
const { response, release } = await postJsonRequest({
url: `${baseUrl}/${model}`,
headers,
body: buildFalMusicRequestBody(req, model),
timeoutMs: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,
fetchFn: fetch,
allowPrivateNetwork,
dispatcherPolicy
});
try {
await assertOkOrThrowHttpError(response, "fal music generation failed");
const payload = await readProviderJsonResponse(response, "fal music generation");
const [candidate] = extractGeneratedMusicFileCandidates(payload);
if (!candidate) throw new Error("fal music generation response missing audio output");
const track = await downloadGeneratedMusicAsset({
candidate,
timeoutMs: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,
fetchFn: fetch,
provider: "fal",
requestFailedMessage: "fal generated music download failed",
maxBytes: resolveGeneratedMediaMaxBytes(req.cfg, "audio")
});
const lyrics = typeof payload === "object" && payload && !Array.isArray(payload) ? normalizeOptionalString(payload.lyrics) : void 0;
return {
tracks: [track],
model,
...lyrics ? { lyrics: [lyrics] } : {},
metadata: {
...resolveFalMusicMetadata(payload),
...track.metadata?.url ? { audioUrl: track.metadata.url } : {},
instrumental: req.instrumental === true,
...req.format ? { requestedFormat: req.format } : {},
...typeof req.durationSeconds === "number" ? { requestedDurationSeconds: req.durationSeconds } : {}
}
};
} finally {
await release();
}
}
};
}
//#endregion
export { buildFalMusicGenerationProvider as t };