production runtime and mock removal
This commit is contained in:
1 parent
2ef3da7af5
commit
6480e503eb
55 files changed
+581
-540
No files matched your search
@@ -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