Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions comfy_api_nodes/apis/bytedance.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,35 +187,6 @@ class SeedanceVirtualLibraryCreateAssetRequest(BaseModel):
asset_type: str | None = Field(None, description="BytePlus asset type. Defaults to Image server-side when omitted.")


# Dollars per 1K tokens, keyed by (model_id, has_video_input, resolution).
SEEDANCE2_PRICE_PER_1K_TOKENS = {
("dreamina-seedance-2-0-260128", False, "480p"): 0.007,
("dreamina-seedance-2-0-260128", True, "480p"): 0.0043,
("dreamina-seedance-2-0-260128", False, "720p"): 0.007,
("dreamina-seedance-2-0-260128", True, "720p"): 0.0043,
("dreamina-seedance-2-0-260128", False, "1080p"): 0.0077,
("dreamina-seedance-2-0-260128", True, "1080p"): 0.0047,
("dreamina-seedance-2-0-260128", False, "4k"): 0.004,
("dreamina-seedance-2-0-260128", True, "4k"): 0.0024,
("dreamina-seedance-2-0-fast-260128", False, "480p"): 0.0056,
("dreamina-seedance-2-0-fast-260128", True, "480p"): 0.0033,
("dreamina-seedance-2-0-fast-260128", False, "720p"): 0.0056,
("dreamina-seedance-2-0-fast-260128", True, "720p"): 0.0033,
("dreamina-seedance-2-0-mini", False, "480p"): 0.0035,
("dreamina-seedance-2-0-mini", True, "480p"): 0.0021,
("dreamina-seedance-2-0-mini", False, "720p"): 0.0035,
("dreamina-seedance-2-0-mini", True, "720p"): 0.0021,
("dreamina-seedance-2-5-260628", False, "480p"): 0.0107,
("dreamina-seedance-2-5-260628", True, "480p"): 0.0064,
("dreamina-seedance-2-5-260628", False, "720p"): 0.0107,
("dreamina-seedance-2-5-260628", True, "720p"): 0.0064,
}


def seedance2_price_per_1k_tokens(model_id: str, has_video_input: bool, resolution: str) -> float | None:
return SEEDANCE2_PRICE_PER_1K_TOKENS.get((model_id, has_video_input, resolution))


RECOMMENDED_PRESETS = [
("1024x1024 (1:1)", 1024, 1024),
("864x1152 (3:4)", 864, 1152),
Expand Down
22 changes: 0 additions & 22 deletions comfy_api_nodes/nodes_bfl.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import math

import torch
from pydantic import BaseModel
from typing_extensions import override

from comfy_api.latest import IO, ComfyExtension, Input
Expand Down Expand Up @@ -588,16 +587,12 @@ async def execute(
),
)

def price_extractor(_r: BaseModel) -> float | None:
return None if initial_response.cost is None else initial_response.cost / 100

response = await poll_op(
cls,
ApiEndpoint(initial_response.polling_url),
response_model=BFLFluxStatusResponse,
status_extractor=lambda r: r.status,
progress_extractor=lambda r: r.progress,
price_extractor=price_extractor,
completed_statuses=[BFLStatus.ready],
failed_statuses=[
BFLStatus.request_moderated,
Expand Down Expand Up @@ -669,16 +664,12 @@ async def execute(
),
)

def price_extractor(_r: BaseModel) -> float | None:
return None if initial_response.cost is None else initial_response.cost / 100

response = await poll_op(
cls,
ApiEndpoint(initial_response.polling_url),
response_model=BFLFluxStatusResponse,
status_extractor=lambda r: r.status,
progress_extractor=lambda r: r.progress,
price_extractor=price_extractor,
completed_statuses=[BFLStatus.ready],
failed_statuses=[
BFLStatus.request_moderated,
Expand Down Expand Up @@ -802,16 +793,12 @@ async def execute(
),
)

def price_extractor(_r: BaseModel) -> float | None:
return None if initial_response.cost is None else initial_response.cost / 100

response = await poll_op(
cls,
ApiEndpoint(initial_response.polling_url),
response_model=BFLFluxStatusResponse,
status_extractor=lambda r: r.status,
progress_extractor=lambda r: r.progress,
price_extractor=price_extractor,
completed_statuses=[BFLStatus.ready],
failed_statuses=[
BFLStatus.request_moderated,
Expand Down Expand Up @@ -994,16 +981,12 @@ async def execute(
),
)

def price_extractor(_r: BaseModel) -> float | None:
return None if initial_response.cost is None else initial_response.cost / 100

response = await poll_op(
cls,
ApiEndpoint(initial_response.polling_url),
response_model=BFLFluxStatusResponse,
status_extractor=lambda r: r.status,
progress_extractor=lambda r: r.progress,
price_extractor=price_extractor,
completed_statuses=[BFLStatus.ready],
failed_statuses=[
BFLStatus.request_moderated,
Expand Down Expand Up @@ -1171,17 +1154,12 @@ async def _flux3_execute(cls: type[IO.ComfyNode], request: Flux3VideoRequest) ->
response_model=BFLFluxProGenerateResponse,
data=request,
)

def price_extractor(_r: BaseModel) -> float | None:
return None if initial_response.cost is None else initial_response.cost / 100

response = await poll_op(
cls,
ApiEndpoint(initial_response.polling_url),
response_model=BFLFluxStatusResponse,
status_extractor=lambda r: r.status,
progress_extractor=lambda r: r.progress,
price_extractor=price_extractor,
completed_statuses=[BFLStatus.ready],
failed_statuses=[
BFLStatus.request_moderated,
Expand Down
34 changes: 2 additions & 32 deletions comfy_api_nodes/nodes_bytedance.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
TaskVideoContentUrl,
Text2ImageTaskCreationRequest,
Text2VideoTaskCreationRequest,
seedance2_price_per_1k_tokens,
seedance2_reference_limits,
)
from comfy_api_nodes.util import (
Expand Down Expand Up @@ -408,20 +407,6 @@ async def _seedance_virtual_library_upload_video_asset(
return f"asset://{create_resp.asset_id}"


def _seedance2_price_extractor(model_id: str, has_video_input: bool, resolution: str):
"""Returns a price_extractor closure for Seedance 2.0 poll_op."""
rate = seedance2_price_per_1k_tokens(model_id, has_video_input, resolution)
if rate is None:
return None

def extractor(response: TaskStatusResponse) -> float | None:
if response.usage is None:
return None
return response.usage.total_tokens * 1.43 * rate / 1_000.0

return extractor


def get_image_url_from_response(response: ImageTaskCreationResponse) -> str:
if response.error:
error_msg = f"ByteDance request failed. Code: {response.error['code']}, message: {response.error['message']}"
Expand Down Expand Up @@ -2300,9 +2285,6 @@ def _seedance2_build_request(
async def _seedance2_poll_video_task(
cls: type[IO.ComfyNode],
task_id: str,
model_id: str,
resolution: str,
has_video_input: bool,
task_type: str | None = None,
) -> TaskStatusResponse:
try:
Expand All @@ -2311,9 +2293,6 @@ async def _seedance2_poll_video_task(
ApiEndpoint(path=f"{BYTEPLUS_SEEDANCE2_TASK_STATUS_ENDPOINT}/{task_id}"),
response_model=TaskStatusResponse,
status_extractor=lambda r: r.status,
price_extractor=_seedance2_price_extractor(
model_id, has_video_input=has_video_input, resolution=resolution
),
poll_interval=9,
)
except Exception as exc:
Expand Down Expand Up @@ -2452,9 +2431,7 @@ async def execute(
),
response_model=TaskCreationResponse,
)
response = await _seedance2_poll_video_task(
cls, initial_response.id, model_id, model["resolution"], has_video_input=False
)
response = await _seedance2_poll_video_task(cls, initial_response.id)
return IO.NodeOutput(await download_url_to_video_output(response.content.video_url))


Expand Down Expand Up @@ -2645,9 +2622,7 @@ async def execute(
data=_seedance2_build_request(model, model_id, content, seed, watermark, ratio=request_ratio),
response_model=TaskCreationResponse,
)
response = await _seedance2_poll_video_task(
cls, initial_response.id, model_id, model["resolution"], has_video_input=False
)
response = await _seedance2_poll_video_task(cls, initial_response.id)
return IO.NodeOutput(await download_url_to_video_output(response.content.video_url))


Expand Down Expand Up @@ -2843,8 +2818,6 @@ async def execute(
for key in reference_images:
reference_images[key] = _prepare_seedance_image(reference_images[key])

has_video_input = total_videos > 0

if model.get("auto_downscale") and reference_videos:
max_px = SEEDANCE2_REF_VIDEO_PIXEL_LIMITS.get(model_id, {}).get(model["resolution"], {}).get("max")
if max_px:
Expand Down Expand Up @@ -2966,9 +2939,6 @@ async def execute(
response = await _seedance2_poll_video_task(
cls,
initial_response.id,
model_id,
model["resolution"],
has_video_input=has_video_input,
task_type=task_type,
)
return IO.NodeOutput(await download_url_to_video_output(response.content.video_url))
Expand Down
17 changes: 0 additions & 17 deletions comfy_api_nodes/nodes_grok.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,6 @@ def repl(match: re.Match) -> str:
return prompt


def _extract_grok_price(response) -> float | None:
if response.usage and response.usage.cost_in_usd_ticks is not None:
return response.usage.cost_in_usd_ticks / 10_000_000_000
return None


def _extract_grok_video_price(response) -> float | None:
price = _extract_grok_price(response)
if price is not None:
return price * 1.43
return None


class GrokImageNode(IO.ComfyNode):

@classmethod
Expand Down Expand Up @@ -747,7 +734,6 @@ async def execute(
ApiEndpoint(path=f"/proxy/xai/v1/videos/{initial_response.request_id}"),
status_extractor=lambda r: r.status if r.status is not None else "complete",
response_model=VideoStatusResponse,
price_extractor=_extract_grok_video_price if model == "grok-imagine-video-1.5" else _extract_grok_price,
)
return IO.NodeOutput(await download_url_to_video_output(response.video.url))

Expand Down Expand Up @@ -825,7 +811,6 @@ async def execute(
ApiEndpoint(path=f"/proxy/xai/v1/videos/{initial_response.request_id}"),
status_extractor=lambda r: r.status if r.status is not None else "complete",
response_model=VideoStatusResponse,
price_extractor=_extract_grok_price,
)
return IO.NodeOutput(await download_url_to_video_output(response.video.url))

Expand Down Expand Up @@ -1022,7 +1007,6 @@ async def execute(
ApiEndpoint(path=f"/proxy/xai/v1/videos/{initial_response.request_id}"),
status_extractor=lambda r: r.status if r.status is not None else "complete",
response_model=VideoStatusResponse,
price_extractor=_extract_grok_video_price,
)
return IO.NodeOutput(await download_url_to_video_output(response.video.url))

Expand Down Expand Up @@ -1127,7 +1111,6 @@ async def execute(
ApiEndpoint(path=f"/proxy/xai/v1/videos/{initial_response.request_id}"),
status_extractor=lambda r: r.status if r.status is not None else "complete",
response_model=VideoStatusResponse,
price_extractor=_extract_grok_video_price,
)
return IO.NodeOutput(await download_url_to_video_output(response.video.url))

Expand Down
4 changes: 0 additions & 4 deletions comfy_api_nodes/nodes_hitpaw.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,12 @@ async def execute(
)
if initial_res.code != 200:
raise ValueError(f"Task creation failed with code {initial_res.code}: {initial_res.message}")
request_price = initial_res.data.consume_coins / 1000
final_response = await poll_op(
cls,
ApiEndpoint(path="/proxy/hitpaw/api/task-status", method="POST"),
data=TaskCreateDataResponse(job_id=initial_res.data.job_id),
response_model=TaskStatusResponse,
status_extractor=lambda x: x.data.status,
price_extractor=lambda x: request_price,
poll_interval=10.0,
)
return IO.NodeOutput(await download_url_to_image_tensor(final_response.data.res_url))
Expand Down Expand Up @@ -312,7 +310,6 @@ async def execute(
wait_label="Creating task",
final_label_on_success="Task created",
)
request_price = initial_res.data.consume_coins / 1000
if initial_res.code != 200:
raise ValueError(f"Task creation failed with code {initial_res.code}: {initial_res.message}")
final_response = await poll_op(
Expand All @@ -321,7 +318,6 @@ async def execute(
data=TaskStatusPollRequest(job_id=initial_res.data.job_id),
response_model=TaskStatusResponse,
status_extractor=lambda x: x.data.status,
price_extractor=lambda x: request_price,
poll_interval=10.0,
)
return IO.NodeOutput(await download_url_to_video_output(final_response.data.res_url))
Expand Down
34 changes: 0 additions & 34 deletions comfy_api_nodes/nodes_magnific.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,6 @@
validate_image_dimensions,
)

_EUR_TO_USD = 1.19


def _tier_price_eur(megapixels: float) -> float:
"""Price in EUR for a single Magnific upscaling step based on input megapixels."""
if megapixels <= 1.3:
return 0.143
if megapixels <= 3.0:
return 0.286
if megapixels <= 6.4:
return 0.429
return 1.716


def _calculate_magnific_upscale_price_usd(width: int, height: int, scale: int) -> float:
"""Calculate total Magnific upscale price in USD for given input dimensions and scale factor."""
num_steps = int(math.log2(scale))
total_eur = 0.0
pixels = width * height
for _ in range(num_steps):
total_eur += _tier_price_eur(pixels / 1_000_000)
pixels *= 4
return round(total_eur * _EUR_TO_USD, 2)


class MagnificImageUpscalerCreativeNode(IO.ComfyNode):
@classmethod
def define_schema(cls):
Expand Down Expand Up @@ -203,10 +178,6 @@ async def execute(
f"Use a smaller input image or lower scale factor."
)

final_height, final_width = get_image_dimensions(image)
actual_scale = int(scale_factor.rstrip("x"))
price_usd = _calculate_magnific_upscale_price_usd(final_width, final_height, actual_scale)

initial_res = await sync_op(
cls,
ApiEndpoint(path="/proxy/freepik/v1/ai/image-upscaler", method="POST"),
Expand All @@ -228,7 +199,6 @@ async def execute(
ApiEndpoint(path=f"/proxy/freepik/v1/ai/image-upscaler/{initial_res.task_id}"),
response_model=TaskResponse,
status_extractor=lambda x: x.status,
price_extractor=lambda _: price_usd,
poll_interval=10.0,
)
return IO.NodeOutput(await download_url_to_image_tensor(final_response.generated[0]))
Expand Down Expand Up @@ -367,9 +337,6 @@ async def execute(
f"Use a smaller input image or lower scale factor."
)

final_height, final_width = get_image_dimensions(image)
price_usd = _calculate_magnific_upscale_price_usd(final_width, final_height, requested_scale)

initial_res = await sync_op(
cls,
ApiEndpoint(path="/proxy/freepik/v1/ai/image-upscaler-precision-v2", method="POST"),
Expand All @@ -388,7 +355,6 @@ async def execute(
ApiEndpoint(path=f"/proxy/freepik/v1/ai/image-upscaler-precision-v2/{initial_res.task_id}"),
response_model=TaskResponse,
status_extractor=lambda x: x.status,
price_extractor=lambda _: price_usd,
poll_interval=10.0,
)
return IO.NodeOutput(await download_url_to_image_tensor(final_response.generated[0]))
Expand Down
Loading
Loading