From 0e944babd649422b262fbc30ac788c364c115309 Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Wed, 31 Dec 2025 15:53:08 +0200 Subject: [PATCH 01/10] api nodes: price badges moved to nodes code --- comfy_api/latest/_io.py | 54 ++++++++++++++++++++- comfy_api_nodes/nodes_bfl.py | 44 +++++++++++++++++ comfy_api_nodes/nodes_bytedance.py | 66 ++++++++++++++++++++++++++ comfy_api_nodes/nodes_gemini.py | 32 +++++++++++++ comfy_api_nodes/nodes_ideogram.py | 42 +++++++++++++++-- comfy_api_nodes/nodes_ltxv.py | 17 +++++++ comfy_api_nodes/nodes_luma.py | 76 ++++++++++++++++++++++++++++++ 7 files changed, 326 insertions(+), 5 deletions(-) diff --git a/comfy_api/latest/_io.py b/comfy_api/latest/_io.py index 764fa8b2b..76d1cf4b5 100644 --- a/comfy_api/latest/_io.py +++ b/comfy_api/latest/_io.py @@ -1213,6 +1213,7 @@ class NodeInfoV1: deprecated: bool=None experimental: bool=None api_node: bool=None + price_badge: dict | None = None @dataclass class NodeInfoV3: @@ -1222,11 +1223,52 @@ class NodeInfoV3: name: str=None display_name: str=None description: str=None + python_module: Any = None category: str=None output_node: bool=None deprecated: bool=None experimental: bool=None api_node: bool=None + price_badge: dict | None = None + + +@dataclass +class PriceBadgeDepends: + widgets: list[str] = field(default_factory=list) + inputs: list[str] = field(default_factory=list) + + def validate(self) -> None: + if not isinstance(self.widgets, list) or any(not isinstance(x, str) for x in self.widgets): + raise ValueError("PriceBadgeDepends.widgets must be a list[str].") + if not isinstance(self.inputs, list) or any(not isinstance(x, str) for x in self.inputs): + raise ValueError("PriceBadgeDepends.inputs must be a list[str].") + + def as_dict(self) -> dict[str, Any]: + return { + "widgets": self.widgets, + "inputs": self.inputs, + } + + +@dataclass +class PriceBadge: + expr: str + depends_on: PriceBadgeDepends = field(default_factory=PriceBadgeDepends) + engine: str = field(default="jsonata") + + def validate(self) -> None: + if self.engine != "jsonata": + raise ValueError(f"Unsupported PriceBadge.engine '{self.engine}'. Only 'jsonata' is supported.") + if not isinstance(self.expr, str) or not self.expr.strip(): + raise ValueError("PriceBadge.expr must be a non-empty string.") + self.depends_on.validate() + + def as_dict(self) -> dict[str, Any]: + return { + "engine": self.engine, + "depends_on": self.depends_on.as_dict(), + "expr": self.expr, + } @dataclass @@ -1272,6 +1314,8 @@ class Schema: """Flags a node as experimental, informing users that it may change or not work as expected.""" is_api_node: bool=False """Flags a node as an API node. See: https://docs.comfy.org/tutorials/api-nodes/overview.""" + price_badge: PriceBadge | None = None + """Optional client-evaluated pricing badge declaration for this node.""" not_idempotent: bool=False """Flags a node as not idempotent; when True, the node will run and not reuse the cached outputs when identical inputs are provided on a different node in the graph.""" enable_expand: bool=False @@ -1302,6 +1346,8 @@ class Schema: input.validate() for output in self.outputs: output.validate() + if self.price_badge is not None: + self.price_badge.validate() def finalize(self): """Add hidden based on selected schema options, and give outputs without ids default ids.""" @@ -1375,7 +1421,8 @@ class Schema: deprecated=self.is_deprecated, experimental=self.is_experimental, api_node=self.is_api_node, - python_module=getattr(cls, "RELATIVE_PYTHON_MODULE", "nodes") + python_module=getattr(cls, "RELATIVE_PYTHON_MODULE", "nodes"), + price_badge=self.price_badge.as_dict() if self.price_badge is not None else None, ) return info @@ -1407,7 +1454,8 @@ class Schema: deprecated=self.is_deprecated, experimental=self.is_experimental, api_node=self.is_api_node, - python_module=getattr(cls, "RELATIVE_PYTHON_MODULE", "nodes") + python_module=getattr(cls, "RELATIVE_PYTHON_MODULE", "nodes"), + price_badge=self.price_badge.as_dict() if self.price_badge is not None else None, ) return info @@ -1958,4 +2006,6 @@ __all__ = [ "add_to_dict_v1", "add_to_dict_v3", "V3Data", + "PriceBadgeDepends", + "PriceBadge", ] diff --git a/comfy_api_nodes/nodes_bfl.py b/comfy_api_nodes/nodes_bfl.py index ce077d6b3..79c20d059 100644 --- a/comfy_api_nodes/nodes_bfl.py +++ b/comfy_api_nodes/nodes_bfl.py @@ -97,6 +97,9 @@ class FluxProUltraImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.06}""", + ), ) @classmethod @@ -352,6 +355,9 @@ class FluxProExpandNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.05}""", + ), ) @classmethod @@ -458,6 +464,9 @@ class FluxProFillNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.05}""", + ), ) @classmethod @@ -511,6 +520,21 @@ class Flux2ProImageNode(IO.ComfyNode): NODE_ID = "Flux2ProImageNode" DISPLAY_NAME = "Flux.2 [pro] Image" API_ENDPOINT = "/proxy/bfl/flux-2-pro/generate" + PRICE_BADGE_EXPR = """ + ( + $MP := 1024 * 1024; + $outMP := $max([1, $floor(((w.width.n * w.height.n) + $MP - 1) / $MP)]); + $outputCost := 0.03 + 0.015 * ($outMP - 1); + i.images.connected + ? { + "type":"range_usd", + "min_usd": $outputCost + 0.015, + "max_usd": $outputCost + 0.12, + "format": { "approximate": true } + } + : {"type":"usd","usd": $outputCost} + ) + """ @classmethod def define_schema(cls) -> IO.Schema: @@ -563,6 +587,10 @@ class Flux2ProImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["width", "height"], inputs=["images"]), + expr=cls.PRICE_BADGE_EXPR, + ), ) @classmethod @@ -623,6 +651,22 @@ class Flux2MaxImageNode(Flux2ProImageNode): NODE_ID = "Flux2MaxImageNode" DISPLAY_NAME = "Flux.2 [max] Image" API_ENDPOINT = "/proxy/bfl/flux-2-max/generate" + PRICE_BADGE_EXPR = """ + ( + $MP := 1024 * 1024; + $outMP := $max([1, $floor(((w.width.n * w.height.n) + $MP - 1) / $MP)]); + $outputCost := 0.07 + 0.03 * ($outMP - 1); + + i.images.connected + ? { + "type":"range_usd", + "min_usd": $outputCost + 0.03, + "max_usd": $outputCost + 0.24, + "format": { "approximate": true } + } + : {"type":"usd","usd": $outputCost} + ) + """ class BFLExtension(ComfyExtension): diff --git a/comfy_api_nodes/nodes_bytedance.py b/comfy_api_nodes/nodes_bytedance.py index d4a2cfae6..471ca8e8b 100644 --- a/comfy_api_nodes/nodes_bytedance.py +++ b/comfy_api_nodes/nodes_bytedance.py @@ -126,6 +126,9 @@ class ByteDanceImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.03}""", + ), ) @classmethod @@ -367,6 +370,19 @@ class ByteDanceSeedreamNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model"]), + expr=""" + ( + $price := $contains(w.model.s, "seedream-4-5-251128") ? 0.04 : 0.03; + { + "type":"usd", + "usd": $price, + "format": { "suffix":" x images/Run", "approximate": true } + } + ) + """, + ), ) @classmethod @@ -522,6 +538,7 @@ class ByteDanceTextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -632,6 +649,7 @@ class ByteDanceImageToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -754,6 +772,7 @@ class ByteDanceFirstLastFrameNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -877,6 +896,7 @@ class ByteDanceImageReferenceNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -946,6 +966,52 @@ def raise_if_text_params(prompt: str, text_params: list[str]) -> None: ) +PRICE_BADGE_VIDEO = IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model", "duration", "resolution"]), + expr=""" + ( + $priceByModel := { + "seedance-1-0-pro": { + "480p":[0.23,0.24], + "720p":[0.51,0.56], + "1080p":[1.18,1.22] + }, + "seedance-1-0-pro-fast": { + "480p":[0.09,0.1], + "720p":[0.21,0.23], + "1080p":[0.47,0.49] + }, + "seedance-1-0-lite": { + "480p":[0.17,0.18], + "720p":[0.37,0.41], + "1080p":[0.85,0.88] + } + }; + $model := w.model.s; + $modelKey := + $contains($model, "seedance-1-0-pro-fast") ? "seedance-1-0-pro-fast" : + $contains($model, "seedance-1-0-pro") ? "seedance-1-0-pro" : + "seedance-1-0-lite"; + $resolution := w.resolution.s; + $resKey := + $contains($resolution, "1080") ? "1080p" : + $contains($resolution, "720") ? "720p" : + "480p"; + $modelPrices := $lookup($priceByModel, $modelKey); + $baseRange := $lookup($modelPrices, $resKey); + $min10s := $baseRange[0]; + $max10s := $baseRange[1]; + $scale := w.duration.n / 10; + $minCost := $min10s * $scale; + $maxCost := $max10s * $scale; + ($minCost = $maxCost) + ? {"type":"usd","usd": $minCost} + : {"type":"range_usd","min_usd": $minCost, "max_usd": $maxCost} + ) + """, +) + + class ByteDanceExtension(ComfyExtension): @override async def get_node_list(self) -> list[type[IO.ComfyNode]]: diff --git a/comfy_api_nodes/nodes_gemini.py b/comfy_api_nodes/nodes_gemini.py index e8ed7e797..ddc2e868a 100644 --- a/comfy_api_nodes/nodes_gemini.py +++ b/comfy_api_nodes/nodes_gemini.py @@ -309,6 +309,22 @@ class GeminiNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model"]), + expr=""" + ( + $m := w.model.s; + + $contains($m, "gemini-2.5-flash") + ? {"type":"list_usd","usd":[0.0003,0.0025]} + : $contains($m, "gemini-2.5-pro") + ? {"type":"list_usd","usd":[0.00125,0.01]} + : $contains($m, "gemini-3-pro-preview") + ? {"type":"list_usd","usd":[0.002,0.012]} + : {"type":"text","text":"Token-based"} + ) + """, + ), ) @classmethod @@ -570,6 +586,9 @@ class GeminiImage(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.039,"format":{"suffix":"/Image (1K)","approximate":true}}""", + ), ) @classmethod @@ -700,6 +719,19 @@ class GeminiImage2(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["resolution"]), + expr=""" + ( + $r := w.resolution.s; + ($contains($r,"1k") or $contains($r,"2k")) + ? {"type":"usd","usd":0.134,"format":{"suffix":"/Image","approximate":true}} + : $contains($r,"4k") + ? {"type":"usd","usd":0.24,"format":{"suffix":"/Image","approximate":true}} + : {"type":"text","text":"Token-based"} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_ideogram.py b/comfy_api_nodes/nodes_ideogram.py index 48f94e612..b93a17755 100644 --- a/comfy_api_nodes/nodes_ideogram.py +++ b/comfy_api_nodes/nodes_ideogram.py @@ -236,7 +236,6 @@ class IdeogramV1(IO.ComfyNode): display_name="Ideogram V1", category="api node/image/Ideogram", description="Generates images using the Ideogram V1 model.", - is_api_node=True, inputs=[ IO.String.Input( "prompt", @@ -298,6 +297,17 @@ class IdeogramV1(IO.ComfyNode): IO.Hidden.api_key_comfy_org, IO.Hidden.unique_id, ], + is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), + expr=""" + ( + $n := w.num_images.n; + $base := (w.turbo.b = true) ? 0.0286 : 0.0858; + {"type":"usd","usd": $round($base * $n, 2)} + ) + """, + ), ) @classmethod @@ -351,7 +361,6 @@ class IdeogramV2(IO.ComfyNode): display_name="Ideogram V2", category="api node/image/Ideogram", description="Generates images using the Ideogram V2 model.", - is_api_node=True, inputs=[ IO.String.Input( "prompt", @@ -436,6 +445,17 @@ class IdeogramV2(IO.ComfyNode): IO.Hidden.api_key_comfy_org, IO.Hidden.unique_id, ], + is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), + expr=""" + ( + $n := w.num_images.n; + $base := (w.turbo.b = true) ? 0.0715 : 0.1144; + {"type":"usd","usd": $round($base * $n, 2)} + ) + """, + ), ) @classmethod @@ -506,7 +526,6 @@ class IdeogramV3(IO.ComfyNode): category="api node/image/Ideogram", description="Generates images using the Ideogram V3 model. " "Supports both regular image generation from text prompts and image editing with mask.", - is_api_node=True, inputs=[ IO.String.Input( "prompt", @@ -591,6 +610,23 @@ class IdeogramV3(IO.ComfyNode): IO.Hidden.api_key_comfy_org, IO.Hidden.unique_id, ], + is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["rendering_speed", "num_images"], inputs=["character_image"]), + expr=""" + ( + $n := w.num_images.n; + $speed := w.rendering_speed.s; + $hasChar := i.character_image.connected; + $base := + $contains($speed,"quality") ? ($hasChar ? 0.286 : 0.1287) : + $contains($speed,"default") ? ($hasChar ? 0.2145 : 0.0858) : + $contains($speed,"turbo") ? ($hasChar ? 0.143 : 0.0429) : + 0.0858; + {"type":"usd","usd": $round($base * $n, 2)} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_ltxv.py b/comfy_api_nodes/nodes_ltxv.py index 7e61560dc..397181bab 100644 --- a/comfy_api_nodes/nodes_ltxv.py +++ b/comfy_api_nodes/nodes_ltxv.py @@ -28,6 +28,21 @@ class ExecuteTaskRequest(BaseModel): image_uri: str | None = Field(None) +PRICE_BADGE = IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model", "duration", "resolution"]), + expr=""" + ( + $pps := { + "ltx-2 (pro)": {"1920x1080":0.06,"2560x1440":0.12,"3840x2160":0.24}, + "ltx-2 (fast)": {"1920x1080":0.04,"2560x1440":0.08,"3840x2160":0.16} + }[w.model.s][w.resolution.s]; + + {"type":"usd","usd": $pps * w.duration.n} + ) + """, +) + + class TextToVideoNode(IO.ComfyNode): @classmethod def define_schema(cls): @@ -69,6 +84,7 @@ class TextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE, ) @classmethod @@ -145,6 +161,7 @@ class ImageToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE, ) @classmethod diff --git a/comfy_api_nodes/nodes_luma.py b/comfy_api_nodes/nodes_luma.py index 894f2b08c..95401bc66 100644 --- a/comfy_api_nodes/nodes_luma.py +++ b/comfy_api_nodes/nodes_luma.py @@ -189,6 +189,19 @@ class LumaImageGenerationNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model"]), + expr=""" + ( + $m := w.model.s; + $contains($m,"photon-flash-1") + ? {"type":"usd","usd":0.0027} + : $contains($m,"photon-1") + ? {"type":"usd","usd":0.0104} + : {"type":"usd","usd":0.0246} + ) + """, + ), ) @classmethod @@ -303,6 +316,19 @@ class LumaImageModifyNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model"]), + expr=""" + ( + $m := w.model.s; + $contains($m,"photon-flash-1") + ? {"type":"usd","usd":0.0027} + : $contains($m,"photon-1") + ? {"type":"usd","usd":0.0104} + : {"type":"usd","usd":0.0246} + ) + """, + ), ) @classmethod @@ -395,6 +421,7 @@ class LumaTextToVideoGenerationNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -505,6 +532,8 @@ class LumaImageToVideoGenerationNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, + ) @classmethod @@ -568,6 +597,53 @@ class LumaImageToVideoGenerationNode(IO.ComfyNode): return LumaKeyframes(frame0=frame0, frame1=frame1) +PRICE_BADGE_VIDEO = IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model", "resolution", "duration"]), + expr=""" + ( + $p := { + "ray-flash-2": { + "5s": {"4k":3.13,"1080p":0.79,"720p":0.34,"540p":0.2}, + "9s": {"4k":5.65,"1080p":1.42,"720p":0.61,"540p":0.36} + }, + "ray-2": { + "5s": {"4k":9.11,"1080p":2.27,"720p":1.02,"540p":0.57}, + "9s": {"4k":16.4,"1080p":4.1,"720p":1.83,"540p":1.03} + } + }; + + $m := w.model.s; + $d := w.duration.s; + $r := w.resolution.s; + + $modelKey := + $contains($m,"ray-flash-2") ? "ray-flash-2" : + $contains($m,"ray-2") ? "ray-2" : + $contains($m,"ray-1-6") ? "ray-1-6" : + "other"; + + $durKey := $contains($d,"5s") ? "5s" : $contains($d,"9s") ? "9s" : ""; + $resKey := + $contains($r,"4k") ? "4k" : + $contains($r,"1080p") ? "1080p" : + $contains($r,"720p") ? "720p" : + $contains($r,"540p") ? "540p" : ""; + + $modelPrices := $lookup($p, $modelKey); + $durPrices := $lookup($modelPrices, $durKey); + $v := $lookup($durPrices, $resKey); + + $price := + ($modelKey = "ray-1-6") ? 0.5 : + ($modelKey = "other") ? 0.79 : + ($exists($v) ? $v : 0.79); + + {"type":"usd","usd": $price} + ) + """, +) + + class LumaExtension(ComfyExtension): @override async def get_node_list(self) -> list[type[IO.ComfyNode]]: From 93e148c548d991fa28ff9ab3867b1f83843f95b6 Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Thu, 1 Jan 2026 10:09:40 +0200 Subject: [PATCH 02/10] added price badges for 4 more node-packs --- comfy_api_nodes/nodes_minimax.py | 30 +++++++++++ comfy_api_nodes/nodes_moonvalley.py | 27 ++++++++++ comfy_api_nodes/nodes_openai.py | 80 +++++++++++++++++++++++++++++ comfy_api_nodes/nodes_pixverse.py | 43 ++++++++++++++++ 4 files changed, 180 insertions(+) diff --git a/comfy_api_nodes/nodes_minimax.py b/comfy_api_nodes/nodes_minimax.py index 05cbb700f..bb025112f 100644 --- a/comfy_api_nodes/nodes_minimax.py +++ b/comfy_api_nodes/nodes_minimax.py @@ -134,6 +134,9 @@ class MinimaxTextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.43}""", + ), ) @classmethod @@ -197,6 +200,9 @@ class MinimaxImageToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.43}""", + ), ) @classmethod @@ -340,6 +346,30 @@ class MinimaxHailuoVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["resolution", "duration"]), + expr=""" + ( + $r := w.resolution.s; + $d := w.duration.s; + + $price := + $contains($r,"768p") + ? ( + $contains($d,"6") ? 0.28 : + $contains($d,"10") ? 0.56 : + 0.43 + ) + : $contains($r,"1080p") + ? ( + $contains($d,"6") ? 0.49 : 0.43 + ) + : 0.43; + + {"type":"usd","usd": $price} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_moonvalley.py b/comfy_api_nodes/nodes_moonvalley.py index 2771e4790..23e64db29 100644 --- a/comfy_api_nodes/nodes_moonvalley.py +++ b/comfy_api_nodes/nodes_moonvalley.py @@ -233,6 +233,15 @@ class MoonvalleyImg2VideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["length"]), + expr=""" + ( + $len := w.length.s; + {"type":"usd","usd": ($len = "10s" ? 3.0 : 1.5)} + ) + """, + ), # TO-DO: This is 1:1 code from frontend, but this makes no sense as we don't have `length` widget ) @classmethod @@ -351,6 +360,15 @@ class MoonvalleyVideo2VideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["length"]), + expr=""" + ( + $len := w.length.s; + {"type":"usd","usd": ($len = "10s" ? 4.0 : 2.25)} + ) + """, + ), # TO-DO: This is 1:1 code from frontend, but this makes no sense as we don't have `length` widget ) @classmethod @@ -471,6 +489,15 @@ class MoonvalleyTxt2VideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["length"]), + expr=""" + ( + $len := w.length.s; + {"type":"usd","usd": ($len = "10s" ? 3.0 : 1.5)} + ) + """, + ), # TO-DO: This is 1:1 code from frontend, but this makes no sense as we don't have `length` widget ) @classmethod diff --git a/comfy_api_nodes/nodes_openai.py b/comfy_api_nodes/nodes_openai.py index a6205a34f..d2e674f68 100644 --- a/comfy_api_nodes/nodes_openai.py +++ b/comfy_api_nodes/nodes_openai.py @@ -160,6 +160,23 @@ class OpenAIDalle2(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["size", "n"]), + expr=""" + ( + $size := w.size.s; + $nRaw := w.n.n; + $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1; + + $base := + $contains($size, "256x256") ? 0.016 : + $contains($size, "512x512") ? 0.018 : + 0.02; + + {"type":"usd","usd": $round($base * $n, 3)} + ) + """, + ), ) @classmethod @@ -287,6 +304,25 @@ class OpenAIDalle3(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["size", "quality"]), + expr=""" + ( + $size := w.size.s; + $q := w.quality.s; + $hd := $contains($q, "hd"); + + $price := + $contains($size, "1024x1024") + ? ($hd ? 0.08 : 0.04) + : (($contains($size, "1792x1024") or $contains($size, "1024x1792")) + ? ($hd ? 0.12 : 0.08) + : 0.04); + + {"type":"usd","usd": $price} + ) + """, + ), ) @classmethod @@ -411,6 +447,28 @@ class OpenAIGPTImage1(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["quality", "n"]), + expr=""" + ( + $ranges := { + "low": [0.011, 0.02], + "medium": [0.046, 0.07], + "high": [0.167, 0.3] + }; + $range := $lookup($ranges, w.quality.s); + $n := w.n.n; + ($n = 1) + ? {"type":"range_usd","min_usd": $range[0], "max_usd": $range[1]} + : { + "type":"range_usd", + "min_usd": $range[0], + "max_usd": $range[1], + "format": { "suffix": " x " & $string($n) & "/Run" } + } + ) + """, + ), ) @classmethod @@ -566,6 +624,28 @@ class OpenAIChatNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model"]), + expr=""" + ( + $m := w.model.s; + + $contains($m,"o4-mini") ? {"type":"list_usd","usd":[0.0011,0.0044]} : + $contains($m,"o1-pro") ? {"type":"list_usd","usd":[0.15,0.6]} : + $contains($m,"o1") ? {"type":"list_usd","usd":[0.015,0.06]} : + $contains($m,"o3-mini") ? {"type":"list_usd","usd":[0.0011,0.0044]} : + $contains($m,"o3") ? {"type":"list_usd","usd":[0.01,0.04]} : + $contains($m,"gpt-4o") ? {"type":"list_usd","usd":[0.0025,0.01]} : + $contains($m,"gpt-4.1-nano") ? {"type":"list_usd","usd":[0.0001,0.0004]} : + $contains($m,"gpt-4.1-mini") ? {"type":"list_usd","usd":[0.0004,0.0016]} : + $contains($m,"gpt-4.1") ? {"type":"list_usd","usd":[0.002,0.008]} : + $contains($m,"gpt-5-nano") ? {"type":"list_usd","usd":[0.00005,0.0004]} : + $contains($m,"gpt-5-mini") ? {"type":"list_usd","usd":[0.00025,0.002]} : + $contains($m,"gpt-5") ? {"type":"list_usd","usd":[0.00125,0.01]} : + {"type":"text","text":"Token-based"} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_pixverse.py b/comfy_api_nodes/nodes_pixverse.py index 6e1686af0..ac95cf5c2 100644 --- a/comfy_api_nodes/nodes_pixverse.py +++ b/comfy_api_nodes/nodes_pixverse.py @@ -128,6 +128,7 @@ class PixverseTextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -242,6 +243,7 @@ class PixverseImageToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -355,6 +357,7 @@ class PixverseTransitionVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=PRICE_BADGE_VIDEO, ) @classmethod @@ -416,6 +419,46 @@ class PixverseTransitionVideoNode(IO.ComfyNode): return IO.NodeOutput(await download_url_to_video_output(response_poll.Resp.url)) +PRICE_BADGE_VIDEO = IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds", "quality", "motion_mode"]), + expr=""" + ( + $d := w.duration_seconds.s; + $q := w.quality.s; + $m := w.motion_mode.s; + + $price := + $contains($d,"5") + ? ( + $contains($q,"1080p") ? 1.2 : + ($contains($q,"720p") and $contains($m,"fast")) ? 1.2 : + ($contains($q,"720p") and $contains($m,"normal")) ? 0.6 : + ($contains($q,"540p") and $contains($m,"fast")) ? 0.9 : + ($contains($q,"540p") and $contains($m,"normal")) ? 0.45 : + ($contains($q,"360p") and $contains($m,"fast")) ? 0.9 : + ($contains($q,"360p") and $contains($m,"normal")) ? 0.45 : + 0.9 + ) + : $contains($d,"8") + ? ( + ($contains($q,"540p") and $contains($m,"normal")) ? 0.9 : + ($contains($q,"540p") and $contains($m,"fast")) ? 1.2 : + ($contains($q,"360p") and $contains($m,"normal")) ? 0.9 : + ($contains($q,"360p") and $contains($m,"fast")) ? 1.2 : + ($contains($q,"1080p") and $contains($m,"normal")) ? 1.2 : + ($contains($q,"1080p") and $contains($m,"fast")) ? 1.2 : + ($contains($q,"720p") and $contains($m,"normal")) ? 1.2 : + ($contains($q,"720p") and $contains($m,"fast")) ? 1.2 : + 0.9 + ) + : 0.9; + + {"type":"usd","usd": $price} + ) + """, +) + + class PixVerseExtension(ComfyExtension): @override async def get_node_list(self) -> list[type[IO.ComfyNode]]: From 1812f5c7f7e64b2211d8db34bb727ea548ac46f2 Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Thu, 1 Jan 2026 18:22:15 +0200 Subject: [PATCH 03/10] added price badges for 10 more node-packs --- comfy_api_nodes/nodes_kling.py | 184 +++++++++++++++++++++++++++++ comfy_api_nodes/nodes_recraft.py | 32 +++++ comfy_api_nodes/nodes_rodin.py | 12 ++ comfy_api_nodes/nodes_runway.py | 15 +++ comfy_api_nodes/nodes_sora.py | 18 +++ comfy_api_nodes/nodes_stability.py | 31 +++++ comfy_api_nodes/nodes_tripo.py | 166 +++++++++++++++++++++++++- comfy_api_nodes/nodes_veo2.py | 42 +++++++ comfy_api_nodes/nodes_vidu.py | 12 ++ comfy_api_nodes/nodes_wan.py | 27 +++++ 10 files changed, 538 insertions(+), 1 deletion(-) diff --git a/comfy_api_nodes/nodes_kling.py b/comfy_api_nodes/nodes_kling.py index 9c707a339..80499d6e4 100644 --- a/comfy_api_nodes/nodes_kling.py +++ b/comfy_api_nodes/nodes_kling.py @@ -764,6 +764,33 @@ class KlingTextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["mode"]), + expr=""" + ( + $m := w.mode.s; + $contains($m,"v2-5-turbo") + ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) + : $contains($m,"v2-1-master") + ? ($contains($m,"10s") ? {"type":"usd","usd":2.8} : {"type":"usd","usd":1.4}) + : $contains($m,"v2-master") + ? ($contains($m,"10s") ? {"type":"usd","usd":2.8} : {"type":"usd","usd":1.4}) + : $contains($m,"v1-6") + ? ( + $contains($m,"pro") + ? ($contains($m,"10s") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($m,"10s") ? {"type":"usd","usd":0.56} : {"type":"usd","usd":0.28}) + ) + : $contains($m,"v1") + ? ( + $contains($m,"pro") + ? ($contains($m,"10s") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($m,"10s") ? {"type":"usd","usd":0.28} : {"type":"usd","usd":0.14}) + ) + : {"type":"usd","usd":0.14} + ) + """, + ), ) @classmethod @@ -818,6 +845,10 @@ class OmniProTextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration"]), + expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + ), ) @classmethod @@ -886,6 +917,10 @@ class OmniProFirstLastFrameNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration"]), + expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + ), ) @classmethod @@ -981,6 +1016,10 @@ class OmniProImageToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration"]), + expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + ), ) @classmethod @@ -1056,6 +1095,10 @@ class OmniProVideoToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration"]), + expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + ), ) @classmethod @@ -1142,6 +1185,9 @@ class OmniProEditVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.168,"format":{"suffix":"/second"}}""", + ), ) @classmethod @@ -1228,6 +1274,9 @@ class OmniProImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.028}""", + ), ) @classmethod @@ -1313,6 +1362,9 @@ class KlingCameraControlT2VNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.14}""", + ), ) @classmethod @@ -1375,6 +1427,33 @@ class KlingImage2VideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]), + expr=""" + ( + $mode := w.mode.s; + $model := w.model_name.s; + $dur := w.duration.s; + $contains($model,"v2-5-turbo") + ? ($contains($dur,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) + : ($contains($model,"v2-1-master") or $contains($model,"v2-master")) + ? ($contains($dur,"10") ? {"type":"usd","usd":2.8} : {"type":"usd","usd":1.4}) + : ($contains($model,"v2-1") or $contains($model,"v1-6") or $contains($model,"v1-5")) + ? ( + $contains($mode,"pro") + ? ($contains($dur,"10") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($dur,"10") ? {"type":"usd","usd":0.56} : {"type":"usd","usd":0.28}) + ) + : $contains($model,"v1") + ? ( + $contains($mode,"pro") + ? ($contains($dur,"10") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($dur,"10") ? {"type":"usd","usd":0.28} : {"type":"usd","usd":0.14}) + ) + : {"type":"usd","usd":0.14} + ) + """, + ), ) @classmethod @@ -1448,6 +1527,9 @@ class KlingCameraControlI2VNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.49}""", + ), ) @classmethod @@ -1518,6 +1600,33 @@ class KlingStartEndFrameNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["mode"]), + expr=""" + ( + $m := w.mode.s; + $contains($m,"v2-5-turbo") + ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) + : $contains($m,"v2-1") + ? ($contains($m,"10s") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : $contains($m,"v2-master") + ? ($contains($m,"10s") ? {"type":"usd","usd":2.8} : {"type":"usd","usd":1.4}) + : $contains($m,"v1-6") + ? ( + $contains($m,"pro") + ? ($contains($m,"10s") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($m,"10s") ? {"type":"usd","usd":0.56} : {"type":"usd","usd":0.28}) + ) + : $contains($m,"v1") + ? ( + $contains($m,"pro") + ? ($contains($m,"10s") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($m,"10s") ? {"type":"usd","usd":0.28} : {"type":"usd","usd":0.14}) + ) + : {"type":"usd","usd":0.14} + ) + """, + ), ) @classmethod @@ -1583,6 +1692,9 @@ class KlingVideoExtendNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.28}""", + ), ) @classmethod @@ -1664,6 +1776,29 @@ class KlingDualCharacterVideoEffectNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]), + expr=""" + ( + $mode := w.mode.s; + $model := w.model_name.s; + $dur := w.duration.s; + ($contains($model,"v1-6") or $contains($model,"v1-5")) + ? ( + $contains($mode,"pro") + ? ($contains($dur,"10") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($dur,"10") ? {"type":"usd","usd":0.56} : {"type":"usd","usd":0.28}) + ) + : $contains($model,"v1") + ? ( + $contains($mode,"pro") + ? ($contains($dur,"10") ? {"type":"usd","usd":0.98} : {"type":"usd","usd":0.49}) + : ($contains($dur,"10") ? {"type":"usd","usd":0.28} : {"type":"usd","usd":0.14}) + ) + : {"type":"usd","usd":0.14} + ) + """, + ), ) @classmethod @@ -1728,6 +1863,16 @@ class KlingSingleImageVideoEffectNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["effect_scene"]), + expr=""" + ( + ($contains(w.effect_scene.s,"dizzydizzy") or $contains(w.effect_scene.s,"bloombloom")) + ? {"type":"usd","usd":0.49} + : {"type":"usd","usd":0.28} + ) + """, + ), ) @classmethod @@ -1782,6 +1927,9 @@ class KlingLipSyncAudioToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.1,"format":{"approximate":true}}""", + ), ) @classmethod @@ -1842,6 +1990,9 @@ class KlingLipSyncTextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.1,"format":{"approximate":true}}""", + ), ) @classmethod @@ -1892,6 +2043,9 @@ class KlingVirtualTryOnNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.7}""", + ), ) @classmethod @@ -1991,6 +2145,19 @@ class KlingImageGenerationNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model_name", "n"], inputs=["image"]), + expr=""" + ( + $m := w.model_name.s; + $base := + $contains($m,"kling-v1-5") + ? (i.image.connected ? 0.028 : 0.014) + : ($contains($m,"kling-v1") ? 0.0035 : 0.014); + {"type":"usd","usd": $base * w.n.n} + ) + """, + ), ) @classmethod @@ -2074,6 +2241,10 @@ class TextToVideoWithAudio(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), + expr="""{"type":"usd","usd": 0.07 * w.duration.n * (w.generate_audio.b ? 2 : 1)}""", + ), ) @classmethod @@ -2138,6 +2309,10 @@ class ImageToVideoWithAudio(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), + expr="""{"type":"usd","usd": 0.07 * w.duration.n * (w.generate_audio.b ? 2 : 1)}""", + ), ) @classmethod @@ -2218,6 +2393,15 @@ class MotionControl(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["mode"]), + expr=""" + ( + $prices := {"std": 0.07, "pro": 0.112}; + {"type":"usd","usd": $lookup($prices, w.mode.s), "format":{"suffix":"/second"}} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_recraft.py b/comfy_api_nodes/nodes_recraft.py index e3440b946..977819d5e 100644 --- a/comfy_api_nodes/nodes_recraft.py +++ b/comfy_api_nodes/nodes_recraft.py @@ -378,6 +378,10 @@ class RecraftTextToImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["n"]), + expr="""{"type":"usd","usd": $round(0.04 * w.n.n, 2)}""", + ), ) @classmethod @@ -490,6 +494,10 @@ class RecraftImageToImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["n"]), + expr="""{"type":"usd","usd": $round(0.04 * w.n.n, 2)}""", + ), ) @classmethod @@ -591,6 +599,10 @@ class RecraftImageInpaintingNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["n"]), + expr="""{"type":"usd","usd": $round(0.04 * w.n.n, 2)}""", + ), ) @classmethod @@ -692,6 +704,10 @@ class RecraftTextToVectorNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["n"]), + expr="""{"type":"usd","usd": $round(0.08 * w.n.n, 2)}""", + ), ) @classmethod @@ -759,6 +775,10 @@ class RecraftVectorizeImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["n"]), + expr="""{"type":"usd","usd": $round(0.01 * w.n.n, 2)}""", + ), ) @classmethod @@ -817,6 +837,9 @@ class RecraftReplaceBackgroundNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.04}""", + ), ) @classmethod @@ -883,6 +906,9 @@ class RecraftRemoveBackgroundNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.01}""", + ), ) @classmethod @@ -929,6 +955,9 @@ class RecraftCrispUpscaleNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.04}""", + ), ) @classmethod @@ -972,6 +1001,9 @@ class RecraftCreativeUpscaleNode(RecraftCrispUpscaleNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.25}""", + ), ) diff --git a/comfy_api_nodes/nodes_rodin.py b/comfy_api_nodes/nodes_rodin.py index e60e7a6d6..b4420cb93 100644 --- a/comfy_api_nodes/nodes_rodin.py +++ b/comfy_api_nodes/nodes_rodin.py @@ -241,6 +241,9 @@ class Rodin3D_Regular(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod @@ -294,6 +297,9 @@ class Rodin3D_Detail(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod @@ -347,6 +353,9 @@ class Rodin3D_Smooth(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod @@ -406,6 +415,9 @@ class Rodin3D_Sketch(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_runway.py b/comfy_api_nodes/nodes_runway.py index 3c55039c9..f66901e80 100644 --- a/comfy_api_nodes/nodes_runway.py +++ b/comfy_api_nodes/nodes_runway.py @@ -184,6 +184,10 @@ class RunwayImageToVideoNodeGen3a(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration"]), + expr="""{"type":"usd","usd": 0.0715 * w.duration.n}""", + ), ) @classmethod @@ -274,6 +278,10 @@ class RunwayImageToVideoNodeGen4(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration"]), + expr="""{"type":"usd","usd": 0.0715 * w.duration.n}""", + ), ) @classmethod @@ -372,6 +380,10 @@ class RunwayFirstLastFrameNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration"]), + expr="""{"type":"usd","usd": 0.0715 * w.duration.n}""", + ), ) @classmethod @@ -457,6 +469,9 @@ class RunwayTextToImageNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.11}""", + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_sora.py b/comfy_api_nodes/nodes_sora.py index 92b225d40..d988b401b 100644 --- a/comfy_api_nodes/nodes_sora.py +++ b/comfy_api_nodes/nodes_sora.py @@ -89,6 +89,24 @@ class OpenAIVideoSora2(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model", "size", "duration"]), + expr=""" + ( + $m := w.model.s; + $size := w.size.s; + $dur := w.duration.n; + $isPro := $contains($m, "sora-2-pro"); + $isSora2 := $contains($m, "sora-2"); + $isProSize := ($size = "1024x1792" or $size = "1792x1024"); + $perSec := + $isPro ? ($isProSize ? 0.5 : 0.3) : + $isSora2 ? 0.1 : + ($isProSize ? 0.5 : 0.1); + {"type":"usd","usd": $round($perSec * $dur, 2)} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_stability.py b/comfy_api_nodes/nodes_stability.py index bb7ceed78..fdcd27dd1 100644 --- a/comfy_api_nodes/nodes_stability.py +++ b/comfy_api_nodes/nodes_stability.py @@ -127,6 +127,9 @@ class StabilityStableImageUltraNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.08}""", + ), ) @classmethod @@ -264,6 +267,16 @@ class StabilityStableImageSD_3_5Node(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model"]), + expr=""" + ( + $contains(w.model.s,"large") + ? {"type":"usd","usd":0.065} + : {"type":"usd","usd":0.035} + ) + """, + ), ) @classmethod @@ -382,6 +395,9 @@ class StabilityUpscaleConservativeNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.25}""", + ), ) @classmethod @@ -486,6 +502,9 @@ class StabilityUpscaleCreativeNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.25}""", + ), ) @classmethod @@ -566,6 +585,9 @@ class StabilityUpscaleFastNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.01}""", + ), ) @classmethod @@ -648,6 +670,9 @@ class StabilityTextToAudio(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.2}""", + ), ) @classmethod @@ -732,6 +757,9 @@ class StabilityAudioToAudio(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.2}""", + ), ) @classmethod @@ -828,6 +856,9 @@ class StabilityAudioInpaint(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.2}""", + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_tripo.py b/comfy_api_nodes/nodes_tripo.py index e72f8e96a..0bbb98fb3 100644 --- a/comfy_api_nodes/nodes_tripo.py +++ b/comfy_api_nodes/nodes_tripo.py @@ -78,7 +78,7 @@ async def poll_until_finished( raise RuntimeError(f"Failed to generate mesh: {response_poll}") -class TripoTextToModelNode(IO.ComfyNode): +class TripoTextToModelNode(IO.ComfyNode): """ Generates 3D models synchronously based on a text prompt using Tripo's API. """ @@ -117,6 +117,38 @@ class TripoTextToModelNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends( + widgets=[ + "model_version", + "style", + "texture", + "pbr", + "quad", + "texture_quality", + "geometry_quality", + ], + ), + expr=""" + ( + $isV14 := $contains(w.model_version.s,"v1.4"); + $style := w.style.s; + $hasStyle := ($style != "" and $style != "none"); + $withTexture := w.texture.b or w.pbr.b; + $isHdTexture := (w.texture_quality.s = "detailed"); + $isDetailedGeometry := (w.geometry_quality.s = "detailed"); + $baseCredits := + $isV14 ? 20 : ($withTexture ? 20 : 10); + $credits := + $baseCredits + + ($hasStyle ? 5 : 0) + + (w.quad.b ? 5 : 0) + + ($isHdTexture ? 10 : 0) + + ($isDetailedGeometry ? 20 : 0); + {"type":"usd","usd": $round($credits * 0.01, 2)} + ) + """, + ), ) @classmethod @@ -210,6 +242,38 @@ class TripoImageToModelNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends( + widgets=[ + "model_version", + "style", + "texture", + "pbr", + "quad", + "texture_quality", + "geometry_quality", + ], + ), + expr=""" + ( + $isV14 := $contains(w.model_version.s,"v1.4"); + $style := w.style.s; + $hasStyle := ($style != "" and $style != "none"); + $withTexture := w.texture.b or w.pbr.b; + $isHdTexture := (w.texture_quality.s = "detailed"); + $isDetailedGeometry := (w.geometry_quality.s = "detailed"); + $baseCredits := + $isV14 ? 30 : ($withTexture ? 30 : 20); + $credits := + $baseCredits + + ($hasStyle ? 5 : 0) + + (w.quad.b ? 5 : 0) + + ($isHdTexture ? 10 : 0) + + ($isDetailedGeometry ? 20 : 0); + {"type":"usd","usd": $round($credits * 0.01, 2)} + ) + """, + ), ) @classmethod @@ -314,6 +378,34 @@ class TripoMultiviewToModelNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends( + widgets=[ + "model_version", + "texture", + "pbr", + "quad", + "texture_quality", + "geometry_quality", + ], + ), + expr=""" + ( + $isV14 := $contains(w.model_version.s,"v1.4"); + $withTexture := w.texture.b or w.pbr.b; + $isHdTexture := (w.texture_quality.s = "detailed"); + $isDetailedGeometry := (w.geometry_quality.s = "detailed"); + $baseCredits := + $isV14 ? 30 : ($withTexture ? 30 : 20); + $credits := + $baseCredits + + (w.quad.b ? 5 : 0) + + ($isHdTexture ? 10 : 0) + + ($isDetailedGeometry ? 20 : 0); + {"type":"usd","usd": $round($credits * 0.01, 2)} + ) + """, + ), ) @classmethod @@ -405,6 +497,15 @@ class TripoTextureNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["texture_quality"]), + expr=""" + ( + $tq := w.texture_quality.s; + {"type":"usd","usd": ($contains($tq,"detailed") ? 0.2 : 0.1)} + ) + """, + ), ) @classmethod @@ -456,6 +557,9 @@ class TripoRefineNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.3}""", + ), ) @classmethod @@ -489,6 +593,9 @@ class TripoRigNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.25}""", + ), ) @classmethod @@ -545,6 +652,9 @@ class TripoRetargetNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.1}""", + ), ) @classmethod @@ -638,6 +748,60 @@ class TripoConversionNode(IO.ComfyNode): ], is_api_node=True, is_output_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends( + widgets=[ + "quad", + "face_limit", + "texture_size", + "texture_format", + "force_symmetry", + "flatten_bottom", + "flatten_bottom_threshold", + "pivot_to_center_bottom", + "scale_factor", + "with_animation", + "pack_uv", + "bake", + "part_names", + "fbx_preset", + "export_vertex_colors", + "export_orientation", + "animate_in_place", + ], + ), + expr=""" + ( + $face := (w.face_limit.n != null) ? w.face_limit.n : -1; + $texSize := (w.texture_size.n != null) ? w.texture_size.n : 4096; + $flatThresh := (w.flatten_bottom_threshold.n != null) ? w.flatten_bottom_threshold.n : 0; + $scale := (w.scale_factor.n != null) ? w.scale_factor.n : 1; + $texFmt := (w.texture_format.s != "" ? w.texture_format.s : "jpeg"); + $part := w.part_names.s; + $fbx := (w.fbx_preset.s != "" ? w.fbx_preset.s : "blender"); + $orient := (w.export_orientation.s != "" ? w.export_orientation.s : "default"); + $advanced := + w.quad.b or + w.force_symmetry.b or + w.flatten_bottom.b or + w.pivot_to_center_bottom.b or + w.with_animation.b or + w.pack_uv.b or + w.bake.b or + w.export_vertex_colors.b or + w.animate_in_place.b or + ($face != -1) or + ($texSize != 4096) or + ($flatThresh != 0) or + ($scale != 1) or + ($texFmt != "jpeg") or + ($part != "") or + ($fbx != "blender") or + ($orient != "default"); + {"type":"usd","usd": ($advanced ? 0.1 : 0.05)} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_veo2.py b/comfy_api_nodes/nodes_veo2.py index 13a6bfd91..6a726e6f2 100644 --- a/comfy_api_nodes/nodes_veo2.py +++ b/comfy_api_nodes/nodes_veo2.py @@ -122,6 +122,10 @@ class VeoVideoGenerationNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds"]), + expr="""{"type":"usd","usd": 0.5 * w.duration_seconds.n}""", + ), ) @classmethod @@ -347,6 +351,20 @@ class Veo3VideoGenerationNode(VeoVideoGenerationNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model", "generate_audio"]), + expr=""" + ( + $m := w.model.s; + $a := w.generate_audio.b; + ($contains($m,"veo-3.0-fast-generate-001") or $contains($m,"veo-3.1-fast-generate")) + ? {"type":"usd","usd": ($a ? 1.2 : 0.8)} + : ($contains($m,"veo-3.0-generate-001") or $contains($m,"veo-3.1-generate")) + ? {"type":"usd","usd": ($a ? 3.2 : 1.6)} + : {"type":"range_usd","min_usd":0.8,"max_usd":3.2} + ) + """, + ), ) @@ -420,6 +438,30 @@ class Veo3FirstLastFrameNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["model", "generate_audio", "duration"]), + expr=""" + ( + $prices := { + "veo-3.1-fast-generate": { "audio": 0.15, "no_audio": 0.10 }, + "veo-3.1-generate": { "audio": 0.40, "no_audio": 0.20 } + }; + $m := w.model.s; + $ga := (w.generate_audio.s = "true"); + $seconds := w.duration.n; + $modelKey := + $contains($m, "veo-3.1-fast-generate") ? "veo-3.1-fast-generate" : + $contains($m, "veo-3.1-generate") ? "veo-3.1-generate" : + ""; + $audioKey := $ga ? "audio" : "no_audio"; + $modelPrices := $lookup($prices, $modelKey); + $pps := $lookup($modelPrices, $audioKey); + ($pps != null) + ? {"type":"usd","usd": $pps * $seconds} + : {"type":"range_usd","min_usd": 0.4, "max_usd": 3.2} + ) + """, + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_vidu.py b/comfy_api_nodes/nodes_vidu.py index 7a679f0d9..2f4c37042 100644 --- a/comfy_api_nodes/nodes_vidu.py +++ b/comfy_api_nodes/nodes_vidu.py @@ -192,6 +192,9 @@ class ViduTextToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod @@ -292,6 +295,9 @@ class ViduImageToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod @@ -403,6 +409,9 @@ class ViduReferenceVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod @@ -519,6 +528,9 @@ class ViduStartEndToVideoNode(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.4}""", + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_wan.py b/comfy_api_nodes/nodes_wan.py index 3e04786a9..f47da2ce1 100644 --- a/comfy_api_nodes/nodes_wan.py +++ b/comfy_api_nodes/nodes_wan.py @@ -244,6 +244,9 @@ class WanTextToImageApi(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.03}""", + ), ) @classmethod @@ -363,6 +366,9 @@ class WanImageToImageApi(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + expr="""{"type":"usd","usd":0.03}""", + ), ) @classmethod @@ -520,6 +526,17 @@ class WanTextToVideoApi(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration", "size"]), + expr=""" + ( + $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; + $resKey := $substringBefore(w.size.s, ":"); + $pps := $lookup($ppsTable, $resKey); + { "type": "usd", "usd": $round($pps * w.duration.n, 2) } + ) + """, + ), ) @classmethod @@ -681,6 +698,16 @@ class WanImageToVideoApi(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), + expr=""" + ( + $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; + $pps := $lookup($ppsTable, w.resolution.s); + { "type": "usd", "usd": $round($pps * w.duration.n, 2) } + ) + """, + ), ) @classmethod From 9f41406c3fc72ac00f8a3124fb71d87401defb11 Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Sun, 4 Jan 2026 11:48:06 +0200 Subject: [PATCH 04/10] added new price badges for Omni STD mode --- comfy_api_nodes/nodes_kling.py | 49 +++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/comfy_api_nodes/nodes_kling.py b/comfy_api_nodes/nodes_kling.py index 80499d6e4..fd724dc7f 100644 --- a/comfy_api_nodes/nodes_kling.py +++ b/comfy_api_nodes/nodes_kling.py @@ -846,8 +846,14 @@ class OmniProTextToVideoNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), + expr=""" + ( + $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $rates := {"std": 0.084, "pro": 0.112}; + {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + ) + """, ), ) @@ -918,8 +924,14 @@ class OmniProFirstLastFrameNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), + expr=""" + ( + $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $rates := {"std": 0.084, "pro": 0.112}; + {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + ) + """, ), ) @@ -1017,8 +1029,14 @@ class OmniProImageToVideoNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), + expr=""" + ( + $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $rates := {"std": 0.084, "pro": 0.112}; + {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + ) + """, ), ) @@ -1096,8 +1114,14 @@ class OmniProVideoToVideoNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.112 * w.duration.n}""", + depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), + expr=""" + ( + $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $rates := {"std": 0.126, "pro": 0.168}; + {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + ) + """, ), ) @@ -1186,7 +1210,14 @@ class OmniProEditVideoNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - expr="""{"type":"usd","usd":0.168,"format":{"suffix":"/second"}}""", + depends_on=IO.PriceBadgeDepends(widgets=["resolution"]), + expr=""" + ( + $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $rates := {"std": 0.126, "pro": 0.168}; + {"type":"usd","usd": $lookup($rates, $mode), "format":{"suffix":"/second"}} + ) + """, ), ) From 5361640267f86b4d1060c51e71f1a24668a0694c Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Sun, 4 Jan 2026 13:23:43 +0200 Subject: [PATCH 05/10] add support for autogrow groups --- comfy_api/latest/_io.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/comfy_api/latest/_io.py b/comfy_api/latest/_io.py index 76d1cf4b5..bbd36d7e2 100644 --- a/comfy_api/latest/_io.py +++ b/comfy_api/latest/_io.py @@ -1236,17 +1236,21 @@ class NodeInfoV3: class PriceBadgeDepends: widgets: list[str] = field(default_factory=list) inputs: list[str] = field(default_factory=list) + input_groups: list[str] = field(default_factory=list) def validate(self) -> None: if not isinstance(self.widgets, list) or any(not isinstance(x, str) for x in self.widgets): raise ValueError("PriceBadgeDepends.widgets must be a list[str].") if not isinstance(self.inputs, list) or any(not isinstance(x, str) for x in self.inputs): raise ValueError("PriceBadgeDepends.inputs must be a list[str].") + if not isinstance(self.input_groups, list) or any(not isinstance(x, str) for x in self.input_groups): + raise ValueError("PriceBadgeDepends.input_groups must be a list[str].") def as_dict(self) -> dict[str, Any]: return { "widgets": self.widgets, "inputs": self.inputs, + "input_groups": self.input_groups, } From dffc081bc829da417b859fdb5e5cf9defabc7e2b Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Tue, 6 Jan 2026 15:49:28 +0200 Subject: [PATCH 06/10] use full names for "widgets", "inputs" and "groups" --- comfy_api_nodes/nodes_bfl.py | 8 ++-- comfy_api_nodes/nodes_bytedance.py | 8 ++-- comfy_api_nodes/nodes_gemini.py | 4 +- comfy_api_nodes/nodes_ideogram.py | 14 +++--- comfy_api_nodes/nodes_kling.py | 48 +++++++++---------- comfy_api_nodes/nodes_ltxv.py | 4 +- comfy_api_nodes/nodes_luma.py | 10 ++-- comfy_api_nodes/nodes_minimax.py | 4 +- comfy_api_nodes/nodes_moonvalley.py | 6 +-- comfy_api_nodes/nodes_openai.py | 14 +++--- comfy_api_nodes/nodes_pixverse.py | 6 +-- comfy_api_nodes/nodes_recraft.py | 10 ++-- comfy_api_nodes/nodes_runway.py | 6 +-- comfy_api_nodes/nodes_sora.py | 6 +-- comfy_api_nodes/nodes_stability.py | 2 +- comfy_api_nodes/nodes_tripo.py | 72 ++++++++++++++--------------- comfy_api_nodes/nodes_veo2.py | 12 ++--- comfy_api_nodes/nodes_wan.py | 8 ++-- 18 files changed, 121 insertions(+), 121 deletions(-) diff --git a/comfy_api_nodes/nodes_bfl.py b/comfy_api_nodes/nodes_bfl.py index 79c20d059..c67076dd6 100644 --- a/comfy_api_nodes/nodes_bfl.py +++ b/comfy_api_nodes/nodes_bfl.py @@ -523,9 +523,9 @@ class Flux2ProImageNode(IO.ComfyNode): PRICE_BADGE_EXPR = """ ( $MP := 1024 * 1024; - $outMP := $max([1, $floor(((w.width.n * w.height.n) + $MP - 1) / $MP)]); + $outMP := $max([1, $floor(((widgets.width.n * widgets.height.n) + $MP - 1) / $MP)]); $outputCost := 0.03 + 0.015 * ($outMP - 1); - i.images.connected + inputs.images.connected ? { "type":"range_usd", "min_usd": $outputCost + 0.015, @@ -654,10 +654,10 @@ class Flux2MaxImageNode(Flux2ProImageNode): PRICE_BADGE_EXPR = """ ( $MP := 1024 * 1024; - $outMP := $max([1, $floor(((w.width.n * w.height.n) + $MP - 1) / $MP)]); + $outMP := $max([1, $floor(((widgets.width.n * widgets.height.n) + $MP - 1) / $MP)]); $outputCost := 0.07 + 0.03 * ($outMP - 1); - i.images.connected + inputs.images.connected ? { "type":"range_usd", "min_usd": $outputCost + 0.03, diff --git a/comfy_api_nodes/nodes_bytedance.py b/comfy_api_nodes/nodes_bytedance.py index 471ca8e8b..05388f970 100644 --- a/comfy_api_nodes/nodes_bytedance.py +++ b/comfy_api_nodes/nodes_bytedance.py @@ -374,7 +374,7 @@ class ByteDanceSeedreamNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $price := $contains(w.model.s, "seedream-4-5-251128") ? 0.04 : 0.03; + $price := $contains(widgets.model.s, "seedream-4-5-251128") ? 0.04 : 0.03; { "type":"usd", "usd": $price, @@ -987,12 +987,12 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( "1080p":[0.85,0.88] } }; - $model := w.model.s; + $model := widgets.model.s; $modelKey := $contains($model, "seedance-1-0-pro-fast") ? "seedance-1-0-pro-fast" : $contains($model, "seedance-1-0-pro") ? "seedance-1-0-pro" : "seedance-1-0-lite"; - $resolution := w.resolution.s; + $resolution := widgets.resolution.s; $resKey := $contains($resolution, "1080") ? "1080p" : $contains($resolution, "720") ? "720p" : @@ -1001,7 +1001,7 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( $baseRange := $lookup($modelPrices, $resKey); $min10s := $baseRange[0]; $max10s := $baseRange[1]; - $scale := w.duration.n / 10; + $scale := widgets.duration.n / 10; $minCost := $min10s * $scale; $maxCost := $max10s * $scale; ($minCost = $maxCost) diff --git a/comfy_api_nodes/nodes_gemini.py b/comfy_api_nodes/nodes_gemini.py index ddc2e868a..6e6dc6f8d 100644 --- a/comfy_api_nodes/nodes_gemini.py +++ b/comfy_api_nodes/nodes_gemini.py @@ -313,7 +313,7 @@ class GeminiNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := w.model.s; + $m := widgets.model.s; $contains($m, "gemini-2.5-flash") ? {"type":"list_usd","usd":[0.0003,0.0025]} @@ -723,7 +723,7 @@ class GeminiImage2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["resolution"]), expr=""" ( - $r := w.resolution.s; + $r := widgets.resolution.s; ($contains($r,"1k") or $contains($r,"2k")) ? {"type":"usd","usd":0.134,"format":{"suffix":"/Image","approximate":true}} : $contains($r,"4k") diff --git a/comfy_api_nodes/nodes_ideogram.py b/comfy_api_nodes/nodes_ideogram.py index b93a17755..d3985ddfd 100644 --- a/comfy_api_nodes/nodes_ideogram.py +++ b/comfy_api_nodes/nodes_ideogram.py @@ -302,8 +302,8 @@ class IdeogramV1(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), expr=""" ( - $n := w.num_images.n; - $base := (w.turbo.b = true) ? 0.0286 : 0.0858; + $n := widgets.num_images.n; + $base := (widgets.turbo.b = true) ? 0.0286 : 0.0858; {"type":"usd","usd": $round($base * $n, 2)} ) """, @@ -450,8 +450,8 @@ class IdeogramV2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), expr=""" ( - $n := w.num_images.n; - $base := (w.turbo.b = true) ? 0.0715 : 0.1144; + $n := widgets.num_images.n; + $base := (widgets.turbo.b = true) ? 0.0715 : 0.1144; {"type":"usd","usd": $round($base * $n, 2)} ) """, @@ -615,9 +615,9 @@ class IdeogramV3(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["rendering_speed", "num_images"], inputs=["character_image"]), expr=""" ( - $n := w.num_images.n; - $speed := w.rendering_speed.s; - $hasChar := i.character_image.connected; + $n := widgets.num_images.n; + $speed := widgets.rendering_speed.s; + $hasChar := inputs.character_image.connected; $base := $contains($speed,"quality") ? ($hasChar ? 0.286 : 0.1287) : $contains($speed,"default") ? ($hasChar ? 0.2145 : 0.0858) : diff --git a/comfy_api_nodes/nodes_kling.py b/comfy_api_nodes/nodes_kling.py index fd724dc7f..3eac529fe 100644 --- a/comfy_api_nodes/nodes_kling.py +++ b/comfy_api_nodes/nodes_kling.py @@ -768,7 +768,7 @@ class KlingTextToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode"]), expr=""" ( - $m := w.mode.s; + $m := widgets.mode.s; $contains($m,"v2-5-turbo") ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) : $contains($m,"v2-1-master") @@ -849,9 +849,9 @@ class OmniProTextToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $rates := {"std": 0.084, "pro": 0.112}; - {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} ) """, ), @@ -927,9 +927,9 @@ class OmniProFirstLastFrameNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $rates := {"std": 0.084, "pro": 0.112}; - {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} ) """, ), @@ -1032,9 +1032,9 @@ class OmniProImageToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $rates := {"std": 0.084, "pro": 0.112}; - {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} ) """, ), @@ -1117,9 +1117,9 @@ class OmniProVideoToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $rates := {"std": 0.126, "pro": 0.168}; - {"type":"usd","usd": $lookup($rates, $mode) * w.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} ) """, ), @@ -1213,7 +1213,7 @@ class OmniProEditVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["resolution"]), expr=""" ( - $mode := (w.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $rates := {"std": 0.126, "pro": 0.168}; {"type":"usd","usd": $lookup($rates, $mode), "format":{"suffix":"/second"}} ) @@ -1462,9 +1462,9 @@ class KlingImage2VideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]), expr=""" ( - $mode := w.mode.s; - $model := w.model_name.s; - $dur := w.duration.s; + $mode := widgets.mode.s; + $model := widgets.model_name.s; + $dur := widgets.duration.s; $contains($model,"v2-5-turbo") ? ($contains($dur,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) : ($contains($model,"v2-1-master") or $contains($model,"v2-master")) @@ -1635,7 +1635,7 @@ class KlingStartEndFrameNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode"]), expr=""" ( - $m := w.mode.s; + $m := widgets.mode.s; $contains($m,"v2-5-turbo") ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) : $contains($m,"v2-1") @@ -1811,9 +1811,9 @@ class KlingDualCharacterVideoEffectNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]), expr=""" ( - $mode := w.mode.s; - $model := w.model_name.s; - $dur := w.duration.s; + $mode := widgets.mode.s; + $model := widgets.model_name.s; + $dur := widgets.duration.s; ($contains($model,"v1-6") or $contains($model,"v1-5")) ? ( $contains($mode,"pro") @@ -1898,7 +1898,7 @@ class KlingSingleImageVideoEffectNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["effect_scene"]), expr=""" ( - ($contains(w.effect_scene.s,"dizzydizzy") or $contains(w.effect_scene.s,"bloombloom")) + ($contains(widgets.effect_scene.s,"dizzydizzy") or $contains(widgets.effect_scene.s,"bloombloom")) ? {"type":"usd","usd":0.49} : {"type":"usd","usd":0.28} ) @@ -2180,12 +2180,12 @@ class KlingImageGenerationNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model_name", "n"], inputs=["image"]), expr=""" ( - $m := w.model_name.s; + $m := widgets.model_name.s; $base := $contains($m,"kling-v1-5") - ? (i.image.connected ? 0.028 : 0.014) + ? (inputs.image.connected ? 0.028 : 0.014) : ($contains($m,"kling-v1") ? 0.0035 : 0.014); - {"type":"usd","usd": $base * w.n.n} + {"type":"usd","usd": $base * widgets.n.n} ) """, ), @@ -2274,7 +2274,7 @@ class TextToVideoWithAudio(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), - expr="""{"type":"usd","usd": 0.07 * w.duration.n * (w.generate_audio.b ? 2 : 1)}""", + expr="""{"type":"usd","usd": 0.07 * widgets.duration.n * (widgets.generate_audio.b ? 2 : 1)}""", ), ) @@ -2342,7 +2342,7 @@ class ImageToVideoWithAudio(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), - expr="""{"type":"usd","usd": 0.07 * w.duration.n * (w.generate_audio.b ? 2 : 1)}""", + expr="""{"type":"usd","usd": 0.07 * widgets.duration.n * (widgets.generate_audio.b ? 2 : 1)}""", ), ) @@ -2429,7 +2429,7 @@ class MotionControl(IO.ComfyNode): expr=""" ( $prices := {"std": 0.07, "pro": 0.112}; - {"type":"usd","usd": $lookup($prices, w.mode.s), "format":{"suffix":"/second"}} + {"type":"usd","usd": $lookup($prices, widgets.mode.s), "format":{"suffix":"/second"}} ) """, ), diff --git a/comfy_api_nodes/nodes_ltxv.py b/comfy_api_nodes/nodes_ltxv.py index 397181bab..3df910380 100644 --- a/comfy_api_nodes/nodes_ltxv.py +++ b/comfy_api_nodes/nodes_ltxv.py @@ -35,9 +35,9 @@ PRICE_BADGE = IO.PriceBadge( $pps := { "ltx-2 (pro)": {"1920x1080":0.06,"2560x1440":0.12,"3840x2160":0.24}, "ltx-2 (fast)": {"1920x1080":0.04,"2560x1440":0.08,"3840x2160":0.16} - }[w.model.s][w.resolution.s]; + }[widgets.model.s][widgets.resolution.s]; - {"type":"usd","usd": $pps * w.duration.n} + {"type":"usd","usd": $pps * widgets.duration.n} ) """, ) diff --git a/comfy_api_nodes/nodes_luma.py b/comfy_api_nodes/nodes_luma.py index 95401bc66..915edcb3f 100644 --- a/comfy_api_nodes/nodes_luma.py +++ b/comfy_api_nodes/nodes_luma.py @@ -193,7 +193,7 @@ class LumaImageGenerationNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := w.model.s; + $m := widgets.model.s; $contains($m,"photon-flash-1") ? {"type":"usd","usd":0.0027} : $contains($m,"photon-1") @@ -320,7 +320,7 @@ class LumaImageModifyNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := w.model.s; + $m := widgets.model.s; $contains($m,"photon-flash-1") ? {"type":"usd","usd":0.0027} : $contains($m,"photon-1") @@ -612,9 +612,9 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( } }; - $m := w.model.s; - $d := w.duration.s; - $r := w.resolution.s; + $m := widgets.model.s; + $d := widgets.duration.s; + $r := widgets.resolution.s; $modelKey := $contains($m,"ray-flash-2") ? "ray-flash-2" : diff --git a/comfy_api_nodes/nodes_minimax.py b/comfy_api_nodes/nodes_minimax.py index bb025112f..03436f3b9 100644 --- a/comfy_api_nodes/nodes_minimax.py +++ b/comfy_api_nodes/nodes_minimax.py @@ -350,8 +350,8 @@ class MinimaxHailuoVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["resolution", "duration"]), expr=""" ( - $r := w.resolution.s; - $d := w.duration.s; + $r := widgets.resolution.s; + $d := widgets.duration.s; $price := $contains($r,"768p") diff --git a/comfy_api_nodes/nodes_moonvalley.py b/comfy_api_nodes/nodes_moonvalley.py index 23e64db29..6f12b10e2 100644 --- a/comfy_api_nodes/nodes_moonvalley.py +++ b/comfy_api_nodes/nodes_moonvalley.py @@ -237,7 +237,7 @@ class MoonvalleyImg2VideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["length"]), expr=""" ( - $len := w.length.s; + $len := widgets.length.s; {"type":"usd","usd": ($len = "10s" ? 3.0 : 1.5)} ) """, @@ -364,7 +364,7 @@ class MoonvalleyVideo2VideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["length"]), expr=""" ( - $len := w.length.s; + $len := widgets.length.s; {"type":"usd","usd": ($len = "10s" ? 4.0 : 2.25)} ) """, @@ -493,7 +493,7 @@ class MoonvalleyTxt2VideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["length"]), expr=""" ( - $len := w.length.s; + $len := widgets.length.s; {"type":"usd","usd": ($len = "10s" ? 3.0 : 1.5)} ) """, diff --git a/comfy_api_nodes/nodes_openai.py b/comfy_api_nodes/nodes_openai.py index d2e674f68..6d036c719 100644 --- a/comfy_api_nodes/nodes_openai.py +++ b/comfy_api_nodes/nodes_openai.py @@ -164,8 +164,8 @@ class OpenAIDalle2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["size", "n"]), expr=""" ( - $size := w.size.s; - $nRaw := w.n.n; + $size := widgets.size.s; + $nRaw := widgets.n.n; $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1; $base := @@ -308,8 +308,8 @@ class OpenAIDalle3(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["size", "quality"]), expr=""" ( - $size := w.size.s; - $q := w.quality.s; + $size := widgets.size.s; + $q := widgets.quality.s; $hd := $contains($q, "hd"); $price := @@ -456,8 +456,8 @@ class OpenAIGPTImage1(IO.ComfyNode): "medium": [0.046, 0.07], "high": [0.167, 0.3] }; - $range := $lookup($ranges, w.quality.s); - $n := w.n.n; + $range := $lookup($ranges, widgets.quality.s); + $n := widgets.n.n; ($n = 1) ? {"type":"range_usd","min_usd": $range[0], "max_usd": $range[1]} : { @@ -628,7 +628,7 @@ class OpenAIChatNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := w.model.s; + $m := widgets.model.s; $contains($m,"o4-mini") ? {"type":"list_usd","usd":[0.0011,0.0044]} : $contains($m,"o1-pro") ? {"type":"list_usd","usd":[0.15,0.6]} : diff --git a/comfy_api_nodes/nodes_pixverse.py b/comfy_api_nodes/nodes_pixverse.py index ac95cf5c2..c6dd1f83f 100644 --- a/comfy_api_nodes/nodes_pixverse.py +++ b/comfy_api_nodes/nodes_pixverse.py @@ -423,9 +423,9 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds", "quality", "motion_mode"]), expr=""" ( - $d := w.duration_seconds.s; - $q := w.quality.s; - $m := w.motion_mode.s; + $d := widgets.duration_seconds.s; + $q := widgets.quality.s; + $m := widgets.motion_mode.s; $price := $contains($d,"5") diff --git a/comfy_api_nodes/nodes_recraft.py b/comfy_api_nodes/nodes_recraft.py index 977819d5e..49fa65b73 100644 --- a/comfy_api_nodes/nodes_recraft.py +++ b/comfy_api_nodes/nodes_recraft.py @@ -380,7 +380,7 @@ class RecraftTextToImageNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.04 * w.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.04 * widgets.n.n, 2)}""", ), ) @@ -496,7 +496,7 @@ class RecraftImageToImageNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.04 * w.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.04 * widgets.n.n, 2)}""", ), ) @@ -601,7 +601,7 @@ class RecraftImageInpaintingNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.04 * w.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.04 * widgets.n.n, 2)}""", ), ) @@ -706,7 +706,7 @@ class RecraftTextToVectorNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.08 * w.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.08 * widgets.n.n, 2)}""", ), ) @@ -777,7 +777,7 @@ class RecraftVectorizeImageNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.01 * w.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.01 * widgets.n.n, 2)}""", ), ) diff --git a/comfy_api_nodes/nodes_runway.py b/comfy_api_nodes/nodes_runway.py index f66901e80..deb7a8419 100644 --- a/comfy_api_nodes/nodes_runway.py +++ b/comfy_api_nodes/nodes_runway.py @@ -186,7 +186,7 @@ class RunwayImageToVideoNodeGen3a(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.0715 * w.duration.n}""", + expr="""{"type":"usd","usd": 0.0715 * widgets.duration.n}""", ), ) @@ -280,7 +280,7 @@ class RunwayImageToVideoNodeGen4(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.0715 * w.duration.n}""", + expr="""{"type":"usd","usd": 0.0715 * widgets.duration.n}""", ), ) @@ -382,7 +382,7 @@ class RunwayFirstLastFrameNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.0715 * w.duration.n}""", + expr="""{"type":"usd","usd": 0.0715 * widgets.duration.n}""", ), ) diff --git a/comfy_api_nodes/nodes_sora.py b/comfy_api_nodes/nodes_sora.py index d988b401b..7f23a9587 100644 --- a/comfy_api_nodes/nodes_sora.py +++ b/comfy_api_nodes/nodes_sora.py @@ -93,9 +93,9 @@ class OpenAIVideoSora2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model", "size", "duration"]), expr=""" ( - $m := w.model.s; - $size := w.size.s; - $dur := w.duration.n; + $m := widgets.model.s; + $size := widgets.size.s; + $dur := widgets.duration.n; $isPro := $contains($m, "sora-2-pro"); $isSora2 := $contains($m, "sora-2"); $isProSize := ($size = "1024x1792" or $size = "1792x1024"); diff --git a/comfy_api_nodes/nodes_stability.py b/comfy_api_nodes/nodes_stability.py index fdcd27dd1..b390f34af 100644 --- a/comfy_api_nodes/nodes_stability.py +++ b/comfy_api_nodes/nodes_stability.py @@ -271,7 +271,7 @@ class StabilityStableImageSD_3_5Node(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $contains(w.model.s,"large") + $contains(widgets.model.s,"large") ? {"type":"usd","usd":0.065} : {"type":"usd","usd":0.035} ) diff --git a/comfy_api_nodes/nodes_tripo.py b/comfy_api_nodes/nodes_tripo.py index 0bbb98fb3..54fbdf33c 100644 --- a/comfy_api_nodes/nodes_tripo.py +++ b/comfy_api_nodes/nodes_tripo.py @@ -78,7 +78,7 @@ async def poll_until_finished( raise RuntimeError(f"Failed to generate mesh: {response_poll}") -class TripoTextToModelNode(IO.ComfyNode): +class TripoTextToModelNode(IO.ComfyNode): """ Generates 3D models synchronously based on a text prompt using Tripo's API. """ @@ -131,18 +131,18 @@ class TripoTextToModelNode(IO.ComfyNode): ), expr=""" ( - $isV14 := $contains(w.model_version.s,"v1.4"); - $style := w.style.s; + $isV14 := $contains(widgets.model_version.s,"v1.4"); + $style := widgets.style.s; $hasStyle := ($style != "" and $style != "none"); - $withTexture := w.texture.b or w.pbr.b; - $isHdTexture := (w.texture_quality.s = "detailed"); - $isDetailedGeometry := (w.geometry_quality.s = "detailed"); + $withTexture := widgets.texture.b or widgets.pbr.b; + $isHdTexture := (widgets.texture_quality.s = "detailed"); + $isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); $baseCredits := $isV14 ? 20 : ($withTexture ? 20 : 10); $credits := $baseCredits + ($hasStyle ? 5 : 0) - + (w.quad.b ? 5 : 0) + + (widgets.quad.b ? 5 : 0) + ($isHdTexture ? 10 : 0) + ($isDetailedGeometry ? 20 : 0); {"type":"usd","usd": $round($credits * 0.01, 2)} @@ -256,18 +256,18 @@ class TripoImageToModelNode(IO.ComfyNode): ), expr=""" ( - $isV14 := $contains(w.model_version.s,"v1.4"); - $style := w.style.s; + $isV14 := $contains(widgets.model_version.s,"v1.4"); + $style := widgets.style.s; $hasStyle := ($style != "" and $style != "none"); - $withTexture := w.texture.b or w.pbr.b; - $isHdTexture := (w.texture_quality.s = "detailed"); - $isDetailedGeometry := (w.geometry_quality.s = "detailed"); + $withTexture := widgets.texture.b or widgets.pbr.b; + $isHdTexture := (widgets.texture_quality.s = "detailed"); + $isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); $baseCredits := $isV14 ? 30 : ($withTexture ? 30 : 20); $credits := $baseCredits + ($hasStyle ? 5 : 0) - + (w.quad.b ? 5 : 0) + + (widgets.quad.b ? 5 : 0) + ($isHdTexture ? 10 : 0) + ($isDetailedGeometry ? 20 : 0); {"type":"usd","usd": $round($credits * 0.01, 2)} @@ -391,15 +391,15 @@ class TripoMultiviewToModelNode(IO.ComfyNode): ), expr=""" ( - $isV14 := $contains(w.model_version.s,"v1.4"); - $withTexture := w.texture.b or w.pbr.b; - $isHdTexture := (w.texture_quality.s = "detailed"); - $isDetailedGeometry := (w.geometry_quality.s = "detailed"); + $isV14 := $contains(widgets.model_version.s,"v1.4"); + $withTexture := widgets.texture.b or widgets.pbr.b; + $isHdTexture := (widgets.texture_quality.s = "detailed"); + $isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); $baseCredits := $isV14 ? 30 : ($withTexture ? 30 : 20); $credits := $baseCredits - + (w.quad.b ? 5 : 0) + + (widgets.quad.b ? 5 : 0) + ($isHdTexture ? 10 : 0) + ($isDetailedGeometry ? 20 : 0); {"type":"usd","usd": $round($credits * 0.01, 2)} @@ -501,7 +501,7 @@ class TripoTextureNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["texture_quality"]), expr=""" ( - $tq := w.texture_quality.s; + $tq := widgets.texture_quality.s; {"type":"usd","usd": ($contains($tq,"detailed") ? 0.2 : 0.1)} ) """, @@ -772,24 +772,24 @@ class TripoConversionNode(IO.ComfyNode): ), expr=""" ( - $face := (w.face_limit.n != null) ? w.face_limit.n : -1; - $texSize := (w.texture_size.n != null) ? w.texture_size.n : 4096; - $flatThresh := (w.flatten_bottom_threshold.n != null) ? w.flatten_bottom_threshold.n : 0; - $scale := (w.scale_factor.n != null) ? w.scale_factor.n : 1; - $texFmt := (w.texture_format.s != "" ? w.texture_format.s : "jpeg"); - $part := w.part_names.s; - $fbx := (w.fbx_preset.s != "" ? w.fbx_preset.s : "blender"); - $orient := (w.export_orientation.s != "" ? w.export_orientation.s : "default"); + $face := (widgets.face_limit.n != null) ? widgets.face_limit.n : -1; + $texSize := (widgets.texture_size.n != null) ? widgets.texture_size.n : 4096; + $flatThresh := (widgets.flatten_bottom_threshold.n != null) ? widgets.flatten_bottom_threshold.n : 0; + $scale := (widgets.scale_factor.n != null) ? widgets.scale_factor.n : 1; + $texFmt := (widgets.texture_format.s != "" ? widgets.texture_format.s : "jpeg"); + $part := widgets.part_names.s; + $fbx := (widgets.fbx_preset.s != "" ? widgets.fbx_preset.s : "blender"); + $orient := (widgets.export_orientation.s != "" ? widgets.export_orientation.s : "default"); $advanced := - w.quad.b or - w.force_symmetry.b or - w.flatten_bottom.b or - w.pivot_to_center_bottom.b or - w.with_animation.b or - w.pack_uv.b or - w.bake.b or - w.export_vertex_colors.b or - w.animate_in_place.b or + widgets.quad.b or + widgets.force_symmetry.b or + widgets.flatten_bottom.b or + widgets.pivot_to_center_bottom.b or + widgets.with_animation.b or + widgets.pack_uv.b or + widgets.bake.b or + widgets.export_vertex_colors.b or + widgets.animate_in_place.b or ($face != -1) or ($texSize != 4096) or ($flatThresh != 0) or diff --git a/comfy_api_nodes/nodes_veo2.py b/comfy_api_nodes/nodes_veo2.py index 6a726e6f2..2b4d61b81 100644 --- a/comfy_api_nodes/nodes_veo2.py +++ b/comfy_api_nodes/nodes_veo2.py @@ -124,7 +124,7 @@ class VeoVideoGenerationNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds"]), - expr="""{"type":"usd","usd": 0.5 * w.duration_seconds.n}""", + expr="""{"type":"usd","usd": 0.5 * widgets.duration_seconds.n}""", ), ) @@ -355,8 +355,8 @@ class Veo3VideoGenerationNode(VeoVideoGenerationNode): depends_on=IO.PriceBadgeDepends(widgets=["model", "generate_audio"]), expr=""" ( - $m := w.model.s; - $a := w.generate_audio.b; + $m := widgets.model.s; + $a := widgets.generate_audio.b; ($contains($m,"veo-3.0-fast-generate-001") or $contains($m,"veo-3.1-fast-generate")) ? {"type":"usd","usd": ($a ? 1.2 : 0.8)} : ($contains($m,"veo-3.0-generate-001") or $contains($m,"veo-3.1-generate")) @@ -446,9 +446,9 @@ class Veo3FirstLastFrameNode(IO.ComfyNode): "veo-3.1-fast-generate": { "audio": 0.15, "no_audio": 0.10 }, "veo-3.1-generate": { "audio": 0.40, "no_audio": 0.20 } }; - $m := w.model.s; - $ga := (w.generate_audio.s = "true"); - $seconds := w.duration.n; + $m := widgets.model.s; + $ga := (widgets.generate_audio.s = "true"); + $seconds := widgets.duration.n; $modelKey := $contains($m, "veo-3.1-fast-generate") ? "veo-3.1-fast-generate" : $contains($m, "veo-3.1-generate") ? "veo-3.1-generate" : diff --git a/comfy_api_nodes/nodes_wan.py b/comfy_api_nodes/nodes_wan.py index f47da2ce1..47406818d 100644 --- a/comfy_api_nodes/nodes_wan.py +++ b/comfy_api_nodes/nodes_wan.py @@ -531,9 +531,9 @@ class WanTextToVideoApi(IO.ComfyNode): expr=""" ( $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; - $resKey := $substringBefore(w.size.s, ":"); + $resKey := $substringBefore(widgets.size.s, ":"); $pps := $lookup($ppsTable, $resKey); - { "type": "usd", "usd": $round($pps * w.duration.n, 2) } + { "type": "usd", "usd": $round($pps * widgets.duration.n, 2) } ) """, ), @@ -703,8 +703,8 @@ class WanImageToVideoApi(IO.ComfyNode): expr=""" ( $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; - $pps := $lookup($ppsTable, w.resolution.s); - { "type": "usd", "usd": $round($pps * w.duration.n, 2) } + $pps := $lookup($ppsTable, widgets.resolution.s); + { "type": "usd", "usd": $round($pps * widgets.duration.n, 2) } ) """, ), From 5b93e7ec9f6ea00e3248ad1beb70d42855d461ea Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Tue, 6 Jan 2026 18:30:35 +0200 Subject: [PATCH 07/10] add strict typing for JSONata rules --- comfy_api/latest/_io.py | 27 ++++++++--- comfy_api_nodes/nodes_bfl.py | 4 +- comfy_api_nodes/nodes_bytedance.py | 8 ++-- comfy_api_nodes/nodes_gemini.py | 4 +- comfy_api_nodes/nodes_ideogram.py | 12 ++--- comfy_api_nodes/nodes_kling.py | 46 +++++++++---------- comfy_api_nodes/nodes_ltxv.py | 4 +- comfy_api_nodes/nodes_luma.py | 10 ++--- comfy_api_nodes/nodes_minimax.py | 4 +- comfy_api_nodes/nodes_moonvalley.py | 33 ++++---------- comfy_api_nodes/nodes_openai.py | 14 +++--- comfy_api_nodes/nodes_pixverse.py | 6 +-- comfy_api_nodes/nodes_recraft.py | 12 ++--- comfy_api_nodes/nodes_runway.py | 6 +-- comfy_api_nodes/nodes_sora.py | 6 +-- comfy_api_nodes/nodes_stability.py | 2 +- comfy_api_nodes/nodes_tripo.py | 70 ++++++++++++++--------------- comfy_api_nodes/nodes_veo2.py | 12 ++--- comfy_api_nodes/nodes_wan.py | 8 ++-- 19 files changed, 144 insertions(+), 144 deletions(-) diff --git a/comfy_api/latest/_io.py b/comfy_api/latest/_io.py index bbd36d7e2..f925cf7b4 100644 --- a/comfy_api/latest/_io.py +++ b/comfy_api/latest/_io.py @@ -1246,9 +1246,24 @@ class PriceBadgeDepends: if not isinstance(self.input_groups, list) or any(not isinstance(x, str) for x in self.input_groups): raise ValueError("PriceBadgeDepends.input_groups must be a list[str].") - def as_dict(self) -> dict[str, Any]: + def as_dict(self, schema_inputs: list["Input"]) -> dict[str, Any]: + # Build lookup: widget_id -> io_type + input_types: dict[str, str] = {} + for inp in schema_inputs: + input_types[inp.id] = inp.get_io_type() + + # Enrich widgets with type information, raising error for unknown widgets + widgets_data: list[dict[str, str]] = [] + for w in self.widgets: + if w not in input_types: + raise ValueError( + f"PriceBadge depends_on.widgets references unknown widget '{w}'. " + f"Available widgets: {list(input_types.keys())}" + ) + widgets_data.append({"name": w, "type": input_types[w]}) + return { - "widgets": self.widgets, + "widgets": widgets_data, "inputs": self.inputs, "input_groups": self.input_groups, } @@ -1267,10 +1282,10 @@ class PriceBadge: raise ValueError("PriceBadge.expr must be a non-empty string.") self.depends_on.validate() - def as_dict(self) -> dict[str, Any]: + def as_dict(self, schema_inputs: list["Input"]) -> dict[str, Any]: return { "engine": self.engine, - "depends_on": self.depends_on.as_dict(), + "depends_on": self.depends_on.as_dict(schema_inputs), "expr": self.expr, } @@ -1426,7 +1441,7 @@ class Schema: experimental=self.is_experimental, api_node=self.is_api_node, python_module=getattr(cls, "RELATIVE_PYTHON_MODULE", "nodes"), - price_badge=self.price_badge.as_dict() if self.price_badge is not None else None, + price_badge=self.price_badge.as_dict(self.inputs) if self.price_badge is not None else None, ) return info @@ -1459,7 +1474,7 @@ class Schema: experimental=self.is_experimental, api_node=self.is_api_node, python_module=getattr(cls, "RELATIVE_PYTHON_MODULE", "nodes"), - price_badge=self.price_badge.as_dict() if self.price_badge is not None else None, + price_badge=self.price_badge.as_dict(self.inputs) if self.price_badge is not None else None, ) return info diff --git a/comfy_api_nodes/nodes_bfl.py b/comfy_api_nodes/nodes_bfl.py index c67076dd6..76021ef7f 100644 --- a/comfy_api_nodes/nodes_bfl.py +++ b/comfy_api_nodes/nodes_bfl.py @@ -523,7 +523,7 @@ class Flux2ProImageNode(IO.ComfyNode): PRICE_BADGE_EXPR = """ ( $MP := 1024 * 1024; - $outMP := $max([1, $floor(((widgets.width.n * widgets.height.n) + $MP - 1) / $MP)]); + $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]); $outputCost := 0.03 + 0.015 * ($outMP - 1); inputs.images.connected ? { @@ -654,7 +654,7 @@ class Flux2MaxImageNode(Flux2ProImageNode): PRICE_BADGE_EXPR = """ ( $MP := 1024 * 1024; - $outMP := $max([1, $floor(((widgets.width.n * widgets.height.n) + $MP - 1) / $MP)]); + $outMP := $max([1, $floor(((widgets.width * widgets.height) + $MP - 1) / $MP)]); $outputCost := 0.07 + 0.03 * ($outMP - 1); inputs.images.connected diff --git a/comfy_api_nodes/nodes_bytedance.py b/comfy_api_nodes/nodes_bytedance.py index 05388f970..f09a4a0ed 100644 --- a/comfy_api_nodes/nodes_bytedance.py +++ b/comfy_api_nodes/nodes_bytedance.py @@ -374,7 +374,7 @@ class ByteDanceSeedreamNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $price := $contains(widgets.model.s, "seedream-4-5-251128") ? 0.04 : 0.03; + $price := $contains(widgets.model, "seedream-4-5-251128") ? 0.04 : 0.03; { "type":"usd", "usd": $price, @@ -987,12 +987,12 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( "1080p":[0.85,0.88] } }; - $model := widgets.model.s; + $model := widgets.model; $modelKey := $contains($model, "seedance-1-0-pro-fast") ? "seedance-1-0-pro-fast" : $contains($model, "seedance-1-0-pro") ? "seedance-1-0-pro" : "seedance-1-0-lite"; - $resolution := widgets.resolution.s; + $resolution := widgets.resolution; $resKey := $contains($resolution, "1080") ? "1080p" : $contains($resolution, "720") ? "720p" : @@ -1001,7 +1001,7 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( $baseRange := $lookup($modelPrices, $resKey); $min10s := $baseRange[0]; $max10s := $baseRange[1]; - $scale := widgets.duration.n / 10; + $scale := widgets.duration / 10; $minCost := $min10s * $scale; $maxCost := $max10s * $scale; ($minCost = $maxCost) diff --git a/comfy_api_nodes/nodes_gemini.py b/comfy_api_nodes/nodes_gemini.py index 6e6dc6f8d..0ca623ee9 100644 --- a/comfy_api_nodes/nodes_gemini.py +++ b/comfy_api_nodes/nodes_gemini.py @@ -313,7 +313,7 @@ class GeminiNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := widgets.model.s; + $m := widgets.model; $contains($m, "gemini-2.5-flash") ? {"type":"list_usd","usd":[0.0003,0.0025]} @@ -723,7 +723,7 @@ class GeminiImage2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["resolution"]), expr=""" ( - $r := widgets.resolution.s; + $r := widgets.resolution; ($contains($r,"1k") or $contains($r,"2k")) ? {"type":"usd","usd":0.134,"format":{"suffix":"/Image","approximate":true}} : $contains($r,"4k") diff --git a/comfy_api_nodes/nodes_ideogram.py b/comfy_api_nodes/nodes_ideogram.py index d3985ddfd..827b3523a 100644 --- a/comfy_api_nodes/nodes_ideogram.py +++ b/comfy_api_nodes/nodes_ideogram.py @@ -302,8 +302,8 @@ class IdeogramV1(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), expr=""" ( - $n := widgets.num_images.n; - $base := (widgets.turbo.b = true) ? 0.0286 : 0.0858; + $n := widgets.num_images; + $base := (widgets.turbo = true) ? 0.0286 : 0.0858; {"type":"usd","usd": $round($base * $n, 2)} ) """, @@ -450,8 +450,8 @@ class IdeogramV2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), expr=""" ( - $n := widgets.num_images.n; - $base := (widgets.turbo.b = true) ? 0.0715 : 0.1144; + $n := widgets.num_images; + $base := (widgets.turbo = true) ? 0.0715 : 0.1144; {"type":"usd","usd": $round($base * $n, 2)} ) """, @@ -615,8 +615,8 @@ class IdeogramV3(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["rendering_speed", "num_images"], inputs=["character_image"]), expr=""" ( - $n := widgets.num_images.n; - $speed := widgets.rendering_speed.s; + $n := widgets.num_images; + $speed := widgets.rendering_speed; $hasChar := inputs.character_image.connected; $base := $contains($speed,"quality") ? ($hasChar ? 0.286 : 0.1287) : diff --git a/comfy_api_nodes/nodes_kling.py b/comfy_api_nodes/nodes_kling.py index 3eac529fe..364babf69 100644 --- a/comfy_api_nodes/nodes_kling.py +++ b/comfy_api_nodes/nodes_kling.py @@ -768,7 +768,7 @@ class KlingTextToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode"]), expr=""" ( - $m := widgets.mode.s; + $m := widgets.mode; $contains($m,"v2-5-turbo") ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) : $contains($m,"v2-1-master") @@ -849,9 +849,9 @@ class OmniProTextToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution = "720p") ? "std" : "pro"; $rates := {"std": 0.084, "pro": 0.112}; - {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration} ) """, ), @@ -927,9 +927,9 @@ class OmniProFirstLastFrameNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution = "720p") ? "std" : "pro"; $rates := {"std": 0.084, "pro": 0.112}; - {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration} ) """, ), @@ -1032,9 +1032,9 @@ class OmniProImageToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution = "720p") ? "std" : "pro"; $rates := {"std": 0.084, "pro": 0.112}; - {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration} ) """, ), @@ -1117,9 +1117,9 @@ class OmniProVideoToVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), expr=""" ( - $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution = "720p") ? "std" : "pro"; $rates := {"std": 0.126, "pro": 0.168}; - {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration.n} + {"type":"usd","usd": $lookup($rates, $mode) * widgets.duration} ) """, ), @@ -1213,7 +1213,7 @@ class OmniProEditVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["resolution"]), expr=""" ( - $mode := (widgets.resolution.s = "720p") ? "std" : "pro"; + $mode := (widgets.resolution = "720p") ? "std" : "pro"; $rates := {"std": 0.126, "pro": 0.168}; {"type":"usd","usd": $lookup($rates, $mode), "format":{"suffix":"/second"}} ) @@ -1462,9 +1462,9 @@ class KlingImage2VideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]), expr=""" ( - $mode := widgets.mode.s; - $model := widgets.model_name.s; - $dur := widgets.duration.s; + $mode := widgets.mode; + $model := widgets.model_name; + $dur := widgets.duration; $contains($model,"v2-5-turbo") ? ($contains($dur,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) : ($contains($model,"v2-1-master") or $contains($model,"v2-master")) @@ -1635,7 +1635,7 @@ class KlingStartEndFrameNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode"]), expr=""" ( - $m := widgets.mode.s; + $m := widgets.mode; $contains($m,"v2-5-turbo") ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) : $contains($m,"v2-1") @@ -1811,9 +1811,9 @@ class KlingDualCharacterVideoEffectNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]), expr=""" ( - $mode := widgets.mode.s; - $model := widgets.model_name.s; - $dur := widgets.duration.s; + $mode := widgets.mode; + $model := widgets.model_name; + $dur := widgets.duration; ($contains($model,"v1-6") or $contains($model,"v1-5")) ? ( $contains($mode,"pro") @@ -1898,7 +1898,7 @@ class KlingSingleImageVideoEffectNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["effect_scene"]), expr=""" ( - ($contains(widgets.effect_scene.s,"dizzydizzy") or $contains(widgets.effect_scene.s,"bloombloom")) + ($contains(widgets.effect_scene,"dizzydizzy") or $contains(widgets.effect_scene,"bloombloom")) ? {"type":"usd","usd":0.49} : {"type":"usd","usd":0.28} ) @@ -2180,12 +2180,12 @@ class KlingImageGenerationNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model_name", "n"], inputs=["image"]), expr=""" ( - $m := widgets.model_name.s; + $m := widgets.model_name; $base := $contains($m,"kling-v1-5") ? (inputs.image.connected ? 0.028 : 0.014) : ($contains($m,"kling-v1") ? 0.0035 : 0.014); - {"type":"usd","usd": $base * widgets.n.n} + {"type":"usd","usd": $base * widgets.n} ) """, ), @@ -2274,7 +2274,7 @@ class TextToVideoWithAudio(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), - expr="""{"type":"usd","usd": 0.07 * widgets.duration.n * (widgets.generate_audio.b ? 2 : 1)}""", + expr="""{"type":"usd","usd": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}""", ), ) @@ -2342,7 +2342,7 @@ class ImageToVideoWithAudio(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), - expr="""{"type":"usd","usd": 0.07 * widgets.duration.n * (widgets.generate_audio.b ? 2 : 1)}""", + expr="""{"type":"usd","usd": 0.07 * widgets.duration * (widgets.generate_audio ? 2 : 1)}""", ), ) @@ -2429,7 +2429,7 @@ class MotionControl(IO.ComfyNode): expr=""" ( $prices := {"std": 0.07, "pro": 0.112}; - {"type":"usd","usd": $lookup($prices, widgets.mode.s), "format":{"suffix":"/second"}} + {"type":"usd","usd": $lookup($prices, widgets.mode), "format":{"suffix":"/second"}} ) """, ), diff --git a/comfy_api_nodes/nodes_ltxv.py b/comfy_api_nodes/nodes_ltxv.py index 3df910380..67dd97fe5 100644 --- a/comfy_api_nodes/nodes_ltxv.py +++ b/comfy_api_nodes/nodes_ltxv.py @@ -35,9 +35,9 @@ PRICE_BADGE = IO.PriceBadge( $pps := { "ltx-2 (pro)": {"1920x1080":0.06,"2560x1440":0.12,"3840x2160":0.24}, "ltx-2 (fast)": {"1920x1080":0.04,"2560x1440":0.08,"3840x2160":0.16} - }[widgets.model.s][widgets.resolution.s]; + }[widgets.model][widgets.resolution]; - {"type":"usd","usd": $pps * widgets.duration.n} + {"type":"usd","usd": $pps * widgets.duration} ) """, ) diff --git a/comfy_api_nodes/nodes_luma.py b/comfy_api_nodes/nodes_luma.py index 915edcb3f..95cb442e5 100644 --- a/comfy_api_nodes/nodes_luma.py +++ b/comfy_api_nodes/nodes_luma.py @@ -193,7 +193,7 @@ class LumaImageGenerationNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := widgets.model.s; + $m := widgets.model; $contains($m,"photon-flash-1") ? {"type":"usd","usd":0.0027} : $contains($m,"photon-1") @@ -320,7 +320,7 @@ class LumaImageModifyNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := widgets.model.s; + $m := widgets.model; $contains($m,"photon-flash-1") ? {"type":"usd","usd":0.0027} : $contains($m,"photon-1") @@ -612,9 +612,9 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( } }; - $m := widgets.model.s; - $d := widgets.duration.s; - $r := widgets.resolution.s; + $m := widgets.model; + $d := widgets.duration; + $r := widgets.resolution; $modelKey := $contains($m,"ray-flash-2") ? "ray-flash-2" : diff --git a/comfy_api_nodes/nodes_minimax.py b/comfy_api_nodes/nodes_minimax.py index 03436f3b9..fe8b81986 100644 --- a/comfy_api_nodes/nodes_minimax.py +++ b/comfy_api_nodes/nodes_minimax.py @@ -350,8 +350,8 @@ class MinimaxHailuoVideoNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["resolution", "duration"]), expr=""" ( - $r := widgets.resolution.s; - $d := widgets.duration.s; + $r := widgets.resolution; + $d := widgets.duration; $price := $contains($r,"768p") diff --git a/comfy_api_nodes/nodes_moonvalley.py b/comfy_api_nodes/nodes_moonvalley.py index 6f12b10e2..769b171b7 100644 --- a/comfy_api_nodes/nodes_moonvalley.py +++ b/comfy_api_nodes/nodes_moonvalley.py @@ -234,14 +234,9 @@ class MoonvalleyImg2VideoNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["length"]), - expr=""" - ( - $len := widgets.length.s; - {"type":"usd","usd": ($len = "10s" ? 3.0 : 1.5)} - ) - """, - ), # TO-DO: This is 1:1 code from frontend, but this makes no sense as we don't have `length` widget + depends_on=IO.PriceBadgeDepends(), + expr="""{"type":"usd","usd": 1.5}""", + ), ) @classmethod @@ -361,14 +356,9 @@ class MoonvalleyVideo2VideoNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["length"]), - expr=""" - ( - $len := widgets.length.s; - {"type":"usd","usd": ($len = "10s" ? 4.0 : 2.25)} - ) - """, - ), # TO-DO: This is 1:1 code from frontend, but this makes no sense as we don't have `length` widget + depends_on=IO.PriceBadgeDepends(), + expr="""{"type":"usd","usd": 2.25}""", + ), ) @classmethod @@ -490,14 +480,9 @@ class MoonvalleyTxt2VideoNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["length"]), - expr=""" - ( - $len := widgets.length.s; - {"type":"usd","usd": ($len = "10s" ? 3.0 : 1.5)} - ) - """, - ), # TO-DO: This is 1:1 code from frontend, but this makes no sense as we don't have `length` widget + depends_on=IO.PriceBadgeDepends(), + expr="""{"type":"usd","usd": 1.5}""", + ), ) @classmethod diff --git a/comfy_api_nodes/nodes_openai.py b/comfy_api_nodes/nodes_openai.py index 6d036c719..0d0305e34 100644 --- a/comfy_api_nodes/nodes_openai.py +++ b/comfy_api_nodes/nodes_openai.py @@ -164,8 +164,8 @@ class OpenAIDalle2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["size", "n"]), expr=""" ( - $size := widgets.size.s; - $nRaw := widgets.n.n; + $size := widgets.size; + $nRaw := widgets.n; $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1; $base := @@ -308,8 +308,8 @@ class OpenAIDalle3(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["size", "quality"]), expr=""" ( - $size := widgets.size.s; - $q := widgets.quality.s; + $size := widgets.size; + $q := widgets.quality; $hd := $contains($q, "hd"); $price := @@ -456,8 +456,8 @@ class OpenAIGPTImage1(IO.ComfyNode): "medium": [0.046, 0.07], "high": [0.167, 0.3] }; - $range := $lookup($ranges, widgets.quality.s); - $n := widgets.n.n; + $range := $lookup($ranges, widgets.quality); + $n := widgets.n; ($n = 1) ? {"type":"range_usd","min_usd": $range[0], "max_usd": $range[1]} : { @@ -628,7 +628,7 @@ class OpenAIChatNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $m := widgets.model.s; + $m := widgets.model; $contains($m,"o4-mini") ? {"type":"list_usd","usd":[0.0011,0.0044]} : $contains($m,"o1-pro") ? {"type":"list_usd","usd":[0.15,0.6]} : diff --git a/comfy_api_nodes/nodes_pixverse.py b/comfy_api_nodes/nodes_pixverse.py index c6dd1f83f..55e84cdec 100644 --- a/comfy_api_nodes/nodes_pixverse.py +++ b/comfy_api_nodes/nodes_pixverse.py @@ -423,9 +423,9 @@ PRICE_BADGE_VIDEO = IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds", "quality", "motion_mode"]), expr=""" ( - $d := widgets.duration_seconds.s; - $q := widgets.quality.s; - $m := widgets.motion_mode.s; + $d := widgets.duration_seconds; + $q := widgets.quality; + $m := widgets.motion_mode; $price := $contains($d,"5") diff --git a/comfy_api_nodes/nodes_recraft.py b/comfy_api_nodes/nodes_recraft.py index 49fa65b73..8c5ca91c5 100644 --- a/comfy_api_nodes/nodes_recraft.py +++ b/comfy_api_nodes/nodes_recraft.py @@ -380,7 +380,7 @@ class RecraftTextToImageNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.04 * widgets.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.04 * widgets.n, 2)}""", ), ) @@ -496,7 +496,7 @@ class RecraftImageToImageNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.04 * widgets.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.04 * widgets.n, 2)}""", ), ) @@ -601,7 +601,7 @@ class RecraftImageInpaintingNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.04 * widgets.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.04 * widgets.n, 2)}""", ), ) @@ -706,7 +706,7 @@ class RecraftTextToVectorNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.08 * widgets.n.n, 2)}""", + expr="""{"type":"usd","usd": $round(0.08 * widgets.n, 2)}""", ), ) @@ -776,8 +776,8 @@ class RecraftVectorizeImageNode(IO.ComfyNode): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["n"]), - expr="""{"type":"usd","usd": $round(0.01 * widgets.n.n, 2)}""", + depends_on=IO.PriceBadgeDepends(), + expr="""{"type":"usd","usd": 0.01}""", ), ) diff --git a/comfy_api_nodes/nodes_runway.py b/comfy_api_nodes/nodes_runway.py index deb7a8419..d19fdb365 100644 --- a/comfy_api_nodes/nodes_runway.py +++ b/comfy_api_nodes/nodes_runway.py @@ -186,7 +186,7 @@ class RunwayImageToVideoNodeGen3a(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.0715 * widgets.duration.n}""", + expr="""{"type":"usd","usd": 0.0715 * widgets.duration}""", ), ) @@ -280,7 +280,7 @@ class RunwayImageToVideoNodeGen4(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.0715 * widgets.duration.n}""", + expr="""{"type":"usd","usd": 0.0715 * widgets.duration}""", ), ) @@ -382,7 +382,7 @@ class RunwayFirstLastFrameNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration"]), - expr="""{"type":"usd","usd": 0.0715 * widgets.duration.n}""", + expr="""{"type":"usd","usd": 0.0715 * widgets.duration}""", ), ) diff --git a/comfy_api_nodes/nodes_sora.py b/comfy_api_nodes/nodes_sora.py index 7f23a9587..87e663845 100644 --- a/comfy_api_nodes/nodes_sora.py +++ b/comfy_api_nodes/nodes_sora.py @@ -93,9 +93,9 @@ class OpenAIVideoSora2(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model", "size", "duration"]), expr=""" ( - $m := widgets.model.s; - $size := widgets.size.s; - $dur := widgets.duration.n; + $m := widgets.model; + $size := widgets.size; + $dur := widgets.duration; $isPro := $contains($m, "sora-2-pro"); $isSora2 := $contains($m, "sora-2"); $isProSize := ($size = "1024x1792" or $size = "1792x1024"); diff --git a/comfy_api_nodes/nodes_stability.py b/comfy_api_nodes/nodes_stability.py index b390f34af..5c48c1f1e 100644 --- a/comfy_api_nodes/nodes_stability.py +++ b/comfy_api_nodes/nodes_stability.py @@ -271,7 +271,7 @@ class StabilityStableImageSD_3_5Node(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model"]), expr=""" ( - $contains(widgets.model.s,"large") + $contains(widgets.model,"large") ? {"type":"usd","usd":0.065} : {"type":"usd","usd":0.035} ) diff --git a/comfy_api_nodes/nodes_tripo.py b/comfy_api_nodes/nodes_tripo.py index 54fbdf33c..aa790143d 100644 --- a/comfy_api_nodes/nodes_tripo.py +++ b/comfy_api_nodes/nodes_tripo.py @@ -131,18 +131,18 @@ class TripoTextToModelNode(IO.ComfyNode): ), expr=""" ( - $isV14 := $contains(widgets.model_version.s,"v1.4"); - $style := widgets.style.s; + $isV14 := $contains(widgets.model_version,"v1.4"); + $style := widgets.style; $hasStyle := ($style != "" and $style != "none"); - $withTexture := widgets.texture.b or widgets.pbr.b; - $isHdTexture := (widgets.texture_quality.s = "detailed"); - $isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); + $withTexture := widgets.texture or widgets.pbr; + $isHdTexture := (widgets.texture_quality = "detailed"); + $isDetailedGeometry := (widgets.geometry_quality = "detailed"); $baseCredits := $isV14 ? 20 : ($withTexture ? 20 : 10); $credits := $baseCredits + ($hasStyle ? 5 : 0) - + (widgets.quad.b ? 5 : 0) + + (widgets.quad ? 5 : 0) + ($isHdTexture ? 10 : 0) + ($isDetailedGeometry ? 20 : 0); {"type":"usd","usd": $round($credits * 0.01, 2)} @@ -256,18 +256,18 @@ class TripoImageToModelNode(IO.ComfyNode): ), expr=""" ( - $isV14 := $contains(widgets.model_version.s,"v1.4"); - $style := widgets.style.s; + $isV14 := $contains(widgets.model_version,"v1.4"); + $style := widgets.style; $hasStyle := ($style != "" and $style != "none"); - $withTexture := widgets.texture.b or widgets.pbr.b; - $isHdTexture := (widgets.texture_quality.s = "detailed"); - $isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); + $withTexture := widgets.texture or widgets.pbr; + $isHdTexture := (widgets.texture_quality = "detailed"); + $isDetailedGeometry := (widgets.geometry_quality = "detailed"); $baseCredits := $isV14 ? 30 : ($withTexture ? 30 : 20); $credits := $baseCredits + ($hasStyle ? 5 : 0) - + (widgets.quad.b ? 5 : 0) + + (widgets.quad ? 5 : 0) + ($isHdTexture ? 10 : 0) + ($isDetailedGeometry ? 20 : 0); {"type":"usd","usd": $round($credits * 0.01, 2)} @@ -391,15 +391,15 @@ class TripoMultiviewToModelNode(IO.ComfyNode): ), expr=""" ( - $isV14 := $contains(widgets.model_version.s,"v1.4"); - $withTexture := widgets.texture.b or widgets.pbr.b; - $isHdTexture := (widgets.texture_quality.s = "detailed"); - $isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); + $isV14 := $contains(widgets.model_version,"v1.4"); + $withTexture := widgets.texture or widgets.pbr; + $isHdTexture := (widgets.texture_quality = "detailed"); + $isDetailedGeometry := (widgets.geometry_quality = "detailed"); $baseCredits := $isV14 ? 30 : ($withTexture ? 30 : 20); $credits := $baseCredits - + (widgets.quad.b ? 5 : 0) + + (widgets.quad ? 5 : 0) + ($isHdTexture ? 10 : 0) + ($isDetailedGeometry ? 20 : 0); {"type":"usd","usd": $round($credits * 0.01, 2)} @@ -501,7 +501,7 @@ class TripoTextureNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["texture_quality"]), expr=""" ( - $tq := widgets.texture_quality.s; + $tq := widgets.texture_quality; {"type":"usd","usd": ($contains($tq,"detailed") ? 0.2 : 0.1)} ) """, @@ -772,24 +772,24 @@ class TripoConversionNode(IO.ComfyNode): ), expr=""" ( - $face := (widgets.face_limit.n != null) ? widgets.face_limit.n : -1; - $texSize := (widgets.texture_size.n != null) ? widgets.texture_size.n : 4096; - $flatThresh := (widgets.flatten_bottom_threshold.n != null) ? widgets.flatten_bottom_threshold.n : 0; - $scale := (widgets.scale_factor.n != null) ? widgets.scale_factor.n : 1; - $texFmt := (widgets.texture_format.s != "" ? widgets.texture_format.s : "jpeg"); - $part := widgets.part_names.s; - $fbx := (widgets.fbx_preset.s != "" ? widgets.fbx_preset.s : "blender"); - $orient := (widgets.export_orientation.s != "" ? widgets.export_orientation.s : "default"); + $face := (widgets.face_limit != null) ? widgets.face_limit : -1; + $texSize := (widgets.texture_size != null) ? widgets.texture_size : 4096; + $flatThresh := (widgets.flatten_bottom_threshold != null) ? widgets.flatten_bottom_threshold : 0; + $scale := (widgets.scale_factor != null) ? widgets.scale_factor : 1; + $texFmt := (widgets.texture_format != "" ? widgets.texture_format : "jpeg"); + $part := widgets.part_names; + $fbx := (widgets.fbx_preset != "" ? widgets.fbx_preset : "blender"); + $orient := (widgets.export_orientation != "" ? widgets.export_orientation : "default"); $advanced := - widgets.quad.b or - widgets.force_symmetry.b or - widgets.flatten_bottom.b or - widgets.pivot_to_center_bottom.b or - widgets.with_animation.b or - widgets.pack_uv.b or - widgets.bake.b or - widgets.export_vertex_colors.b or - widgets.animate_in_place.b or + widgets.quad or + widgets.force_symmetry or + widgets.flatten_bottom or + widgets.pivot_to_center_bottom or + widgets.with_animation or + widgets.pack_uv or + widgets.bake or + widgets.export_vertex_colors or + widgets.animate_in_place or ($face != -1) or ($texSize != 4096) or ($flatThresh != 0) or diff --git a/comfy_api_nodes/nodes_veo2.py b/comfy_api_nodes/nodes_veo2.py index 2b4d61b81..c14d6ad68 100644 --- a/comfy_api_nodes/nodes_veo2.py +++ b/comfy_api_nodes/nodes_veo2.py @@ -124,7 +124,7 @@ class VeoVideoGenerationNode(IO.ComfyNode): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds"]), - expr="""{"type":"usd","usd": 0.5 * widgets.duration_seconds.n}""", + expr="""{"type":"usd","usd": 0.5 * widgets.duration_seconds}""", ), ) @@ -355,8 +355,8 @@ class Veo3VideoGenerationNode(VeoVideoGenerationNode): depends_on=IO.PriceBadgeDepends(widgets=["model", "generate_audio"]), expr=""" ( - $m := widgets.model.s; - $a := widgets.generate_audio.b; + $m := widgets.model; + $a := widgets.generate_audio; ($contains($m,"veo-3.0-fast-generate-001") or $contains($m,"veo-3.1-fast-generate")) ? {"type":"usd","usd": ($a ? 1.2 : 0.8)} : ($contains($m,"veo-3.0-generate-001") or $contains($m,"veo-3.1-generate")) @@ -446,9 +446,9 @@ class Veo3FirstLastFrameNode(IO.ComfyNode): "veo-3.1-fast-generate": { "audio": 0.15, "no_audio": 0.10 }, "veo-3.1-generate": { "audio": 0.40, "no_audio": 0.20 } }; - $m := widgets.model.s; - $ga := (widgets.generate_audio.s = "true"); - $seconds := widgets.duration.n; + $m := widgets.model; + $ga := (widgets.generate_audio = "true"); + $seconds := widgets.duration; $modelKey := $contains($m, "veo-3.1-fast-generate") ? "veo-3.1-fast-generate" : $contains($m, "veo-3.1-generate") ? "veo-3.1-generate" : diff --git a/comfy_api_nodes/nodes_wan.py b/comfy_api_nodes/nodes_wan.py index 47406818d..52129ec6d 100644 --- a/comfy_api_nodes/nodes_wan.py +++ b/comfy_api_nodes/nodes_wan.py @@ -531,9 +531,9 @@ class WanTextToVideoApi(IO.ComfyNode): expr=""" ( $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; - $resKey := $substringBefore(widgets.size.s, ":"); + $resKey := $substringBefore(widgets.size, ":"); $pps := $lookup($ppsTable, $resKey); - { "type": "usd", "usd": $round($pps * widgets.duration.n, 2) } + { "type": "usd", "usd": $round($pps * widgets.duration, 2) } ) """, ), @@ -703,8 +703,8 @@ class WanImageToVideoApi(IO.ComfyNode): expr=""" ( $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; - $pps := $lookup($ppsTable, widgets.resolution.s); - { "type": "usd", "usd": $round($pps * widgets.duration.n, 2) } + $pps := $lookup($ppsTable, widgets.resolution); + { "type": "usd", "usd": $round($pps * widgets.duration, 2) } ) """, ), From 1cd88a03dde473e4f9039fa00489a5d43ea2b013 Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Wed, 7 Jan 2026 10:21:23 +0200 Subject: [PATCH 08/10] add price badge for WanReferenceVideoApi node --- comfy_api_nodes/nodes_wan.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/comfy_api_nodes/nodes_wan.py b/comfy_api_nodes/nodes_wan.py index 52129ec6d..a1355d4f1 100644 --- a/comfy_api_nodes/nodes_wan.py +++ b/comfy_api_nodes/nodes_wan.py @@ -855,6 +855,22 @@ class WanReferenceVideoApi(IO.ComfyNode): IO.Hidden.unique_id, ], is_api_node=True, + price_badge=IO.PriceBadge( + depends_on=IO.PriceBadgeDepends(widgets=["size", "duration"]), + expr=""" + ( + $rate := $contains(widgets.size, "1080p") ? 0.15 : 0.10; + $inputMin := 2 * $rate; + $inputMax := 5 * $rate; + $outputPrice := widgets.duration * $rate; + { + "type": "range_usd", + "min_usd": $inputMin + $outputPrice, + "max_usd": $inputMax + $outputPrice + } + ) + """, + ), ) @classmethod From 759fe56500de12bc3674f1a3c49a725df5a6e6c2 Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Wed, 7 Jan 2026 12:46:57 +0200 Subject: [PATCH 09/10] add support for DynamicCombo --- comfy_api/latest/_io.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/comfy_api/latest/_io.py b/comfy_api/latest/_io.py index f925cf7b4..93fcbafa4 100644 --- a/comfy_api/latest/_io.py +++ b/comfy_api/latest/_io.py @@ -1250,7 +1250,13 @@ class PriceBadgeDepends: # Build lookup: widget_id -> io_type input_types: dict[str, str] = {} for inp in schema_inputs: - input_types[inp.id] = inp.get_io_type() + all_inputs = inp.get_all() + input_types[inp.id] = inp.get_io_type() # First input is always the parent itself + for nested_inp in all_inputs[1:]: + # For DynamicCombo/DynamicSlot, nested inputs are prefixed with parent ID + # to match frontend naming convention (e.g., "should_texture.enable_pbr") + prefixed_id = f"{inp.id}.{nested_inp.id}" + input_types[prefixed_id] = nested_inp.get_io_type() # Enrich widgets with type information, raising error for unknown widgets widgets_data: list[dict[str, str]] = [] From 292d44f9f911b257b0c12706915e96c975e8bc5f Mon Sep 17 00:00:00 2001 From: bigcat88 Date: Thu, 8 Jan 2026 09:57:28 +0200 Subject: [PATCH 10/10] sync price badges changes (https://github.com/Comfy-Org/ComfyUI_frontend/pull/7900) --- comfy_api_nodes/nodes_gemini.py | 24 +++++++---- comfy_api_nodes/nodes_openai.py | 75 +++++++++++++++++++++++++++------ 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/comfy_api_nodes/nodes_gemini.py b/comfy_api_nodes/nodes_gemini.py index 0ca623ee9..30fe68b06 100644 --- a/comfy_api_nodes/nodes_gemini.py +++ b/comfy_api_nodes/nodes_gemini.py @@ -314,14 +314,22 @@ class GeminiNode(IO.ComfyNode): expr=""" ( $m := widgets.model; - - $contains($m, "gemini-2.5-flash") - ? {"type":"list_usd","usd":[0.0003,0.0025]} - : $contains($m, "gemini-2.5-pro") - ? {"type":"list_usd","usd":[0.00125,0.01]} - : $contains($m, "gemini-3-pro-preview") - ? {"type":"list_usd","usd":[0.002,0.012]} - : {"type":"text","text":"Token-based"} + $contains($m, "gemini-2.5-flash") ? { + "type": "list_usd", + "usd": [0.0003, 0.0025], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens"} + } + : $contains($m, "gemini-2.5-pro") ? { + "type": "list_usd", + "usd": [0.00125, 0.01], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gemini-3-pro-preview") ? { + "type": "list_usd", + "usd": [0.002, 0.012], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : {"type":"text", "text":"Token-based"} ) """, ), diff --git a/comfy_api_nodes/nodes_openai.py b/comfy_api_nodes/nodes_openai.py index 0d0305e34..2f144c5c3 100644 --- a/comfy_api_nodes/nodes_openai.py +++ b/comfy_api_nodes/nodes_openai.py @@ -629,20 +629,67 @@ class OpenAIChatNode(IO.ComfyNode): expr=""" ( $m := widgets.model; - - $contains($m,"o4-mini") ? {"type":"list_usd","usd":[0.0011,0.0044]} : - $contains($m,"o1-pro") ? {"type":"list_usd","usd":[0.15,0.6]} : - $contains($m,"o1") ? {"type":"list_usd","usd":[0.015,0.06]} : - $contains($m,"o3-mini") ? {"type":"list_usd","usd":[0.0011,0.0044]} : - $contains($m,"o3") ? {"type":"list_usd","usd":[0.01,0.04]} : - $contains($m,"gpt-4o") ? {"type":"list_usd","usd":[0.0025,0.01]} : - $contains($m,"gpt-4.1-nano") ? {"type":"list_usd","usd":[0.0001,0.0004]} : - $contains($m,"gpt-4.1-mini") ? {"type":"list_usd","usd":[0.0004,0.0016]} : - $contains($m,"gpt-4.1") ? {"type":"list_usd","usd":[0.002,0.008]} : - $contains($m,"gpt-5-nano") ? {"type":"list_usd","usd":[0.00005,0.0004]} : - $contains($m,"gpt-5-mini") ? {"type":"list_usd","usd":[0.00025,0.002]} : - $contains($m,"gpt-5") ? {"type":"list_usd","usd":[0.00125,0.01]} : - {"type":"text","text":"Token-based"} + $contains($m, "o4-mini") ? { + "type": "list_usd", + "usd": [0.0011, 0.0044], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "o1-pro") ? { + "type": "list_usd", + "usd": [0.15, 0.6], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "o1") ? { + "type": "list_usd", + "usd": [0.015, 0.06], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "o3-mini") ? { + "type": "list_usd", + "usd": [0.0011, 0.0044], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "o3") ? { + "type": "list_usd", + "usd": [0.01, 0.04], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gpt-4o") ? { + "type": "list_usd", + "usd": [0.0025, 0.01], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gpt-4.1-nano") ? { + "type": "list_usd", + "usd": [0.0001, 0.0004], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gpt-4.1-mini") ? { + "type": "list_usd", + "usd": [0.0004, 0.0016], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gpt-4.1") ? { + "type": "list_usd", + "usd": [0.002, 0.008], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gpt-5-nano") ? { + "type": "list_usd", + "usd": [0.00005, 0.0004], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gpt-5-mini") ? { + "type": "list_usd", + "usd": [0.00025, 0.002], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : $contains($m, "gpt-5") ? { + "type": "list_usd", + "usd": [0.00125, 0.01], + "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" } + } + : {"type": "text", "text": "Token-based"} ) """, ),