From 2e64c64ac7b5eb913d6fad65ddd4c0108bce5ec5 Mon Sep 17 00:00:00 2001 From: Alexander Piskun <13381981+bigcat88@users.noreply.github.com> Date: Thu, 11 Sep 2025 03:46:47 +0300 Subject: [PATCH] add pricing for new ByteDance node (#5481) --- src/composables/node/useNodePricing.ts | 31 ++++++++++++++++++ .../composables/node/useNodePricing.test.ts | 32 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/composables/node/useNodePricing.ts b/src/composables/node/useNodePricing.ts index 48529fec1..e85e6adb6 100644 --- a/src/composables/node/useNodePricing.ts +++ b/src/composables/node/useNodePricing.ts @@ -1511,6 +1511,32 @@ const apiNodeCosts: Record = return 'Token-based' } }, + ByteDanceSeedreamNode: { + displayPrice: (node: LGraphNode): string => { + const sequentialGenerationWidget = node.widgets?.find( + (w) => w.name === 'sequential_image_generation' + ) as IComboWidget + const maxImagesWidget = node.widgets?.find( + (w) => w.name === 'max_images' + ) as IComboWidget + + if (!sequentialGenerationWidget || !maxImagesWidget) + return '$0.03/Run ($0.03 for one output image)' + + if ( + String(sequentialGenerationWidget.value).toLowerCase() === 'disabled' + ) { + return '$0.03/Run' + } + + const maxImages = Number(maxImagesWidget.value) + if (maxImages === 1) { + return '$0.03/Run' + } + const cost = (0.03 * maxImages).toFixed(2) + return `$${cost}/Run ($0.03 for one output image)` + } + }, ByteDanceTextToVideoNode: { displayPrice: byteDanceVideoPricingCalculator }, @@ -1613,6 +1639,11 @@ export const useNodePricing = () => { // ByteDance ByteDanceImageNode: ['model'], ByteDanceImageEditNode: ['model'], + ByteDanceSeedreamNode: [ + 'model', + 'sequential_image_generation', + 'max_images' + ], ByteDanceTextToVideoNode: ['model', 'duration', 'resolution'], ByteDanceImageToVideoNode: ['model', 'duration', 'resolution'], ByteDanceFirstLastFrameNode: ['model', 'duration', 'resolution'], diff --git a/tests-ui/tests/composables/node/useNodePricing.test.ts b/tests-ui/tests/composables/node/useNodePricing.test.ts index 89df12a36..6cd76cb75 100644 --- a/tests-ui/tests/composables/node/useNodePricing.test.ts +++ b/tests-ui/tests/composables/node/useNodePricing.test.ts @@ -1781,6 +1781,38 @@ describe('useNodePricing', () => { }) }) + describe('dynamic pricing - ByteDanceSeedreamNode', () => { + it('should return fallback when widgets are missing', () => { + const { getNodeDisplayPrice } = useNodePricing() + const node = createMockNode('ByteDanceSeedreamNode', []) + + const price = getNodeDisplayPrice(node) + expect(price).toBe('$0.03/Run ($0.03 for one output image)') + }) + + it('should return $0.03/Run when sequential generation is disabled', () => { + const { getNodeDisplayPrice } = useNodePricing() + const node = createMockNode('ByteDanceSeedreamNode', [ + { name: 'sequential_image_generation', value: 'disabled' }, + { name: 'max_images', value: 5 } + ]) + + const price = getNodeDisplayPrice(node) + expect(price).toBe('$0.03/Run') + }) + + it('should multiply by max_images when sequential generation is enabled', () => { + const { getNodeDisplayPrice } = useNodePricing() + const node = createMockNode('ByteDanceSeedreamNode', [ + { name: 'sequential_image_generation', value: 'enabled' }, + { name: 'max_images', value: 4 } + ]) + + const price = getNodeDisplayPrice(node) + expect(price).toBe('$0.12/Run ($0.03 for one output image)') + }) + }) + describe('dynamic pricing - ByteDance Seedance video nodes', () => { it('should return base 10s range for PRO 1080p on ByteDanceTextToVideoNode', () => { const { getNodeDisplayPrice } = useNodePricing()