增加即梦图片5.0和视频2.5的能力
This commit is contained in:
1 parent
542246e4ce
commit
88a4268d40
55 files changed
+1412
-200
No files matched your search
@@ -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 "系统生成";
|
||||
}
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user