功能增加
This commit is contained in:
1 parent
b340fc7ad7
commit
f1993eb388
69 files changed
+2243
-162
No files matched your search
@@ -5,15 +5,16 @@ import {
|
||||
recordUsageForJob,
|
||||
updateGenerationJob
|
||||
} from "@/lib/server/data-store";
|
||||
import { chargeGenerationJob, quoteGenerationCharge, settleSeedanceGenerationCharge } from "@/lib/server/billing-service";
|
||||
import { chargeGenerationJob, quoteGenerationCharge, settleMinimaxGenerationCharge, settleSeedanceGenerationCharge } from "@/lib/server/billing-service";
|
||||
import { DEFAULT_OWNER_ID } from "@/lib/server/runtime";
|
||||
import { importRemoteAssetAsAsset } from "@/lib/server/storage";
|
||||
import { createSeedanceTask, getSeedanceConfig, querySeedanceTask, type SeedanceSettings } from "@/lib/seedance/client";
|
||||
import type { BillingJobCharge, GenerationJob, UsageContext } from "@/lib/types";
|
||||
import { VIDEO_DURATION_DEFAULT, clampVideoDuration, isSupportedSeedanceModel, normalizeSeedanceModel, normalizeVideoDuration, normalizeVideoRatio, normalizeVideoResolution } from "@/lib/video-settings";
|
||||
import { bailianResultUrls, bailianStatus, bailianTaskId, buildBailianVideoPayload, getBailianConfig, queryBailianTask, submitBailianTask } from "@/lib/bailian/client";
|
||||
import { buildMinimaxH3Payload, createMinimaxH3Task, getMinimaxConfig, MINIMAX_H3_MODEL, queryMinimaxH3Task } from "@/lib/minimax/client";
|
||||
|
||||
export type VideoCreationEngine = "seedance" | "bailian";
|
||||
export type VideoCreationEngine = "seedance" | "bailian" | "minimax";
|
||||
|
||||
export type SubmitVideoJobInput = PromptAssemblyInput & {
|
||||
model?: string;
|
||||
@@ -40,7 +41,7 @@ type PreparedVideoGeneration = {
|
||||
finalPrompt: string;
|
||||
settings: SeedanceSettings;
|
||||
missingProviderCredentials: boolean;
|
||||
provider: "bailian" | "seedance";
|
||||
provider: "bailian" | "seedance" | "minimax";
|
||||
reqKey: string;
|
||||
requestPayload: Record<string, unknown>;
|
||||
};
|
||||
@@ -110,8 +111,10 @@ export async function submitVideoJob(input: SubmitVideoJobInput, origin: string)
|
||||
|
||||
function prepareVideoGeneration(input: SubmitVideoJobInput, origin: string): PreparedVideoGeneration {
|
||||
const ownerId = input.ownerId || DEFAULT_OWNER_ID;
|
||||
const configuredEngine = process.env.VIDEO_GENERATE_ENGINE === "seedance" ? "seedance" : "bailian";
|
||||
const engine: VideoCreationEngine = input.engine === "seedance" || input.engine === "bailian"
|
||||
const configuredEngine: VideoCreationEngine = process.env.VIDEO_GENERATE_ENGINE === "seedance"
|
||||
? "seedance"
|
||||
: process.env.VIDEO_GENERATE_ENGINE === "minimax" ? "minimax" : "bailian";
|
||||
const engine: VideoCreationEngine = input.engine === "seedance" || input.engine === "bailian" || input.engine === "minimax"
|
||||
? input.engine
|
||||
: configuredEngine;
|
||||
const config = getSeedanceConfig();
|
||||
@@ -130,13 +133,20 @@ function prepareVideoGeneration(input: SubmitVideoJobInput, origin: string): Pre
|
||||
settings.duration = normalizeVideoDuration(settings.duration) ?? 10;
|
||||
settings.resolution = String(settings.resolution || "720P").toUpperCase();
|
||||
buildBailianVideoPayload({ prompt: finalPrompt, materials: assembled.materials, origin, settings });
|
||||
} else if (engine === "minimax") {
|
||||
const payload = buildMinimaxH3Payload({ prompt: finalPrompt, materials: assembled.materials, settings, origin });
|
||||
settings.duration = payload.duration;
|
||||
settings.resolution = payload.resolution;
|
||||
settings.ratio = payload.ratio;
|
||||
} else {
|
||||
settings.ratio = normalizeVideoRatio(settings.ratio, config.ratio);
|
||||
settings.duration = normalizeVideoDuration(settings.duration, model)
|
||||
?? clampVideoDuration(config.duration, VIDEO_DURATION_DEFAULT, { model });
|
||||
settings.resolution = normalizeVideoResolution(settings.resolution, model, config.resolution);
|
||||
}
|
||||
const missingProviderCredentials = engine === "bailian" ? !getBailianConfig().apiKey : !config.apiKey;
|
||||
const missingProviderCredentials = engine === "bailian"
|
||||
? !getBailianConfig().apiKey
|
||||
: engine === "minimax" ? !getMinimaxConfig().apiKey : !config.apiKey;
|
||||
const requestPayload = {
|
||||
input,
|
||||
assembled,
|
||||
@@ -153,12 +163,13 @@ function prepareVideoGeneration(input: SubmitVideoJobInput, origin: string): Pre
|
||||
settings,
|
||||
missingProviderCredentials,
|
||||
provider: engine,
|
||||
reqKey: engine === "bailian" ? getBailianConfig().videoModel : model,
|
||||
reqKey: engine === "bailian" ? getBailianConfig().videoModel : engine === "minimax" ? MINIMAX_H3_MODEL : model,
|
||||
requestPayload
|
||||
};
|
||||
}
|
||||
|
||||
function missingProviderMessage(engine: VideoCreationEngine) {
|
||||
if (engine === "minimax") return "缺少 MINIMAX_API_KEY,请先配置 MiniMax 凭据。";
|
||||
return engine === "bailian"
|
||||
? "缺少 BAILIAN_API_KEY 或 DASHSCOPE_API_KEY,请先配置阿里云百炼凭据。"
|
||||
: "缺少 SEEDANCE_API_KEY,请先配置 Seedance 凭据。";
|
||||
@@ -187,6 +198,11 @@ async function dispatchVideoJob(job: GenerationJob, origin: string): Promise<Gen
|
||||
if (!providerTaskId) throw new Error("视频任务响应缺少 task_id。");
|
||||
return updateGenerationJob(job.id, { status: "running", providerTaskId, responsePayload: response });
|
||||
}
|
||||
if (job.provider === "minimax") {
|
||||
const payload = buildMinimaxH3Payload({ prompt: job.prompt || "", settings, materials, origin });
|
||||
const response = await createMinimaxH3Task(payload);
|
||||
return updateGenerationJob(job.id, { status: "running", providerTaskId: response.providerTaskId, responsePayload: response.raw });
|
||||
}
|
||||
const response = await createSeedanceTask({ model: job.reqKey, prompt: job.prompt || "", settings, materials, origin });
|
||||
return updateGenerationJob(job.id, { status: "running", providerTaskId: response.providerTaskId, responsePayload: response.raw });
|
||||
} catch (error) {
|
||||
@@ -217,6 +233,17 @@ export async function syncVideoJob(jobId: string, origin: string): Promise<Gener
|
||||
}
|
||||
return completeRemoteVideo(job, origin, resultUrl, response);
|
||||
}
|
||||
if (job.provider === "minimax") {
|
||||
const result = await queryMinimaxH3Task(job.providerTaskId);
|
||||
if (result.status !== "succeeded" || !result.resultUrl) {
|
||||
return updateGenerationJob(job.id, {
|
||||
status: result.status,
|
||||
responsePayload: result.raw,
|
||||
error: result.errorMessage ? { message: result.errorMessage, retryable: false } : undefined
|
||||
});
|
||||
}
|
||||
return completeRemoteVideo(job, origin, result.resultUrl, result.raw, undefined, result.usage);
|
||||
}
|
||||
const result = await querySeedanceTask(job.providerTaskId);
|
||||
if (result.status !== "succeeded" || !result.resultUrl) {
|
||||
return updateGenerationJob(job.id, {
|
||||
@@ -242,11 +269,14 @@ async function completeRemoteVideo(
|
||||
origin: string,
|
||||
resultUrl: string,
|
||||
responsePayload: Record<string, unknown>,
|
||||
completionTokens?: number
|
||||
completionTokens?: number,
|
||||
minimaxUsage?: { outputSeconds: number; inputSeconds: number; inputImageCount: number }
|
||||
) {
|
||||
const settledJob = job.provider === "seedance"
|
||||
? await settleSeedanceGenerationCharge(job, completionTokens) || job
|
||||
: job;
|
||||
: job.provider === "minimax"
|
||||
? await settleMinimaxGenerationCharge(job, minimaxUsage) || job
|
||||
: job;
|
||||
const asset = await importRemoteAssetAsAsset({
|
||||
ownerId: settledJob.ownerId,
|
||||
url: resultUrl,
|
||||
|
||||
Reference in new issue
Block a user