fix: prevent unsupported seedream size and lock size when model disallows
This commit is contained in:
parent
b3ce87ca2b
commit
b28f1013da
@ -102,13 +102,18 @@ export function ImageParamsBar({
|
||||
// Gemini:1~2 张
|
||||
return [1, 2];
|
||||
};
|
||||
const supportsSize = imageGenConfig?.supportsSize !== false;
|
||||
|
||||
const clampParamsByProvider = (raw: ImageGenerationParams): ImageGenerationParams => {
|
||||
const options = getImageCountOptions();
|
||||
const fallbackCount = options[0] ?? 1;
|
||||
const imageCount = options.includes(raw.imageCount || fallbackCount) ? (raw.imageCount || fallbackCount) : fallbackCount;
|
||||
const imageSize = supportsSize
|
||||
? (raw.imageSize || "2K")
|
||||
: "2K";
|
||||
return {
|
||||
...raw,
|
||||
imageSize,
|
||||
imageCount,
|
||||
};
|
||||
};
|
||||
@ -204,26 +209,37 @@ export function ImageParamsBar({
|
||||
</DropdownMenu>
|
||||
|
||||
{/* 分辨率 */}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 px-2 gap-1 focus-visible:ring-0 focus-visible:ring-offset-0 focus:outline-none focus:ring-0">
|
||||
<Maximize2 size={14} />
|
||||
<span className="font-medium text-xs">{params.imageSize}</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="center" className="min-w-[100px]">
|
||||
{IMAGE_SIZE_OPTIONS.map((option) => (
|
||||
<DropdownMenuItem
|
||||
key={option.value}
|
||||
onClick={() => updateParam("imageSize", option.value)}
|
||||
className="focus-visible:ring-0 focus-visible:ring-offset-0 focus:outline-none focus:ring-0"
|
||||
>
|
||||
<Check className={cn("mr-2 h-4 w-4", params.imageSize === option.value ? "opacity-100" : "opacity-0")} />
|
||||
{option.label}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
{supportsSize ? (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 px-2 gap-1 focus-visible:ring-0 focus-visible:ring-offset-0 focus:outline-none focus:ring-0">
|
||||
<Maximize2 size={14} />
|
||||
<span className="font-medium text-xs">{params.imageSize}</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="center" className="min-w-[100px]">
|
||||
{IMAGE_SIZE_OPTIONS.map((option) => (
|
||||
<DropdownMenuItem
|
||||
key={option.value}
|
||||
onClick={() => updateParam("imageSize", option.value)}
|
||||
className="focus-visible:ring-0 focus-visible:ring-offset-0 focus:outline-none focus:ring-0"
|
||||
>
|
||||
<Check className={cn("mr-2 h-4 w-4", params.imageSize === option.value ? "opacity-100" : "opacity-0")} />
|
||||
{option.label}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
) : (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 px-2 gap-1 text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0 focus:outline-none focus:ring-0"
|
||||
disabled
|
||||
>
|
||||
<Maximize2 size={14} />
|
||||
<span className="font-medium text-xs">2K</span>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{showImageCountSelector && (
|
||||
<DropdownMenu>
|
||||
|
||||
@ -18,6 +18,7 @@ let cachedRewriteConfig: VolcanoUrlRewriteConfig | null | undefined;
|
||||
const VOLCANO_IMAGE_FETCH_TIMEOUT_MS = 20_000;
|
||||
const VOLCANO_INLINE_MAX_SIDE = 1024;
|
||||
const DEFAULT_VOLCANO_IMAGE_SIZE = "2K";
|
||||
const SEEDREAM_MODEL_ID_PATTERN = /doubao-seedream-4-5/i;
|
||||
|
||||
function normalizeVolcanoImageSize(imageSize?: string): "1K" | "2K" | "4K" {
|
||||
const normalized = String(imageSize || "").trim().toUpperCase();
|
||||
@ -27,6 +28,23 @@ function normalizeVolcanoImageSize(imageSize?: string): "1K" | "2K" | "4K" {
|
||||
return DEFAULT_VOLCANO_IMAGE_SIZE;
|
||||
}
|
||||
|
||||
function resolveVolcanoImageSizeForModel(
|
||||
modelId: string,
|
||||
imageSize?: string
|
||||
): "1K" | "2K" | "4K" {
|
||||
const normalized = normalizeVolcanoImageSize(imageSize);
|
||||
if (SEEDREAM_MODEL_ID_PATTERN.test(modelId)) {
|
||||
// doubao-seedream-4-5 在当前链路下 1K 会返回 InvalidParameter,强制回落到 2K
|
||||
if (normalized === "1K") {
|
||||
console.log(
|
||||
`[Volcano Vision] Size normalized for ${modelId}: 1K -> 2K (model constraint)`
|
||||
);
|
||||
return "2K";
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function guessImageMimeTypeFromUrl(url: string): string {
|
||||
const cleanUrl = url.split("?")[0]?.toLowerCase() || "";
|
||||
if (cleanUrl.endsWith(".png")) return "image/png";
|
||||
@ -478,7 +496,7 @@ async function sendVolcanoRequest(
|
||||
console.log("[Volcano Vision] Image count:", image ? (Array.isArray(image) ? image.length : 1) : 0);
|
||||
|
||||
// 构建请求体
|
||||
const normalizedSize = normalizeVolcanoImageSize(imageSize);
|
||||
const normalizedSize = resolveVolcanoImageSizeForModel(modelId, imageSize);
|
||||
const requestBody: any = {
|
||||
model: modelId,
|
||||
prompt,
|
||||
@ -711,7 +729,10 @@ export function createVolcanoVision({ apiKey, baseURL }: VolcanoVisionConfig) {
|
||||
const activeModelId = options.overrideModelId || modelId;
|
||||
console.log("[Volcano Vision] Using modelId:", activeModelId);
|
||||
console.log("[Volcano Vision] Image params from options:", options.imageParams);
|
||||
const imageSize = normalizeVolcanoImageSize(options.imageParams?.imageSize);
|
||||
const imageSize = resolveVolcanoImageSizeForModel(
|
||||
activeModelId,
|
||||
options.imageParams?.imageSize
|
||||
);
|
||||
|
||||
// 🆕 优先使用用户选择的图片数量,其次是 maxImages 参数,默认 1 张
|
||||
const imageCount = options.imageParams?.imageCount || options.maxImages || 1;
|
||||
@ -772,7 +793,10 @@ export function createVolcanoVision({ apiKey, baseURL }: VolcanoVisionConfig) {
|
||||
const allImages: Array<{ thumbnail: string; original: string }> = [];
|
||||
|
||||
// 使用流式请求
|
||||
const imageSize = normalizeVolcanoImageSize(options.imageParams?.imageSize);
|
||||
const imageSize = resolveVolcanoImageSizeForModel(
|
||||
modelId,
|
||||
options.imageParams?.imageSize
|
||||
);
|
||||
for await (const event of sendVolcanoStreamRequest(baseURL, apiKey, options.messages, modelId, imageSize)) {
|
||||
if (event.type === "image_generation.partial_succeeded" && event.url) {
|
||||
// 每张图片生成完成后立即上传并发送
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user