ai-chatbot/lib/ai/grsai-gpt-image-sizes.ts
Your Name 2cf2162fba
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
fix: map grsai gpt image sizes
2026-05-11 21:03:53 +08:00

95 lines
3.6 KiB
TypeScript

export type GrsaiGptImageSizeBucket = "1K" | "2K" | "4K";
type GrsaiGptImageSizeOption = {
bucket: GrsaiGptImageSizeBucket;
width: number;
height: number;
};
const GRSAI_GPT_IMAGE_SIZE_OPTIONS: GrsaiGptImageSizeOption[] = [
{ bucket: "1K", width: 1024, height: 1024 },
{ bucket: "1K", width: 1774, height: 887 },
{ bucket: "1K", width: 887, height: 1774 },
{ bucket: "1K", width: 1536, height: 1024 },
{ bucket: "1K", width: 1024, height: 1536 },
{ bucket: "2K", width: 2048, height: 2048 },
{ bucket: "2K", width: 2048, height: 1152 },
{ bucket: "2K", width: 1152, height: 2048 },
{ bucket: "2K", width: 2048, height: 1360 },
{ bucket: "2K", width: 1360, height: 2048 },
{ bucket: "2K", width: 2048, height: 880 },
{ bucket: "2K", width: 880, height: 2048 },
{ bucket: "2K", width: 2048, height: 688 },
{ bucket: "2K", width: 688, height: 2048 },
{ bucket: "2K", width: 2048, height: 1024 },
{ bucket: "2K", width: 1024, height: 2048 },
{ bucket: "4K", width: 2880, height: 2880 },
{ bucket: "4K", width: 3840, height: 2160 },
{ bucket: "4K", width: 2160, height: 3840 },
{ bucket: "4K", width: 3504, height: 2336 },
{ bucket: "4K", width: 2336, height: 3504 },
{ bucket: "4K", width: 3840, height: 1648 },
{ bucket: "4K", width: 1648, height: 3840 },
{ bucket: "4K", width: 3840, height: 1280 },
{ bucket: "4K", width: 1280, height: 3840 },
{ bucket: "4K", width: 3840, height: 1920 },
{ bucket: "4K", width: 1920, height: 3840 },
];
const GRSAI_GPT_IMAGE_SIZE_VALUES = new Set(
GRSAI_GPT_IMAGE_SIZE_OPTIONS.map((option) => `${option.width}x${option.height}`)
);
function normalizeGrsaiGptImageBucket(imageSize?: string): GrsaiGptImageSizeBucket {
const normalized = String(imageSize || "").trim().toUpperCase();
if (normalized === "1K" || normalized === "2K" || normalized === "4K") {
return normalized;
}
return "2K";
}
function parseAspectRatioValue(aspectRatio?: string): number {
const normalized = String(aspectRatio || "").trim().toLowerCase();
if (!normalized || normalized === "auto") {
return 1;
}
const [widthRaw, heightRaw] = normalized.split(":").map((part) => Number(part));
if (!Number.isFinite(widthRaw) || !Number.isFinite(heightRaw) || widthRaw <= 0 || heightRaw <= 0) {
return 1;
}
return widthRaw / heightRaw;
}
export function getGrsaiGptImageOutputSize(aspectRatio?: string, imageSize?: string) {
const bucket = normalizeGrsaiGptImageBucket(imageSize);
const targetRatio = parseAspectRatioValue(aspectRatio);
const candidates = GRSAI_GPT_IMAGE_SIZE_OPTIONS.filter((option) => option.bucket === bucket);
const best = candidates.reduce((currentBest, option) => {
const currentDelta = Math.abs(currentBest.width / currentBest.height - targetRatio);
const optionDelta = Math.abs(option.width / option.height - targetRatio);
if (optionDelta < currentDelta) {
return option;
}
if (optionDelta === currentDelta) {
const currentArea = currentBest.width * currentBest.height;
const optionArea = option.width * option.height;
return optionArea > currentArea ? option : currentBest;
}
return currentBest;
}, candidates[0]);
return { width: best.width, height: best.height };
}
export function resolveGrsaiGptImageSize(aspectRatio?: string, imageSize?: string): string {
const requestedSize = String(imageSize || "").trim().toLowerCase();
if (/^\d+x\d+$/.test(requestedSize) && GRSAI_GPT_IMAGE_SIZE_VALUES.has(requestedSize)) {
return requestedSize;
}
const { width, height } = getGrsaiGptImageOutputSize(aspectRatio, imageSize);
return `${width}x${height}`;
}