feat(*): 模型计费与渠道目录 - 支持视频 Token 报价结算和稳定模型展示

This commit is contained in:
ddCat committed 2026-09-18 23:26:54 +08:00
1 parent 90add8c466
commit 1a79005d25
57 files changed
+2904 -341

No files matched your search

+36 -2
View File
@@ -8,7 +8,7 @@ import { buildGenerationConfig } from "../src/lib/canvas/canvas-project-generati
import { modelRequestOptions } from "../src/lib/model-selection";
import { CanvasNodeType, type CanvasNodeData } from "../src/types/canvas";
function systemConfig(input: { capability?: "image" | "video"; logicalModelId?: string; tiers: Array<{ selector: Record<string, string>; billingMode: "fixed_request" | "per_second" | "token"; unitPriceMicrocredits: number }> }) {
function systemConfig(input: { capability?: "image" | "video"; logicalModelId?: string; tiers: Array<{ selector: Record<string, string>; billingMode: "fixed_request" | "per_second" | "token"; unitPriceMicrocredits: number; outputTokenPriceMicrocredits?: number }> }) {
const capability = input.capability || "video";
const model = capability === "video" ? "agnes-video-2.5" : "image-model";
const channel = createModelChannel({
@@ -32,7 +32,7 @@ function systemConfig(input: { capability?: "image" | "video"; logicalModelId?:
resolution: tier.selector.vquality || "*",
videoSeconds: Number(tier.selector.videoSeconds || 0),
inputTokenPriceMicrocredits: 0,
outputTokenPriceMicrocredits: 0,
outputTokenPriceMicrocredits: tier.outputTokenPriceMicrocredits ?? 0,
cachedTokenPriceMicrocredits: 0,
})),
},
@@ -235,4 +235,38 @@ describe("model request pricing", () => {
},
});
});
test("matches video audio, resolution and duration from actual request overrides", () => {
const config = systemConfig({ tiers: [
{ selector: {}, billingMode: "token", unitPriceMicrocredits: 0, outputTokenPriceMicrocredits: 1_000_000 },
{ selector: { vquality: "1080p", videoSeconds: "10", videoGenerateAudio: "false" }, billingMode: "token", unitPriceMicrocredits: 0, outputTokenPriceMicrocredits: 2_000_000 },
{ selector: { vquality: "1080p", videoSeconds: "10", videoGenerateAudio: "true" }, billingMode: "token", unitPriceMicrocredits: 0, outputTokenPriceMicrocredits: 3_000_000 },
] });
const tiers = resolveModelChannel(config, config.model).modelCosts![0]!.logicalPriceTiers!;
for (const videoGenerateAudio of [false, "false", true, "true"]) {
const requirements = { ...textVideoRequirements, videoSeconds: "10", options: { vquality: "1080P", videoSeconds: 5, videoGenerateAudio } };
const matched = priceTiersForCurrentSelection(tiers, "video", config, requirements);
expect(matched).toHaveLength(1);
expect(matched[0]?.outputTokenPriceMicrocredits).toBe(videoGenerateAudio === true || videoGenerateAudio === "true" ? 3_000_000 : 2_000_000);
expect(requestCreditCost({ channelMode: "remote", modelCosts: resolveModelChannel(config, config.model).modelCosts, model: "agnes-video-2.5", capability: "video", config, requirements })).toBeNull();
}
});
test("shows the configured video Token rate including free and fractional rates", () => {
const config = systemConfig({ tiers: [
{ selector: { videoGenerateAudio: "false" }, billingMode: "token", unitPriceMicrocredits: 0, outputTokenPriceMicrocredits: 0 },
{ selector: { videoGenerateAudio: "true" }, billingMode: "token", unitPriceMicrocredits: 0, outputTokenPriceMicrocredits: 1 },
] });
const tiers = resolveModelChannel(config, config.model).modelCosts![0]!.logicalPriceTiers!;
expect(priceTierSummaryLabel(tiers, "video")).toBe("0-0.000001 积分/百万视频 Token");
expect(priceTierSummaryLabel(tiers.slice(0, 1), "video")).toBe("0 积分/百万视频 Token");
});
test("builds a direct system-video quote without inventing a logical model ID", () => {
const config = systemConfig({ tiers: [{ selector: {}, billingMode: "token", unitPriceMicrocredits: 0 }] });
const requirements = { ...textVideoRequirements, options: { videoGenerateAudio: false, vquality: "1080p" } };
expect(modelQuoteRequest(config, config.model, "video", requirements)).toMatchObject({ channelId: "system-channel", modelKey: "agnes-video-2.5", intent: { options: { videoGenerateAudio: false, vquality: "1080p" } } });
expect(modelQuoteRequest(config, config.model, "video", requirements)?.logicalModelID).toBeUndefined();
expect(modelQuoteRequest(config, config.model, "image", requirements)).toBeUndefined();
});
});