production runtime and mock removal
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { getEvolinkImageSettings, getSelectedImageEngine, shouldMockEvolinkApi, type ImageCreationEngine } from "@/lib/evolink/image-client";
|
||||
import { getEvolinkImageConfig, getEvolinkImageSettings, getSelectedImageEngine, type ImageCreationEngine } from "@/lib/evolink/image-client";
|
||||
import { authConfigSummary, getAuthRuntimeConfig } from "@/lib/auth/config";
|
||||
import { getJimengCapabilities } from "@/lib/jimeng/capabilities";
|
||||
import { getSeedanceConfig, shouldMockSeedance } from "@/lib/seedance/client";
|
||||
import { getSeedanceConfig } from "@/lib/seedance/client";
|
||||
import { platformAccountStoreConfigured } from "@/lib/server/account-store";
|
||||
import { rootDir } from "@/lib/server/runtime";
|
||||
import { shouldMockVisualApi } from "@/lib/volcengine/visual-client";
|
||||
import { getVisualClientConfig } from "@/lib/volcengine/visual-client";
|
||||
import type { EnabledImageCapability } from "@/lib/types";
|
||||
import { getBailianConfig, shouldMockBailian } from "@/lib/bailian/client";
|
||||
import { getBailianConfig } from "@/lib/bailian/client";
|
||||
|
||||
export type SettingsField = {
|
||||
key: string;
|
||||
@@ -190,10 +190,10 @@ export async function getApiSettings() {
|
||||
const engineAssignments = buildEngineAssignments(fileEnv);
|
||||
return {
|
||||
services: {
|
||||
visual: !shouldMockVisualApi(),
|
||||
evolink: !shouldMockEvolinkApi(),
|
||||
seedance: !shouldMockSeedance(),
|
||||
bailian: !shouldMockBailian() && Boolean(getBailianConfig().apiKey),
|
||||
visual: Boolean(getVisualClientConfig()),
|
||||
evolink: Boolean(getEvolinkImageConfig()),
|
||||
seedance: Boolean(seedance.apiKey),
|
||||
bailian: Boolean(getBailianConfig().apiKey),
|
||||
auth: authConfigSummary(auth) === "configured",
|
||||
organization: platformAccountStoreConfigured()
|
||||
},
|
||||
@@ -251,7 +251,7 @@ function buildEngineAssignments(fileEnv: Map<string, string>): EngineAssignment[
|
||||
const bailian = getBailianConfig();
|
||||
const generateEngine = currentEngineValue(engineFieldDefinitions[0], fileEnv);
|
||||
const videoEngine = currentVideoEngineValue(engineFieldDefinitions[1], fileEnv);
|
||||
const videoConnected = videoEngine === "bailian" ? !shouldMockBailian() : !shouldMockSeedance();
|
||||
const videoConnected = videoEngine === "bailian" ? Boolean(bailian.apiKey) : Boolean(seedance.apiKey);
|
||||
|
||||
return [
|
||||
imageEngineAssignment({
|
||||
@@ -326,9 +326,9 @@ function imageEngineLabel(engine: ImageCreationEngine) {
|
||||
}
|
||||
|
||||
function imageEngineConnected(engine: ImageCreationEngine) {
|
||||
if (engine === "evolink") return !shouldMockEvolinkApi();
|
||||
if (engine === "bailian") return !shouldMockBailian();
|
||||
return !shouldMockVisualApi();
|
||||
if (engine === "evolink") return Boolean(getEvolinkImageConfig());
|
||||
if (engine === "bailian") return Boolean(getBailianConfig().apiKey);
|
||||
return Boolean(getVisualClientConfig());
|
||||
}
|
||||
|
||||
function currentVideoEngineValue(field: FieldDefinition, fileEnv: Map<string, string>) {
|
||||
|
||||
@@ -50,7 +50,7 @@ export type BillingGenerationInput = {
|
||||
};
|
||||
|
||||
export async function quoteGenerationCharge(input: BillingGenerationInput): Promise<BillingJobCharge | undefined> {
|
||||
if (!billingEnabled() || input.provider === "mock") return undefined;
|
||||
if (!billingEnabled()) return undefined;
|
||||
const quotaExempt = isQuotaExemptUsageContext(input.usageContext);
|
||||
if (!input.usageContext?.organizationId && !quotaExempt) {
|
||||
if (input.externalClientId || input.usageContext?.source === "api") return undefined;
|
||||
|
||||
@@ -8,11 +8,11 @@ import {
|
||||
buildEvolinkImagePayload,
|
||||
extractEvolinkResultUrls,
|
||||
getEffectiveImageEngine,
|
||||
getEvolinkImageConfig,
|
||||
getEvolinkImageSettings,
|
||||
getEvolinkTaskId,
|
||||
mapEvolinkStatus,
|
||||
queryEvolinkTask,
|
||||
shouldMockEvolinkApi,
|
||||
submitEvolinkImageTask,
|
||||
type ImageCreationEngine,
|
||||
type EvolinkTaskResponse
|
||||
@@ -24,11 +24,10 @@ import {
|
||||
updateGenerationJob
|
||||
} from "@/lib/server/data-store";
|
||||
import { chargeGenerationJob, quoteGenerationCharge } from "@/lib/server/billing-service";
|
||||
import { createMockImageBuffer } from "@/lib/server/mock-image";
|
||||
import { importRemoteImageAsAsset, saveGeneratedAsset } from "@/lib/server/storage";
|
||||
import { importRemoteImageAsAsset } from "@/lib/server/storage";
|
||||
import { DEFAULT_OWNER_ID, toAbsoluteUrl } from "@/lib/server/runtime";
|
||||
import type { BillingJobCharge, EnabledImageCapability, GenerationJob, UsageContext, VisualTaskQueryResponse } from "@/lib/types";
|
||||
import { queryVisualTask, shouldMockVisualApi, submitVisualTask } from "@/lib/volcengine/visual-client";
|
||||
import { getVisualClientConfig, queryVisualTask, submitVisualTask } from "@/lib/volcengine/visual-client";
|
||||
import {
|
||||
bailianResultUrls,
|
||||
bailianStatus,
|
||||
@@ -36,7 +35,6 @@ import {
|
||||
buildBailianImagePayload,
|
||||
getBailianConfig,
|
||||
queryBailianTask,
|
||||
shouldMockBailian,
|
||||
submitBailianTask
|
||||
} from "@/lib/bailian/client";
|
||||
|
||||
@@ -69,15 +67,15 @@ type PreparedImageGeneration = {
|
||||
normalizedUrls: string[];
|
||||
engine: ImageCreationEngine;
|
||||
providerPayload: Record<string, unknown>;
|
||||
missingBailianKey: boolean;
|
||||
provider: "mock" | "bailian" | "evolink" | "volcengine-visual";
|
||||
missingProviderCredentials: boolean;
|
||||
provider: "bailian" | "evolink" | "volcengine-visual";
|
||||
reqKey: string;
|
||||
requestPayload: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export async function quoteImageGeneration(input: SubmitImageJobInput, origin: string): Promise<BillingJobCharge | undefined> {
|
||||
const prepared = prepareImageGeneration(input, origin);
|
||||
if (prepared.missingBailianKey) return undefined;
|
||||
if (prepared.missingProviderCredentials) return undefined;
|
||||
return quoteGenerationCharge({
|
||||
provider: prepared.provider,
|
||||
capability: input.capability,
|
||||
@@ -91,8 +89,8 @@ export async function quoteImageGeneration(input: SubmitImageJobInput, origin: s
|
||||
|
||||
export async function submitImageJob(input: SubmitImageJobInput, origin: string): Promise<GenerationJob> {
|
||||
const prepared = prepareImageGeneration(input, origin);
|
||||
const { ownerId, normalizedUrls, providerPayload, missingBailianKey, provider, reqKey, requestPayload } = prepared;
|
||||
const billing = missingBailianKey ? undefined : await quoteGenerationCharge({
|
||||
const { ownerId, normalizedUrls, providerPayload, missingProviderCredentials, engine, provider, reqKey, requestPayload } = prepared;
|
||||
const billing = missingProviderCredentials ? undefined : await quoteGenerationCharge({
|
||||
provider,
|
||||
capability: input.capability,
|
||||
reqKey,
|
||||
@@ -106,13 +104,13 @@ export async function submitImageJob(input: SubmitImageJobInput, origin: string)
|
||||
capability: input.capability,
|
||||
provider,
|
||||
reqKey,
|
||||
status: missingBailianKey ? "failed" : "queued",
|
||||
status: missingProviderCredentials ? "failed" : "queued",
|
||||
prompt: input.prompt,
|
||||
inputAssetIds: input.inputAssetIds || [],
|
||||
inputUrls: normalizedUrls,
|
||||
outputAssetIds: [],
|
||||
requestPayload,
|
||||
error: missingBailianKey ? { message: "缺少 BAILIAN_API_KEY,请先在设置页配置阿里云百炼 API Key。", retryable: true } : undefined,
|
||||
error: missingProviderCredentials ? { message: missingProviderMessage(engine), retryable: true } : undefined,
|
||||
retryOf: input.retryOf,
|
||||
idempotencyKey: input.idempotencyKey,
|
||||
idempotencyFingerprint: input.idempotencyFingerprint,
|
||||
@@ -149,16 +147,25 @@ function prepareImageGeneration(input: SubmitImageJobInput, origin: string): Pre
|
||||
? buildEvolinkImagePayload(input.capability, { ...input, imageUrls: normalizedUrls })
|
||||
: buildJimengPayload(input.capability, capability.reqKey, { ...input, imageUrls: normalizedUrls });
|
||||
const bailianConfig = getBailianConfig();
|
||||
const mock = engine === "bailian" ? shouldMockBailian() : engine === "evolink" ? shouldMockEvolinkApi() : shouldMockVisualApi();
|
||||
const missingBailianKey = engine === "bailian" && !mock && !bailianConfig.apiKey;
|
||||
const missingProviderCredentials = engine === "bailian"
|
||||
? !bailianConfig.apiKey
|
||||
: engine === "evolink"
|
||||
? !getEvolinkImageConfig()
|
||||
: !getVisualClientConfig();
|
||||
const reqKey = engine === "bailian" ? bailianConfig.imageModel : engine === "evolink" ? getEvolinkImageSettings().model : capability.reqKey;
|
||||
const provider = mock ? "mock" : engine === "bailian" ? "bailian" : engine === "evolink" ? "evolink" : "volcengine-visual";
|
||||
const provider = engine === "bailian" ? "bailian" : engine === "evolink" ? "evolink" : "volcengine-visual";
|
||||
const requestPayload = {
|
||||
engine,
|
||||
input,
|
||||
providerPayload
|
||||
};
|
||||
return { ownerId, normalizedUrls, engine, providerPayload, missingBailianKey, provider, reqKey, requestPayload };
|
||||
return { ownerId, normalizedUrls, engine, providerPayload, missingProviderCredentials, provider, reqKey, requestPayload };
|
||||
}
|
||||
|
||||
function missingProviderMessage(engine: ImageCreationEngine) {
|
||||
if (engine === "bailian") return "缺少 BAILIAN_API_KEY 或 DASHSCOPE_API_KEY,请先配置阿里云百炼凭据。";
|
||||
if (engine === "evolink") return "缺少 EVOLINK_API_KEY,请先配置 EvoLink 凭据。";
|
||||
return "缺少 VOLCENGINE_ACCESS_KEY_ID 或 VOLCENGINE_SECRET_ACCESS_KEY,请先配置即梦凭据。";
|
||||
}
|
||||
|
||||
export async function advanceImageJob(jobId: string, origin: string): Promise<GenerationJob> {
|
||||
@@ -166,7 +173,6 @@ export async function advanceImageJob(jobId: string, origin: string): Promise<Ge
|
||||
if (!job) throw new Error(`Generation job not found: ${jobId}`);
|
||||
if (["succeeded", "failed", "expired", "cancelled"].includes(job.status)) return job;
|
||||
if (job.billing?.status === "pending") job = await chargeGenerationJob(job);
|
||||
if (job.provider === "mock") return completeMockJob(job, origin);
|
||||
if (!job.providerTaskId) return dispatchImageJob(job);
|
||||
return syncImageJob(job.id, origin);
|
||||
}
|
||||
@@ -235,7 +241,6 @@ export async function syncImageJob(jobId: string, origin: string): Promise<Gener
|
||||
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 job;
|
||||
|
||||
if (job.provider === "evolink") {
|
||||
@@ -427,41 +432,6 @@ export async function retryImageJob(
|
||||
}, origin);
|
||||
}
|
||||
|
||||
async function completeMockJob(job: GenerationJob, origin: string): Promise<GenerationJob> {
|
||||
if (job.status === "succeeded" && job.outputAssetIds.length > 0) return job;
|
||||
const requestInput = (job.requestPayload.input || {}) as SubmitImageJobInput;
|
||||
const buffer = createMockImageBuffer({
|
||||
title: "智念AIGC生成结果",
|
||||
prompt: job.prompt || requestInput.prompt,
|
||||
capability: job.capability
|
||||
});
|
||||
const asset = await saveGeneratedAsset({
|
||||
ownerId: job.ownerId,
|
||||
bytes: buffer,
|
||||
fileName: `${job.capability.replace(/\W+/g, "-")}-${job.id}.svg`,
|
||||
contentType: "image/svg+xml",
|
||||
origin,
|
||||
source: sourceForCapability(job.capability),
|
||||
capability: job.capability,
|
||||
jobId: job.id,
|
||||
tags: assetTagsForJob(job),
|
||||
metadata: {
|
||||
mock: true
|
||||
}
|
||||
});
|
||||
return updateGenerationJob(job.id, {
|
||||
status: "succeeded",
|
||||
outputAssetIds: [asset.id],
|
||||
responsePayload: {
|
||||
mock: true,
|
||||
data: {
|
||||
status: "done",
|
||||
image_urls: [asset.url]
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sourceForCapability(_capability: string): "generated" {
|
||||
return "generated";
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
export function createMockImageBuffer(input: {
|
||||
title: string;
|
||||
prompt?: string;
|
||||
capability: string;
|
||||
resolution?: string;
|
||||
}): Buffer {
|
||||
const seed = createHash("sha1").update(`${input.capability}:${input.prompt || ""}`).digest("hex");
|
||||
const colorA = `#${seed.slice(0, 6)}`;
|
||||
const colorB = `#${seed.slice(6, 12)}`;
|
||||
const colorC = `#${seed.slice(12, 18)}`;
|
||||
const prompt = escapeXml(shorten(input.prompt || input.title, 96));
|
||||
const subtitle = escapeXml(input.resolution ? `${input.capability} / ${input.resolution}` : input.capability);
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="1536" height="1024" viewBox="0 0 1536 1024">
|
||||
<rect width="1536" height="1024" fill="#f8faf7"/>
|
||||
<rect x="88" y="88" width="1360" height="848" rx="20" fill="${colorA}" opacity="0.92"/>
|
||||
<path d="M88 782 C320 620 452 942 676 760 C915 565 1058 785 1448 530 L1448 936 L88 936 Z" fill="${colorB}" opacity="0.72"/>
|
||||
<path d="M90 230 C282 151 450 328 660 224 C870 120 1060 170 1446 104 L1446 366 C1080 455 880 326 682 426 C480 528 282 408 90 508 Z" fill="${colorC}" opacity="0.56"/>
|
||||
<circle cx="1218" cy="276" r="106" fill="#ffffff" opacity="0.78"/>
|
||||
<text x="144" y="720" font-family="Arial, 'PingFang SC', sans-serif" font-size="62" font-weight="700" fill="#ffffff">${prompt}</text>
|
||||
<text x="144" y="792" font-family="Arial, 'PingFang SC', sans-serif" font-size="30" fill="#ffffff" opacity="0.86">${subtitle}</text>
|
||||
<text x="144" y="856" font-family="Arial, 'PingFang SC', sans-serif" font-size="24" fill="#ffffff" opacity="0.72">Mock result: configure Volcengine credentials to call Jimeng Visual API.</text>
|
||||
</svg>`;
|
||||
return Buffer.from(svg);
|
||||
}
|
||||
|
||||
function shorten(value: string, max: number): string {
|
||||
return value.length > max ? `${value.slice(0, max - 1)}...` : value;
|
||||
}
|
||||
|
||||
function escapeXml(value: string): string {
|
||||
return value
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { assemblePrompt, type PromptAssemblyInput, type PromptMaterial } from "@/lib/prompt/assembler";
|
||||
import {
|
||||
createAsset,
|
||||
createGenerationJob,
|
||||
getGenerationJob,
|
||||
recordUsageForJob,
|
||||
@@ -9,10 +8,10 @@ import {
|
||||
import { chargeGenerationJob, quoteGenerationCharge, settleSeedanceGenerationCharge } from "@/lib/server/billing-service";
|
||||
import { DEFAULT_OWNER_ID } from "@/lib/server/runtime";
|
||||
import { importRemoteAssetAsAsset } from "@/lib/server/storage";
|
||||
import { createSeedanceTask, getSeedanceConfig, querySeedanceTask, shouldMockSeedance, type SeedanceSettings } from "@/lib/seedance/client";
|
||||
import { createSeedanceTask, getSeedanceConfig, querySeedanceTask, type SeedanceSettings } from "@/lib/seedance/client";
|
||||
import type { BillingJobCharge, GenerationJob, UsageContext } from "@/lib/types";
|
||||
import { normalizeVideoDuration, normalizeVideoRatio, normalizeVideoResolution } from "@/lib/video-settings";
|
||||
import { bailianResultUrls, bailianStatus, bailianTaskId, buildBailianVideoPayload, getBailianConfig, queryBailianTask, shouldMockBailian, submitBailianTask } from "@/lib/bailian/client";
|
||||
import { bailianResultUrls, bailianStatus, bailianTaskId, buildBailianVideoPayload, getBailianConfig, queryBailianTask, submitBailianTask } from "@/lib/bailian/client";
|
||||
|
||||
export type VideoCreationEngine = "seedance" | "bailian";
|
||||
|
||||
@@ -39,15 +38,15 @@ type PreparedVideoGeneration = {
|
||||
assembled: ReturnType<typeof assemblePrompt>;
|
||||
finalPrompt: string;
|
||||
settings: SeedanceSettings;
|
||||
missingBailianKey: boolean;
|
||||
provider: "mock" | "bailian" | "seedance";
|
||||
missingProviderCredentials: boolean;
|
||||
provider: "bailian" | "seedance";
|
||||
reqKey: string;
|
||||
requestPayload: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export async function quoteVideoGeneration(input: SubmitVideoJobInput, origin: string): Promise<BillingJobCharge | undefined> {
|
||||
const prepared = prepareVideoGeneration(input, origin);
|
||||
if (prepared.missingBailianKey) return undefined;
|
||||
if (prepared.missingProviderCredentials) return undefined;
|
||||
return quoteGenerationCharge({
|
||||
provider: prepared.provider,
|
||||
capability: "video.generate",
|
||||
@@ -61,8 +60,8 @@ export async function quoteVideoGeneration(input: SubmitVideoJobInput, origin: s
|
||||
|
||||
export async function submitVideoJob(input: SubmitVideoJobInput, origin: string): Promise<GenerationJob> {
|
||||
const prepared = prepareVideoGeneration(input, origin);
|
||||
const { ownerId, engine, config, assembled, finalPrompt, settings, missingBailianKey, provider, reqKey, requestPayload } = prepared;
|
||||
const billing = missingBailianKey ? undefined : await quoteGenerationCharge({
|
||||
const { ownerId, engine, config, assembled, finalPrompt, settings, missingProviderCredentials, provider, reqKey, requestPayload } = prepared;
|
||||
const billing = missingProviderCredentials ? undefined : await quoteGenerationCharge({
|
||||
provider,
|
||||
capability: "video.generate",
|
||||
reqKey,
|
||||
@@ -76,13 +75,13 @@ export async function submitVideoJob(input: SubmitVideoJobInput, origin: string)
|
||||
capability: "video.generate",
|
||||
provider,
|
||||
reqKey,
|
||||
status: missingBailianKey ? "failed" : "queued",
|
||||
status: missingProviderCredentials ? "failed" : "queued",
|
||||
prompt: finalPrompt,
|
||||
inputAssetIds: input.materials?.map((material) => material.id).filter(Boolean) as string[] || [],
|
||||
inputUrls: assembled.materials.map((material) => material.url),
|
||||
outputAssetIds: [],
|
||||
requestPayload,
|
||||
error: missingBailianKey ? { message: "缺少 BAILIAN_API_KEY,请先在设置页配置阿里云百炼 API Key。", retryable: true } : undefined,
|
||||
error: missingProviderCredentials ? { message: missingProviderMessage(engine), retryable: true } : undefined,
|
||||
retryOf: input.retryOf,
|
||||
idempotencyKey: input.idempotencyKey,
|
||||
idempotencyFingerprint: input.idempotencyFingerprint,
|
||||
@@ -131,9 +130,7 @@ function prepareVideoGeneration(input: SubmitVideoJobInput, origin: string): Pre
|
||||
settings.duration = normalizeVideoDuration(settings.duration) ?? config.duration;
|
||||
settings.resolution = normalizeVideoResolution(settings.resolution, config.model, config.resolution);
|
||||
}
|
||||
const mock = engine === "bailian" ? shouldMockBailian() : shouldMockSeedance();
|
||||
const missingBailianKey = engine === "bailian" && !mock && !getBailianConfig().apiKey;
|
||||
const provider = mock ? "mock" : engine;
|
||||
const missingProviderCredentials = engine === "bailian" ? !getBailianConfig().apiKey : !config.apiKey;
|
||||
const requestPayload = {
|
||||
input,
|
||||
assembled,
|
||||
@@ -147,19 +144,24 @@ function prepareVideoGeneration(input: SubmitVideoJobInput, origin: string): Pre
|
||||
assembled,
|
||||
finalPrompt,
|
||||
settings,
|
||||
missingBailianKey,
|
||||
provider,
|
||||
missingProviderCredentials,
|
||||
provider: engine,
|
||||
reqKey: engine === "bailian" ? getBailianConfig().videoModel : config.model,
|
||||
requestPayload
|
||||
};
|
||||
}
|
||||
|
||||
function missingProviderMessage(engine: VideoCreationEngine) {
|
||||
return engine === "bailian"
|
||||
? "缺少 BAILIAN_API_KEY 或 DASHSCOPE_API_KEY,请先配置阿里云百炼凭据。"
|
||||
: "缺少 SEEDANCE_API_KEY,请先配置 Seedance 凭据。";
|
||||
}
|
||||
|
||||
export async function advanceVideoJob(jobId: string, origin: string): Promise<GenerationJob> {
|
||||
let 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.billing?.status === "pending") job = await chargeGenerationJob(job);
|
||||
if (job.provider === "mock") return completeMockVideoJob(job);
|
||||
if (!job.providerTaskId) return dispatchVideoJob(job, origin);
|
||||
return syncVideoJob(job.id, origin);
|
||||
}
|
||||
@@ -196,7 +198,6 @@ export async function syncVideoJob(jobId: string, origin: string): Promise<Gener
|
||||
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 job;
|
||||
|
||||
try {
|
||||
@@ -271,34 +272,6 @@ export async function retryVideoJob(jobId: string, origin: string, ownerId?: str
|
||||
}, origin);
|
||||
}
|
||||
|
||||
async function completeMockVideoJob(job: GenerationJob): Promise<GenerationJob> {
|
||||
if (job.status === "succeeded" && job.outputAssetIds.length > 0) return job;
|
||||
const asset = await createAsset({
|
||||
ownerId: job.ownerId,
|
||||
kind: "video",
|
||||
name: `mock-video-${job.id}.mp4`,
|
||||
url: "/mock/seedance-mock.mp4",
|
||||
source: "generated",
|
||||
tags: [...assetTagsForJob(job), "mock"],
|
||||
metadata: {
|
||||
mock: true,
|
||||
capability: "video.generate",
|
||||
jobId: job.id
|
||||
}
|
||||
});
|
||||
return updateGenerationJob(job.id, {
|
||||
status: "succeeded",
|
||||
outputAssetIds: [asset.id],
|
||||
responsePayload: {
|
||||
mock: true,
|
||||
data: {
|
||||
status: "done",
|
||||
video_url: asset.url
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value)
|
||||
? value as Record<string, unknown>
|
||||
|
||||
Reference in New Issue
Block a user