mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
[fix] Add dynamic pricing for Ideogram nodes based on num_images parameter (#4351)
This commit is contained in:
@@ -111,30 +111,55 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
|
|||||||
displayPrice: '$0.06/Run'
|
displayPrice: '$0.06/Run'
|
||||||
},
|
},
|
||||||
IdeogramV1: {
|
IdeogramV1: {
|
||||||
displayPrice: '$0.06/Run'
|
displayPrice: (node: LGraphNode): string => {
|
||||||
|
const numImagesWidget = node.widgets?.find(
|
||||||
|
(w) => w.name === 'num_images'
|
||||||
|
) as IComboWidget
|
||||||
|
if (!numImagesWidget) return '$0.06 x num_images/Run'
|
||||||
|
|
||||||
|
const numImages = Number(numImagesWidget.value) || 1
|
||||||
|
const cost = (0.06 * numImages).toFixed(2)
|
||||||
|
return `$${cost}/Run`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
IdeogramV2: {
|
IdeogramV2: {
|
||||||
displayPrice: '$0.08/Run'
|
displayPrice: (node: LGraphNode): string => {
|
||||||
|
const numImagesWidget = node.widgets?.find(
|
||||||
|
(w) => w.name === 'num_images'
|
||||||
|
) as IComboWidget
|
||||||
|
if (!numImagesWidget) return '$0.08 x num_images/Run'
|
||||||
|
|
||||||
|
const numImages = Number(numImagesWidget.value) || 1
|
||||||
|
const cost = (0.08 * numImages).toFixed(2)
|
||||||
|
return `$${cost}/Run`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
IdeogramV3: {
|
IdeogramV3: {
|
||||||
displayPrice: (node: LGraphNode): string => {
|
displayPrice: (node: LGraphNode): string => {
|
||||||
const renderingSpeedWidget = node.widgets?.find(
|
const renderingSpeedWidget = node.widgets?.find(
|
||||||
(w) => w.name === 'rendering_speed'
|
(w) => w.name === 'rendering_speed'
|
||||||
) as IComboWidget
|
) as IComboWidget
|
||||||
|
const numImagesWidget = node.widgets?.find(
|
||||||
|
(w) => w.name === 'num_images'
|
||||||
|
) as IComboWidget
|
||||||
|
|
||||||
if (!renderingSpeedWidget)
|
if (!renderingSpeedWidget)
|
||||||
return '$0.03-0.08/Run (varies with rendering speed)'
|
return '$0.03-0.08 x num_images/Run (varies with rendering speed & num_images)'
|
||||||
|
|
||||||
|
const numImages = Number(numImagesWidget?.value) || 1
|
||||||
|
let basePrice = 0.06 // default balanced price
|
||||||
|
|
||||||
const renderingSpeed = String(renderingSpeedWidget.value)
|
const renderingSpeed = String(renderingSpeedWidget.value)
|
||||||
if (renderingSpeed.toLowerCase().includes('quality')) {
|
if (renderingSpeed.toLowerCase().includes('quality')) {
|
||||||
return '$0.08/Run'
|
basePrice = 0.08
|
||||||
} else if (renderingSpeed.toLowerCase().includes('balanced')) {
|
} else if (renderingSpeed.toLowerCase().includes('balanced')) {
|
||||||
return '$0.06/Run'
|
basePrice = 0.06
|
||||||
} else if (renderingSpeed.toLowerCase().includes('turbo')) {
|
} else if (renderingSpeed.toLowerCase().includes('turbo')) {
|
||||||
return '$0.03/Run'
|
basePrice = 0.03
|
||||||
}
|
}
|
||||||
|
|
||||||
return '$0.06/Run'
|
const totalCost = (basePrice * numImages).toFixed(2)
|
||||||
|
return `$${totalCost}/Run`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
KlingCameraControlI2VNode: {
|
KlingCameraControlI2VNode: {
|
||||||
@@ -897,7 +922,9 @@ export const useNodePricing = () => {
|
|||||||
OpenAIDalle3: ['size', 'quality'],
|
OpenAIDalle3: ['size', 'quality'],
|
||||||
OpenAIDalle2: ['size'],
|
OpenAIDalle2: ['size'],
|
||||||
OpenAIGPTImage1: ['quality'],
|
OpenAIGPTImage1: ['quality'],
|
||||||
IdeogramV3: ['rendering_speed'],
|
IdeogramV1: ['num_images'],
|
||||||
|
IdeogramV2: ['num_images'],
|
||||||
|
IdeogramV3: ['rendering_speed', 'num_images'],
|
||||||
VeoVideoGenerationNode: ['duration_seconds'],
|
VeoVideoGenerationNode: ['duration_seconds'],
|
||||||
LumaVideoNode: ['model', 'resolution', 'duration'],
|
LumaVideoNode: ['model', 'resolution', 'duration'],
|
||||||
LumaImageToVideoNode: ['model', 'resolution', 'duration'],
|
LumaImageToVideoNode: ['model', 'resolution', 'duration'],
|
||||||
|
|||||||
@@ -335,7 +335,31 @@ describe('useNodePricing', () => {
|
|||||||
const node = createMockNode('IdeogramV3', [])
|
const node = createMockNode('IdeogramV3', [])
|
||||||
|
|
||||||
const price = getNodeDisplayPrice(node)
|
const price = getNodeDisplayPrice(node)
|
||||||
expect(price).toBe('$0.03-0.08/Run (varies with rendering speed)')
|
expect(price).toBe(
|
||||||
|
'$0.03-0.08 x num_images/Run (varies with rendering speed & num_images)'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should multiply price by num_images for Quality rendering speed', () => {
|
||||||
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
const node = createMockNode('IdeogramV3', [
|
||||||
|
{ name: 'rendering_speed', value: 'Quality' },
|
||||||
|
{ name: 'num_images', value: 3 }
|
||||||
|
])
|
||||||
|
|
||||||
|
const price = getNodeDisplayPrice(node)
|
||||||
|
expect(price).toBe('$0.24/Run') // 0.08 * 3
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should multiply price by num_images for Turbo rendering speed', () => {
|
||||||
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
const node = createMockNode('IdeogramV3', [
|
||||||
|
{ name: 'rendering_speed', value: 'Turbo' },
|
||||||
|
{ name: 'num_images', value: 5 }
|
||||||
|
])
|
||||||
|
|
||||||
|
const price = getNodeDisplayPrice(node)
|
||||||
|
expect(price).toBe('$0.15/Run') // 0.03 * 5
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -742,6 +766,29 @@ describe('useNodePricing', () => {
|
|||||||
expect(widgetNames).toEqual([])
|
expect(widgetNames).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Ideogram nodes with num_images parameter', () => {
|
||||||
|
it('should return correct widget names for IdeogramV1', () => {
|
||||||
|
const { getRelevantWidgetNames } = useNodePricing()
|
||||||
|
|
||||||
|
const widgetNames = getRelevantWidgetNames('IdeogramV1')
|
||||||
|
expect(widgetNames).toEqual(['num_images'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return correct widget names for IdeogramV2', () => {
|
||||||
|
const { getRelevantWidgetNames } = useNodePricing()
|
||||||
|
|
||||||
|
const widgetNames = getRelevantWidgetNames('IdeogramV2')
|
||||||
|
expect(widgetNames).toEqual(['num_images'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return correct widget names for IdeogramV3', () => {
|
||||||
|
const { getRelevantWidgetNames } = useNodePricing()
|
||||||
|
|
||||||
|
const widgetNames = getRelevantWidgetNames('IdeogramV3')
|
||||||
|
expect(widgetNames).toEqual(['rendering_speed', 'num_images'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Recraft nodes with n parameter', () => {
|
describe('Recraft nodes with n parameter', () => {
|
||||||
it('should return correct widget names for RecraftTextToImageNode', () => {
|
it('should return correct widget names for RecraftTextToImageNode', () => {
|
||||||
const { getRelevantWidgetNames } = useNodePricing()
|
const { getRelevantWidgetNames } = useNodePricing()
|
||||||
@@ -759,6 +806,54 @@ describe('useNodePricing', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Ideogram nodes dynamic pricing', () => {
|
||||||
|
it('should calculate dynamic pricing for IdeogramV1 based on num_images value', () => {
|
||||||
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
const node = createMockNode('IdeogramV1', [
|
||||||
|
{ name: 'num_images', value: 3 }
|
||||||
|
])
|
||||||
|
|
||||||
|
const price = getNodeDisplayPrice(node)
|
||||||
|
expect(price).toBe('$0.18/Run') // 0.06 * 3
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should calculate dynamic pricing for IdeogramV2 based on num_images value', () => {
|
||||||
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
const node = createMockNode('IdeogramV2', [
|
||||||
|
{ name: 'num_images', value: 4 }
|
||||||
|
])
|
||||||
|
|
||||||
|
const price = getNodeDisplayPrice(node)
|
||||||
|
expect(price).toBe('$0.32/Run') // 0.08 * 4
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fall back to static display when num_images widget is missing for IdeogramV1', () => {
|
||||||
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
const node = createMockNode('IdeogramV1', [])
|
||||||
|
|
||||||
|
const price = getNodeDisplayPrice(node)
|
||||||
|
expect(price).toBe('$0.06 x num_images/Run')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fall back to static display when num_images widget is missing for IdeogramV2', () => {
|
||||||
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
const node = createMockNode('IdeogramV2', [])
|
||||||
|
|
||||||
|
const price = getNodeDisplayPrice(node)
|
||||||
|
expect(price).toBe('$0.08 x num_images/Run')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle edge case when num_images value is 1 for IdeogramV1', () => {
|
||||||
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
const node = createMockNode('IdeogramV1', [
|
||||||
|
{ name: 'num_images', value: 1 }
|
||||||
|
])
|
||||||
|
|
||||||
|
const price = getNodeDisplayPrice(node)
|
||||||
|
expect(price).toBe('$0.06/Run') // 0.06 * 1
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Recraft nodes dynamic pricing', () => {
|
describe('Recraft nodes dynamic pricing', () => {
|
||||||
it('should calculate dynamic pricing for RecraftTextToImageNode based on n value', () => {
|
it('should calculate dynamic pricing for RecraftTextToImageNode based on n value', () => {
|
||||||
const { getNodeDisplayPrice } = useNodePricing()
|
const { getNodeDisplayPrice } = useNodePricing()
|
||||||
|
|||||||
Reference in New Issue
Block a user