feat(*): 创作与运维 - 新增图片尺寸预设和系统性能面板并优化图片组动画

This commit is contained in:
ddCat
2026-09-07 14:03:50 +08:00
parent df94c3bdf1
commit bd639745ac
41 changed files with 2785 additions and 353 deletions

View File

@@ -1,3 +1,5 @@
import { ImageSizePresetsEditor } from "./image-size-presets-editor";
import { imageSizeConfigWithPresets, imageSizePresets } from "@/lib/image-size-presets";
import { Input, InputNumber, Segmented, Select, Switch } from "antd";
import type { ReactNode } from "react";
@@ -18,20 +20,8 @@ const operationOptions = [
{ label: "音频生视频", value: "audio_to_video" },
];
function formatImageSizeTagLabel(size: string): string {
const raw = size.trim();
if (raw === "1:1") return "1:1 (方图)";
if (raw === "16:9") return "16:9 (横屏)";
if (raw === "9:16") return "9:16 (竖屏)";
if (raw === "1024x1024") return "1024x1024 (1:1)";
if (raw === "2048x2048") return "2048x2048 (2K 方)";
if (raw === "3840x2160") return "3840x2160 (4K 横屏)";
if (raw === "2160x3840") return "2160x3840 (4K 竖屏)";
return raw;
}
function imageSizeOptions(values: string[]) {
return values.map((v) => ({ label: formatImageSizeTagLabel(v), value: v }));
function ImageSizeHelp() {
return <p className="text-[var(--fs-label)] leading-relaxed text-foreground/60">按分辨率配置支持的比例,尺寸自动换算。size 发送像素,aspect_ratio 发送比例;独立分辨率由模型协议适配。实际输出尺寸以上游为准。</p>;
}
type Props = {
@@ -434,57 +424,40 @@ function ImageCapabilityEditor({ value, onChange, protocol, model, disabled, sec
if (section === "protocol") {
return (
<div className="admin-capability-protocol-editor">
<div className="admin-capability-protocol-grid">
<ProtocolParameterCard step="01" title="输出数量" description="设置单次生成图片数量">
<NumberField label="单次生成张数" value={profile.maxOutputs} min={1} disabled={disabled} onChange={(maxOutputs) => update({ maxOutputs: maxOutputs || 1 })} />
</ProtocolParameterCard>
<ProtocolParameterCard step="02" title="尺寸参数" description="定义尺寸字段、支持值与默认值">
<Segmented
block
disabled={disabled}
value={profile.size.parameter}
options={[
{ label: "不发送", value: "none" },
{ label: "size", value: "size" },
{ label: "aspect_ratio", value: "aspect_ratio" },
]}
onChange={(value) => {
const parameter = value as ImageCapabilityConfig["size"]["parameter"];
updateSize(
parameter === "none"
? { parameter, values: [], default: "auto", allowCustom: false }
: { parameter, values: profile.size.values.length ? profile.size.values : ["1:1"], default: profile.size.default === "auto" ? "1:1" : profile.size.default },
);
}}
/>
<div className="admin-capability-protocol-editor admin-image-protocol-editor">
<div className="admin-capability-protocol-grid admin-image-protocol-grid">
<ProtocolParameterCard step="01" title="尺寸参数" description="按分辨率配置可用画幅,直接点选或输入比例" className="admin-image-size-card">
<div className="admin-image-size-intro">
<Segmented
block
disabled={disabled}
value={profile.size.parameter}
options={[
{ label: "不发送", value: "none" },
{ label: "size", value: "size" },
{ label: "aspect_ratio", value: "aspect_ratio" },
]}
onChange={(value) => {
const parameter = value as ImageCapabilityConfig["size"]["parameter"];
updateSize(
parameter === "none"
? { parameter, values: [], presets: undefined, default: "auto", allowCustom: false }
: imageSizeConfigWithPresets({ ...profile, size: { ...profile.size, parameter } }, imageSizePresets(profile)),
);
}}
/>
<ImageSizeHelp />
</div>
{profile.size.parameter !== "none" ? (
<>
<Field label="支持值">
<Select
mode="tags"
className="admin-capability-tags w-full"
disabled={disabled}
value={profile.size.values}
options={imageSizeOptions(profile.size.values)}
tokenSeparators={[","]}
placeholder="例如 1:1、1024x1024"
onChange={(values) => updateSize({ values, default: values.includes(profile.size.default) || profile.size.allowCustom ? profile.size.default : values[0] || "auto" })}
/>
</Field>
<Field label="默认值">
<Select
className="w-full"
disabled={disabled}
value={profile.size.default}
options={profile.size.values.map((item) => ({ label: item, value: item }))}
onChange={(defaultValue) => updateSize({ default: defaultValue })}
/>
</Field>
<ImageSizePresetsEditor profile={profile} disabled={disabled} onChange={updateSize} />
<ParameterField label="允许自定义" description="允许支持值之外的尺寸" supported={profile.size.allowCustom} disabled={disabled} onChange={(allowCustom) => updateSize({ allowCustom })} />
</>
) : null}
</ProtocolParameterCard>
<ProtocolParameterCard step="02" title="输出数量" description="设置单次生成图片数量">
<NumberField label="单次生成张数" value={profile.maxOutputs} min={1} disabled={disabled} onChange={(maxOutputs) => update({ maxOutputs: maxOutputs || 1 })} />
</ProtocolParameterCard>
<ProtocolParameterCard step="03" title="可选参数" description="控制质量、背景与响应格式">
<ParameterField label="图片质量" description="发送 quality 参数" supported={profile.quality.supported} disabled={disabled} onChange={(supported) => updateQuality({ supported })} />
{profile.quality.supported ? (
@@ -543,6 +516,7 @@ function ImageCapabilityEditor({ value, onChange, protocol, model, disabled, sec
<NumberField label="单次生成张数" value={profile.maxOutputs} min={1} disabled={disabled} onChange={(maxOutputs) => update({ maxOutputs: maxOutputs || 1 })} />
</CapabilityBlock>
<CapabilityBlock title="尺寸参数">
<ImageSizeHelp />
<Segmented
block
disabled={disabled}
@@ -555,38 +529,14 @@ function ImageCapabilityEditor({ value, onChange, protocol, model, disabled, sec
onChange={(value) => {
const parameter = value as ImageCapabilityConfig["size"]["parameter"];
updateSize(
parameter === "none"
? { parameter, values: [], default: "auto", allowCustom: false }
: { parameter, values: profile.size.values.length ? profile.size.values : ["1:1"], default: profile.size.default === "auto" ? "1:1" : profile.size.default },
parameter === "none" ? { parameter, values: [], presets: undefined, default: "auto", allowCustom: false } : imageSizeConfigWithPresets({ ...profile, size: { ...profile.size, parameter } }, imageSizePresets(profile)),
);
}}
/>
{profile.size.parameter !== "none" ? (
<>
<Field label="支持值">
<Select
mode="tags"
className="admin-capability-tags w-full"
disabled={disabled}
value={profile.size.values}
options={imageSizeOptions(profile.size.values)}
tokenSeparators={[","]}
placeholder="例如 1:1、1024x1024"
onChange={(values) => updateSize({ values, default: values.includes(profile.size.default) || profile.size.allowCustom ? profile.size.default : values[0] || "auto" })}
/>
</Field>
<div className="grid gap-3 sm:grid-cols-2">
<Field label="默认值">
<Select
className="w-full"
disabled={disabled}
value={profile.size.default}
options={profile.size.values.map((item) => ({ label: item, value: item }))}
onChange={(defaultValue) => updateSize({ default: defaultValue })}
/>
</Field>
<ParameterField label="允许自定义" description="允许用户输入支持值之外的尺寸" supported={profile.size.allowCustom} disabled={disabled} onChange={(allowCustom) => updateSize({ allowCustom })} />
</div>
<ImageSizePresetsEditor profile={profile} disabled={disabled} onChange={updateSize} />
<ParameterField label="允许自定义" description="允许用户输入支持值之外的尺寸" supported={profile.size.allowCustom} disabled={disabled} onChange={(allowCustom) => updateSize({ allowCustom })} />
</>
) : null}
</CapabilityBlock>
@@ -665,9 +615,9 @@ function ReferenceCard({ title, description, children }: { title: string; descri
);
}
function ProtocolParameterCard({ step, title, description, children }: { step: string; title: string; description: string; children: ReactNode }) {
function ProtocolParameterCard({ step, title, description, children, className = "" }: { step: string; title: string; description: string; children: ReactNode; className?: string }) {
return (
<section className="admin-capability-protocol-card">
<section className={`admin-capability-protocol-card ${className}`}>
<header className="admin-capability-protocol-card-heading">
<span>{step}</span>
<div>