From 071a98bd9693de2df5ce7f4fc310f740ac30d249 Mon Sep 17 00:00:00 2001 From: stringadmin Date: Mon, 8 Jun 2026 16:03:49 +0800 Subject: [PATCH] Scale generation billing charges to 1-to-100 credits --- src/billing.js | 5 ++++- src/enterpriseVideoBilling.js | 7 +++++-- src/routes/user.js | 12 ++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/billing.js b/src/billing.js index 7e6f0c9..f14b94c 100644 --- a/src/billing.js +++ b/src/billing.js @@ -18,9 +18,12 @@ const { pool, withTransaction } = require("./db"); const { calculateCostMills, getModelPrice } = require("./pricing"); const CREDIT_UNITS_PER_CREDIT = 100; +const CREDITS_PER_CNY = 100; const CREDIT_UNITS_PER_CNY_CENT = 100; const CREDIT_UNITS_PER_CNY_MILL = 10; -const IMAGE_GENERATION_FLAT_COST_CENTS = 20 * CREDIT_UNITS_PER_CREDIT; +const IMAGE_GENERATION_FLAT_COST_CNY = 20; +const IMAGE_GENERATION_FLAT_COST_CENTS = + IMAGE_GENERATION_FLAT_COST_CNY * CREDITS_PER_CNY * CREDIT_UNITS_PER_CREDIT; function creditsToCreditUnits(credits) { return Math.max(0, Math.round(Number(credits || 0) * CREDIT_UNITS_PER_CREDIT)); diff --git a/src/enterpriseVideoBilling.js b/src/enterpriseVideoBilling.js index d44da31..23dd027 100644 --- a/src/enterpriseVideoBilling.js +++ b/src/enterpriseVideoBilling.js @@ -19,6 +19,9 @@ const ENTERPRISE_VIDEO_ALLOWED_MODELS = new Set([ "pixverse-c1-i2v", ]); +const CREDITS_PER_CNY = 100; +const CREDIT_UNITS_PER_CREDIT = 100; + function normalizeModel(value) { return String(value || "").trim().toLowerCase(); } @@ -102,7 +105,7 @@ function getEnterpriseVideoCreditRate(input) { function calculateEnterpriseVideoCredits(input) { const duration = normalizeEnterpriseVideoDuration(input.durationSeconds || input.duration); - return Number((getEnterpriseVideoCreditRate(input) * duration).toFixed(2)); + return Number((getEnterpriseVideoCreditRate(input) * duration * CREDITS_PER_CNY).toFixed(2)); } function calculateEnterpriseVideoCost(input) { @@ -113,7 +116,7 @@ function calculateEnterpriseVideoCost(input) { resolution, durationSeconds, }); - const rateCentsPerSecond = Math.round(rateCreditsPerSecond * 100); + const rateCentsPerSecond = Math.round(rateCreditsPerSecond * CREDITS_PER_CNY * CREDIT_UNITS_PER_CREDIT); return { resolution, durationSeconds, diff --git a/src/routes/user.js b/src/routes/user.js index 5e0c24e..6fd39fe 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -136,8 +136,8 @@ function registerUserRoutes(router) { CASE WHEN billing_refunded = 1 THEN 0 WHEN cost_cents > 0 THEN cost_cents - WHEN status = 'completed' AND type = 'image' THEN 2000 - WHEN status = 'completed' AND type = 'video' THEN 500 + WHEN status = 'completed' AND type = 'image' THEN 200000 + WHEN status = 'completed' AND type = 'video' THEN 50000 ELSE 0 END ), 0) AS used_cents @@ -162,7 +162,7 @@ function registerUserRoutes(router) { resolution = params.resolution || params.quality || params.ratio || null; if (row.status === "completed") { if (row.type === "image") { - estimatedCents = 2000; + estimatedCents = 200000; } else if (row.type === "video") { const dur = params.duration || 5; const res = String(params.resolution || params.quality || "").toUpperCase(); @@ -172,7 +172,7 @@ function registerUserRoutes(router) { else if (model.includes("wan2.7-i2v") || model.includes("wanxiang")) rate = res === "720P" ? 0.6 : 1; else if (model.includes("animate-mix") || model.includes("s2v")) rate = res === "720P" ? 0.6 : 1; else if (model.includes("kling")) rate = res === "720P" ? 0.6 : 0.8; - estimatedCents = Math.ceil(rate * dur * 100); + estimatedCents = Math.ceil(rate * dur * 10000); } } } catch { @@ -209,8 +209,8 @@ function registerUserRoutes(router) { CASE WHEN billing_refunded = 1 THEN 0 WHEN cost_cents > 0 THEN cost_cents - WHEN status = 'completed' AND type = 'image' THEN 2000 - WHEN status = 'completed' AND type = 'video' THEN 500 + WHEN status = 'completed' AND type = 'image' THEN 200000 + WHEN status = 'completed' AND type = 'video' THEN 50000 ELSE 0 END ), 0) AS used_cents