add strict typing for JSONata rules

This commit is contained in:
bigcat88 2026-01-06 18:30:35 +02:00
parent dffc081bc8
commit 5b93e7ec9f
No known key found for this signature in database
GPG Key ID: 1F0BF0EC3CF22721
19 changed files with 144 additions and 144 deletions

View File

@ -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): 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].") 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 { return {
"widgets": self.widgets, "widgets": widgets_data,
"inputs": self.inputs, "inputs": self.inputs,
"input_groups": self.input_groups, "input_groups": self.input_groups,
} }
@ -1267,10 +1282,10 @@ class PriceBadge:
raise ValueError("PriceBadge.expr must be a non-empty string.") raise ValueError("PriceBadge.expr must be a non-empty string.")
self.depends_on.validate() self.depends_on.validate()
def as_dict(self) -> dict[str, Any]: def as_dict(self, schema_inputs: list["Input"]) -> dict[str, Any]:
return { return {
"engine": self.engine, "engine": self.engine,
"depends_on": self.depends_on.as_dict(), "depends_on": self.depends_on.as_dict(schema_inputs),
"expr": self.expr, "expr": self.expr,
} }
@ -1426,7 +1441,7 @@ class Schema:
experimental=self.is_experimental, experimental=self.is_experimental,
api_node=self.is_api_node, 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, price_badge=self.price_badge.as_dict(self.inputs) if self.price_badge is not None else None,
) )
return info return info
@ -1459,7 +1474,7 @@ class Schema:
experimental=self.is_experimental, experimental=self.is_experimental,
api_node=self.is_api_node, 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, price_badge=self.price_badge.as_dict(self.inputs) if self.price_badge is not None else None,
) )
return info return info

View File

@ -523,7 +523,7 @@ class Flux2ProImageNode(IO.ComfyNode):
PRICE_BADGE_EXPR = """ PRICE_BADGE_EXPR = """
( (
$MP := 1024 * 1024; $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); $outputCost := 0.03 + 0.015 * ($outMP - 1);
inputs.images.connected inputs.images.connected
? { ? {
@ -654,7 +654,7 @@ class Flux2MaxImageNode(Flux2ProImageNode):
PRICE_BADGE_EXPR = """ PRICE_BADGE_EXPR = """
( (
$MP := 1024 * 1024; $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); $outputCost := 0.07 + 0.03 * ($outMP - 1);
inputs.images.connected inputs.images.connected

View File

@ -374,7 +374,7 @@ class ByteDanceSeedreamNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model"]), depends_on=IO.PriceBadgeDepends(widgets=["model"]),
expr=""" 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", "type":"usd",
"usd": $price, "usd": $price,
@ -987,12 +987,12 @@ PRICE_BADGE_VIDEO = IO.PriceBadge(
"1080p":[0.85,0.88] "1080p":[0.85,0.88]
} }
}; };
$model := widgets.model.s; $model := widgets.model;
$modelKey := $modelKey :=
$contains($model, "seedance-1-0-pro-fast") ? "seedance-1-0-pro-fast" : $contains($model, "seedance-1-0-pro-fast") ? "seedance-1-0-pro-fast" :
$contains($model, "seedance-1-0-pro") ? "seedance-1-0-pro" : $contains($model, "seedance-1-0-pro") ? "seedance-1-0-pro" :
"seedance-1-0-lite"; "seedance-1-0-lite";
$resolution := widgets.resolution.s; $resolution := widgets.resolution;
$resKey := $resKey :=
$contains($resolution, "1080") ? "1080p" : $contains($resolution, "1080") ? "1080p" :
$contains($resolution, "720") ? "720p" : $contains($resolution, "720") ? "720p" :
@ -1001,7 +1001,7 @@ PRICE_BADGE_VIDEO = IO.PriceBadge(
$baseRange := $lookup($modelPrices, $resKey); $baseRange := $lookup($modelPrices, $resKey);
$min10s := $baseRange[0]; $min10s := $baseRange[0];
$max10s := $baseRange[1]; $max10s := $baseRange[1];
$scale := widgets.duration.n / 10; $scale := widgets.duration / 10;
$minCost := $min10s * $scale; $minCost := $min10s * $scale;
$maxCost := $max10s * $scale; $maxCost := $max10s * $scale;
($minCost = $maxCost) ($minCost = $maxCost)

View File

@ -313,7 +313,7 @@ class GeminiNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model"]), depends_on=IO.PriceBadgeDepends(widgets=["model"]),
expr=""" expr="""
( (
$m := widgets.model.s; $m := widgets.model;
$contains($m, "gemini-2.5-flash") $contains($m, "gemini-2.5-flash")
? {"type":"list_usd","usd":[0.0003,0.0025]} ? {"type":"list_usd","usd":[0.0003,0.0025]}
@ -723,7 +723,7 @@ class GeminiImage2(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["resolution"]), depends_on=IO.PriceBadgeDepends(widgets=["resolution"]),
expr=""" expr="""
( (
$r := widgets.resolution.s; $r := widgets.resolution;
($contains($r,"1k") or $contains($r,"2k")) ($contains($r,"1k") or $contains($r,"2k"))
? {"type":"usd","usd":0.134,"format":{"suffix":"/Image","approximate":true}} ? {"type":"usd","usd":0.134,"format":{"suffix":"/Image","approximate":true}}
: $contains($r,"4k") : $contains($r,"4k")

View File

@ -302,8 +302,8 @@ class IdeogramV1(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]),
expr=""" expr="""
( (
$n := widgets.num_images.n; $n := widgets.num_images;
$base := (widgets.turbo.b = true) ? 0.0286 : 0.0858; $base := (widgets.turbo = true) ? 0.0286 : 0.0858;
{"type":"usd","usd": $round($base * $n, 2)} {"type":"usd","usd": $round($base * $n, 2)}
) )
""", """,
@ -450,8 +450,8 @@ class IdeogramV2(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]), depends_on=IO.PriceBadgeDepends(widgets=["num_images", "turbo"]),
expr=""" expr="""
( (
$n := widgets.num_images.n; $n := widgets.num_images;
$base := (widgets.turbo.b = true) ? 0.0715 : 0.1144; $base := (widgets.turbo = true) ? 0.0715 : 0.1144;
{"type":"usd","usd": $round($base * $n, 2)} {"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"]), depends_on=IO.PriceBadgeDepends(widgets=["rendering_speed", "num_images"], inputs=["character_image"]),
expr=""" expr="""
( (
$n := widgets.num_images.n; $n := widgets.num_images;
$speed := widgets.rendering_speed.s; $speed := widgets.rendering_speed;
$hasChar := inputs.character_image.connected; $hasChar := inputs.character_image.connected;
$base := $base :=
$contains($speed,"quality") ? ($hasChar ? 0.286 : 0.1287) : $contains($speed,"quality") ? ($hasChar ? 0.286 : 0.1287) :

View File

@ -768,7 +768,7 @@ class KlingTextToVideoNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["mode"]), depends_on=IO.PriceBadgeDepends(widgets=["mode"]),
expr=""" expr="""
( (
$m := widgets.mode.s; $m := widgets.mode;
$contains($m,"v2-5-turbo") $contains($m,"v2-5-turbo")
? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35})
: $contains($m,"v2-1-master") : $contains($m,"v2-1-master")
@ -849,9 +849,9 @@ class OmniProTextToVideoNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]), depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]),
expr=""" expr="""
( (
$mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $mode := (widgets.resolution = "720p") ? "std" : "pro";
$rates := {"std": 0.084, "pro": 0.112}; $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"]), depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]),
expr=""" expr="""
( (
$mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $mode := (widgets.resolution = "720p") ? "std" : "pro";
$rates := {"std": 0.084, "pro": 0.112}; $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"]), depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]),
expr=""" expr="""
( (
$mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $mode := (widgets.resolution = "720p") ? "std" : "pro";
$rates := {"std": 0.084, "pro": 0.112}; $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"]), depends_on=IO.PriceBadgeDepends(widgets=["duration", "resolution"]),
expr=""" expr="""
( (
$mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $mode := (widgets.resolution = "720p") ? "std" : "pro";
$rates := {"std": 0.126, "pro": 0.168}; $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"]), depends_on=IO.PriceBadgeDepends(widgets=["resolution"]),
expr=""" expr="""
( (
$mode := (widgets.resolution.s = "720p") ? "std" : "pro"; $mode := (widgets.resolution = "720p") ? "std" : "pro";
$rates := {"std": 0.126, "pro": 0.168}; $rates := {"std": 0.126, "pro": 0.168};
{"type":"usd","usd": $lookup($rates, $mode), "format":{"suffix":"/second"}} {"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"]), depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]),
expr=""" expr="""
( (
$mode := widgets.mode.s; $mode := widgets.mode;
$model := widgets.model_name.s; $model := widgets.model_name;
$dur := widgets.duration.s; $dur := widgets.duration;
$contains($model,"v2-5-turbo") $contains($model,"v2-5-turbo")
? ($contains($dur,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) ? ($contains($dur,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35})
: ($contains($model,"v2-1-master") or $contains($model,"v2-master")) : ($contains($model,"v2-1-master") or $contains($model,"v2-master"))
@ -1635,7 +1635,7 @@ class KlingStartEndFrameNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["mode"]), depends_on=IO.PriceBadgeDepends(widgets=["mode"]),
expr=""" expr="""
( (
$m := widgets.mode.s; $m := widgets.mode;
$contains($m,"v2-5-turbo") $contains($m,"v2-5-turbo")
? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35}) ? ($contains($m,"10") ? {"type":"usd","usd":0.7} : {"type":"usd","usd":0.35})
: $contains($m,"v2-1") : $contains($m,"v2-1")
@ -1811,9 +1811,9 @@ class KlingDualCharacterVideoEffectNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]), depends_on=IO.PriceBadgeDepends(widgets=["mode", "model_name", "duration"]),
expr=""" expr="""
( (
$mode := widgets.mode.s; $mode := widgets.mode;
$model := widgets.model_name.s; $model := widgets.model_name;
$dur := widgets.duration.s; $dur := widgets.duration;
($contains($model,"v1-6") or $contains($model,"v1-5")) ($contains($model,"v1-6") or $contains($model,"v1-5"))
? ( ? (
$contains($mode,"pro") $contains($mode,"pro")
@ -1898,7 +1898,7 @@ class KlingSingleImageVideoEffectNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["effect_scene"]), depends_on=IO.PriceBadgeDepends(widgets=["effect_scene"]),
expr=""" 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.49}
: {"type":"usd","usd":0.28} : {"type":"usd","usd":0.28}
) )
@ -2180,12 +2180,12 @@ class KlingImageGenerationNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model_name", "n"], inputs=["image"]), depends_on=IO.PriceBadgeDepends(widgets=["model_name", "n"], inputs=["image"]),
expr=""" expr="""
( (
$m := widgets.model_name.s; $m := widgets.model_name;
$base := $base :=
$contains($m,"kling-v1-5") $contains($m,"kling-v1-5")
? (inputs.image.connected ? 0.028 : 0.014) ? (inputs.image.connected ? 0.028 : 0.014)
: ($contains($m,"kling-v1") ? 0.0035 : 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["duration", "generate_audio"]), 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=""" expr="""
( (
$prices := {"std": 0.07, "pro": 0.112}; $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"}}
) )
""", """,
), ),

View File

@ -35,9 +35,9 @@ PRICE_BADGE = IO.PriceBadge(
$pps := { $pps := {
"ltx-2 (pro)": {"1920x1080":0.06,"2560x1440":0.12,"3840x2160":0.24}, "ltx-2 (pro)": {"1920x1080":0.06,"2560x1440":0.12,"3840x2160":0.24},
"ltx-2 (fast)": {"1920x1080":0.04,"2560x1440":0.08,"3840x2160":0.16} "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}
) )
""", """,
) )

View File

@ -193,7 +193,7 @@ class LumaImageGenerationNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model"]), depends_on=IO.PriceBadgeDepends(widgets=["model"]),
expr=""" expr="""
( (
$m := widgets.model.s; $m := widgets.model;
$contains($m,"photon-flash-1") $contains($m,"photon-flash-1")
? {"type":"usd","usd":0.0027} ? {"type":"usd","usd":0.0027}
: $contains($m,"photon-1") : $contains($m,"photon-1")
@ -320,7 +320,7 @@ class LumaImageModifyNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model"]), depends_on=IO.PriceBadgeDepends(widgets=["model"]),
expr=""" expr="""
( (
$m := widgets.model.s; $m := widgets.model;
$contains($m,"photon-flash-1") $contains($m,"photon-flash-1")
? {"type":"usd","usd":0.0027} ? {"type":"usd","usd":0.0027}
: $contains($m,"photon-1") : $contains($m,"photon-1")
@ -612,9 +612,9 @@ PRICE_BADGE_VIDEO = IO.PriceBadge(
} }
}; };
$m := widgets.model.s; $m := widgets.model;
$d := widgets.duration.s; $d := widgets.duration;
$r := widgets.resolution.s; $r := widgets.resolution;
$modelKey := $modelKey :=
$contains($m,"ray-flash-2") ? "ray-flash-2" : $contains($m,"ray-flash-2") ? "ray-flash-2" :

View File

@ -350,8 +350,8 @@ class MinimaxHailuoVideoNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["resolution", "duration"]), depends_on=IO.PriceBadgeDepends(widgets=["resolution", "duration"]),
expr=""" expr="""
( (
$r := widgets.resolution.s; $r := widgets.resolution;
$d := widgets.duration.s; $d := widgets.duration;
$price := $price :=
$contains($r,"768p") $contains($r,"768p")

View File

@ -234,14 +234,9 @@ class MoonvalleyImg2VideoNode(IO.ComfyNode):
], ],
is_api_node=True, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["length"]), depends_on=IO.PriceBadgeDepends(),
expr=""" expr="""{"type":"usd","usd": 1.5}""",
( ),
$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
) )
@classmethod @classmethod
@ -361,14 +356,9 @@ class MoonvalleyVideo2VideoNode(IO.ComfyNode):
], ],
is_api_node=True, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["length"]), depends_on=IO.PriceBadgeDepends(),
expr=""" expr="""{"type":"usd","usd": 2.25}""",
( ),
$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
) )
@classmethod @classmethod
@ -490,14 +480,9 @@ class MoonvalleyTxt2VideoNode(IO.ComfyNode):
], ],
is_api_node=True, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["length"]), depends_on=IO.PriceBadgeDepends(),
expr=""" expr="""{"type":"usd","usd": 1.5}""",
( ),
$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
) )
@classmethod @classmethod

View File

@ -164,8 +164,8 @@ class OpenAIDalle2(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["size", "n"]), depends_on=IO.PriceBadgeDepends(widgets=["size", "n"]),
expr=""" expr="""
( (
$size := widgets.size.s; $size := widgets.size;
$nRaw := widgets.n.n; $nRaw := widgets.n;
$n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1; $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;
$base := $base :=
@ -308,8 +308,8 @@ class OpenAIDalle3(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["size", "quality"]), depends_on=IO.PriceBadgeDepends(widgets=["size", "quality"]),
expr=""" expr="""
( (
$size := widgets.size.s; $size := widgets.size;
$q := widgets.quality.s; $q := widgets.quality;
$hd := $contains($q, "hd"); $hd := $contains($q, "hd");
$price := $price :=
@ -456,8 +456,8 @@ class OpenAIGPTImage1(IO.ComfyNode):
"medium": [0.046, 0.07], "medium": [0.046, 0.07],
"high": [0.167, 0.3] "high": [0.167, 0.3]
}; };
$range := $lookup($ranges, widgets.quality.s); $range := $lookup($ranges, widgets.quality);
$n := widgets.n.n; $n := widgets.n;
($n = 1) ($n = 1)
? {"type":"range_usd","min_usd": $range[0], "max_usd": $range[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"]), depends_on=IO.PriceBadgeDepends(widgets=["model"]),
expr=""" expr="""
( (
$m := widgets.model.s; $m := widgets.model;
$contains($m,"o4-mini") ? {"type":"list_usd","usd":[0.0011,0.0044]} : $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-pro") ? {"type":"list_usd","usd":[0.15,0.6]} :

View File

@ -423,9 +423,9 @@ PRICE_BADGE_VIDEO = IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds", "quality", "motion_mode"]), depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds", "quality", "motion_mode"]),
expr=""" expr="""
( (
$d := widgets.duration_seconds.s; $d := widgets.duration_seconds;
$q := widgets.quality.s; $q := widgets.quality;
$m := widgets.motion_mode.s; $m := widgets.motion_mode;
$price := $price :=
$contains($d,"5") $contains($d,"5")

View File

@ -380,7 +380,7 @@ class RecraftTextToImageNode(IO.ComfyNode):
is_api_node=True, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["n"]), 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["n"]), 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["n"]), 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["n"]), 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["n"]), depends_on=IO.PriceBadgeDepends(),
expr="""{"type":"usd","usd": $round(0.01 * widgets.n.n, 2)}""", expr="""{"type":"usd","usd": 0.01}""",
), ),
) )

View File

@ -186,7 +186,7 @@ class RunwayImageToVideoNodeGen3a(IO.ComfyNode):
is_api_node=True, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["duration"]), 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["duration"]), 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, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["duration"]), depends_on=IO.PriceBadgeDepends(widgets=["duration"]),
expr="""{"type":"usd","usd": 0.0715 * widgets.duration.n}""", expr="""{"type":"usd","usd": 0.0715 * widgets.duration}""",
), ),
) )

View File

@ -93,9 +93,9 @@ class OpenAIVideoSora2(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model", "size", "duration"]), depends_on=IO.PriceBadgeDepends(widgets=["model", "size", "duration"]),
expr=""" expr="""
( (
$m := widgets.model.s; $m := widgets.model;
$size := widgets.size.s; $size := widgets.size;
$dur := widgets.duration.n; $dur := widgets.duration;
$isPro := $contains($m, "sora-2-pro"); $isPro := $contains($m, "sora-2-pro");
$isSora2 := $contains($m, "sora-2"); $isSora2 := $contains($m, "sora-2");
$isProSize := ($size = "1024x1792" or $size = "1792x1024"); $isProSize := ($size = "1024x1792" or $size = "1792x1024");

View File

@ -271,7 +271,7 @@ class StabilityStableImageSD_3_5Node(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model"]), depends_on=IO.PriceBadgeDepends(widgets=["model"]),
expr=""" expr="""
( (
$contains(widgets.model.s,"large") $contains(widgets.model,"large")
? {"type":"usd","usd":0.065} ? {"type":"usd","usd":0.065}
: {"type":"usd","usd":0.035} : {"type":"usd","usd":0.035}
) )

View File

@ -131,18 +131,18 @@ class TripoTextToModelNode(IO.ComfyNode):
), ),
expr=""" expr="""
( (
$isV14 := $contains(widgets.model_version.s,"v1.4"); $isV14 := $contains(widgets.model_version,"v1.4");
$style := widgets.style.s; $style := widgets.style;
$hasStyle := ($style != "" and $style != "none"); $hasStyle := ($style != "" and $style != "none");
$withTexture := widgets.texture.b or widgets.pbr.b; $withTexture := widgets.texture or widgets.pbr;
$isHdTexture := (widgets.texture_quality.s = "detailed"); $isHdTexture := (widgets.texture_quality = "detailed");
$isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); $isDetailedGeometry := (widgets.geometry_quality = "detailed");
$baseCredits := $baseCredits :=
$isV14 ? 20 : ($withTexture ? 20 : 10); $isV14 ? 20 : ($withTexture ? 20 : 10);
$credits := $credits :=
$baseCredits $baseCredits
+ ($hasStyle ? 5 : 0) + ($hasStyle ? 5 : 0)
+ (widgets.quad.b ? 5 : 0) + (widgets.quad ? 5 : 0)
+ ($isHdTexture ? 10 : 0) + ($isHdTexture ? 10 : 0)
+ ($isDetailedGeometry ? 20 : 0); + ($isDetailedGeometry ? 20 : 0);
{"type":"usd","usd": $round($credits * 0.01, 2)} {"type":"usd","usd": $round($credits * 0.01, 2)}
@ -256,18 +256,18 @@ class TripoImageToModelNode(IO.ComfyNode):
), ),
expr=""" expr="""
( (
$isV14 := $contains(widgets.model_version.s,"v1.4"); $isV14 := $contains(widgets.model_version,"v1.4");
$style := widgets.style.s; $style := widgets.style;
$hasStyle := ($style != "" and $style != "none"); $hasStyle := ($style != "" and $style != "none");
$withTexture := widgets.texture.b or widgets.pbr.b; $withTexture := widgets.texture or widgets.pbr;
$isHdTexture := (widgets.texture_quality.s = "detailed"); $isHdTexture := (widgets.texture_quality = "detailed");
$isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); $isDetailedGeometry := (widgets.geometry_quality = "detailed");
$baseCredits := $baseCredits :=
$isV14 ? 30 : ($withTexture ? 30 : 20); $isV14 ? 30 : ($withTexture ? 30 : 20);
$credits := $credits :=
$baseCredits $baseCredits
+ ($hasStyle ? 5 : 0) + ($hasStyle ? 5 : 0)
+ (widgets.quad.b ? 5 : 0) + (widgets.quad ? 5 : 0)
+ ($isHdTexture ? 10 : 0) + ($isHdTexture ? 10 : 0)
+ ($isDetailedGeometry ? 20 : 0); + ($isDetailedGeometry ? 20 : 0);
{"type":"usd","usd": $round($credits * 0.01, 2)} {"type":"usd","usd": $round($credits * 0.01, 2)}
@ -391,15 +391,15 @@ class TripoMultiviewToModelNode(IO.ComfyNode):
), ),
expr=""" expr="""
( (
$isV14 := $contains(widgets.model_version.s,"v1.4"); $isV14 := $contains(widgets.model_version,"v1.4");
$withTexture := widgets.texture.b or widgets.pbr.b; $withTexture := widgets.texture or widgets.pbr;
$isHdTexture := (widgets.texture_quality.s = "detailed"); $isHdTexture := (widgets.texture_quality = "detailed");
$isDetailedGeometry := (widgets.geometry_quality.s = "detailed"); $isDetailedGeometry := (widgets.geometry_quality = "detailed");
$baseCredits := $baseCredits :=
$isV14 ? 30 : ($withTexture ? 30 : 20); $isV14 ? 30 : ($withTexture ? 30 : 20);
$credits := $credits :=
$baseCredits $baseCredits
+ (widgets.quad.b ? 5 : 0) + (widgets.quad ? 5 : 0)
+ ($isHdTexture ? 10 : 0) + ($isHdTexture ? 10 : 0)
+ ($isDetailedGeometry ? 20 : 0); + ($isDetailedGeometry ? 20 : 0);
{"type":"usd","usd": $round($credits * 0.01, 2)} {"type":"usd","usd": $round($credits * 0.01, 2)}
@ -501,7 +501,7 @@ class TripoTextureNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["texture_quality"]), depends_on=IO.PriceBadgeDepends(widgets=["texture_quality"]),
expr=""" expr="""
( (
$tq := widgets.texture_quality.s; $tq := widgets.texture_quality;
{"type":"usd","usd": ($contains($tq,"detailed") ? 0.2 : 0.1)} {"type":"usd","usd": ($contains($tq,"detailed") ? 0.2 : 0.1)}
) )
""", """,
@ -772,24 +772,24 @@ class TripoConversionNode(IO.ComfyNode):
), ),
expr=""" expr="""
( (
$face := (widgets.face_limit.n != null) ? widgets.face_limit.n : -1; $face := (widgets.face_limit != null) ? widgets.face_limit : -1;
$texSize := (widgets.texture_size.n != null) ? widgets.texture_size.n : 4096; $texSize := (widgets.texture_size != null) ? widgets.texture_size : 4096;
$flatThresh := (widgets.flatten_bottom_threshold.n != null) ? widgets.flatten_bottom_threshold.n : 0; $flatThresh := (widgets.flatten_bottom_threshold != null) ? widgets.flatten_bottom_threshold : 0;
$scale := (widgets.scale_factor.n != null) ? widgets.scale_factor.n : 1; $scale := (widgets.scale_factor != null) ? widgets.scale_factor : 1;
$texFmt := (widgets.texture_format.s != "" ? widgets.texture_format.s : "jpeg"); $texFmt := (widgets.texture_format != "" ? widgets.texture_format : "jpeg");
$part := widgets.part_names.s; $part := widgets.part_names;
$fbx := (widgets.fbx_preset.s != "" ? widgets.fbx_preset.s : "blender"); $fbx := (widgets.fbx_preset != "" ? widgets.fbx_preset : "blender");
$orient := (widgets.export_orientation.s != "" ? widgets.export_orientation.s : "default"); $orient := (widgets.export_orientation != "" ? widgets.export_orientation : "default");
$advanced := $advanced :=
widgets.quad.b or widgets.quad or
widgets.force_symmetry.b or widgets.force_symmetry or
widgets.flatten_bottom.b or widgets.flatten_bottom or
widgets.pivot_to_center_bottom.b or widgets.pivot_to_center_bottom or
widgets.with_animation.b or widgets.with_animation or
widgets.pack_uv.b or widgets.pack_uv or
widgets.bake.b or widgets.bake or
widgets.export_vertex_colors.b or widgets.export_vertex_colors or
widgets.animate_in_place.b or widgets.animate_in_place or
($face != -1) or ($face != -1) or
($texSize != 4096) or ($texSize != 4096) or
($flatThresh != 0) or ($flatThresh != 0) or

View File

@ -124,7 +124,7 @@ class VeoVideoGenerationNode(IO.ComfyNode):
is_api_node=True, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["duration_seconds"]), 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"]), depends_on=IO.PriceBadgeDepends(widgets=["model", "generate_audio"]),
expr=""" expr="""
( (
$m := widgets.model.s; $m := widgets.model;
$a := widgets.generate_audio.b; $a := widgets.generate_audio;
($contains($m,"veo-3.0-fast-generate-001") or $contains($m,"veo-3.1-fast-generate")) ($contains($m,"veo-3.0-fast-generate-001") or $contains($m,"veo-3.1-fast-generate"))
? {"type":"usd","usd": ($a ? 1.2 : 0.8)} ? {"type":"usd","usd": ($a ? 1.2 : 0.8)}
: ($contains($m,"veo-3.0-generate-001") or $contains($m,"veo-3.1-generate")) : ($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-fast-generate": { "audio": 0.15, "no_audio": 0.10 },
"veo-3.1-generate": { "audio": 0.40, "no_audio": 0.20 } "veo-3.1-generate": { "audio": 0.40, "no_audio": 0.20 }
}; };
$m := widgets.model.s; $m := widgets.model;
$ga := (widgets.generate_audio.s = "true"); $ga := (widgets.generate_audio = "true");
$seconds := widgets.duration.n; $seconds := widgets.duration;
$modelKey := $modelKey :=
$contains($m, "veo-3.1-fast-generate") ? "veo-3.1-fast-generate" : $contains($m, "veo-3.1-fast-generate") ? "veo-3.1-fast-generate" :
$contains($m, "veo-3.1-generate") ? "veo-3.1-generate" : $contains($m, "veo-3.1-generate") ? "veo-3.1-generate" :

View File

@ -531,9 +531,9 @@ class WanTextToVideoApi(IO.ComfyNode):
expr=""" expr="""
( (
$ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 };
$resKey := $substringBefore(widgets.size.s, ":"); $resKey := $substringBefore(widgets.size, ":");
$pps := $lookup($ppsTable, $resKey); $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=""" expr="""
( (
$ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 }; $ppsTable := { "480p": 0.05, "720p": 0.1, "1080p": 0.15 };
$pps := $lookup($ppsTable, widgets.resolution.s); $pps := $lookup($ppsTable, widgets.resolution);
{ "type": "usd", "usd": $round($pps * widgets.duration.n, 2) } { "type": "usd", "usd": $round($pps * widgets.duration, 2) }
) )
""", """,
), ),