增加2.5模型调用
This commit is contained in:
1 parent
3f29ba716a
commit
be655b6569
32 files changed
+1075
-56
No files matched your search
@@ -6,6 +6,7 @@ import clsx from "clsx";
|
||||
import { clampPage, pageItems, Pagination } from "@/components/pagination";
|
||||
import { SeedreamWorkspace } from "@/components/seedream-workspace";
|
||||
import { imageSizePresets, imageDimensionsForEngine, imageSizePresetFromDimensions, type ImageSizePreset } from "@/lib/image-size-presets";
|
||||
import { DEFAULT_IMAGE_MODEL, IMAGE_MODEL_OPTIONS, configuredImageModel, evolinkModelCapability, imageModelAfterHealth, imageModelFromJob, imageModelLabel, templateImageModel } from "@/lib/image-models";
|
||||
import { SeedreamLayerResultViewer, type SeedreamLayerOutput } from "@/components/seedream-layer-result-viewer";
|
||||
import { crossfadeIn, pulseFeedback, revealChildren, runScopedMotion } from "@/lib/ui/motion";
|
||||
import {
|
||||
@@ -74,6 +75,8 @@ type HealthCapability = {
|
||||
id: string;
|
||||
engine?: string;
|
||||
reqKey?: string;
|
||||
models?: Array<{ id: string; label: string }>;
|
||||
evolink?: { reqKey?: string; models?: Array<{ id: string; label: string }> };
|
||||
};
|
||||
|
||||
type ImageTemplate = {
|
||||
@@ -83,6 +86,7 @@ type ImageTemplate = {
|
||||
previewImageUrl?: string;
|
||||
settings: {
|
||||
engine?: ImageGenerateEngine;
|
||||
model?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
forceSingle?: boolean;
|
||||
@@ -101,6 +105,7 @@ type TemplateForm = {
|
||||
prompt: string;
|
||||
previewImageUrl: string;
|
||||
engine: ImageGenerateEngine;
|
||||
evolinkModel: string;
|
||||
jimengInfluence: string;
|
||||
evolinkQuality: string;
|
||||
seedreamSize: string;
|
||||
@@ -123,6 +128,8 @@ const evolinkQualityOptions = [
|
||||
{ id: "high", label: "精细", quality: "high" }
|
||||
];
|
||||
|
||||
const evolinkModelOptions = IMAGE_MODEL_OPTIONS;
|
||||
|
||||
const seedreamSizeOptions = ["1K", "1.5K", "2K"] as const;
|
||||
const seedreamLayerSizeOptions = ["auto", "1K", "1.5K", "2K"] as const;
|
||||
const seedreamOutputFormatOptions = [
|
||||
@@ -138,6 +145,8 @@ type TemplateConsoleSnapshot = {
|
||||
promptByMode: Record<GenerateMode, string>;
|
||||
imageSize: ImageSizePreset;
|
||||
imageEngine: ImageGenerateEngine;
|
||||
evolinkModel: string;
|
||||
evolinkModelChosen: boolean;
|
||||
jimengInfluence: string;
|
||||
evolinkQuality: string;
|
||||
seedreamSize: string;
|
||||
@@ -155,6 +164,7 @@ const defaultTemplateForm: TemplateForm = {
|
||||
prompt: "",
|
||||
previewImageUrl: "",
|
||||
engine: "jimeng",
|
||||
evolinkModel: DEFAULT_IMAGE_MODEL,
|
||||
jimengInfluence: jimengInfluenceOptions[1].id,
|
||||
evolinkQuality: evolinkQualityOptions[1].id,
|
||||
seedreamSize: "1.5K",
|
||||
@@ -197,6 +207,9 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
const [notice, setNotice] = useState<string | null>(null);
|
||||
const [imageSize, setImageSize] = useState(imageSizePresets[0]);
|
||||
const [imageEngine, setImageEngine] = useState<ImageGenerateEngine>("jimeng");
|
||||
const [evolinkModel, setEvolinkModel] = useState<string>(DEFAULT_IMAGE_MODEL);
|
||||
const [evolinkDefaultModel, setEvolinkDefaultModel] = useState<string>(DEFAULT_IMAGE_MODEL);
|
||||
const [evolinkModels, setEvolinkModels] = useState<Array<{ id: string; label: string }>>([...evolinkModelOptions]);
|
||||
const [jimengInfluence, setJimengInfluence] = useState(jimengInfluenceOptions[1].id);
|
||||
const [evolinkQuality, setEvolinkQuality] = useState(evolinkQualityOptions[1].id);
|
||||
const [seedreamSize, setSeedreamSize] = useState("1.5K");
|
||||
@@ -226,6 +239,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
const promptRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
const templatePromptRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
const materialDraftInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const evolinkModelChosenRef = useRef(false);
|
||||
|
||||
const generateMode: GenerateMode = mode === "video" ? "video" : "image";
|
||||
const prompt = promptByMode[generateMode];
|
||||
@@ -400,6 +414,13 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
if (active && (imageCapability?.engine === "evolink" || imageCapability?.engine === "jimeng" || imageCapability?.engine === "bailian" || imageCapability?.engine === "seedream")) {
|
||||
setImageEngine(imageCapability.engine);
|
||||
}
|
||||
const evolinkCapability = evolinkModelCapability(imageCapability);
|
||||
if (active && evolinkCapability) {
|
||||
const models = normalizedImageModelOptions(evolinkCapability.models);
|
||||
setEvolinkModels(models);
|
||||
setEvolinkDefaultModel(configuredImageModel(models, evolinkCapability.reqKey));
|
||||
setEvolinkModel((current) => imageModelAfterHealth(models, evolinkCapability.reqKey, current, evolinkModelChosenRef.current));
|
||||
}
|
||||
if (active && (videoCapability?.engine === "seedance" || videoCapability?.engine === "bailian" || videoCapability?.engine === "minimax")) {
|
||||
setVideoEngine(videoCapability.engine);
|
||||
if (videoCapability.engine === "seedance") {
|
||||
@@ -498,7 +519,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
active = false;
|
||||
window.clearTimeout(timer);
|
||||
};
|
||||
}, [generateMode, imageCreationMode, imageEngine, imageSize.height, imageSize.width, seedreamInteractiveSourceKeys, seedreamRequestAnnotations, seedreamLayerSize, seedreamOptimizeMode, seedreamOutputFormat, seedreamSize, seedreamSourceKey, selectedEvolinkQuality.quality, selectedJimengInfluence.scale, videoDuration, videoEngine, videoModel, videoRatio, videoResolution, materials, generationInputReady, prompt]);
|
||||
}, [generateMode, imageCreationMode, imageEngine, evolinkModel, imageSize.height, imageSize.width, seedreamInteractiveSourceKeys, seedreamRequestAnnotations, seedreamLayerSize, seedreamOptimizeMode, seedreamOutputFormat, seedreamSize, seedreamSourceKey, selectedEvolinkQuality.quality, selectedJimengInfluence.scale, videoDuration, videoEngine, videoModel, videoRatio, videoResolution, materials, generationInputReady, prompt]);
|
||||
|
||||
async function loadImageTemplates(isActive: () => boolean = () => true) {
|
||||
setTemplatesLoading(true);
|
||||
@@ -775,6 +796,8 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
promptByMode: { ...promptByMode },
|
||||
imageSize,
|
||||
imageEngine,
|
||||
evolinkModel,
|
||||
evolinkModelChosen: evolinkModelChosenRef.current,
|
||||
jimengInfluence,
|
||||
evolinkQuality,
|
||||
seedreamSize,
|
||||
@@ -797,6 +820,8 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
setPromptByMode(snapshot.promptByMode);
|
||||
setImageSize(snapshot.imageSize);
|
||||
setImageEngine(snapshot.imageEngine);
|
||||
evolinkModelChosenRef.current = snapshot.evolinkModelChosen;
|
||||
setEvolinkModel(snapshot.evolinkModel);
|
||||
setJimengInfluence(snapshot.jimengInfluence);
|
||||
setEvolinkQuality(snapshot.evolinkQuality);
|
||||
setSeedreamSize(snapshot.seedreamSize);
|
||||
@@ -806,6 +831,8 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
setPromptByMode((items) => ({ ...items, [generateMode]: "" }));
|
||||
setImageSize(imageSizePresets[0]);
|
||||
setImageEngine(imageCreationMode === "basic" ? "jimeng" : "seedream");
|
||||
evolinkModelChosenRef.current = false;
|
||||
setEvolinkModel(evolinkDefaultModel);
|
||||
setJimengInfluence(jimengInfluenceOptions[1].id);
|
||||
setEvolinkQuality(evolinkQualityOptions[1].id);
|
||||
setSeedreamSize("1.5K");
|
||||
@@ -822,6 +849,10 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
if (generateMode === "image") {
|
||||
const templateEngine = normalizeImageEngine(template.settings.engine);
|
||||
if (templateEngine) setImageEngine(imageCreationMode === "basic" ? templateEngine : "seedream");
|
||||
if (templateEngine === "evolink") {
|
||||
evolinkModelChosenRef.current = Boolean(template.settings.model);
|
||||
setEvolinkModel(templateImageModel(template.settings.model, evolinkDefaultModel));
|
||||
}
|
||||
const preset = imageSizePresetFromDimensions(template.settings.width, template.settings.height);
|
||||
if (preset) setImageSize(preset);
|
||||
const templateInfluence = jimengInfluenceOptions.find((option) => option.scale === template.settings.scale);
|
||||
@@ -839,7 +870,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
}
|
||||
|
||||
function resetTemplateForm() {
|
||||
setTemplateForm(defaultTemplateFormForEngine(imageEngine));
|
||||
setTemplateForm(defaultTemplateFormForEngine(imageEngine, evolinkModel));
|
||||
setEditingTemplateId(null);
|
||||
setTemplateError(null);
|
||||
setMaterialDraft(null);
|
||||
@@ -853,7 +884,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
|
||||
function openTemplateEditor(template: ImageTemplate) {
|
||||
setTemplateForm({
|
||||
...formFromTemplate(template),
|
||||
...formFromTemplate(template, evolinkDefaultModel),
|
||||
previewImageUrl: storedAssetPreviewUrl(template.previewImageUrl, taskAssets)
|
||||
});
|
||||
setEditingTemplateId(template.id);
|
||||
@@ -889,7 +920,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
const rest = items.filter((item) => item.id !== saved.id);
|
||||
return [...rest, saved].sort(sortTemplates);
|
||||
});
|
||||
setTemplateForm(formFromTemplate(saved));
|
||||
setTemplateForm(formFromTemplate(saved, evolinkDefaultModel));
|
||||
setEditingTemplateId(null);
|
||||
setTemplateEditorOpen(false);
|
||||
applyTemplateToConsole(saved, isEditing ? "模板已更新并应用。" : "模板已保存并应用。");
|
||||
@@ -1069,7 +1100,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
materials: materials.filter((material) => material.type === "image"),
|
||||
...imageDimensionsForEngine(imageSize, imageEngine),
|
||||
...(imageEngine === "evolink"
|
||||
? { quality: selectedEvolinkQuality.quality }
|
||||
? { model: evolinkModel, quality: selectedEvolinkQuality.quality }
|
||||
: { scale: selectedJimengInfluence.scale }),
|
||||
force_single: true
|
||||
};
|
||||
@@ -1241,6 +1272,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
<div className="image-template-card-footer">
|
||||
<div className="image-template-card-copy">
|
||||
<strong>{template.name}</strong>
|
||||
{template.settings.engine === "evolink" ? <span>{imageModelLabel(templateImageModel(template.settings.model, evolinkDefaultModel))}</span> : null}
|
||||
</div>
|
||||
<button
|
||||
className="image-template-edit-button"
|
||||
@@ -1481,10 +1513,21 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
<select id="imageEngine" value={specializedImageMode ? "seedream" : imageEngine} disabled={specializedImageMode} 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="evolink">EvoLink</option>
|
||||
<option value="bailian">阿里云百炼</option>
|
||||
</select>
|
||||
</div>
|
||||
{!specializedImageMode && imageEngine === "evolink" ? (
|
||||
<div className="field inline-field">
|
||||
<label htmlFor="evolinkModel">生图模型</label>
|
||||
<select id="evolinkModel" value={evolinkModel} onChange={(event) => {
|
||||
evolinkModelChosenRef.current = true;
|
||||
setEvolinkModel(event.target.value);
|
||||
}}>
|
||||
{modelOptionsWithSelection(evolinkModels, evolinkModel).map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="field inline-field">
|
||||
<label htmlFor="imageSize">{imageEngine === "seedream" ? "分辨率" : "画幅"}</label>
|
||||
{imageEngine === "seedream" ? (
|
||||
@@ -1660,7 +1703,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
/>
|
||||
</label>
|
||||
<div className="template-preview-meta" aria-label="模板参数预览">
|
||||
<span>{imageEngineLabel(templateForm.engine)}</span>
|
||||
<span>{templateForm.engine === "evolink" ? imageModelLabel(templateForm.evolinkModel) : imageEngineLabel(templateForm.engine)}</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>
|
||||
@@ -1687,7 +1730,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
aria-pressed={templateForm.engine === "evolink"}
|
||||
onClick={() => setTemplateForm((form) => ({ ...form, engine: "evolink" }))}
|
||||
>
|
||||
Image2
|
||||
EvoLink
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -1707,6 +1750,14 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{templateForm.engine === "evolink" ? (
|
||||
<label className="field">
|
||||
<span>生图模型</span>
|
||||
<select value={templateForm.evolinkModel} onChange={(event) => setTemplateForm((form) => ({ ...form, evolinkModel: event.target.value }))}>
|
||||
{modelOptionsWithSelection(evolinkModels, templateForm.evolinkModel).map((option) => <option key={option.id} value={option.id}>{option.label}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
) : null}
|
||||
<label className="field">
|
||||
<span>{templateForm.engine === "evolink" ? "生成质量" : templateForm.engine === "bailian" ? "生成模式" : templateForm.engine === "seedream" ? "提示词优化" : "文本影响"}</span>
|
||||
{templateForm.engine === "evolink" ? (
|
||||
@@ -1896,6 +1947,7 @@ export function CreateStudio({ initialMode = "image" }: { initialMode?: Generate
|
||||
<h3 title={taskName(job)}>{taskName(job)}</h3>
|
||||
<div className="create-task-meta">
|
||||
<span className={`status ${taskStatusClass(job, taskAssetById)}`}>{statusLabel(job.status, Boolean(firstOutputAsset(job, taskAssetById)))}</span>
|
||||
{imageModelFromJob(job) ? <span>{imageModelLabel(imageModelFromJob(job)!)}</span> : null}
|
||||
<span>{durationLabel(job, durationNow)}</span>
|
||||
<span className="billing-task-cost">{billingLabel(job)}</span>
|
||||
</div>
|
||||
@@ -2290,6 +2342,8 @@ function taskParameterEntries(job: GenerationJob) {
|
||||
const engine = stringValue(values.engine);
|
||||
if (engine) entries.push({ label: "引擎", value: taskEngineLabel(engine) });
|
||||
if (job.capability === "image.generate") {
|
||||
const model = imageModelFromJob(job);
|
||||
if (model) entries.push({ label: "生图模型", value: imageModelLabel(model) });
|
||||
const creationMode = taskImageCreationMode(job);
|
||||
if (creationMode) entries.push({ label: "创作方式", value: seedreamCreationModeLabel(creationMode) });
|
||||
const width = scalarValue(values.width);
|
||||
@@ -2328,7 +2382,7 @@ function taskImageCreationMode(job: GenerationJob): SeedreamCreationMode | undef
|
||||
function taskEngineLabel(value: string) {
|
||||
if (value === "jimeng") return "即梦";
|
||||
if (value === "seedream") return "Seedream 5.0 Pro";
|
||||
if (value === "evolink") return "Image2";
|
||||
if (value === "evolink") return "EvoLink";
|
||||
if (value === "bailian") return "阿里云百炼";
|
||||
if (value === "seedance") return "Seedance";
|
||||
if (value === "minimax") return "MiniMax H3";
|
||||
@@ -2458,7 +2512,7 @@ function renderMaterialPreview(material: PromptMaterial, size: "normal" | "tiny"
|
||||
);
|
||||
}
|
||||
|
||||
function formFromTemplate(template: ImageTemplate): TemplateForm {
|
||||
function formFromTemplate(template: ImageTemplate, defaultModel: string): TemplateForm {
|
||||
const engine = normalizeImageEngine(template.settings.engine) || "jimeng";
|
||||
const jimengInfluence = jimengInfluenceOptions.find((option) => option.scale === template.settings.scale)?.id || jimengInfluenceOptions[1].id;
|
||||
const evolinkQuality = evolinkQualityOptions.find((option) => option.quality === template.settings.quality)?.id || evolinkQualityOptions[1].id;
|
||||
@@ -2467,6 +2521,7 @@ function formFromTemplate(template: ImageTemplate): TemplateForm {
|
||||
prompt: template.prompt,
|
||||
previewImageUrl: template.previewImageUrl || "",
|
||||
engine,
|
||||
evolinkModel: templateImageModel(template.settings.model, defaultModel),
|
||||
jimengInfluence,
|
||||
evolinkQuality,
|
||||
seedreamSize: seedreamSizeOptions.includes(template.settings.size as (typeof seedreamSizeOptions)[number]) ? template.settings.size! : "1.5K",
|
||||
@@ -2492,7 +2547,7 @@ function templatePayloadFromForm(form: TemplateForm) {
|
||||
? { size: form.seedreamSize, outputFormat: form.seedreamOutputFormat, optimizeMode: form.seedreamOptimizeMode }
|
||||
: imageDimensionsForEngine(size, form.engine)),
|
||||
...(form.engine === "evolink"
|
||||
? { quality: selectedQuality.quality }
|
||||
? { model: form.evolinkModel, quality: selectedQuality.quality }
|
||||
: form.engine === "jimeng"
|
||||
? { scale: selectedInfluence.scale }
|
||||
: {})
|
||||
@@ -2501,10 +2556,11 @@ function templatePayloadFromForm(form: TemplateForm) {
|
||||
};
|
||||
}
|
||||
|
||||
function defaultTemplateFormForEngine(engine: ImageGenerateEngine): TemplateForm {
|
||||
function defaultTemplateFormForEngine(engine: ImageGenerateEngine, defaultModel: string): TemplateForm {
|
||||
return {
|
||||
...defaultTemplateForm,
|
||||
engine,
|
||||
evolinkModel: defaultModel,
|
||||
jimengInfluence: jimengInfluenceOptions[1].id,
|
||||
evolinkQuality: evolinkQualityOptions[1].id,
|
||||
seedreamSize: "1.5K",
|
||||
@@ -2522,8 +2578,25 @@ function normalizeImageEngine(value?: string): ImageGenerateEngine | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function normalizedImageModelOptions(models: HealthCapability["models"]): Array<{ id: string; label: string }> {
|
||||
if (!Array.isArray(models)) return [...IMAGE_MODEL_OPTIONS];
|
||||
const seen = new Set<string>();
|
||||
const options = models.filter((model): model is { id: string; label: string } => {
|
||||
if (!model || typeof model.id !== "string" || !/^[a-z0-9][a-z0-9._-]{0,99}$/.test(model.id) || seen.has(model.id)) return false;
|
||||
seen.add(model.id);
|
||||
return true;
|
||||
}).map((model) => ({ id: model.id, label: typeof model.label === "string" && model.label.trim() ? model.label : imageModelLabel(model.id) }));
|
||||
return options.length ? options : [...IMAGE_MODEL_OPTIONS];
|
||||
}
|
||||
|
||||
function modelOptionsWithSelection(options: ReadonlyArray<{ id: string; label: string }>, selected: string) {
|
||||
return options.some((option) => option.id === selected)
|
||||
? options
|
||||
: [...options, { id: selected, label: imageModelLabel(selected) }];
|
||||
}
|
||||
|
||||
function imageEngineLabel(engine: ImageGenerateEngine) {
|
||||
return engine === "evolink" ? "Image2" : engine === "bailian" ? "百炼" : engine === "seedream" ? "Seedream 5.0" : "即梦";
|
||||
return engine === "evolink" ? "EvoLink" : engine === "bailian" ? "百炼" : engine === "seedream" ? "Seedream 5.0" : "即梦";
|
||||
}
|
||||
|
||||
function sortTemplates(a: ImageTemplate, b: ImageTemplate) {
|
||||
|
||||
Reference in new issue
Block a user