增加即梦图片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

+27 -6
View File
@@ -1,9 +1,13 @@
import { materialContentForProvider, type PromptMaterial } from "@/lib/prompt/assembler";
import {
SEEDANCE_20_MODEL,
VIDEO_DURATION_DEFAULT,
VIDEO_RATIO_DEFAULT,
VIDEO_RESOLUTION_DEFAULT,
clampVideoDuration,
isSeedance25Model,
isSupportedSeedanceModel,
normalizeSeedanceModel,
normalizeVideoDuration,
normalizeVideoRatio,
normalizeVideoResolution
@@ -16,6 +20,7 @@ export type SeedanceSettings = {
};
export type SeedanceCreateInput = {
model?: string;
prompt: string;
settings: SeedanceSettings;
materials: PromptMaterial[];
@@ -35,13 +40,13 @@ export type SeedanceUsage = {
};
export function getSeedanceConfig() {
const model = process.env.SEEDANCE_MODEL || "doubao-seedance-2-0-260128";
const model = normalizeSeedanceModel(process.env.SEEDANCE_MODEL, SEEDANCE_20_MODEL);
return {
apiKey: process.env.SEEDANCE_API_KEY,
baseUrl: process.env.SEEDANCE_BASE_URL || "https://ark.cn-beijing.volces.com/api/v3",
model,
ratio: normalizeVideoRatio(process.env.SEEDANCE_RATIO, VIDEO_RATIO_DEFAULT),
duration: clampVideoDuration(process.env.SEEDANCE_DURATION, VIDEO_DURATION_DEFAULT),
duration: clampVideoDuration(process.env.SEEDANCE_DURATION, VIDEO_DURATION_DEFAULT, { model }),
resolution: normalizeVideoResolution(process.env.SEEDANCE_RESOLUTION, model, VIDEO_RESOLUTION_DEFAULT)
};
}
@@ -49,20 +54,26 @@ export function getSeedanceConfig() {
export async function createSeedanceTask(input: SeedanceCreateInput) {
const config = getSeedanceConfig();
if (!config.apiKey) throw new Error("缺少 SEEDANCE_API_KEY。请在 .env.local 配置火山方舟 API Key。");
if (input.model !== undefined && !isSupportedSeedanceModel(input.model)) {
throw new Error("不支持的 Seedance 视频模型。");
}
const model = normalizeSeedanceModel(input.model, config.model);
const materialContent = materialContentForProvider(input.materials, input.origin);
if (materialContent.length > 4) {
if (!isSeedance25Model(model) && materialContent.length > 4) {
throw new Error("Seedance 2.0 最多支持 4 个素材(加上文本后 content 最多 5 项)。");
}
if (isSeedance25Model(model)) validateSeedance25Materials(input.materials);
const payload = {
model: config.model,
model,
content: [
{ type: "text", text: input.prompt },
...materialContent
],
generate_audio: true,
...(isSeedance25Model(model) && materialContent.length > 0 ? { omni_reference_task_type: "auto" } : {}),
ratio: normalizeVideoRatio(input.settings.ratio, config.ratio),
duration: normalizeVideoDuration(input.settings.duration) ?? config.duration,
resolution: normalizeVideoResolution(input.settings.resolution, config.model, config.resolution),
duration: normalizeVideoDuration(input.settings.duration, model) ?? config.duration,
resolution: normalizeVideoResolution(input.settings.resolution, model, config.resolution),
watermark: false
};
const response = await fetch(`${config.baseUrl.replace(/\/$/, "")}/contents/generations/tasks`, {
@@ -84,6 +95,16 @@ export async function createSeedanceTask(input: SeedanceCreateInput) {
};
}
function validateSeedance25Materials(materials: PromptMaterial[]) {
const counts = materials.reduce((result, material) => {
result[material.type] += 1;
return result;
}, { image: 0, video: 0, audio: 0 });
if (counts.image > 30 || counts.video > 10 || counts.audio > 10 || materials.length > 50) {
throw new Error("Seedance 2.5 最多支持 30 张图片、10 个视频和 10 个音频素材。");
}
}
export async function querySeedanceTask(providerTaskId: string): Promise<SeedanceQueryResult> {
const config = getSeedanceConfig();
if (!config.apiKey) throw new Error("缺少 SEEDANCE_API_KEY,无法查询真实生成任务。");