feat: add task workflow and asset downloads

This commit is contained in:
inman
2026-05-29 12:32:02 +08:00
parent f9c3393f84
commit 63e62d444c
61 changed files with 2773 additions and 2181 deletions

View File

@@ -14,10 +14,16 @@ import { normalizeVideoDuration, normalizeVideoRatio, normalizeVideoResolution }
export type SubmitVideoJobInput = PromptAssemblyInput & {
ownerId?: string;
externalClientId?: string;
prompt?: string;
settings?: SeedanceSettings;
materials?: PromptMaterial[];
retryOf?: string;
idempotencyKey?: string;
idempotencyFingerprint?: string;
priority?: number;
maxAttempts?: number;
webhookUrl?: string;
};
export async function submitVideoJob(input: SubmitVideoJobInput, origin: string): Promise<GenerationJob> {
@@ -36,6 +42,7 @@ export async function submitVideoJob(input: SubmitVideoJobInput, origin: string)
const mock = shouldMockSeedance();
let job = await createGenerationJob({
ownerId,
externalClientId: input.externalClientId,
capability: "video.generate",
provider: mock ? "mock" : "seedance",
reqKey: config.model,
@@ -49,16 +56,38 @@ export async function submitVideoJob(input: SubmitVideoJobInput, origin: string)
assembled,
settings
},
retryOf: input.retryOf
retryOf: input.retryOf,
idempotencyKey: input.idempotencyKey,
idempotencyFingerprint: input.idempotencyFingerprint,
priority: input.priority,
maxAttempts: input.maxAttempts,
webhookUrl: input.webhookUrl
});
if (mock) return completeMockVideoJob(job);
return job;
}
export async function advanceVideoJob(jobId: string, origin: string): Promise<GenerationJob> {
const job = await getGenerationJob(jobId);
if (!job) throw new Error(`Generation job not found: ${jobId}`);
if (["succeeded", "failed", "cancelled", "expired"].includes(job.status)) return job;
if (job.provider === "mock") return completeMockVideoJob(job);
if (!job.providerTaskId) return dispatchVideoJob(job, origin);
return syncVideoJob(job.id, origin);
}
async function dispatchVideoJob(job: GenerationJob, origin: string): Promise<GenerationJob> {
try {
const input = asRecord(job.requestPayload.input) as SubmitVideoJobInput;
const assembled = asRecord(job.requestPayload.assembled);
const settings = asRecord(job.requestPayload.settings) as SeedanceSettings;
const materials = Array.isArray(assembled.materials)
? assembled.materials as PromptMaterial[]
: input.materials || [];
const response = await createSeedanceTask({
prompt: finalPrompt,
prompt: job.prompt || "",
settings,
materials: assembled.materials,
materials,
origin
});
return updateGenerationJob(job.id, {
@@ -140,7 +169,7 @@ async function completeMockVideoJob(job: GenerationJob): Promise<GenerationJob>
ownerId: job.ownerId,
kind: "video",
name: `mock-video-${job.id}.mp4`,
url: "/seedance-starter-assets/music_sync_ad/2-3-9-1/result.mp4",
url: "/mock/seedance-mock.mp4",
source: "generated",
tags: ["video.generate", "mock"],
metadata: {
@@ -168,3 +197,9 @@ async function completeMockVideoJob(job: GenerationJob): Promise<GenerationJob>
}
});
}
function asRecord(value: unknown): Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value)
? value as Record<string, unknown>
: {};
}