diff --git a/lib/ai/providers/ruxa-image.ts b/lib/ai/providers/ruxa-image.ts index b1f9cf058..078179c5a 100644 --- a/lib/ai/providers/ruxa-image.ts +++ b/lib/ai/providers/ruxa-image.ts @@ -24,6 +24,21 @@ const DEFAULT_RESOLUTION = "1k"; const DEFAULT_OUTPUT_FORMAT = "png"; const POLL_INTERVAL_MS = 2000; const POLL_MAX_ATTEMPTS = 90; +const RUXA_NANO_BANANA_2_DOC_MODEL_ID = "gemini-3.1-flash-image-preview"; +const RUXA_MODEL_ID_ALIASES: Record = { + "google/nano-banana-2": RUXA_NANO_BANANA_2_DOC_MODEL_ID, +}; + +function normalizeRuxaModelId(modelId?: string) { + const raw = String(modelId || "").trim(); + if (!raw) return "gpt-image-1.5"; + return RUXA_MODEL_ID_ALIASES[raw] || raw; +} + +function isRuxaNanoBanana2Model(modelId?: string) { + const normalized = normalizeRuxaModelId(modelId); + return normalized === RUXA_NANO_BANANA_2_DOC_MODEL_ID; +} function normalizeUrlForCompare(url: string) { try { @@ -74,6 +89,14 @@ function normalizeOutputFormat(outputFormat?: string): "png" | "jpg" | "webp" { return "png"; } +function normalizeRuxaOutputFormat(modelId: string | undefined, outputFormat?: string) { + const normalized = normalizeOutputFormat(outputFormat); + if (!isRuxaNanoBanana2Model(modelId)) { + return normalized; + } + return normalized === "jpg" ? "jpeg" : normalized; +} + function extractTaskId(payload: any): string | undefined { if (typeof payload === "string" && payload.trim()) { return payload.trim(); @@ -370,17 +393,23 @@ export function createRuxaImage({ apiKey, baseURL }: RuxaImageConfig) { const { prompt, imageUrls } = extractPromptAndImages(options.messages); const aspectRatio = normalizeAspectRatio(options.imageParams?.aspectRatio); const resolution = normalizeResolution(options.imageParams?.imageSize); - const outputFormat = normalizeOutputFormat(options.imageParams?.outputFormat); - const activeModelId = options.overrideModelId || modelId || "gpt-image-1.5"; + const requestedModelId = options.overrideModelId || modelId || "gpt-image-1.5"; + const activeModelId = normalizeRuxaModelId(requestedModelId); + const outputFormat = normalizeRuxaOutputFormat(activeModelId, options.imageParams?.outputFormat); + const isNanoBanana2 = isRuxaNanoBanana2Model(activeModelId); const createEndpoint = joinApiPath(baseURL, "/api/v1/tasks/create"); const callbackUrl = process.env.RUXA_CALLBACK_URL?.trim(); const input: Record = { prompt, - resolution, output_format: outputFormat, }; - if (aspectRatio) { + if (isNanoBanana2) { + input.size = aspectRatio || "1:1"; + } else { + input.resolution = resolution; + } + if (aspectRatio && !isNanoBanana2) { input.size = aspectRatio; input.aspect_ratio = aspectRatio; } @@ -395,6 +424,12 @@ export function createRuxaImage({ apiKey, baseURL }: RuxaImageConfig) { model: activeModelId, ...(callbackUrl ? { callBackUrl: callbackUrl } : {}), }; + if (activeModelId !== requestedModelId) { + console.log("[Ruxa Image] Remapped modelId for provider compatibility:", { + requestedModelId, + activeModelId, + }); + } const createResponse = await fetch(createEndpoint, { method: "POST", headers: {