import { useId, useState } from "react"; import { Button, Input } from "antd"; import { Check, Plus } from "lucide-react"; import { Switch } from "@/components/ui/base/switch"; import "./image-size-picker.css"; import type { ImageCapabilityConfig } from "@/lib/model-capabilities"; import { IMAGE_RATIOS, IMAGE_RESOLUTIONS, imagePresetForRatio, imageSizeConfigWithPresets, imageSizePresets, imageTierAvailable } from "@/lib/image-size-presets"; import type { ImageResolutionTier } from "@/lib/image-resolution-tiers"; export function ImageSizePresetsEditor({ profile, disabled, onChange }: { profile: ImageCapabilityConfig; disabled?: boolean; onChange: (size: ImageCapabilityConfig["size"]) => void }) { const presets = imageSizePresets(profile); const id = useId(); const [drafts, setDrafts] = useState>>({}); const [errors, setErrors] = useState>>({}); const toggleTier = (tier: ImageResolutionTier, ratios: string[], enabled: boolean) => { if (disabled) return; update(tier, enabled ? ratios : []); }; const update = (tier: ImageResolutionTier, ratios: string[]) => { if (disabled) return false; try { const next = [ ...new Map( ratios.map((ratio) => { const normalized = imagePresetForRatio(tier, ratio); const preset = presets.find((preset) => preset.tier === tier && preset.ratio === normalized.ratio) || normalized; return [preset.ratio, preset] as const; }), ).values(), ]; onChange(imageSizeConfigWithPresets(profile, [...presets.filter((preset) => preset.tier !== tier), ...next])); setErrors((current) => ({ ...current, [tier]: "" })); return true; } catch (reason) { setErrors((current) => ({ ...current, [tier]: reason instanceof Error ? reason.message : "比例格式无效" })); return false; } }; const addRatio = (tier: ImageResolutionTier) => { const ratios = (drafts[tier] || "") .split(/[,,\n]/) .map((value) => value.trim()) .filter(Boolean); if (!ratios.length) return; if (update(tier, [...presets.filter((preset) => preset.tier === tier).map((preset) => preset.ratio), ...ratios])) { setDrafts((current) => ({ ...current, [tier]: "" })); } }; return (

点选支持的比例,再次点击可移除。尺寸自动换算,已有精确尺寸保持不变。

{IMAGE_RESOLUTIONS.map((tier) => { const items = presets.filter((preset) => preset.tier === tier); const ratios = [...new Set([...IMAGE_RATIOS, ...items.map((item) => item.ratio)])]; return (
{tier.toUpperCase()} {items.length ? `${items.length} 个比例` : "未启用"} toggleTier(tier, ratios, enabled)} />
{!imageTierAvailable(profile, tier) ?

需先配置此档位对应的质量值,用户端才会开放。

: null}
{ratios.map((ratio) => { const selected = items.find((item) => item.ratio === ratio); const dimensions = selected || imagePresetForRatio(tier, ratio); return ( ); })}
{ setDrafts((current) => ({ ...current, [tier]: event.target.value })); setErrors((current) => ({ ...current, [tier]: "" })); }} onPressEnter={(event) => { event.preventDefault(); event.stopPropagation(); addRatio(tier); }} />
{errors[tier] ? ( ) : null}
); })}
默认输出 用户选择模型时的初始尺寸
{profile.size.values.map((value) => { const preset = presets.find((item) => (profile.size.parameter === "aspect_ratio" ? item.ratio === value : item.size === value)); const label = value === "auto" ? "自动" : preset && profile.size.parameter === "size" ? `${preset.tier.toUpperCase()} · ${preset.ratio}` : value; return ( ); })}
); }