Skip to content

Commit 1e6ba5c

Browse files
bigcat88AustinMroz
andauthored
api_nodes: added prices for Ideogram V3 node (character reference) (#5241)
* api_nodes: added prices for Ideogram V3 node (character reference) * Support watching changes on connections. (#5250) * rename renderingSpeed default value from 'balanced' to 'default' * added missing type --------- Co-authored-by: AustinMroz <[email protected]>
1 parent ddd7b48 commit 1e6ba5c

File tree

3 files changed

+131
-38
lines changed

3 files changed

+131
-38
lines changed

src/composables/node/useNodePricing.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
1+
import type { INodeInputSlot, LGraphNode } from '@/lib/litegraph/src/litegraph'
22
import type { IComboWidget } from '@/lib/litegraph/src/types/widgets'
33

44
/**
@@ -179,6 +179,12 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
179179
const numImagesWidget = node.widgets?.find(
180180
(w) => w.name === 'num_images'
181181
) as IComboWidget
182+
const characterInput = node.inputs?.find(
183+
(i) => i.name === 'character_image'
184+
) as INodeInputSlot
185+
const hasCharacter =
186+
typeof characterInput?.link !== 'undefined' &&
187+
characterInput.link != null
182188

183189
if (!renderingSpeedWidget)
184190
return '$0.03-0.08 x num_images/Run (varies with rendering speed & num_images)'
@@ -188,11 +194,23 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
188194

189195
const renderingSpeed = String(renderingSpeedWidget.value)
190196
if (renderingSpeed.toLowerCase().includes('quality')) {
191-
basePrice = 0.09
192-
} else if (renderingSpeed.toLowerCase().includes('balanced')) {
193-
basePrice = 0.06
197+
if (hasCharacter) {
198+
basePrice = 0.2
199+
} else {
200+
basePrice = 0.09
201+
}
202+
} else if (renderingSpeed.toLowerCase().includes('default')) {
203+
if (hasCharacter) {
204+
basePrice = 0.15
205+
} else {
206+
basePrice = 0.06
207+
}
194208
} else if (renderingSpeed.toLowerCase().includes('turbo')) {
195-
basePrice = 0.03
209+
if (hasCharacter) {
210+
basePrice = 0.1
211+
} else {
212+
basePrice = 0.03
213+
}
196214
}
197215

198216
const totalCost = (basePrice * numImages).toFixed(2)
@@ -1462,7 +1480,7 @@ export const useNodePricing = () => {
14621480
OpenAIGPTImage1: ['quality', 'n'],
14631481
IdeogramV1: ['num_images', 'turbo'],
14641482
IdeogramV2: ['num_images', 'turbo'],
1465-
IdeogramV3: ['rendering_speed', 'num_images'],
1483+
IdeogramV3: ['rendering_speed', 'num_images', 'character_image'],
14661484
FluxProKontextProNode: [],
14671485
FluxProKontextMaxNode: [],
14681486
VeoVideoGenerationNode: ['duration_seconds'],

src/composables/node/useWatchWidget.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,29 @@ export const useComputedWithWidgetWatch = (
7575
}
7676
})
7777
})
78+
if (widgetNames && widgetNames.length > widgetsToObserve.length) {
79+
//Inputs have been included
80+
const indexesToObserve = widgetNames
81+
.map((name) =>
82+
widgetsToObserve.some((w) => w.name == name)
83+
? -1
84+
: node.inputs.findIndex((i) => i.name == name)
85+
)
86+
.filter((i) => i >= 0)
87+
node.onConnectionsChange = useChainCallback(
88+
node.onConnectionsChange,
89+
(_type: unknown, index: number, isConnected: boolean) => {
90+
if (!indexesToObserve.includes(index)) return
91+
widgetValues.value = {
92+
...widgetValues.value,
93+
[indexesToObserve[index]]: isConnected
94+
}
95+
if (triggerCanvasRedraw) {
96+
node.graph?.setDirtyCanvas(true, true)
97+
}
98+
}
99+
)
100+
}
78101
}
79102

80103
// Returns a function that creates a computed that responds to widget changes.

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

Lines changed: 84 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,29 @@ import type { IComboWidget } from '@/lib/litegraph/src/types/widgets'
88
function createMockNode(
99
nodeTypeName: string,
1010
widgets: Array<{ name: string; value: any }> = [],
11-
isApiNode = true
11+
isApiNode = true,
12+
inputs: Array<{
13+
name: string
14+
connected?: boolean
15+
useLinksArray?: boolean
16+
}> = []
1217
): LGraphNode {
1318
const mockWidgets = widgets.map(({ name, value }) => ({
1419
name,
1520
value,
1621
type: 'combo'
1722
})) as IComboWidget[]
1823

19-
return {
24+
const mockInputs =
25+
inputs.length > 0
26+
? inputs.map(({ name, connected, useLinksArray }) =>
27+
useLinksArray
28+
? { name, links: connected ? [1] : [] }
29+
: { name, link: connected ? 1 : null }
30+
)
31+
: undefined
32+
33+
const node: any = {
2034
id: Math.random().toString(),
2135
widgets: mockWidgets,
2236
constructor: {
@@ -25,7 +39,24 @@ function createMockNode(
2539
api_node: isApiNode
2640
}
2741
}
28-
} as unknown as LGraphNode
42+
}
43+
44+
if (mockInputs) {
45+
node.inputs = mockInputs
46+
// Provide the common helpers some frontend code may call
47+
node.findInputSlot = function (portName: string) {
48+
return this.inputs?.findIndex((i: any) => i.name === portName) ?? -1
49+
}
50+
node.isInputConnected = function (idx: number) {
51+
const port = this.inputs?.[idx]
52+
if (!port) return false
53+
if (typeof port.link !== 'undefined') return port.link != null
54+
if (Array.isArray(port.links)) return port.links.length > 0
55+
return false
56+
}
57+
}
58+
59+
return node as LGraphNode
2960
}
3061

3162
describe('useNodePricing', () => {
@@ -363,34 +394,51 @@ describe('useNodePricing', () => {
363394
})
364395

365396
describe('dynamic pricing - IdeogramV3', () => {
366-
it('should return $0.09 for Quality rendering speed', () => {
367-
const { getNodeDisplayPrice } = useNodePricing()
368-
const node = createMockNode('IdeogramV3', [
369-
{ name: 'rendering_speed', value: 'Quality' }
370-
])
371-
372-
const price = getNodeDisplayPrice(node)
373-
expect(price).toBe('$0.09/Run')
374-
})
375-
376-
it('should return $0.06 for Balanced rendering speed', () => {
377-
const { getNodeDisplayPrice } = useNodePricing()
378-
const node = createMockNode('IdeogramV3', [
379-
{ name: 'rendering_speed', value: 'Balanced' }
380-
])
381-
382-
const price = getNodeDisplayPrice(node)
383-
expect(price).toBe('$0.06/Run')
384-
})
385-
386-
it('should return $0.03 for Turbo rendering speed', () => {
387-
const { getNodeDisplayPrice } = useNodePricing()
388-
const node = createMockNode('IdeogramV3', [
389-
{ name: 'rendering_speed', value: 'Turbo' }
390-
])
391-
392-
const price = getNodeDisplayPrice(node)
393-
expect(price).toBe('$0.03/Run')
397+
it('should return correct prices for IdeogramV3 node', () => {
398+
const { getNodeDisplayPrice } = useNodePricing()
399+
400+
const testCases = [
401+
{
402+
rendering_speed: 'Quality',
403+
character_image: false,
404+
expected: '$0.09/Run'
405+
},
406+
{
407+
rendering_speed: 'Quality',
408+
character_image: true,
409+
expected: '$0.20/Run'
410+
},
411+
{
412+
rendering_speed: 'Default',
413+
character_image: false,
414+
expected: '$0.06/Run'
415+
},
416+
{
417+
rendering_speed: 'Default',
418+
character_image: true,
419+
expected: '$0.15/Run'
420+
},
421+
{
422+
rendering_speed: 'Turbo',
423+
character_image: false,
424+
expected: '$0.03/Run'
425+
},
426+
{
427+
rendering_speed: 'Turbo',
428+
character_image: true,
429+
expected: '$0.10/Run'
430+
}
431+
]
432+
433+
testCases.forEach(({ rendering_speed, character_image, expected }) => {
434+
const node = createMockNode(
435+
'IdeogramV3',
436+
[{ name: 'rendering_speed', value: rendering_speed }],
437+
true,
438+
[{ name: 'character_image', connected: character_image }]
439+
)
440+
expect(getNodeDisplayPrice(node)).toBe(expected)
441+
})
394442
})
395443

396444
it('should return range when rendering_speed widget is missing', () => {
@@ -935,7 +983,11 @@ describe('useNodePricing', () => {
935983
const { getRelevantWidgetNames } = useNodePricing()
936984

937985
const widgetNames = getRelevantWidgetNames('IdeogramV3')
938-
expect(widgetNames).toEqual(['rendering_speed', 'num_images'])
986+
expect(widgetNames).toEqual([
987+
'rendering_speed',
988+
'num_images',
989+
'character_image'
990+
])
939991
})
940992
})
941993

0 commit comments

Comments
 (0)