From b75dfa9295bbba761e47bbd14439f63673b71eac Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 13 Mar 2026 09:47:50 +0800 Subject: [PATCH] Preserve auto ratio in OpenAI and RUXA image providers --- lib/ai/providers/openai-image.ts | 23 +++++++++++------------ lib/ai/providers/ruxa-image.ts | 13 +++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/ai/providers/openai-image.ts b/lib/ai/providers/openai-image.ts index b872176a4..bdce58c0d 100644 --- a/lib/ai/providers/openai-image.ts +++ b/lib/ai/providers/openai-image.ts @@ -23,7 +23,6 @@ interface UploadedImage { original: string; } -const DEFAULT_ASPECT_RATIO = "1:1"; const DEFAULT_IMAGE_SIZE = "2K"; const DEFAULT_TIMEOUT_MS = 300000; const SUPPORTED_ASPECT_RATIOS = [ @@ -65,7 +64,7 @@ function normalizeAspectRatio(value?: string) { const normalized = String(value || "").trim(); if (!normalized || normalized.toLowerCase() === "auto") return "auto"; if ((SUPPORTED_ASPECT_RATIOS as readonly string[]).includes(normalized)) return normalized; - return DEFAULT_ASPECT_RATIO; + return undefined; } function parseAspectRatioValue(ratio: string) { @@ -81,8 +80,8 @@ function roundEven(value: number) { } function inferClosestAspectRatio(aspectValue: number) { - if (!Number.isFinite(aspectValue) || aspectValue <= 0) return DEFAULT_ASPECT_RATIO; - let closest = DEFAULT_ASPECT_RATIO; + if (!Number.isFinite(aspectValue) || aspectValue <= 0) return "1:1"; + let closest = "1:1"; let minDiff = Number.POSITIVE_INFINITY; for (const candidate of SUPPORTED_ASPECT_RATIOS) { const diff = Math.abs(parseAspectRatioValue(candidate) - aspectValue); @@ -361,7 +360,7 @@ async function requestOpenAIImageGeneration(params: { apiKey: string; model: string; prompt: string; - size: string; + size?: string; imageUrls: string[]; quality?: string; background?: string; @@ -378,7 +377,7 @@ async function requestOpenAIImageGeneration(params: { const formData = new FormData(); formData.append("model", model); formData.append("prompt", prompt); - formData.append("size", size); + if (size) formData.append("size", size); formData.append("response_format", "url"); if (quality) formData.append("quality", quality); @@ -420,7 +419,7 @@ async function requestOpenAIImageGeneration(params: { body: JSON.stringify({ model, prompt, - size, + ...(size ? { size } : {}), response_format: "url", ...(quality ? { quality } : {}), ...(background ? { background } : {}), @@ -474,15 +473,15 @@ export function createOpenAIImage({ apiKey, baseURL }: OpenAIImageConfig) { }) => { const { prompt, imageUrls } = extractPromptAndImages(options.messages); const activeModelId = options.overrideModelId || modelId; + const normalizedAspectRatio = normalizeAspectRatio(options.imageParams?.aspectRatio); const aspectRatio = - normalizeAspectRatio(options.imageParams?.aspectRatio) === "auto" + normalizedAspectRatio === "auto" ? await inferAspectRatioFromImageUrl(imageUrls[0] || "") - : normalizeAspectRatio(options.imageParams?.aspectRatio); + : normalizedAspectRatio; const imageSize = normalizeImageSizeLabel(options.imageParams?.imageSize); - const effectiveAspectRatio = aspectRatio || DEFAULT_ASPECT_RATIO; const size = options.imageParams?.size || - resolveOpenAISize(effectiveAspectRatio, imageSize); + (aspectRatio ? resolveOpenAISize(aspectRatio, imageSize) : undefined); const quality = normalizeQuality(options.imageParams?.quality); const background = normalizeBackground(options.imageParams?.background); const outputFormat = normalizeOutputFormat(options.imageParams?.outputFormat); @@ -490,7 +489,7 @@ export function createOpenAIImage({ apiKey, baseURL }: OpenAIImageConfig) { console.log("[OpenAI Image] Submitting request", { model: activeModelId, size, - aspectRatio: effectiveAspectRatio, + aspectRatio: aspectRatio || "auto", imageCount: imageUrls.length, baseURL: normalizeBaseURL(baseURL), }); diff --git a/lib/ai/providers/ruxa-image.ts b/lib/ai/providers/ruxa-image.ts index 6d3a02156..b1f9cf058 100644 --- a/lib/ai/providers/ruxa-image.ts +++ b/lib/ai/providers/ruxa-image.ts @@ -20,7 +20,6 @@ interface UploadedImage { original: string; } -const DEFAULT_SIZE = "1:1"; const DEFAULT_RESOLUTION = "1k"; const DEFAULT_OUTPUT_FORMAT = "png"; const POLL_INTERVAL_MS = 2000; @@ -50,14 +49,14 @@ function joinApiPath(baseURL: string, path: string) { } function normalizeAspectRatio(aspectRatio?: string) { - if (!aspectRatio) return DEFAULT_SIZE; + if (!aspectRatio) return undefined; const normalized = aspectRatio.trim().toLowerCase(); - if (normalized === "auto") return DEFAULT_SIZE; + if (normalized === "auto") return undefined; const ratio = aspectRatio.trim(); if (["1:1", "16:9", "9:16", "4:3", "3:4", "2:3", "3:2"].includes(ratio)) { return ratio; } - return DEFAULT_SIZE; + return undefined; } function normalizeResolution(imageSize?: string) { @@ -378,11 +377,13 @@ export function createRuxaImage({ apiKey, baseURL }: RuxaImageConfig) { const callbackUrl = process.env.RUXA_CALLBACK_URL?.trim(); const input: Record = { prompt, - size: aspectRatio, - aspect_ratio: aspectRatio, resolution, output_format: outputFormat, }; + if (aspectRatio) { + input.size = aspectRatio; + input.aspect_ratio = aspectRatio; + } if (imageUrls[0]) { input.image = imageUrls[0]; }