add strict typing for JSONata rules

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

View File

@ -1258,9 +1258,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,
}
@ -1279,10 +1294,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,
}
@ -1438,7 +1453,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
@ -1471,7 +1486,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

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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) :

View File

@ -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"}}
)
""",
),

View File

@ -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}
)
""",
)

View File

@ -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" :

View File

@ -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")

View File

@ -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

View File

@ -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]} :

View File

@ -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")

View File

@ -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}""",
),
)

View File

@ -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}""",
),
)

View File

@ -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");

View File

@ -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}
)

View File

@ -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

View File

@ -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" :

View File

@ -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) }
)
""",
),