From af62835d48297a2ed7232787f83e61a899075dfe Mon Sep 17 00:00:00 2001 From: Neal Shah <30693865+ProgrammerIn-wonderland@users.noreply.github.com> Date: Fri, 30 Jan 2026 22:33:36 +0530 Subject: [PATCH] video model costs (#2383) --- .../OpenAIVideoGenerationService.js | 41 ++++++++++++++++++- .../TogetherVideoGenerationService.js | 27 +++++++++++- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/backend/src/services/ai/video/OpenAIVideoGenerationService/OpenAIVideoGenerationService.js b/src/backend/src/services/ai/video/OpenAIVideoGenerationService/OpenAIVideoGenerationService.js index b4d4644dc..7ba4b80e7 100644 --- a/src/backend/src/services/ai/video/OpenAIVideoGenerationService/OpenAIVideoGenerationService.js +++ b/src/backend/src/services/ai/video/OpenAIVideoGenerationService/OpenAIVideoGenerationService.js @@ -95,8 +95,45 @@ class OpenAIVideoGenerationService extends BaseService { }, }; - models () { - return OPENAI_VIDEO_MODELS; + async models () { + // Import cost map dynamically + const costMapModule = await import('../../../MeteringService/costMaps/openaiVideoCostMap.ts'); + const OPENAI_VIDEO_COST_MAP = costMapModule.OPENAI_VIDEO_COST_MAP; + + // Convert microcents to cents (divide by 1,000,000) + const microCentsToCents = (microCents) => microCents / 1_000_000; + + return OPENAI_VIDEO_MODELS.map(model => { + const result = { ...model }; + + // Get cost for default usage key + const defaultCostMicroCents = OPENAI_VIDEO_COST_MAP[model.defaultUsageKey]; + if ( defaultCostMicroCents !== undefined ) { + const perSecondCost = microCentsToCents(defaultCostMicroCents); + result.costs_currency = 'usd-cents'; + result.costs = { + 'per-second': perSecondCost, + 'default-duration-per-video': perSecondCost * DEFAULT_DURATION_SECONDS, + }; + result.output_cost_key = 'default-duration-per-video'; + } + + // Add cost for xl variant if it exists (sora-2-pro only) + if ( model.id === 'sora-2-pro' ) { + const xlCostMicroCents = OPENAI_VIDEO_COST_MAP['openai:sora-2-pro:xl']; + if ( xlCostMicroCents !== undefined ) { + if ( ! result.costs ) { + result.costs = {}; + result.costs_currency = 'usd-cents'; + } + const perSecondXlCost = microCentsToCents(xlCostMicroCents); + result.costs['per-second-xl'] = perSecondXlCost; + result.costs['default-duration-per-video-xl'] = perSecondXlCost * DEFAULT_DURATION_SECONDS; + } + } + + return result; + }); } async generateVideo (params) { diff --git a/src/backend/src/services/ai/video/TogetherVideoGenerationService/TogetherVideoGenerationService.js b/src/backend/src/services/ai/video/TogetherVideoGenerationService/TogetherVideoGenerationService.js index 965d44926..b0f8c3177 100644 --- a/src/backend/src/services/ai/video/TogetherVideoGenerationService/TogetherVideoGenerationService.js +++ b/src/backend/src/services/ai/video/TogetherVideoGenerationService/TogetherVideoGenerationService.js @@ -199,12 +199,35 @@ class TogetherVideoGenerationService extends BaseService { } async models () { - if ( models.length > 0 ) { + if ( models.length > 0 && models[0].costs_currency ) { return models; } const { TOGETHER_VIDEO_GENERATION_MODELS } = await import('./models.js'); - models = TOGETHER_VIDEO_GENERATION_MODELS; + const costMapModule = await import('../../../MeteringService/costMaps/togetherCostMap.ts'); + const TOGETHER_COST_MAP = costMapModule.TOGETHER_COST_MAP; + + // Convert microcents to cents (divide by 1,000,000) + const microCentsToCents = (microCents) => microCents / 1_000_000; + + models = TOGETHER_VIDEO_GENERATION_MODELS.map(model => { + const result = { ...model }; + + // Convert model ID from 'togetherai:google/veo-3.0' to cost key 'together-video:google/veo-3.0' + const costKey = model.id.replace('togetherai:', 'together-video:'); + const costMicroCents = TOGETHER_COST_MAP[costKey]; + + if ( costMicroCents !== undefined && costMicroCents > 0 ) { + result.costs_currency = 'usd-cents'; + result.costs = { + 'per-video': microCentsToCents(costMicroCents), + }; + result.output_cost_key = 'per-video'; + } + + return result; + }); + return models; }