From 8e146bbac5cd42b90cc29e0b1674778b49b00175 Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Thu, 4 Dec 2025 12:55:43 +0200 Subject: [PATCH] changed some API nodes pricing --- src/composables/node/useNodePricing.ts | 122 +++++++++--------- .../composables/node/useNodePricing.test.ts | 52 ++++---- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/src/composables/node/useNodePricing.ts b/src/composables/node/useNodePricing.ts index 6a6bf08130..be52ef12ea 100644 --- a/src/composables/node/useNodePricing.ts +++ b/src/composables/node/useNodePricing.ts @@ -40,12 +40,12 @@ const calculateRunwayDurationPrice = (node: LGraphNode): string => { (w) => w.name === 'duration' ) as IComboWidget - if (!durationWidget) return '$0.05/second' + if (!durationWidget) return '$0.0715/second' const duration = Number(durationWidget.value) // If duration is 0 or NaN, don't fall back to 5 seconds - just use 0 const validDuration = isNaN(duration) ? 5 : duration - const cost = (0.05 * validDuration).toFixed(2) + const cost = (0.0715 * validDuration).toFixed(2) return `$${cost}/Run` } @@ -377,11 +377,11 @@ const apiNodeCosts: Record = (w) => w.name === 'turbo' ) as IComboWidget - if (!numImagesWidget) return '$0.02-0.06 x num_images/Run' + if (!numImagesWidget) return '$0.03-0.09 x num_images/Run' const numImages = Number(numImagesWidget.value) || 1 const turbo = String(turboWidget?.value).toLowerCase() === 'true' - const basePrice = turbo ? 0.02 : 0.06 + const basePrice = turbo ? 0.0286 : 0.0858 const cost = (basePrice * numImages).toFixed(2) return `$${cost}/Run` } @@ -395,11 +395,11 @@ const apiNodeCosts: Record = (w) => w.name === 'turbo' ) as IComboWidget - if (!numImagesWidget) return '$0.05-0.08 x num_images/Run' + if (!numImagesWidget) return '$0.07-0.11 x num_images/Run' const numImages = Number(numImagesWidget.value) || 1 const turbo = String(turboWidget?.value).toLowerCase() === 'true' - const basePrice = turbo ? 0.05 : 0.08 + const basePrice = turbo ? 0.0715 : 0.1144 const cost = (basePrice * numImages).toFixed(2) return `$${cost}/Run` } @@ -420,29 +420,29 @@ const apiNodeCosts: Record = characterInput.link != null if (!renderingSpeedWidget) - return '$0.03-0.08 x num_images/Run (varies with rendering speed & num_images)' + return '$0.04-0.11 x num_images/Run (varies with rendering speed & num_images)' const numImages = Number(numImagesWidget?.value) || 1 - let basePrice = 0.06 // default balanced price + let basePrice = 0.0858 // default balanced price const renderingSpeed = String(renderingSpeedWidget.value) if (renderingSpeed.toLowerCase().includes('quality')) { if (hasCharacter) { - basePrice = 0.2 + basePrice = 0.286 } else { - basePrice = 0.09 + basePrice = 0.1287 } } else if (renderingSpeed.toLowerCase().includes('default')) { if (hasCharacter) { - basePrice = 0.15 + basePrice = 0.2145 } else { - basePrice = 0.06 + basePrice = 0.0858 } } else if (renderingSpeed.toLowerCase().includes('turbo')) { if (hasCharacter) { - basePrice = 0.1 + basePrice = 0.143 } else { - basePrice = 0.03 + basePrice = 0.0429 } } @@ -755,7 +755,7 @@ const apiNodeCosts: Record = ) as IComboWidget if (!modelWidget || !resolutionWidget || !durationWidget) { - return '$0.14-11.47/Run (varies with model, resolution & duration)' + return '$0.20-16.40/Run (varies with model, resolution & duration)' } const model = String(modelWidget.value) @@ -764,33 +764,33 @@ const apiNodeCosts: Record = if (model.includes('ray-flash-2')) { if (duration.includes('5s')) { - if (resolution.includes('4k')) return '$2.19/Run' - if (resolution.includes('1080p')) return '$0.55/Run' - if (resolution.includes('720p')) return '$0.24/Run' - if (resolution.includes('540p')) return '$0.14/Run' + if (resolution.includes('4k')) return '$3.13/Run' + if (resolution.includes('1080p')) return '$0.79/Run' + if (resolution.includes('720p')) return '$0.34/Run' + if (resolution.includes('540p')) return '$0.20/Run' } else if (duration.includes('9s')) { - if (resolution.includes('4k')) return '$3.95/Run' - if (resolution.includes('1080p')) return '$0.99/Run' - if (resolution.includes('720p')) return '$0.43/Run' - if (resolution.includes('540p')) return '$0.252/Run' + if (resolution.includes('4k')) return '$5.65/Run' + if (resolution.includes('1080p')) return '$1.42/Run' + if (resolution.includes('720p')) return '$0.61/Run' + if (resolution.includes('540p')) return '$0.36/Run' } } else if (model.includes('ray-2')) { if (duration.includes('5s')) { - if (resolution.includes('4k')) return '$6.37/Run' - if (resolution.includes('1080p')) return '$1.59/Run' - if (resolution.includes('720p')) return '$0.71/Run' - if (resolution.includes('540p')) return '$0.40/Run' + if (resolution.includes('4k')) return '$9.11/Run' + if (resolution.includes('1080p')) return '$2.27/Run' + if (resolution.includes('720p')) return '$1.02/Run' + if (resolution.includes('540p')) return '$0.57/Run' } else if (duration.includes('9s')) { - if (resolution.includes('4k')) return '$11.47/Run' - if (resolution.includes('1080p')) return '$2.87/Run' - if (resolution.includes('720p')) return '$1.28/Run' - if (resolution.includes('540p')) return '$0.72/Run' + if (resolution.includes('4k')) return '$16.40/Run' + if (resolution.includes('1080p')) return '$4.10/Run' + if (resolution.includes('720p')) return '$1.83/Run' + if (resolution.includes('540p')) return '$1.03/Run' } } else if (model.includes('ray-1.6')) { - return '$0.35/Run' + return '$0.50/Run' } - return '$0.55/Run' + return '$0.79/Run' } }, LumaVideoNode: { @@ -806,7 +806,7 @@ const apiNodeCosts: Record = ) as IComboWidget if (!modelWidget || !resolutionWidget || !durationWidget) { - return '$0.14-11.47/Run (varies with model, resolution & duration)' + return '$0.20-16.40/Run (varies with model, resolution & duration)' } const model = String(modelWidget.value) @@ -815,33 +815,33 @@ const apiNodeCosts: Record = if (model.includes('ray-flash-2')) { if (duration.includes('5s')) { - if (resolution.includes('4k')) return '$2.19/Run' - if (resolution.includes('1080p')) return '$0.55/Run' - if (resolution.includes('720p')) return '$0.24/Run' - if (resolution.includes('540p')) return '$0.14/Run' + if (resolution.includes('4k')) return '$3.13/Run' + if (resolution.includes('1080p')) return '$0.79/Run' + if (resolution.includes('720p')) return '$0.34/Run' + if (resolution.includes('540p')) return '$0.20/Run' } else if (duration.includes('9s')) { - if (resolution.includes('4k')) return '$3.95/Run' - if (resolution.includes('1080p')) return '$0.99/Run' - if (resolution.includes('720p')) return '$0.43/Run' - if (resolution.includes('540p')) return '$0.252/Run' + if (resolution.includes('4k')) return '$5.65/Run' + if (resolution.includes('1080p')) return '$1.42/Run' + if (resolution.includes('720p')) return '$0.61/Run' + if (resolution.includes('540p')) return '$$0.36/Run' } } else if (model.includes('ray-2')) { if (duration.includes('5s')) { - if (resolution.includes('4k')) return '$6.37/Run' - if (resolution.includes('1080p')) return '$1.59/Run' - if (resolution.includes('720p')) return '$0.71/Run' - if (resolution.includes('540p')) return '$0.40/Run' + if (resolution.includes('4k')) return '$9.11/Run' + if (resolution.includes('1080p')) return '$2.27/Run' + if (resolution.includes('720p')) return '$1.02/Run' + if (resolution.includes('540p')) return '$0.57/Run' } else if (duration.includes('9s')) { - if (resolution.includes('4k')) return '$11.47/Run' - if (resolution.includes('1080p')) return '$2.87/Run' - if (resolution.includes('720p')) return '$1.28/Run' - if (resolution.includes('540p')) return '$0.72/Run' + if (resolution.includes('4k')) return '$16.40/Run' + if (resolution.includes('1080p')) return '$4.10/Run' + if (resolution.includes('720p')) return '$1.83/Run' + if (resolution.includes('540p')) return '$1.03/Run' } } else if (model.includes('ray-1-6')) { - return '$0.35/Run' + return '$0.50/Run' } - return '$0.55/Run' + return '$0.79/Run' } }, MinimaxImageToVideoNode: { @@ -1323,18 +1323,18 @@ const apiNodeCosts: Record = ) as IComboWidget if (!modelWidget || !aspectRatioWidget) { - return '$0.0045-0.0182/Run (varies with model & aspect ratio)' + return '$0.0064-0.026/Run (varies with model & aspect ratio)' } const model = String(modelWidget.value) if (model.includes('photon-flash-1')) { - return '$0.0019/Run' + return '$0.0027/Run' } else if (model.includes('photon-1')) { - return '$0.0073/Run' + return '$0.0104/Run' } - return '$0.0172/Run' + return '$0.0246/Run' } }, LumaImageModifyNode: { @@ -1344,18 +1344,18 @@ const apiNodeCosts: Record = ) as IComboWidget if (!modelWidget) { - return '$0.0019-0.0073/Run (varies with model)' + return '$0.0027-0.0104/Run (varies with model)' } const model = String(modelWidget.value) if (model.includes('photon-flash-1')) { - return '$0.0019/Run' + return '$0.0027/Run' } else if (model.includes('photon-1')) { - return '$0.0073/Run' + return '$0.0104/Run' } - return '$0.0172/Run' + return '$0.0246/Run' } }, MoonvalleyTxt2VideoNode: { @@ -1417,7 +1417,7 @@ const apiNodeCosts: Record = }, // Runway nodes - using actual node names from ComfyUI RunwayTextToImageNode: { - displayPrice: '$0.08/Run' + displayPrice: '$0.11/Run' }, RunwayImageToVideoNodeGen3a: { displayPrice: calculateRunwayDurationPrice diff --git a/tests-ui/tests/composables/node/useNodePricing.test.ts b/tests-ui/tests/composables/node/useNodePricing.test.ts index dad9e878ad..ae62699c52 100644 --- a/tests-ui/tests/composables/node/useNodePricing.test.ts +++ b/tests-ui/tests/composables/node/useNodePricing.test.ts @@ -577,32 +577,32 @@ describe('useNodePricing', () => { { rendering_speed: 'Quality', character_image: false, - expected: '$0.09/Run' + expected: '$0.13/Run' }, { rendering_speed: 'Quality', character_image: true, - expected: '$0.20/Run' + expected: '$0.29/Run' }, { rendering_speed: 'Default', character_image: false, - expected: '$0.06/Run' + expected: '$0.09/Run' }, { rendering_speed: 'Default', character_image: true, - expected: '$0.15/Run' + expected: '$0.21/Run' }, { rendering_speed: 'Turbo', character_image: false, - expected: '$0.03/Run' + expected: '$0.04/Run' }, { rendering_speed: 'Turbo', character_image: true, - expected: '$0.10/Run' + expected: '$0.14/Run' } ] @@ -623,7 +623,7 @@ describe('useNodePricing', () => { const price = getNodeDisplayPrice(node) expect(price).toBe( - '$0.03-0.08 x num_images/Run (varies with rendering speed & num_images)' + '$0.04-0.11 x num_images/Run (varies with rendering speed & num_images)' ) }) @@ -635,7 +635,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.27/Run') // 0.09 * 3 + expect(price).toBe('$0.39/Run') // 0.09 * 3 * 1.43 }) it('should multiply price by num_images for Turbo rendering speed', () => { @@ -646,7 +646,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.15/Run') // 0.03 * 5 + expect(price).toBe('$0.21/Run') // 0.03 * 5 * 1.43 }) }) @@ -770,7 +770,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$2.19/Run') + expect(price).toBe('$3.13/Run') }) it('should return $6.37 for ray-2 4K 5s', () => { @@ -782,7 +782,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$6.37/Run') + expect(price).toBe('$9.11/Run') }) it('should return $0.35 for ray-1-6 model', () => { @@ -794,7 +794,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.35/Run') + expect(price).toBe('$0.50/Run') }) it('should return range when widgets are missing', () => { @@ -803,7 +803,7 @@ describe('useNodePricing', () => { const price = getNodeDisplayPrice(node) expect(price).toBe( - '$0.14-11.47/Run (varies with model, resolution & duration)' + '$0.20-16.40/Run (varies with model, resolution & duration)' ) }) }) @@ -1192,7 +1192,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.18/Run') // 0.06 * 3 + expect(price).toBe('$0.26/Run') // 0.06 * 3 * 1.43 }) it('should calculate dynamic pricing for IdeogramV2 based on num_images value', () => { @@ -1202,7 +1202,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.32/Run') // 0.08 * 4 + expect(price).toBe('$0.46/Run') // 0.08 * 4 * 1.43 }) it('should fall back to static display when num_images widget is missing for IdeogramV1', () => { @@ -1210,7 +1210,7 @@ describe('useNodePricing', () => { const node = createMockNode('IdeogramV1', []) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.02-0.06 x num_images/Run') + expect(price).toBe('$0.03-0.09 x num_images/Run') }) it('should fall back to static display when num_images widget is missing for IdeogramV2', () => { @@ -1218,7 +1218,7 @@ describe('useNodePricing', () => { const node = createMockNode('IdeogramV2', []) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.05-0.08 x num_images/Run') + expect(price).toBe('$0.07-0.11 x num_images/Run') }) it('should handle edge case when num_images value is 1 for IdeogramV1', () => { @@ -1228,7 +1228,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.06/Run') // 0.06 * 1 (turbo=false by default) + expect(price).toBe('$0.09/Run') // 0.06 * 1 * 1.43 (turbo=false by default) }) }) @@ -1435,7 +1435,7 @@ describe('useNodePricing', () => { const node = createMockNode('RunwayTextToImageNode') const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.08/Run') + expect(price).toBe('$0.11/Run') }) it('should calculate dynamic pricing for RunwayImageToVideoNodeGen3a', () => { @@ -1445,7 +1445,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.50/Run') // 0.05 * 10 + expect(price).toBe('$0.71/Run') // 0.05 * 10 * 1.43 }) it('should return fallback for RunwayImageToVideoNodeGen3a without duration', () => { @@ -1453,7 +1453,7 @@ describe('useNodePricing', () => { const node = createMockNode('RunwayImageToVideoNodeGen3a', []) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.05/second') + expect(price).toBe('$0.0715/second') }) it('should handle zero duration for RunwayImageToVideoNodeGen3a', () => { @@ -1473,7 +1473,7 @@ describe('useNodePricing', () => { ]) const price = getNodeDisplayPrice(node) - expect(price).toBe('$0.25/Run') // Falls back to 5 seconds: 0.05 * 5 + expect(price).toBe('$0.36/Run') // Falls back to 5 seconds: 0.05 * 5 * 1.43 }) }) @@ -1810,8 +1810,8 @@ describe('useNodePricing', () => { // Test edge cases const testCases = [ { duration: 0, expected: '$0.00/Run' }, // Now correctly handles 0 duration - { duration: 1, expected: '$0.05/Run' }, - { duration: 30, expected: '$1.50/Run' } + { duration: 1, expected: '$0.07/Run' }, + { duration: 30, expected: '$2.15/Run' } ] testCases.forEach(({ duration, expected }) => { @@ -1828,7 +1828,7 @@ describe('useNodePricing', () => { { name: 'duration', value: 'invalid-string' } ]) // When Number('invalid-string') returns NaN, it falls back to 5 seconds - expect(getNodeDisplayPrice(node)).toBe('$0.25/Run') + expect(getNodeDisplayPrice(node)).toBe('$0.36/Run') }) it('should handle missing duration widget gracefully', () => { @@ -1841,7 +1841,7 @@ describe('useNodePricing', () => { nodes.forEach((nodeType) => { const node = createMockNode(nodeType, []) - expect(getNodeDisplayPrice(node)).toBe('$0.05/second') + expect(getNodeDisplayPrice(node)).toBe('$0.0715/second') }) }) })