Skip to content

Commit 1022286

Browse files
authored
feat(api-nodes-pricing): add prices for Flux2ProImageNode (#6921)
## Summary Price badges for comfyanonymous/ComfyUI#10880 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6921-feat-api-nodes-pricing-add-prices-for-Flux2ProImageNode-2b66d73d365081f2b269c77df7ef93d6) by [Unito](https://www.unito.io)
1 parent 4597b7e commit 1022286

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

src/composables/node/useNodePricing.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,46 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
303303
FluxProKontextMaxNode: {
304304
displayPrice: '$0.08/Run'
305305
},
306+
Flux2ProImageNode: {
307+
displayPrice: (node: LGraphNode): string => {
308+
const widthW = node.widgets?.find(
309+
(w) => w.name === 'width'
310+
) as IComboWidget
311+
const heightW = node.widgets?.find(
312+
(w) => w.name === 'height'
313+
) as IComboWidget
314+
315+
const w = Number(widthW?.value)
316+
const h = Number(heightW?.value)
317+
if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
318+
// global min/max for this node given schema bounds (1MP..4MP output)
319+
return '$0.03–$0.15/Run'
320+
}
321+
322+
// Is the 'images' input connected?
323+
const imagesInput = node.inputs?.find(
324+
(i) => i.name === 'images'
325+
) as INodeInputSlot
326+
const hasRefs =
327+
typeof imagesInput?.link !== 'undefined' && imagesInput.link != null
328+
329+
// Output cost: ceil((w*h)/MP); first MP $0.03, each additional $0.015
330+
const MP = 1024 * 1024
331+
const outMP = Math.max(1, Math.floor((w * h + MP - 1) / MP))
332+
const outputCost = 0.03 + 0.015 * Math.max(outMP - 1, 0)
333+
334+
if (hasRefs) {
335+
// Unknown ref count/size on the frontend:
336+
// min extra is $0.015, max extra is $0.120 (8 MP cap / 8 refs)
337+
const minTotal = outputCost + 0.015
338+
const maxTotal = outputCost + 0.12
339+
return `~$${parseFloat(minTotal.toFixed(3))}–$${parseFloat(maxTotal.toFixed(3))}/Run`
340+
}
341+
342+
// Precise text-to-image price
343+
return `$${parseFloat(outputCost.toFixed(3))}/Run`
344+
}
345+
},
306346
OpenAIVideoSora2: {
307347
displayPrice: sora2PricingCalculator
308348
},
@@ -1809,6 +1849,7 @@ export const useNodePricing = () => {
18091849
IdeogramV3: ['rendering_speed', 'num_images', 'character_image'],
18101850
FluxProKontextProNode: [],
18111851
FluxProKontextMaxNode: [],
1852+
Flux2ProImageNode: ['width', 'height', 'images'],
18121853
VeoVideoGenerationNode: ['duration_seconds'],
18131854
Veo3VideoGenerationNode: ['model', 'generate_audio'],
18141855
LumaVideoNode: ['model', 'resolution', 'duration'],

tests-ui/tests/composables/node/useNodePricing.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,42 @@ describe('useNodePricing', () => {
9494
})
9595
})
9696

97+
describe('dynamic pricing - Flux2ProImageNode', () => {
98+
it('should return precise price for text-to-image 1024x1024 (no refs)', () => {
99+
const { getNodeDisplayPrice } = useNodePricing()
100+
const node = createMockNode('Flux2ProImageNode', [
101+
{ name: 'width', value: 1024 },
102+
{ name: 'height', value: 1024 }
103+
])
104+
105+
// 1024x1024 => 1 MP => $0.03
106+
expect(getNodeDisplayPrice(node)).toBe('$0.03/Run')
107+
})
108+
109+
it('should return minimum estimate when refs are connected (1024x1024)', () => {
110+
const { getNodeDisplayPrice } = useNodePricing()
111+
const node = createMockNode(
112+
'Flux2ProImageNode',
113+
[
114+
{ name: 'width', value: 1024 },
115+
{ name: 'height', value: 1024 }
116+
],
117+
true,
118+
// connect the 'images' input
119+
[{ name: 'images', connected: true }]
120+
)
121+
122+
// 1024x1024 => 1 MP output = $0.03, min input add = $0.015 => ~$0.045 min
123+
expect(getNodeDisplayPrice(node)).toBe('~$0.045–$0.15/Run')
124+
})
125+
126+
it('should show fallback when width/height are missing', () => {
127+
const { getNodeDisplayPrice } = useNodePricing()
128+
const node = createMockNode('Flux2ProImageNode', [])
129+
expect(getNodeDisplayPrice(node)).toBe('$0.03–$0.15/Run')
130+
})
131+
})
132+
97133
describe('dynamic pricing - KlingTextToVideoNode', () => {
98134
it('should return high price for kling-v2-1-master model', () => {
99135
const { getNodeDisplayPrice } = useNodePricing()

0 commit comments

Comments
 (0)