增加即梦图片5.0和视频2.5的能力

This commit is contained in:
andy committed 2026-08-21 13:44:56 +08:00
1 parent 542246e4ce
commit 88a4268d40
55 files changed
+1412 -200

No files matched your search

+1
View File
@@ -488,6 +488,7 @@ function providerLabel(provider: GenerationJob["provider"]) {
if (provider === "volcengine-visual") return "火山视觉";
if (provider === "evolink") return "EvoLink";
if (provider === "seedance") return "Seedance";
if (provider === "seedream") return "Seedream 5.0 Pro";
if (provider === "bailian") return "阿里云百炼";
return "系统生成";
}
+1
View File
@@ -761,6 +761,7 @@ function providerName(provider: string) {
if (provider === "volcengine-visual") return "即梦";
if (provider === "evolink") return "EvoLink";
if (provider === "seedance") return "Seedance";
if (provider === "seedream") return "Seedream 5.0 Pro";
if (provider === "bailian") return "百炼";
return provider;
}
+189 -31
View File
@@ -5,7 +5,16 @@ import { Check, CircleDollarSign, Download, Film, ImageIcon, ImagePlus, Info, Lo
import clsx from "clsx";
import { clampPage, pageItems, Pagination } from "@/components/pagination";
import { crossfadeIn, pulseFeedback, revealChildren, runScopedMotion } from "@/lib/ui/motion";
import { VIDEO_DURATION_DEFAULT, VIDEO_DURATION_OPTIONS, VIDEO_RATIOS, VIDEO_RESOLUTIONS, clampVideoDuration } from "@/lib/video-settings";
import {
SEEDANCE_20_MODEL,
SEEDANCE_MODELS,
VIDEO_DURATION_DEFAULT,
VIDEO_RATIOS,
VIDEO_RESOLUTIONS,
clampVideoDuration,
normalizeSeedanceModel,
seedanceDurationOptions
} from "@/lib/video-settings";
import type { Asset, GenerationJob } from "@/lib/types";
import type { PromptMaterial } from "@/lib/prompt/assembler";
import {
@@ -22,7 +31,7 @@ import type { BillingQuote } from "@/lib/types";
type GenerateMode = "image" | "video";
type MaterialKind = PromptMaterial["type"];
type ImageGenerateEngine = "jimeng" | "evolink" | "bailian";
type ImageGenerateEngine = "jimeng" | "evolink" | "bailian" | "seedream";
type VideoGenerateEngine = "seedance" | "bailian";
type MentionState = {
@@ -49,6 +58,7 @@ type MaterialDraftOption = {
type HealthCapability = {
id: string;
engine?: string;
reqKey?: string;
};
type ImageTemplate = {
@@ -63,6 +73,9 @@ type ImageTemplate = {
forceSingle?: boolean;
scale?: number;
quality?: string;
size?: string;
outputFormat?: string;
optimizeMode?: string;
};
sortOrder: number;
updatedAt?: string;
@@ -75,6 +88,9 @@ type TemplateForm = {
engine: ImageGenerateEngine;
jimengInfluence: string;
evolinkQuality: string;
seedreamSize: string;
seedreamOutputFormat: string;
seedreamOptimizeMode: string;
size: string;
sortOrder: string;
};
@@ -92,6 +108,16 @@ const evolinkQualityOptions = [
{ id: "high", label: "精细", quality: "high" }
];
const seedreamSizeOptions = ["1K", "1.5K", "2K"] as const;
const seedreamOutputFormatOptions = [
{ id: "png", label: "PNG" },
{ id: "jpeg", label: "JPEG" }
] as const;
const seedreamOptimizeModeOptions = [
{ id: "standard", label: "标准优化" },
{ id: "fast", label: "快速优化" }
] as const;
const imageSizePresets = [
{ label: "1:1", width: 2048, height: 2048 },
{ label: "4:3", width: 2304, height: 1728 },
@@ -107,6 +133,9 @@ type TemplateConsoleSnapshot = {
imageEngine: ImageGenerateEngine;
jimengInfluence: string;
evolinkQuality: string;
seedreamSize: string;
seedreamOutputFormat: string;
seedreamOptimizeMode: string;
};
const materialUploadAccept = "image/*,video/*,audio/*";
@@ -119,6 +148,9 @@ const defaultTemplateForm: TemplateForm = {
engine: "jimeng",
jimengInfluence: jimengInfluenceOptions[1].id,
evolinkQuality: evolinkQualityOptions[1].id,
seedreamSize: "1.5K",
seedreamOutputFormat: "png",
seedreamOptimizeMode: "standard",
size: imageSizePresets[0].label,
sortOrder: "0"
};
@@ -158,7 +190,11 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
const [imageEngine, setImageEngine] = useState<ImageGenerateEngine>("jimeng");
const [jimengInfluence, setJimengInfluence] = useState(jimengInfluenceOptions[1].id);
const [evolinkQuality, setEvolinkQuality] = useState(evolinkQualityOptions[1].id);
const [seedreamSize, setSeedreamSize] = useState("1.5K");
const [seedreamOutputFormat, setSeedreamOutputFormat] = useState("png");
const [seedreamOptimizeMode, setSeedreamOptimizeMode] = useState("standard");
const [videoEngine, setVideoEngine] = useState<VideoGenerateEngine>("bailian");
const [videoModel, setVideoModel] = useState(SEEDANCE_20_MODEL);
const [videoRatio, setVideoRatio] = useState("9:16");
const [videoDuration, setVideoDuration] = useState(VIDEO_DURATION_DEFAULT);
const [videoResolution, setVideoResolution] = useState("720p");
@@ -182,6 +218,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
const selectedEvolinkQuality = evolinkQualityOptions.find((option) => option.id === evolinkQuality) || evolinkQualityOptions[1];
const selectedTemplateJimengInfluence = jimengInfluenceOptions.find((option) => option.id === templateForm.jimengInfluence) || jimengInfluenceOptions[1];
const selectedTemplateEvolinkQuality = evolinkQualityOptions.find((option) => option.id === templateForm.evolinkQuality) || evolinkQualityOptions[1];
const selectedTemplateSeedreamOptimizeMode = seedreamOptimizeModeOptions.find((option) => option.id === templateForm.seedreamOptimizeMode) || seedreamOptimizeModeOptions[0];
const templateFormReady = Boolean(templateForm.name.trim() && templateForm.prompt.trim() && templateForm.previewImageUrl.trim());
const templateFormPlaceholders = useMemo(() => extractMaterialPlaceholders(templateForm.prompt), [templateForm.prompt]);
const materialPlaceholders = useMemo(() => extractMaterialPlaceholders(prompt), [prompt]);
@@ -255,8 +292,19 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
void fetch("/api/health")
.then((response) => response.ok ? response.json() : null)
.then((payload: { capabilities?: HealthCapability[] } | null) => {
const engine = payload?.capabilities?.find((capability) => capability.id === "image.generate")?.engine;
if (active && (engine === "evolink" || engine === "jimeng" || engine === "bailian")) setImageEngine(engine);
const imageCapability = payload?.capabilities?.find((capability) => capability.id === "image.generate");
const videoCapability = payload?.capabilities?.find((capability) => capability.id === "video.generate");
if (active && (imageCapability?.engine === "evolink" || imageCapability?.engine === "jimeng" || imageCapability?.engine === "bailian" || imageCapability?.engine === "seedream")) {
setImageEngine(imageCapability.engine);
}
if (active && (videoCapability?.engine === "seedance" || videoCapability?.engine === "bailian")) {
setVideoEngine(videoCapability.engine);
if (videoCapability.engine === "seedance") {
const nextModel = normalizeSeedanceModel(videoCapability.reqKey);
setVideoModel(nextModel);
setVideoDuration((duration) => clampVideoDuration(duration, VIDEO_DURATION_DEFAULT, { allowAuto: false, model: nextModel }));
}
}
})
.catch(() => undefined);
return () => {
@@ -344,7 +392,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
active = false;
window.clearTimeout(timer);
};
}, [generateMode, imageEngine, imageSize.height, imageSize.width, selectedEvolinkQuality.quality, selectedJimengInfluence.scale, videoDuration, videoEngine, videoRatio, videoResolution, materials, missingMaterialPlaceholders.length, prompt]);
}, [generateMode, imageEngine, imageSize.height, imageSize.width, seedreamOptimizeMode, seedreamOutputFormat, seedreamSize, selectedEvolinkQuality.quality, selectedJimengInfluence.scale, videoDuration, videoEngine, videoModel, videoRatio, videoResolution, materials, missingMaterialPlaceholders.length, prompt]);
async function loadImageTemplates(isActive: () => boolean = () => true) {
setTemplatesLoading(true);
@@ -546,7 +594,10 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
imageSize,
imageEngine,
jimengInfluence,
evolinkQuality
evolinkQuality,
seedreamSize,
seedreamOutputFormat,
seedreamOptimizeMode
});
}
applyTemplateToConsole(template, `已应用模板:${template.name}`);
@@ -566,12 +617,18 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
setImageEngine(snapshot.imageEngine);
setJimengInfluence(snapshot.jimengInfluence);
setEvolinkQuality(snapshot.evolinkQuality);
setSeedreamSize(snapshot.seedreamSize);
setSeedreamOutputFormat(snapshot.seedreamOutputFormat);
setSeedreamOptimizeMode(snapshot.seedreamOptimizeMode);
} else {
setPromptByMode((items) => ({ ...items, [generateMode]: "" }));
setImageSize(imageSizePresets[0]);
setImageEngine("jimeng");
setJimengInfluence(jimengInfluenceOptions[1].id);
setEvolinkQuality(evolinkQualityOptions[1].id);
setSeedreamSize("1.5K");
setSeedreamOutputFormat("png");
setSeedreamOptimizeMode("standard");
}
setNotice("已取消模板选择");
}
@@ -589,6 +646,9 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
if (templateInfluence) setJimengInfluence(templateInfluence.id);
const templateQuality = evolinkQualityOptions.find((option) => option.quality === template.settings.quality);
if (templateQuality) setEvolinkQuality(templateQuality.id);
if (seedreamSizeOptions.includes(template.settings.size as (typeof seedreamSizeOptions)[number])) setSeedreamSize(template.settings.size!);
if (template.settings.outputFormat === "png" || template.settings.outputFormat === "jpeg") setSeedreamOutputFormat(template.settings.outputFormat);
if (template.settings.optimizeMode === "standard" || template.settings.optimizeMode === "fast") setSeedreamOptimizeMode(template.settings.optimizeMode);
}
setMentionState(null);
setPromptScrollTop(0);
@@ -796,6 +856,20 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
function buildGenerationBody(): Record<string, unknown> {
if (generateMode === "image") {
if (imageEngine === "seedream") {
return {
capability: "image.generate",
engine: imageEngine,
prompt,
materials: materials.filter((material) => material.type === "image"),
settings: {
size: seedreamSize,
outputFormat: seedreamOutputFormat,
optimizeMode: seedreamOptimizeMode,
imageCount: 1
}
};
}
return {
capability: "image.generate",
engine: imageEngine,
@@ -813,6 +887,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
kind: "video",
capability: "video.generate",
engine: videoEngine,
...(videoEngine === "seedance" ? { model: videoModel } : {}),
prompt,
materials,
settings: {
@@ -833,6 +908,9 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
setNotice(null);
try {
const endpoint = generateMode === "image" ? "/api/generations/image" : "/api/generations/video";
if (generateMode === "image" && imageEngine === "seedream" && materials.filter((material) => material.type === "image").length > 10) {
throw new Error("Seedream 5.0 Pro 最多支持 10 张参考图。");
}
if (generateMode === "video" && videoEngine === "bailian") {
const imageCount = materials.filter((material) => material.type === "image").length;
if (imageCount < 1 || imageCount > 2 || materials.some((material) => material.type !== "image")) {
@@ -1113,45 +1191,82 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
<label htmlFor="imageEngine">生图引擎</label>
<select id="imageEngine" value={imageEngine} onChange={(event) => setImageEngine(normalizeImageEngine(event.target.value) || "jimeng")}>
<option value="jimeng">即梦</option>
<option value="seedream">Seedream 5.0 Pro</option>
<option value="evolink">Image2</option>
<option value="bailian">阿里云百炼</option>
</select>
</div>
<div className="field inline-field">
<label htmlFor="imageSize">画幅</label>
<select
id="imageSize"
value={imageSize.label}
onChange={(event) => setImageSize(imageSizePresets.find((item) => item.label === event.target.value) || imageSizePresets[0])}
>
{imageSizePresets.map((preset) => <option key={preset.label}>{preset.label}</option>)}
</select>
<label htmlFor="imageSize">{imageEngine === "seedream" ? "分辨率" : "画幅"}</label>
{imageEngine === "seedream" ? (
<select id="imageSize" value={seedreamSize} onChange={(event) => setSeedreamSize(event.target.value)}>
{seedreamSizeOptions.map((size) => <option key={size} value={size}>{size}</option>)}
</select>
) : (
<select
id="imageSize"
value={imageSize.label}
onChange={(event) => setImageSize(imageSizePresets.find((item) => item.label === event.target.value) || imageSizePresets[0])}
>
{imageSizePresets.map((preset) => <option key={preset.label}>{preset.label}</option>)}
</select>
)}
</div>
<div className="field inline-field">
<label htmlFor="imageEngineTuning">{imageEngine === "evolink" ? "生成质量" : imageEngine === "bailian" ? "生成模式" : "文本影响"}</label>
<label htmlFor="imageEngineTuning">{imageEngine === "evolink" ? "生成质量" : imageEngine === "bailian" ? "生成模式" : imageEngine === "seedream" ? "提示词优化" : "文本影响"}</label>
{imageEngine === "evolink" ? (
<select id="imageEngineTuning" value={evolinkQuality} onChange={(event) => setEvolinkQuality(event.target.value)}>
{evolinkQualityOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
</select>
) : imageEngine === "bailian" ? (
<select id="imageEngineTuning" value="thinking" disabled><option value="thinking">智能推理</option></select>
) : imageEngine === "seedream" ? (
<select id="imageEngineTuning" value={seedreamOptimizeMode} onChange={(event) => setSeedreamOptimizeMode(event.target.value)}>
{seedreamOptimizeModeOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
</select>
) : (
<select id="imageEngineTuning" value={jimengInfluence} onChange={(event) => setJimengInfluence(event.target.value)}>
{jimengInfluenceOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
</select>
)}
</div>
{imageEngine === "seedream" ? (
<div className="field inline-field">
<label htmlFor="seedreamOutputFormat">输出格式</label>
<select id="seedreamOutputFormat" value={seedreamOutputFormat} onChange={(event) => setSeedreamOutputFormat(event.target.value)}>
{seedreamOutputFormatOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
</select>
</div>
) : null}
</>
) : (
<>
<div className="field inline-field">
<label htmlFor="videoEngine">视频引擎</label>
<select id="videoEngine" value={videoEngine} onChange={(event) => setVideoEngine(event.target.value === "bailian" ? "bailian" : "seedance")}>
<select id="videoEngine" value={videoEngine} onChange={(event) => {
const nextEngine = event.target.value === "bailian" ? "bailian" : "seedance";
setVideoEngine(nextEngine);
setVideoDuration((duration) => nextEngine === "bailian"
? Math.min(15, Math.max(2, duration))
: clampVideoDuration(duration, VIDEO_DURATION_DEFAULT, { allowAuto: false, model: videoModel }));
}}>
<option value="seedance">Seedance</option>
<option value="bailian">阿里云百炼</option>
</select>
</div>
{videoEngine === "seedance" ? (
<div className="field inline-field">
<label htmlFor="videoModel">Seedance 模型</label>
<select id="videoModel" value={videoModel} onChange={(event) => {
const nextModel = normalizeSeedanceModel(event.target.value);
setVideoModel(nextModel);
setVideoDuration((duration) => clampVideoDuration(duration, VIDEO_DURATION_DEFAULT, { allowAuto: false, model: nextModel }));
}}>
{SEEDANCE_MODELS.map((model) => <option key={model.id} value={model.id}>{model.label}</option>)}
</select>
</div>
) : null}
{videoEngine === "seedance" ? (
<div className="field inline-field">
<label htmlFor="videoRatio">比例</label>
<select id="videoRatio" value={videoRatio} onChange={(event) => setVideoRatio(event.target.value)}>
@@ -1166,9 +1281,9 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
<select
id="videoDuration"
value={videoDuration}
onChange={(event) => setVideoDuration(clampVideoDuration(event.target.value, videoDuration, { allowAuto: false }))}
onChange={(event) => setVideoDuration(clampVideoDuration(event.target.value, videoDuration, { allowAuto: false, model: videoModel }))}
>
{(videoEngine === "bailian" ? Array.from({ length: 14 }, (_, index) => index + 2) : VIDEO_DURATION_OPTIONS).map((seconds) => <option key={seconds} value={seconds}>{seconds} 秒</option>)}
{(videoEngine === "bailian" ? Array.from({ length: 14 }, (_, index) => index + 2) : seedanceDurationOptions(videoModel)).map((seconds) => <option key={seconds} value={seconds}>{seconds} 秒</option>)}
</select>
</div>
<div className="field inline-field">
@@ -1230,8 +1345,8 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
</label>
<div className="template-preview-meta" aria-label="模板参数预览">
<span>{imageEngineLabel(templateForm.engine)}</span>
<span>{templateForm.engine === "evolink" ? selectedTemplateEvolinkQuality.label : templateForm.engine === "bailian" ? "智能推理" : selectedTemplateJimengInfluence.label}</span>
<span>{templateForm.size}</span>
<span>{templateForm.engine === "evolink" ? selectedTemplateEvolinkQuality.label : templateForm.engine === "bailian" ? "智能推理" : templateForm.engine === "seedream" ? selectedTemplateSeedreamOptimizeMode.label : selectedTemplateJimengInfluence.label}</span>
<span>{templateForm.engine === "seedream" ? templateForm.seedreamSize : templateForm.size}</span>
</div>
</aside>
<div className="template-inline-form template-editor-form">
@@ -1258,6 +1373,14 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
>
Image2
</button>
<button
type="button"
className={clsx(templateForm.engine === "seedream" && "active")}
aria-pressed={templateForm.engine === "seedream"}
onClick={() => setTemplateForm((form) => ({ ...form, engine: "seedream" }))}
>
Seedream 5.0
</button>
<button
type="button"
className={clsx(templateForm.engine === "bailian" && "active")}
@@ -1269,7 +1392,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
</div>
</div>
<label className="field">
<span>{templateForm.engine === "evolink" ? "生成质量" : templateForm.engine === "bailian" ? "生成模式" : "文本影响"}</span>
<span>{templateForm.engine === "evolink" ? "生成质量" : templateForm.engine === "bailian" ? "生成模式" : templateForm.engine === "seedream" ? "提示词优化" : "文本影响"}</span>
{templateForm.engine === "evolink" ? (
<select value={templateForm.evolinkQuality} onChange={(event) => setTemplateForm((form) => ({ ...form, evolinkQuality: event.target.value }))}>
{evolinkQualityOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
@@ -1278,6 +1401,10 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
<select value="thinking" disabled>
<option value="thinking">智能推理</option>
</select>
) : templateForm.engine === "seedream" ? (
<select value={templateForm.seedreamOptimizeMode} onChange={(event) => setTemplateForm((form) => ({ ...form, seedreamOptimizeMode: event.target.value }))}>
{seedreamOptimizeModeOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
</select>
) : (
<select value={templateForm.jimengInfluence} onChange={(event) => setTemplateForm((form) => ({ ...form, jimengInfluence: event.target.value }))}>
{jimengInfluenceOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
@@ -1285,11 +1412,25 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
)}
</label>
<label className="field">
<span>画幅</span>
<select value={templateForm.size} onChange={(event) => setTemplateForm((form) => ({ ...form, size: event.target.value }))}>
{imageSizePresets.map((preset) => <option value={preset.label} key={preset.label}>{preset.label}</option>)}
</select>
<span>{templateForm.engine === "seedream" ? "分辨率" : "画幅"}</span>
{templateForm.engine === "seedream" ? (
<select value={templateForm.seedreamSize} onChange={(event) => setTemplateForm((form) => ({ ...form, seedreamSize: event.target.value }))}>
{seedreamSizeOptions.map((size) => <option value={size} key={size}>{size}</option>)}
</select>
) : (
<select value={templateForm.size} onChange={(event) => setTemplateForm((form) => ({ ...form, size: event.target.value }))}>
{imageSizePresets.map((preset) => <option value={preset.label} key={preset.label}>{preset.label}</option>)}
</select>
)}
</label>
{templateForm.engine === "seedream" ? (
<label className="field">
<span>输出格式</span>
<select value={templateForm.seedreamOutputFormat} onChange={(event) => setTemplateForm((form) => ({ ...form, seedreamOutputFormat: event.target.value }))}>
{seedreamOutputFormatOptions.map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
</select>
</label>
) : null}
<label className="field">
<span>排序</span>
<input type="number" value={templateForm.sortOrder} onChange={(event) => setTemplateForm((form) => ({ ...form, sortOrder: event.target.value }))} />
@@ -1767,6 +1908,12 @@ function taskParameterEntries(job: GenerationJob) {
if (scale) entries.push({ label: "文本影响", value: scale });
const quality = stringValue(values.quality);
if (quality) entries.push({ label: "生成质量", value: qualityLabel(quality) });
const size = stringValue(values.size);
if (size) entries.push({ label: "分辨率", value: size.toUpperCase() });
const optimizeMode = stringValue(values.optimizeMode);
if (optimizeMode) entries.push({ label: "提示词优化", value: optimizeMode === "fast" ? "快速优化" : "标准优化" });
const outputFormat = stringValue(values.outputFormat);
if (outputFormat) entries.push({ label: "输出格式", value: outputFormat.toUpperCase() });
if (values.force_single !== undefined) entries.push({ label: "输出模式", value: values.force_single === true ? "单图" : "多图" });
} else {
const ratio = stringValue(values.ratio);
@@ -1781,6 +1928,7 @@ function taskParameterEntries(job: GenerationJob) {
function taskEngineLabel(value: string) {
if (value === "jimeng") return "即梦";
if (value === "seedream") return "Seedream 5.0 Pro";
if (value === "evolink") return "Image2";
if (value === "bailian") return "阿里云百炼";
if (value === "seedance") return "Seedance";
@@ -1850,6 +1998,7 @@ function providerLabel(provider: GenerationJob["provider"]) {
if (provider === "volcengine-visual") return "火山视觉";
if (provider === "evolink") return "EvoLink";
if (provider === "seedance") return "Seedance";
if (provider === "seedream") return "Seedream 5.0 Pro";
if (provider === "bailian") return "阿里云百炼";
return "系统生成";
}
@@ -1918,6 +2067,9 @@ function formFromTemplate(template: ImageTemplate): TemplateForm {
engine,
jimengInfluence,
evolinkQuality,
seedreamSize: seedreamSizeOptions.includes(template.settings.size as (typeof seedreamSizeOptions)[number]) ? template.settings.size! : "1.5K",
seedreamOutputFormat: template.settings.outputFormat === "jpeg" ? "jpeg" : "png",
seedreamOptimizeMode: template.settings.optimizeMode === "fast" ? "fast" : "standard",
size: sizeLabelFromSettings(template.settings.width, template.settings.height),
sortOrder: String(template.sortOrder ?? 0)
};
@@ -1933,12 +2085,15 @@ function templatePayloadFromForm(form: TemplateForm) {
previewImageUrl: form.previewImageUrl,
settings: {
engine: form.engine,
width: size.width,
height: size.height,
forceSingle: true,
...(form.engine === "seedream"
? { size: form.seedreamSize, outputFormat: form.seedreamOutputFormat, optimizeMode: form.seedreamOptimizeMode }
: { width: size.width, height: size.height }),
...(form.engine === "evolink"
? { quality: selectedQuality.quality }
: { scale: selectedInfluence.scale })
: form.engine === "jimeng"
? { scale: selectedInfluence.scale }
: {})
},
sortOrder: Number(form.sortOrder || 0)
};
@@ -1949,7 +2104,10 @@ function defaultTemplateFormForEngine(engine: ImageGenerateEngine): TemplateForm
...defaultTemplateForm,
engine,
jimengInfluence: jimengInfluenceOptions[1].id,
evolinkQuality: evolinkQualityOptions[1].id
evolinkQuality: evolinkQualityOptions[1].id,
seedreamSize: "1.5K",
seedreamOutputFormat: "png",
seedreamOptimizeMode: "standard"
};
}
@@ -1958,12 +2116,12 @@ function sizeLabelFromSettings(width?: number, height?: number) {
}
function normalizeImageEngine(value?: string): ImageGenerateEngine | undefined {
if (value === "jimeng" || value === "evolink" || value === "bailian") return value;
if (value === "jimeng" || value === "evolink" || value === "bailian" || value === "seedream") return value;
return undefined;
}
function imageEngineLabel(engine: ImageGenerateEngine) {
return engine === "evolink" ? "Image2" : engine === "bailian" ? "百炼" : "即梦";
return engine === "evolink" ? "Image2" : engine === "bailian" ? "百炼" : engine === "seedream" ? "Seedream 5.0" : "即梦";
}
function sortTemplates(a: ImageTemplate, b: ImageTemplate) {
+3 -1
View File
@@ -29,6 +29,7 @@ type SettingsPayload = {
visual: boolean;
evolink: boolean;
seedance: boolean;
seedream: boolean;
bailian: boolean;
auth: boolean;
organization: boolean;
@@ -241,6 +242,7 @@ export function SettingsPanel() {
<ServiceBadge label="即梦" value={serviceStatusLabel(payload?.services.visual)} ready={Boolean(payload?.services.visual)} />
<ServiceBadge label="EvoLink" value={serviceStatusLabel(payload?.services.evolink)} ready={Boolean(payload?.services.evolink)} />
<ServiceBadge label="Seedance" value={serviceStatusLabel(payload?.services.seedance)} ready={Boolean(payload?.services.seedance)} />
<ServiceBadge label="Seedream" value={serviceStatusLabel(payload?.services.seedream)} ready={Boolean(payload?.services.seedream)} />
<ServiceBadge label="百炼" value={serviceStatusLabel(payload?.services.bailian)} ready={Boolean(payload?.services.bailian)} />
<ServiceBadge label="账户" value={serviceStatusLabel(payload?.services.auth)} ready={Boolean(payload?.services.auth)} />
<ServiceBadge label="组织" value={serviceStatusLabel(payload?.services.organization)} ready={Boolean(payload?.services.organization)} />
@@ -314,7 +316,7 @@ function shortGroupLabel(id: string, title: string) {
if (id === "auth") return "登录";
if (id === "visual") return "图片";
if (id === "evolink") return "EvoLink";
if (id === "seedance") return "视频";
if (id === "seedance") return "方舟";
if (id === "oss") return "OSS";
return title;
}