mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
fix(price-badges): improve Gemini and OpenAI chat nodes (#7900)
## Summary Added `~` to the price badges and a correct separator. ## Screenshots (if applicable) Before commit: <img width="1163" height="516" alt="Screenshot From 2026-01-08 09-53-00" src="https://github.com/user-attachments/assets/8f5afa87-0b25-4748-a254-5ae09990f83f" /> After: <img width="1163" height="516" alt="Screenshot From 2026-01-08 09-52-09" src="https://github.com/user-attachments/assets/f4332e4a-4943-4c0d-8ed5-9ec0c119d0b4" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7900-fix-price-badges-improve-Gemini-and-OpenAI-chat-nodes-2e26d73d3650812093f2d173de50052d) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -1664,31 +1664,41 @@ describe('useNodePricing', () => {
|
||||
{
|
||||
model: 'gemini-2.5-pro-preview-05-06',
|
||||
expected: creditsListLabel([0.00125, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gemini-2.5-pro',
|
||||
expected: creditsListLabel([0.00125, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gemini-3-pro-preview',
|
||||
expected: creditsListLabel([0.002, 0.012], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gemini-2.5-flash-preview-04-17',
|
||||
expected: creditsListLabel([0.0003, 0.0025], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gemini-2.5-flash',
|
||||
expected: creditsListLabel([0.0003, 0.0025], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{ model: 'unknown-gemini-model', expected: 'Token-based' }
|
||||
@@ -1702,16 +1712,6 @@ describe('useNodePricing', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should return per-second pricing for Gemini Veo models', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('GeminiNode', [
|
||||
{ name: 'model', value: 'veo-2.0-generate-001' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe(creditsLabel(0.5, { suffix: '/second' }))
|
||||
})
|
||||
|
||||
it('should return fallback for GeminiNode without model widget', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('GeminiNode', [])
|
||||
@@ -1737,73 +1737,97 @@ describe('useNodePricing', () => {
|
||||
{
|
||||
model: 'o4-mini',
|
||||
expected: creditsListLabel([0.0011, 0.0044], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'o1-pro',
|
||||
expected: creditsListLabel([0.15, 0.6], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'o1',
|
||||
expected: creditsListLabel([0.015, 0.06], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'o3-mini',
|
||||
expected: creditsListLabel([0.0011, 0.0044], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'o3',
|
||||
expected: creditsListLabel([0.01, 0.04], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-4o',
|
||||
expected: creditsListLabel([0.0025, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-4.1-nano',
|
||||
expected: creditsListLabel([0.0001, 0.0004], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-4.1-mini',
|
||||
expected: creditsListLabel([0.0004, 0.0016], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-4.1',
|
||||
expected: creditsListLabel([0.002, 0.008], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-5-nano',
|
||||
expected: creditsListLabel([0.00005, 0.0004], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-5-mini',
|
||||
expected: creditsListLabel([0.00025, 0.002], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-5',
|
||||
expected: creditsListLabel([0.00125, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -1824,37 +1848,49 @@ describe('useNodePricing', () => {
|
||||
{
|
||||
model: 'gpt-4.1-nano-test',
|
||||
expected: creditsListLabel([0.0001, 0.0004], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-4.1-mini-test',
|
||||
expected: creditsListLabel([0.0004, 0.0016], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'gpt-4.1-test',
|
||||
expected: creditsListLabel([0.002, 0.008], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'o1-pro-test',
|
||||
expected: creditsListLabel([0.15, 0.6], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'o1-test',
|
||||
expected: creditsListLabel([0.015, 0.06], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{
|
||||
model: 'o3-mini-test',
|
||||
expected: creditsListLabel([0.0011, 0.0044], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
},
|
||||
{ model: 'unknown-model', expected: 'Token-based' }
|
||||
|
||||
@@ -1823,28 +1823,35 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
|
||||
|
||||
const model = String(modelWidget.value)
|
||||
|
||||
// Google Veo video generation
|
||||
if (model.includes('veo-2.0')) {
|
||||
return formatCreditsLabel(0.5, { suffix: '/second' })
|
||||
} else if (model.includes('gemini-2.5-flash-preview-04-17')) {
|
||||
if (model.includes('gemini-2.5-flash-preview-04-17')) {
|
||||
return formatCreditsListLabel([0.0003, 0.0025], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gemini-2.5-flash')) {
|
||||
return formatCreditsListLabel([0.0003, 0.0025], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gemini-2.5-pro-preview-05-06')) {
|
||||
return formatCreditsListLabel([0.00125, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gemini-2.5-pro')) {
|
||||
return formatCreditsListLabel([0.00125, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gemini-3-pro-preview')) {
|
||||
return formatCreditsListLabel([0.002, 0.012], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
}
|
||||
// For other Gemini models, show token-based pricing info
|
||||
@@ -1899,51 +1906,75 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
|
||||
// Specific pricing for exposed models based on official pricing data (converted to per 1K tokens)
|
||||
if (model.includes('o4-mini')) {
|
||||
return formatCreditsListLabel([0.0011, 0.0044], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('o1-pro')) {
|
||||
return formatCreditsListLabel([0.15, 0.6], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('o1')) {
|
||||
return formatCreditsListLabel([0.015, 0.06], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('o3-mini')) {
|
||||
return formatCreditsListLabel([0.0011, 0.0044], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('o3')) {
|
||||
return formatCreditsListLabel([0.01, 0.04], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gpt-4o')) {
|
||||
return formatCreditsListLabel([0.0025, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gpt-4.1-nano')) {
|
||||
return formatCreditsListLabel([0.0001, 0.0004], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gpt-4.1-mini')) {
|
||||
return formatCreditsListLabel([0.0004, 0.0016], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gpt-4.1')) {
|
||||
return formatCreditsListLabel([0.002, 0.008], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gpt-5-nano')) {
|
||||
return formatCreditsListLabel([0.00005, 0.0004], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gpt-5-mini')) {
|
||||
return formatCreditsListLabel([0.00025, 0.002], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
} else if (model.includes('gpt-5')) {
|
||||
return formatCreditsListLabel([0.00125, 0.01], {
|
||||
suffix: ' per 1K tokens'
|
||||
suffix: ' per 1K tokens',
|
||||
approximate: true,
|
||||
separator: '-'
|
||||
})
|
||||
}
|
||||
return 'Token-based'
|
||||
|
||||
Reference in New Issue
Block a user