feat: add API node pricing display in node badges

- Adds pricing data for API nodes from various providers
- Displays pricing in the credits badge next to API nodes
- Implements pricing display in gold badge color to distinguish costs
This commit is contained in:
bymyself
2025-05-17 23:01:57 -07:00
parent 4804f6d62f
commit 9d0fee44e3
5 changed files with 582 additions and 4 deletions

View File

@@ -0,0 +1,396 @@
import { ApiNodeCostRecord } from '@/types/apiNodeTypes'
/**
* API Node cost data sourced from pricing database
*
* GENERATED FILE - DO NOT EDIT DIRECTLY
* Generated from Price Run Range for each API Node CSV
*/
export const apiNodeCosts: ApiNodeCostRecord = {
FluxProCannyNode: {
vendor: 'Unknown',
nodeName: 'Flux 1: Canny Control Image',
pricingParams: '-',
pricePerRunRange: '$0.05',
displayPrice: '$0.05/Run'
},
FluxProDepthNode: {
vendor: 'Unknown',
nodeName: 'Flux 1: Depth Control Image',
pricingParams: '-',
pricePerRunRange: '$0.05',
displayPrice: '$0.05/Run'
},
FluxProExpandNode: {
vendor: 'Unknown',
nodeName: 'Flux 1: Expand Image',
pricingParams: '-',
pricePerRunRange: '$0.05',
rateDocumentation: 'https://docs.bfl.ml/pricing/',
displayPrice: '$0.05/Run'
},
FluxProFillNode: {
vendor: 'Unknown',
nodeName: 'Flux 1: Fill Image',
pricingParams: '-',
pricePerRunRange: '$0.05',
displayPrice: '$0.05/Run'
},
FluxProUltraImageNode: {
vendor: 'Unknown',
nodeName: 'Flux 1.1: [pro] Ultra Image',
pricingParams: '-',
pricePerRunRange: '$0.06',
displayPrice: '$0.06/Run'
},
IdeogramV1: {
vendor: 'Unknown',
nodeName: 'Ideogram V1',
pricingParams: '-',
pricePerRunRange: '$0.06',
rateDocumentation: 'https://about.ideogram.ai/api-pricing',
displayPrice: '$0.06/Run'
},
IdeogramV2: {
vendor: 'Unknown',
nodeName: 'Ideogram V2',
pricingParams: '-',
pricePerRunRange: '$0.08',
displayPrice: '$0.08/Run'
},
IdeogramV3: {
vendor: 'Unknown',
nodeName: 'Ideogram V3',
pricingParams: 'rendering_speed',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
KlingCameraControlI2VNode: {
vendor: 'Unknown',
nodeName: 'Kling Image to Video (Camera Control)',
pricingParams: '-',
pricePerRunRange: '$0.49',
displayPrice: '$0.49/Run'
},
KlingCameraControlT2VNode: {
vendor: 'Unknown',
nodeName: 'Kling Text to Video (Camera Control)',
pricingParams: '-',
pricePerRunRange: '$0.14',
displayPrice: '$0.14/Run'
},
KlingDualCharacterVideoEffectNode: {
vendor: 'Unknown',
nodeName: 'Kling Dual Character Video Effects',
pricingParams: 'Priced the same as t2v based on mode, model, and duration.',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
KlingImage2VideoNode: {
vendor: 'Unknown',
nodeName: 'Kling Image to Video',
pricingParams: 'Same as Text to Video',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
KlingImageGenerationNode: {
vendor: 'Unknown',
nodeName: 'Kling Image Generation',
pricingParams: 'modality | model',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
KlingLipSyncAudioToVideoNode: {
vendor: 'Unknown',
nodeName: 'Kling Lip Sync Video with Audio',
pricingParams: 'duration of input video',
pricePerRunRange: '$0.07',
displayPrice: '$0.07/Run'
},
KlingLipSyncTextToVideoNode: {
vendor: 'Unknown',
nodeName: 'Kling Lip Sync Video with Text',
pricingParams: 'duration of input video',
pricePerRunRange: '$0.07',
displayPrice: '$0.07/Run'
},
KlingSingleImageVideoEffectNode: {
vendor: 'Unknown',
nodeName: 'Kling Video Effects',
pricingParams: 'effect_scene',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
KlingStartEndFrameNode: {
vendor: 'Unknown',
nodeName: 'Kling Start-End Frame to Video',
pricingParams: 'Same as text to video',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
KlingTextToVideoNode: {
vendor: 'Unknown',
nodeName: 'Kling Text to Video',
pricingParams: 'model | duration | mode',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
KlingVideoExtendNode: {
vendor: 'Unknown',
nodeName: 'Kling Video Extend',
pricingParams: '-',
pricePerRunRange: '$0.28',
displayPrice: '$0.28/Run'
},
KlingVirtualTryOnNode: {
vendor: 'Unknown',
nodeName: 'Kling Virtual Try On',
pricingParams: '-',
pricePerRunRange: '$0.07',
displayPrice: '$0.07/Run'
},
LumaImageToVideoNode: {
vendor: 'Unknown',
nodeName: 'Luma Image to Video',
pricingParams: 'Same as Text to Video',
pricePerRunRange: 'dynamic',
rateDocumentation: 'https://lumalabs.ai/api/pricing',
displayPrice: 'Variable pricing'
},
LumaVideoNode: {
vendor: 'Unknown',
nodeName: 'Luma Text to Video',
pricingParams: 'model | resolution | duration',
pricePerRunRange: 'dynamic',
rateDocumentation: 'https://lumalabs.ai/api/pricing',
displayPrice: 'Variable pricing'
},
MinimaxImageToVideoNode: {
vendor: 'Unknown',
nodeName: 'MiniMax Image to Video',
pricingParams: '-',
pricePerRunRange: '$0.43',
rateDocumentation: 'https://www.minimax.io/price',
displayPrice: '$0.43/Run'
},
MinimaxTextToVideoNode: {
vendor: 'Unknown',
nodeName: 'MiniMax Text to Video',
pricingParams: '-',
pricePerRunRange: '$0.43',
rateDocumentation: 'https://www.minimax.io/price',
displayPrice: '$0.43/Run'
},
OpenAIDalle2: {
vendor: 'Unknown',
nodeName: 'dall-e-2',
pricingParams: 'size',
pricePerRunRange: 'dynamic',
rateDocumentation: 'https://platform.openai.com/docs/pricing',
displayPrice: 'Variable pricing'
},
OpenAIDalle3: {
vendor: 'Unknown',
nodeName: 'dall-e-3',
pricingParams: '1024×1024 | hd',
pricePerRunRange: '$0.08',
displayPrice: '$0.08/Run'
},
OpenAIGPTImage1: {
vendor: 'Unknown',
nodeName: 'gpt-image-1',
pricingParams: 'medium',
pricePerRunRange: '$[0.046 - 0.07]',
displayPrice: '$0.07/Run'
},
PikaImageToVideoNode2_2: {
vendor: 'Unknown',
nodeName: 'Pika Image to Video',
pricingParams: 'duration | resolution',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
PikaScenesV2_2: {
vendor: 'Unknown',
nodeName: 'Pika Scenes (Video Image Composition)',
pricingParams: 'duration | resolution',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
PikaStartEndFrameNode2_2: {
vendor: 'Unknown',
nodeName: 'Pika Start and End Frame to Video',
pricingParams: 'duration | resolution',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
PikaTextToVideoNode2_2: {
vendor: 'Unknown',
nodeName: 'Pika Text to Video',
pricingParams: 'duration | resolution',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
Pikadditions: {
vendor: 'Unknown',
nodeName: 'Pikadditions (Video Object Insertion)',
pricingParams: '-',
pricePerRunRange: '$0.3',
displayPrice: '$0.3/Run'
},
Pikaffects: {
vendor: 'Unknown',
nodeName: 'Pikaffects (Video Effects)',
pricingParams: '-',
pricePerRunRange: '0.45',
displayPrice: '$0.45/Run'
},
Pikaswaps: {
vendor: 'Unknown',
nodeName: 'Pika Swaps (Video Object Replacement)',
pricingParams: '-',
pricePerRunRange: '$0.3',
displayPrice: '$0.3/Run'
},
PixverseImageToVideoNode: {
vendor: 'Unknown',
nodeName: 'PixVerse Image to Video',
pricingParams: 'same as text to video',
pricePerRunRange: '$0.9',
displayPrice: '$0.9/Run'
},
PixverseTextToVideoNode: {
vendor: 'Unknown',
nodeName: 'PixVerse Text to Video',
pricingParams: 'duration | quality | motion_mode',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
PixverseTransitionVideoNode: {
vendor: 'Unknown',
nodeName: 'PixVerse Transition Video',
pricingParams: 'same as text to video',
pricePerRunRange: '$0.9',
displayPrice: '$0.9/Run'
},
RecraftCrispUpscaleNode: {
vendor: 'Unknown',
nodeName: 'Recraft Crisp Upscale Image',
pricingParams: '-',
pricePerRunRange: '$0.004',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$0.004/Run'
},
RecraftImageInpaintingNode: {
vendor: 'Unknown',
nodeName: 'Recraft Image Inpainting',
pricingParams: 'n',
pricePerRunRange: '$$0.04 x n',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$$0.04 x n/Run'
},
RecraftImageToImageNode: {
vendor: 'Unknown',
nodeName: 'Recraft Image to Image',
pricingParams: 'n',
pricePerRunRange: '$0.04 x n',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$0.04 x n/Run'
},
RecraftRemoveBackgroundNode: {
vendor: 'Unknown',
nodeName: 'Recraft Remove Background',
pricingParams: '-',
pricePerRunRange: '$0.01',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$0.01/Run'
},
RecraftReplaceBackgroundNode: {
vendor: 'Unknown',
nodeName: 'Recraft Replace Background',
pricingParams: 'n',
pricePerRunRange: '$0.04',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$0.04/Run'
},
RecraftTextToImageNode: {
vendor: 'Unknown',
nodeName: 'Recraft Text to Image',
pricingParams: 'model | n',
pricePerRunRange: '$0.04 x n',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$0.04 x n/Run'
},
RecraftTextToVectorNode: {
vendor: 'Unknown',
nodeName: 'Recraft Text to Vector',
pricingParams: 'model | n',
pricePerRunRange: '$0.08 x n',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$0.08 x n/Run'
},
RecraftVectorizeImageNode: {
vendor: 'Unknown',
nodeName: 'Recraft Vectorize Image',
pricingParams: '-',
pricePerRunRange: '$0.01',
rateDocumentation: 'https://www.recraft.ai/docs#pricing',
displayPrice: '$0.01/Run'
},
StabilityStableImageSD_3_5Node: {
vendor: 'Unknown',
nodeName: 'Stability AI Stable Diffusion 3.5 Image',
pricingParams: 'model',
pricePerRunRange: 'dynamic',
displayPrice: 'Variable pricing'
},
StabilityStableImageUltraNode: {
vendor: 'Unknown',
nodeName: 'Stability AI Stable Image Ultra',
pricingParams: '-',
pricePerRunRange: '$0.08',
displayPrice: '$0.08/Run'
},
StabilityUpscaleConservativeNode: {
vendor: 'Unknown',
nodeName: 'Stability AI Upscale Conservative',
pricingParams: '-',
pricePerRunRange: '$0.25',
displayPrice: '$0.25/Run'
},
StabilityUpscaleCreativeNode: {
vendor: 'Unknown',
nodeName: 'Stability AI Upscale Creative',
pricingParams: '-',
pricePerRunRange: '$0.25',
displayPrice: '$0.25/Run'
},
StabilityUpscaleFastNode: {
vendor: 'Unknown',
nodeName: 'Stability AI Upscale Fast',
pricingParams: '-',
pricePerRunRange: '$0.01',
displayPrice: '$0.01/Run'
},
VeoVideoGenerationNode: {
vendor: 'Unknown',
nodeName: 'Google Veo2 Video Generation',
pricingParams: '10s',
pricePerRunRange: '$5.0',
rateDocumentation:
'https://cloud.google.com/vertex-ai/generative-ai/pricing',
displayPrice: '$5.0/Run'
}
}
/**
* Get the display price for a node
* Returns a default value if the node isn't found
*/
export function getNodeDisplayPrice(
nodeName: string,
defaultPrice = '0.02/Run (approx)'
): string {
return apiNodeCosts[nodeName]?.displayPrice || defaultPrice
}

View File

@@ -13,6 +13,8 @@ import { useSettingStore } from '@/stores/settingStore'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
import { NodeBadgeMode } from '@/types/nodeSource'
import { useNodePricing } from './useNodePricing'
/**
* Add LGraphBadge to LGraphNode based on settings.
*
@@ -57,6 +59,8 @@ export const useNodeBadge = () => {
}
onMounted(() => {
const nodePricing = useNodePricing()
extensionStore.registerExtension({
name: 'Comfy.NodeBadge',
nodeCreated(node: LGraphNode) {
@@ -95,9 +99,12 @@ export const useNodeBadge = () => {
node.badges.push(() => badge.value)
if (node.constructor.nodeData?.api_node) {
// Get price from our mapping service
const price = nodePricing.getNodePriceDisplay(node)
const creditsBadge = computed(() => {
return new LGraphBadge({
text: '',
text: price ?? '',
iconOptions: {
unicode: '\ue96b',
fontFamily: 'PrimeIcons',
@@ -108,9 +115,7 @@ export const useNodeBadge = () => {
fgColor:
colorPaletteStore.completedActivePalette.colors.litegraph_base
.BADGE_FG_COLOR,
bgColor:
colorPaletteStore.completedActivePalette.colors.litegraph_base
.BADGE_BG_COLOR
bgColor: '#8D6932'
})
})

View File

@@ -0,0 +1,103 @@
import type { LGraphNode } from '@comfyorg/litegraph'
// Direct mapping of node names to prices
export const NODE_PRICES: Record<string, string> = {
// OpenAI models
OpenAIDalle2: '$0.02/Run',
OpenAIDalle3: '$0.08/Run',
OpenAIGPTImage1: '$0.07/Run',
// Ideogram models
IdeogramV1: '$0.06/Run',
IdeogramV2: '$0.08/Run',
IdeogramV3: 'Variable pricing',
// Minimax models
MinimaxTextToVideoNode: '$0.43/Run',
MinimaxImageToVideoNode: '$0.43/Run',
// Google Veo
VeoVideoGenerationNode: '$5.0/Run',
// Kling models
KlingTextToVideoNode: 'Variable pricing',
KlingImage2VideoNode: 'Variable pricing',
KlingCameraControlI2VNode: '$0.49/Run',
KlingCameraControlT2VNode: '$0.14/Run',
KlingStartEndFrameNode: 'Variable pricing',
KlingVideoExtendNode: '$0.28/Run',
KlingLipSyncAudioToVideoNode: '$0.07/Run',
KlingLipSyncTextToVideoNode: '$0.07/Run',
KlingVirtualTryOnNode: '$0.07/Run',
KlingImageGenerationNode: 'Variable pricing',
KlingSingleImageVideoEffectNode: 'Variable pricing',
KlingDualCharacterVideoEffectNode: 'Variable pricing',
// Flux Pro models
FluxProUltraImageNode: '$0.06/Run',
FluxProExpandNode: '$0.05/Run',
FluxProFillNode: '$0.05/Run',
FluxProCannyNode: '$0.05/Run',
FluxProDepthNode: '$0.05/Run',
// Luma models
LumaVideoNode: 'Variable pricing',
LumaImageToVideoNode: 'Variable pricing',
LumaImageNode: 'Variable pricing',
LumaImageModifyNode: 'Variable pricing',
// Recraft models
RecraftTextToImageNode: '$0.04/Run',
RecraftImageToImageNode: '$0.04/Run',
RecraftImageInpaintingNode: '$0.04/Run',
RecraftTextToVectorNode: '$0.08/Run',
RecraftVectorizeImageNode: '$0.01/Run',
RecraftRemoveBackgroundNode: '$0.01/Run',
RecraftReplaceBackgroundNode: '$0.04/Run',
RecraftCrispUpscaleNode: '$0.004/Run',
RecraftCreativeUpscaleNode: '$0.004/Run',
// Pixverse models
PixverseTextToVideoNode: '$0.9/Run',
PixverseImageToVideoNode: '$0.9/Run',
PixverseTransitionVideoNode: '$0.9/Run',
// Stability models
StabilityStableImageUltraNode: '$0.08/Run',
StabilityStableImageSD_3_5Node: 'Variable pricing',
StabilityUpscaleConservativeNode: '$0.25/Run',
StabilityUpscaleCreativeNode: '$0.25/Run',
StabilityUpscaleFastNode: '$0.01/Run',
// Pika models
PikaImageToVideoNode2_2: 'Variable pricing',
PikaTextToVideoNode2_2: 'Variable pricing',
PikaScenesV2_2: 'Variable pricing',
PikaStartEndFrameNode2_2: 'Variable pricing',
Pikadditions: '$0.3/Run',
Pikaswaps: '$0.3/Run',
Pikaffects: '$0.45/Run'
}
/**
* Simple utility function to get the price for a node
* Returns a formatted price string or default value if the node isn't found
*/
export function getNodePrice(
node: LGraphNode,
defaultPrice = '0.02/Run (approx)'
): string {
if (!node.constructor.nodeData?.api_node) {
return ''
}
return NODE_PRICES[node.constructor.name] || defaultPrice
}
/**
* Composable to get node pricing information for API nodes
*/
export const useNodePricing = () => {
/**
* Get the price display for a node
*/
const getNodePriceDisplay = (node: LGraphNode): string => {
if (!node.constructor.nodeData?.api_node) {
return ''
}
return NODE_PRICES[node.constructor.name] || '0.02/Run (approx)'
}
return {
getNodePriceDisplay
}
}

View File

@@ -0,0 +1,63 @@
const apiNodeNames = [
'IdeogramV1',
'IdeogramV2',
'IdeogramV3',
'MinimaxTextToVideoNode',
'MinimaxImageToVideoNode',
'VeoVideoGenerationNode',
'KlingCameraControls',
'KlingTextToVideoNode',
'KlingImage2VideoNode',
'KlingCameraControlI2VNode',
'KlingCameraControlT2VNode',
'KlingStartEndFrameNode',
'KlingVideoExtendNode',
'KlingLipSyncAudioToVideoNode',
'KlingLipSyncTextToVideoNode',
'KlingVirtualTryOnNode',
'KlingImageGenerationNode',
'KlingSingleImageVideoEffectNode',
'KlingDualCharacterVideoEffectNode',
'FluxProUltraImageNode',
'FluxProExpandNode',
'FluxProFillNode',
'FluxProCannyNode',
'FluxProDepthNode',
'LumaImageNode',
'LumaImageModifyNode',
'LumaVideoNode',
'LumaImageToVideoNode',
'LumaReferenceNode',
'LumaConceptsNode',
'RecraftTextToImageNode',
'RecraftImageToImageNode',
'RecraftImageInpaintingNode',
'RecraftTextToVectorNode',
'RecraftVectorizeImageNode',
'RecraftRemoveBackgroundNode',
'RecraftReplaceBackgroundNode',
'RecraftCrispUpscaleNode',
'RecraftCreativeUpscaleNode',
'RecraftStyleV3RealisticImage',
'RecraftStyleV3DigitalIllustration',
'RecraftStyleV3LogoRaster',
'RecraftStyleV3InfiniteStyleLibrary',
'RecraftColorRGB',
'RecraftControls',
'PixverseTextToVideoNode',
'PixverseImageToVideoNode',
'PixverseTransitionVideoNode',
'PixverseTemplateNode',
'StabilityStableImageUltraNode',
'StabilityStableImageSD_3_5Node',
'StabilityUpscaleConservativeNode',
'StabilityUpscaleCreativeNode',
'StabilityUpscaleFastNode',
'PikaImageToVideoNode2_2',
'PikaTextToVideoNode2_2',
'PikaScenesV2_2',
'Pikadditions',
'Pikaswaps',
'Pikaffects',
'PikaStartEndFrameNode2_2'
]

View File

@@ -2,3 +2,14 @@ export interface ApiNodeCost {
name: string
cost: number
}
export interface ApiNodeCostData {
vendor: string
nodeName: string
pricingParams: string
pricePerRunRange: string
displayPrice: string
rateDocumentation?: string
}
export type ApiNodeCostRecord = Record<string, ApiNodeCostData>