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

@@ -30,6 +30,7 @@ import { queryVisualTask, shouldMockVisualApi, submitVisualTask } from "@/lib/vo
export type SubmitImageJobInput = {
ownerId?: string;
externalClientId?: string;
capability: EnabledImageCapability;
prompt?: string;
imageUrls?: string[];
@@ -43,6 +44,11 @@ export type SubmitImageJobInput = {
resolution?: "4k" | "8k";
seed?: number;
retryOf?: string;
idempotencyKey?: string;
idempotencyFingerprint?: string;
priority?: number;
maxAttempts?: number;
webhookUrl?: string;
};
export async function submitImageJob(input: SubmitImageJobInput, origin: string): Promise<GenerationJob> {
@@ -57,6 +63,7 @@ export async function submitImageJob(input: SubmitImageJobInput, origin: string)
const reqKey = engine === "evolink" ? getEvolinkImageSettings().model : capability.reqKey;
let job = await createGenerationJob({
ownerId,
externalClientId: input.externalClientId,
capability: input.capability,
provider: mock ? "mock" : engine === "evolink" ? "evolink" : "volcengine-visual",
reqKey,
@@ -70,15 +77,30 @@ export async function submitImageJob(input: SubmitImageJobInput, origin: string)
input,
providerPayload
},
retryOf: input.retryOf
retryOf: input.retryOf,
idempotencyKey: input.idempotencyKey,
idempotencyFingerprint: input.idempotencyFingerprint,
priority: input.priority,
maxAttempts: input.maxAttempts,
webhookUrl: input.webhookUrl
});
if (mock) {
return completeMockJob(job, origin);
}
return job;
}
export async function advanceImageJob(jobId: string, origin: string): Promise<GenerationJob> {
const job = await getGenerationJob(jobId);
if (!job) throw new Error(`Generation job not found: ${jobId}`);
if (["succeeded", "failed", "expired", "cancelled"].includes(job.status)) return job;
if (job.provider === "mock") return completeMockJob(job, origin);
if (!job.providerTaskId) return dispatchImageJob(job);
return syncImageJob(job.id, origin);
}
async function dispatchImageJob(job: GenerationJob): Promise<GenerationJob> {
const providerPayload = asRecord(job.requestPayload.providerPayload);
try {
if (engine === "evolink") {
if (job.provider === "evolink") {
const response = await submitEvolinkImageTask(providerPayload);
const taskId = getEvolinkTaskId(response);
if (!taskId) {
@@ -132,7 +154,7 @@ export async function submitImageJob(input: SubmitImageJobInput, origin: string)
export async function syncImageJob(jobId: string, origin: string): Promise<GenerationJob> {
const job = await getGenerationJob(jobId);
if (!job) throw new Error(`Generation job not found: ${jobId}`);
if (["succeeded", "failed", "expired"].includes(job.status)) return job;
if (["succeeded", "failed", "expired", "cancelled"].includes(job.status)) return job;
if (job.provider === "mock") return completeMockJob(job, origin);
if (!job.providerTaskId) return job;
@@ -353,3 +375,9 @@ function sourceForCapability(capability: string) {
if (capability === "image.upscale") return "upscaled";
return "generated";
}
function asRecord(value: unknown): Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value)
? value as Record<string, unknown>
: {};
}