From ab9f710d3e6119c80ac961bbca60fbd4767489d7 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Aug 2026 21:44:13 +0300 Subject: [PATCH 1/8] docs: plan fal.ai external provider integration --- .../plans/2026-08-27-fal-external-provider.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/plans/2026-08-27-fal-external-provider.md diff --git a/docs/plans/2026-08-27-fal-external-provider.md b/docs/plans/2026-08-27-fal-external-provider.md new file mode 100644 index 00000000000..fb57561b947 --- /dev/null +++ b/docs/plans/2026-08-27-fal-external-provider.md @@ -0,0 +1,56 @@ +# fal.ai External Provider Implementation Plan + +**Goal:** Add fal.ai as a native InvokeAI external image provider usable from the Canvas Image Editor. + +**Architecture:** Reuse InvokeAI's existing `ExternalProvider`, external model records, starter model synchronization, and Canvas external graph. Add one REST queue adapter using fal.ai's upload and queue APIs. Ship curated image models with accurate capabilities: Flux Schnell/Dev for txt2img, Flux Kontext Pro for img2img, and Flux Fill for inpaint. Keep generic/video support outside this PR. + +**Tech Stack:** Python 3.11+, requests, Pydantic settings, InvokeAI external generation service, React/TypeScript frontend, Vitest/Pytest. + +## Global Constraints + +- Do not submit billable fal.ai inference jobs in automated tests. +- Store provider credentials through InvokeAI's external provider secret handling; never log or persist raw credentials in normal config. +- Use only existing runtime dependencies; `requests` already belongs to InvokeAI. +- Preserve Canvas model capability filtering and external model installation behavior. +- Use fal.ai queue REST endpoints and fal CDN upload REST endpoints, not a new Python client dependency. +- Keep current standalone custom-node integration separate; native provider covers Canvas image generation/editing only. + +### Task 1: Provider contract and configuration + +**Files:** `invokeai/app/services/config/config_default.py`, `invokeai/app/api/dependencies.py`, `invokeai/app/api/routers/app_info.py`, `invokeai/app/services/external_generation/providers/__init__.py`, tests for config/API/provider registration. + +- [ ] Add `external_fal_api_key` and `external_fal_base_url` to provider config fields and API mapping. +- [ ] Register `FalProvider` in service construction and export it. +- [ ] Add tests proving fal appears in provider config/status APIs and secret redaction remains intact. + +### Task 2: fal.ai REST adapter + +**Files:** `invokeai/app/services/external_generation/providers/fal.py`, `tests/app/services/external_generation/test_fal_provider.py`. + +- [ ] Write failing tests for configuration, queue submission, status polling, result parsing, image upload, Flux payload mapping, Kontext payload mapping, Fill mask inversion, HTTP errors, rate limits, and download size limits. +- [ ] Implement upload initiation (`rest.fal.ai/storage/upload/initiate`), PUT upload, queue submit/status/result calls, bounded polling, HTTPS image download, and model-specific payload builders. +- [ ] Parse fal image URL outputs and provider seed/request metadata without exposing credentials. + +### Task 3: Native invocation and curated models + +**Files:** `invokeai/app/invocations/external_image_generation.py`, `invokeai/backend/model_manager/starter_models.py`, `tests/app/invocations/test_external_image_generation.py`, `tests/backend/model_manager/test_starter_models.py` or focused tests. + +- [ ] Add `FalImageGenerationInvocation` with provider filter `fal`. +- [ ] Add starter models for `fal-ai/flux/schnell`, `fal-ai/flux/dev`, `fal-ai/flux-pro/kontext`, and `fal-ai/flux-lora-fill` with accurate modes, image requirements, aspect ratios, seed/batch capabilities, and default settings. +- [ ] Ensure external starter sync installs these models after fal credentials are configured. + +### Task 4: Canvas and frontend contract + +**Files:** `invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.ts`, `invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx`, locale files, generated OpenAPI/type files, frontend tests. + +- [ ] Map provider `fal` to `fal_image_generation` in Canvas graph construction. +- [ ] Add fal provider ordering/icon fallback and localized provider wording. +- [ ] Regenerate OpenAPI/type artifacts and test that the generated graph uses fal node for txt2img/img2img/inpaint. + +### Task 5: Documentation, validation, and PR + +**Files:** `docs/src/content/docs/features/External Models/index.mdx`, new fal provider docs, changelog/PR description as appropriate. + +- [ ] Document setup, supported models, Canvas usage, API cost warning, and current scope. +- [ ] Run focused Python tests, frontend tests/typecheck, ruff, OpenAPI/typegen checks, and a server smoke test without inference. +- [ ] Create fork, push branch, open PR with test evidence and explicit note that no paid inference was submitted. From 5ff716e26f8e1ab5bf5abf3f0a80ca1dc1189ba8 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Aug 2026 22:29:26 +0300 Subject: [PATCH 2/8] feat: add fal.ai external image provider --- .../plans/2026-08-27-fal-external-provider.md | 24 +- invokeai/app/api/dependencies.py | 2 + invokeai/app/api/routers/app_info.py | 7 +- .../invocations/external_image_generation.py | 21 + .../app/services/config/config_default.py | 8 + .../external_generation/providers/__init__.py | 3 +- .../external_generation/providers/fal.py | 361 ++++++++++++++++++ .../backend/model_manager/starter_models.py | 85 +++++ .../test_external_image_generation.py | 23 +- tests/app/routers/test_app_info.py | 38 +- .../external_generation/test_fal_provider.py | 334 ++++++++++++++++ .../model_manager/test_starter_models.py | 19 + 12 files changed, 909 insertions(+), 16 deletions(-) create mode 100644 invokeai/app/services/external_generation/providers/fal.py create mode 100644 tests/app/services/external_generation/test_fal_provider.py diff --git a/docs/plans/2026-08-27-fal-external-provider.md b/docs/plans/2026-08-27-fal-external-provider.md index fb57561b947..1b89e5b35f8 100644 --- a/docs/plans/2026-08-27-fal-external-provider.md +++ b/docs/plans/2026-08-27-fal-external-provider.md @@ -19,33 +19,33 @@ **Files:** `invokeai/app/services/config/config_default.py`, `invokeai/app/api/dependencies.py`, `invokeai/app/api/routers/app_info.py`, `invokeai/app/services/external_generation/providers/__init__.py`, tests for config/API/provider registration. -- [ ] Add `external_fal_api_key` and `external_fal_base_url` to provider config fields and API mapping. -- [ ] Register `FalProvider` in service construction and export it. -- [ ] Add tests proving fal appears in provider config/status APIs and secret redaction remains intact. +- [x] Add `external_fal_api_key` and `external_fal_base_url` to provider config fields and API mapping. +- [x] Register `FalProvider` in service construction and export it. +- [x] Add tests proving fal appears in provider config/status APIs and secret redaction remains intact. ### Task 2: fal.ai REST adapter **Files:** `invokeai/app/services/external_generation/providers/fal.py`, `tests/app/services/external_generation/test_fal_provider.py`. -- [ ] Write failing tests for configuration, queue submission, status polling, result parsing, image upload, Flux payload mapping, Kontext payload mapping, Fill mask inversion, HTTP errors, rate limits, and download size limits. -- [ ] Implement upload initiation (`rest.fal.ai/storage/upload/initiate`), PUT upload, queue submit/status/result calls, bounded polling, HTTPS image download, and model-specific payload builders. -- [ ] Parse fal image URL outputs and provider seed/request metadata without exposing credentials. +- [x] Write failing tests for configuration, queue submission, status polling, result parsing, image upload, Flux payload mapping, Kontext payload mapping, Fill mask inversion, HTTP errors, rate limits, and download size limits. +- [x] Implement upload initiation (`rest.fal.ai/storage/upload/initiate`), PUT upload, queue submit/status/result calls, bounded polling, HTTPS image download, and model-specific payload builders. +- [x] Parse fal image URL outputs and provider seed/request metadata without exposing credentials. ### Task 3: Native invocation and curated models **Files:** `invokeai/app/invocations/external_image_generation.py`, `invokeai/backend/model_manager/starter_models.py`, `tests/app/invocations/test_external_image_generation.py`, `tests/backend/model_manager/test_starter_models.py` or focused tests. -- [ ] Add `FalImageGenerationInvocation` with provider filter `fal`. -- [ ] Add starter models for `fal-ai/flux/schnell`, `fal-ai/flux/dev`, `fal-ai/flux-pro/kontext`, and `fal-ai/flux-lora-fill` with accurate modes, image requirements, aspect ratios, seed/batch capabilities, and default settings. -- [ ] Ensure external starter sync installs these models after fal credentials are configured. +- [x] Add `FalImageGenerationInvocation` with provider filter `fal`. +- [x] Add starter models for `fal-ai/flux/schnell`, `fal-ai/flux/dev`, `fal-ai/flux-pro/kontext`, and `fal-ai/flux-lora-fill` with accurate modes, image requirements, aspect ratios, seed/batch capabilities, and default settings. +- [x] Ensure external starter sync installs these models after fal credentials are configured. ### Task 4: Canvas and frontend contract **Files:** `invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.ts`, `invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx`, locale files, generated OpenAPI/type files, frontend tests. -- [ ] Map provider `fal` to `fal_image_generation` in Canvas graph construction. -- [ ] Add fal provider ordering/icon fallback and localized provider wording. -- [ ] Regenerate OpenAPI/type artifacts and test that the generated graph uses fal node for txt2img/img2img/inpaint. +- [x] Map provider `fal` to `fal_image_generation` in Canvas graph construction. +- [x] Add fal provider ordering/icon fallback and localized provider wording. +- [x] Regenerate OpenAPI/type artifacts and test that the generated graph uses fal node for txt2img/img2img/inpaint. ### Task 5: Documentation, validation, and PR diff --git a/invokeai/app/api/dependencies.py b/invokeai/app/api/dependencies.py index b3ba3be75cf..8c531b21377 100644 --- a/invokeai/app/api/dependencies.py +++ b/invokeai/app/api/dependencies.py @@ -20,6 +20,7 @@ from invokeai.app.services.external_generation.external_generation_default import ExternalGenerationService from invokeai.app.services.external_generation.providers import ( AlibabaCloudProvider, + FalProvider, GeminiProvider, OpenAIProvider, SeedreamProvider, @@ -188,6 +189,7 @@ def initialize( external_generation = ExternalGenerationService( providers={ AlibabaCloudProvider.provider_id: AlibabaCloudProvider(app_config=configuration, logger=logger), + FalProvider.provider_id: FalProvider(app_config=configuration, logger=logger), GeminiProvider.provider_id: GeminiProvider(app_config=configuration, logger=logger), OpenAIProvider.provider_id: OpenAIProvider(app_config=configuration, logger=logger), SeedreamProvider.provider_id: SeedreamProvider(app_config=configuration, logger=logger), diff --git a/invokeai/app/api/routers/app_info.py b/invokeai/app/api/routers/app_info.py index 3564e296b1d..ee091398c37 100644 --- a/invokeai/app/api/routers/app_info.py +++ b/invokeai/app/api/routers/app_info.py @@ -1,4 +1,5 @@ import locale +import os import re from enum import Enum from importlib.metadata import distributions @@ -101,6 +102,7 @@ class ExternalProviderConfigModel(BaseModel): EXTERNAL_PROVIDER_FIELDS: dict[str, tuple[str, str]] = { + "fal": ("external_fal_api_key", "external_fal_base_url"), "alibabacloud": ("external_alibabacloud_api_key", "external_alibabacloud_base_url"), "gemini": ("external_gemini_api_key", "external_gemini_base_url"), "openai": ("external_openai_api_key", "external_openai_base_url"), @@ -421,9 +423,12 @@ def _apply_external_provider_update(updates: dict[str, str | None]) -> None: def _build_external_provider_config(provider_id: str, config: InvokeAIAppConfig) -> ExternalProviderConfigModel: api_key_field, base_url_field = _get_external_provider_fields(provider_id) + api_key_configured = bool(getattr(config, api_key_field)) + if provider_id == "fal" and not api_key_configured: + api_key_configured = bool(os.getenv("FAL_KEY") or os.getenv("FAL_API_KEY")) return ExternalProviderConfigModel( provider_id=provider_id, - api_key_configured=bool(getattr(config, api_key_field)), + api_key_configured=api_key_configured, base_url=getattr(config, base_url_field), ) diff --git a/invokeai/app/invocations/external_image_generation.py b/invokeai/app/invocations/external_image_generation.py index a6c6822d9dd..88cc772ff0f 100644 --- a/invokeai/app/invocations/external_image_generation.py +++ b/invokeai/app/invocations/external_image_generation.py @@ -349,3 +349,24 @@ class AlibabaCloudImageGenerationInvocation(BaseExternalImageGenerationInvocatio ui_model_format=[ModelFormat.ExternalApi], ui_model_provider_id=["alibabacloud"], ) + + +@invocation( + "fal_image_generation", + title="fal.ai Image Generation", + tags=["external", "generation", "fal", "fal.ai"], + category="image", + version="1.0.0", +) +class FalImageGenerationInvocation(BaseExternalImageGenerationInvocation): + """Generate or edit images using a fal.ai-hosted model.""" + + provider_id = "fal" + + model: ModelIdentifierField = InputField( + description=FieldDescriptions.main_model, + ui_model_base=[BaseModelType.External], + ui_model_type=[ModelType.ExternalImageGenerator], + ui_model_format=[ModelFormat.ExternalApi], + ui_model_provider_id=["fal"], + ) diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index 7174742a66d..6e5f8e9f053 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -45,6 +45,8 @@ "external_openai_base_url", "external_seedream_api_key", "external_seedream_base_url", + "external_fal_api_key", + "external_fal_base_url", ) @@ -135,6 +137,8 @@ class InvokeAIAppConfig(BaseSettings): allow_unknown_models: Allow installation of models that we are unable to identify. If enabled, models will be marked as `unknown` in the database, and will not have any metadata associated with them. If disabled, unknown models will be rejected during installation. multiuser: Enable multiuser support. When disabled, the application runs in single-user mode using a default system account with administrator privileges. When enabled, requires user authentication and authorization. strict_password_checking: Enforce strict password requirements. When True, passwords must contain uppercase, lowercase, and numbers. When False (default), any password is accepted but its strength (weak/moderate/strong) is reported to the user. + external_fal_api_key: API key for fal.ai image generation. + external_fal_base_url: Base URL override for fal.ai queue API. external_alibabacloud_api_key: API key for Alibaba Cloud DashScope image generation. external_alibabacloud_base_url: Base URL override for Alibaba Cloud DashScope image generation. external_gemini_api_key: API key for Gemini image generation. @@ -256,6 +260,10 @@ class InvokeAIAppConfig(BaseSettings): strict_password_checking: bool = Field(default=False, description="Enforce strict password requirements. When True, passwords must contain uppercase, lowercase, and numbers. When False (default), any password is accepted but its strength (weak/moderate/strong) is reported to the user.") # EXTERNAL PROVIDERS + external_fal_api_key: Optional[str] = Field(default=None, description="API key for fal.ai image generation.") + external_fal_base_url: Optional[str] = Field( + default=None, description="Base URL override for fal.ai queue API.", + ) external_alibabacloud_api_key: Optional[str] = Field(default=None, description="API key for Alibaba Cloud DashScope image generation.") external_alibabacloud_base_url: Optional[str] = Field( default=None, description="Base URL override for Alibaba Cloud DashScope image generation." diff --git a/invokeai/app/services/external_generation/providers/__init__.py b/invokeai/app/services/external_generation/providers/__init__.py index 9926302addf..cfc2afdbdac 100644 --- a/invokeai/app/services/external_generation/providers/__init__.py +++ b/invokeai/app/services/external_generation/providers/__init__.py @@ -1,6 +1,7 @@ from invokeai.app.services.external_generation.providers.alibabacloud import AlibabaCloudProvider +from invokeai.app.services.external_generation.providers.fal import FalProvider from invokeai.app.services.external_generation.providers.gemini import GeminiProvider from invokeai.app.services.external_generation.providers.openai import OpenAIProvider from invokeai.app.services.external_generation.providers.seedream import SeedreamProvider -__all__ = ["AlibabaCloudProvider", "GeminiProvider", "OpenAIProvider", "SeedreamProvider"] +__all__ = ["AlibabaCloudProvider", "FalProvider", "GeminiProvider", "OpenAIProvider", "SeedreamProvider"] diff --git a/invokeai/app/services/external_generation/providers/fal.py b/invokeai/app/services/external_generation/providers/fal.py new file mode 100644 index 00000000000..61137c55ac0 --- /dev/null +++ b/invokeai/app/services/external_generation/providers/fal.py @@ -0,0 +1,361 @@ +from __future__ import annotations + +import base64 +import io +import os +import time +from typing import Any + +import requests +from PIL import Image, ImageOps +from PIL.Image import Image as PILImageType + +from invokeai.app.services.external_generation.errors import ( + ExternalProviderRateLimitError, + ExternalProviderRequestError, +) +from invokeai.app.services.external_generation.external_generation_base import ExternalProvider +from invokeai.app.services.external_generation.external_generation_common import ( + ExternalGeneratedImage, + ExternalGenerationRequest, + ExternalGenerationResult, +) + +_DEFAULT_QUEUE_URL = "https://queue.fal.run" +_UPLOAD_URL = "https://rest.fal.ai/storage/upload/initiate?storage_type=fal-cdn-v3" +_POLL_INTERVAL = 1.0 +_POLL_TIMEOUT = 300.0 +_REQUEST_TIMEOUT = 60 +_DOWNLOAD_TIMEOUT = 60 +_DOWNLOAD_MAX_BYTES = 32 * 1024 * 1024 +_RETRY_STATUS_CODES = {500, 502, 503, 504} + +_IMAGE_SIZE_BY_RATIO = { + "1:1": "square_hd", + "4:3": "landscape_4_3", + "3:4": "portrait_4_3", + "16:9": "landscape_16_9", + "9:16": "portrait_16_9", +} + +_FLUX_FILL_MODELS = {"fal-ai/flux-lora-fill"} +_FLUX_KONTEXT_MODELS = {"fal-ai/flux-pro/kontext", "fal-ai/flux-pro/kontext/max"} +_FLUX_TEXT_MODELS = {"fal-ai/flux/schnell", "fal-ai/flux/dev"} + + +class FalProvider(ExternalProvider): + """InvokeAI adapter for fal.ai's queue and CDN APIs.""" + + provider_id = "fal" + + def is_configured(self) -> bool: + return bool(self._api_key()) + + def generate(self, request: ExternalGenerationRequest) -> ExternalGenerationResult: + api_key = self._api_key() + if not api_key: + raise ExternalProviderRequestError("fal.ai API key is not configured") + + headers = {"Authorization": f"Key {api_key}", "Content-Type": "application/json"} + image_url = None + mask_url = None + if request.init_image is not None: + image_url = self._upload_image(request.init_image, "image.png", headers) + if request.mask_image is not None: + mask = ImageOps.invert(request.mask_image.convert("L")) + mask_url = self._upload_image(mask, "mask.png", headers) + + payload = self._build_payload(request, image_url=image_url, mask_url=mask_url) + model_id = request.model.provider_model_id + queue_url = f"{self._queue_base_url}/{model_id}" + submit_response = self._request( + "POST", + queue_url, + headers=headers, + json=payload, + timeout=_REQUEST_TIMEOUT, + ) + self._raise_for_response(submit_response, "fal.ai request") + submitted = self._parse_json(submit_response, "fal.ai queue response") + + request_id = submitted.get("request_id") + if not isinstance(request_id, str) or not request_id: + if self._has_images(submitted): + return self._parse_result(submitted, request, request_id=None) + raise ExternalProviderRequestError("fal.ai queue response missing request_id") + + result_payload = self._wait_for_result(model_id, request_id, headers) + return self._parse_result(result_payload, request, request_id=request_id) + + def _api_key(self) -> str | None: + return self._app_config.external_fal_api_key or os.getenv("FAL_KEY") or os.getenv("FAL_API_KEY") + + @property + def _queue_base_url(self) -> str: + return (self._app_config.external_fal_base_url or _DEFAULT_QUEUE_URL).rstrip("/") + + def _build_payload( + self, + request: ExternalGenerationRequest, + *, + image_url: str | None, + mask_url: str | None, + ) -> dict[str, Any]: + model_id = request.model.provider_model_id + ratio = _select_aspect_ratio(request.width, request.height, request.model.capabilities.allowed_aspect_ratios) + payload: dict[str, Any] = {"prompt": request.prompt} + + if request.seed is not None and request.model.capabilities.supports_seed: + payload["seed"] = request.seed + if request.num_images > 1 or request.model.capabilities.max_images_per_request is not None: + payload["num_images"] = request.num_images + + if model_id in _FLUX_FILL_MODELS or request.mode == "inpaint": + if image_url is None or mask_url is None: + raise ExternalProviderRequestError("fal.ai inpainting requires both image and mask inputs") + payload.update( + { + "image_size": _image_size_for_ratio(ratio), + "image_url": image_url, + "mask_url": mask_url, + "paste_back": True, + "resize_to_original": True, + } + ) + return payload + + if model_id in _FLUX_KONTEXT_MODELS or request.mode == "img2img": + if image_url is None: + raise ExternalProviderRequestError("fal.ai image editing requires an input image") + payload["image_url"] = image_url + payload["aspect_ratio"] = ratio + return payload + + if model_id in _FLUX_TEXT_MODELS or request.mode == "txt2img": + payload["image_size"] = _image_size_for_ratio(ratio) + return payload + + # Unknown external models get conservative common arguments. Curated models above + # use exact schemas; custom external model records can still use txt2img safely. + if image_url is not None: + payload["image_url"] = image_url + if mask_url is not None: + payload["mask_url"] = mask_url + payload["image_size"] = _image_size_for_ratio(ratio) + return payload + + def _upload_image(self, image: PILImageType, filename: str, headers: dict[str, str]) -> str: + upload_headers = {"Authorization": headers["Authorization"], "Content-Type": "application/json"} + response = self._request( + "POST", + _UPLOAD_URL, + headers=upload_headers, + json={"file_name": filename, "content_type": "image/png"}, + timeout=_REQUEST_TIMEOUT, + ) + self._raise_for_response(response, "fal.ai upload initiation") + upload = self._parse_json(response, "fal.ai upload initiation response") + file_url = upload.get("file_url") + upload_url = upload.get("upload_url") + if not isinstance(file_url, str) or not file_url or not isinstance(upload_url, str) or not upload_url: + raise ExternalProviderRequestError("fal.ai upload response missing file_url or upload_url") + + image_bytes = _encode_png(image) + put_response = self._request( + "PUT", + upload_url, + headers={"Content-Type": "image/png"}, + data=image_bytes, + timeout=_REQUEST_TIMEOUT, + ) + self._raise_for_response(put_response, "fal.ai file upload") + return file_url + + def _wait_for_result(self, model_id: str, request_id: str, headers: dict[str, str]) -> dict[str, Any]: + status_url = f"{self._queue_base_url}/{model_id}/requests/{request_id}/status" + result_url = f"{self._queue_base_url}/{model_id}/requests/{request_id}" + deadline = time.monotonic() + _POLL_TIMEOUT + while True: + if time.monotonic() >= deadline: + raise ExternalProviderRequestError(f"fal.ai request {request_id} timed out") + + try: + status_response = self._request("GET", status_url, headers=headers, timeout=_REQUEST_TIMEOUT) + except ExternalProviderRequestError: + # The job already exists. Retrying polling avoids submitting a second billable job. + time.sleep(_POLL_INTERVAL) + continue + if status_response.status_code == 429 or status_response.status_code in _RETRY_STATUS_CODES: + time.sleep(_retry_delay(status_response)) + continue + self._raise_for_response(status_response, "fal.ai status request") + status_payload = self._parse_json(status_response, "fal.ai status response") + status = status_payload.get("status") + if status == "COMPLETED": + try: + result_response = self._request("GET", result_url, headers=headers, timeout=_REQUEST_TIMEOUT) + except ExternalProviderRequestError: + time.sleep(_POLL_INTERVAL) + continue + if result_response.status_code == 429 or result_response.status_code in _RETRY_STATUS_CODES: + time.sleep(_retry_delay(result_response)) + continue + self._raise_for_response(result_response, "fal.ai result request") + return self._parse_json(result_response, "fal.ai result response") + if status in {"FAILED", "CANCELED", "CANCELLED"}: + detail = status_payload.get("error") or status_payload.get("message") or status + raise ExternalProviderRequestError(f"fal.ai request {request_id} failed: {detail}") + if status not in {"IN_QUEUE", "IN_PROGRESS"}: + raise ExternalProviderRequestError(f"fal.ai returned unknown request status: {status}") + time.sleep(_POLL_INTERVAL) + + def _parse_result( + self, + payload: dict[str, Any], + request: ExternalGenerationRequest, + *, + request_id: str | None, + ) -> ExternalGenerationResult: + image_items = payload.get("images") + if not isinstance(image_items, list): + data_items = payload.get("data") + image_items = data_items if isinstance(data_items, list) else [] + + seed_value = payload.get("seed") + seed = seed_value if isinstance(seed_value, int) else request.seed + images: list[ExternalGeneratedImage] = [] + for item in image_items: + if not isinstance(item, dict): + continue + url = item.get("url") or item.get("image_url") + if isinstance(url, str) and url: + images.append(ExternalGeneratedImage(image=self._download_image(url), seed=seed)) + + if not images: + raise ExternalProviderRequestError("fal.ai response contained no images") + + return ExternalGenerationResult( + images=images, + seed_used=seed, + provider_request_id=request_id, + provider_metadata={"model": request.model.provider_model_id}, + ) + + def _download_image(self, url: str) -> PILImageType: + if url.startswith("data:image/"): + try: + encoded = url.split(",", 1)[1] + return Image.open(io.BytesIO(base64.b64decode(encoded))).convert("RGB") + except (IndexError, ValueError, OSError) as exc: + raise ExternalProviderRequestError("fal.ai returned an invalid image data URI") from exc + if not url.startswith("https://"): + raise ExternalProviderRequestError("fal.ai returned a non-HTTPS image URL") + + response = self._request("GET", url, headers={}, timeout=_DOWNLOAD_TIMEOUT, stream=True) + self._raise_for_response(response, "fal.ai image download") + content_length = response.headers.get("Content-Length") + if content_length: + try: + if int(content_length) > _DOWNLOAD_MAX_BYTES: + raise ExternalProviderRequestError("fal.ai image exceeds the download size limit") + except ValueError: + pass + + buffer = bytearray() + for chunk in response.iter_content(chunk_size=64 * 1024): + if chunk: + buffer.extend(chunk) + if len(buffer) > _DOWNLOAD_MAX_BYTES: + raise ExternalProviderRequestError("fal.ai image exceeds the download size limit") + try: + return Image.open(io.BytesIO(bytes(buffer))).convert("RGB") + except OSError as exc: + raise ExternalProviderRequestError("fal.ai returned invalid image data") from exc + + @staticmethod + def _has_images(payload: dict[str, Any]) -> bool: + images = payload.get("images") + return isinstance(images, list) and bool(images) + + @staticmethod + def _parse_json(response: requests.Response, label: str) -> dict[str, Any]: + try: + payload = response.json() + except ValueError as exc: + raise ExternalProviderRequestError(f"{label} was not valid JSON") from exc + if not isinstance(payload, dict): + raise ExternalProviderRequestError(f"{label} was not a JSON object") + return payload + + @staticmethod + def _request(method: str, url: str, **kwargs: Any) -> requests.Response: + try: + if method == "POST": + return requests.post(url, **kwargs) + if method == "PUT": + return requests.put(url, **kwargs) + return requests.get(url, **kwargs) + except requests.RequestException as exc: + raise ExternalProviderRequestError(f"fal.ai network request failed: {exc}") from exc + + @staticmethod + def _raise_for_response(response: requests.Response, operation: str) -> None: + if response.ok: + return + if response.status_code == 429: + retry_after = _parse_retry_after(response.headers.get("Retry-After")) + detail = f" Retry after {retry_after:.0f}s." if retry_after is not None else "" + raise ExternalProviderRateLimitError(f"fal.ai rate limit exceeded.{detail}", retry_after=retry_after) + if response.status_code in _RETRY_STATUS_CODES: + raise ExternalProviderRequestError(f"{operation} failed with status {response.status_code}; retry later") + raise ExternalProviderRequestError(f"{operation} failed with status {response.status_code}: {response.text}") + + +def _encode_png(image: PILImageType) -> bytes: + buffer = io.BytesIO() + image.save(buffer, format="PNG") + return buffer.getvalue() + + +def _select_aspect_ratio(width: int, height: int, allowed: list[str] | None) -> str: + if width <= 0 or height <= 0: + return "1:1" + ratio = width / height + candidates = allowed or list(_IMAGE_SIZE_BY_RATIO) + parsed = [(value, _parse_ratio(value)) for value in candidates] + valid = [(value, value_ratio) for value, value_ratio in parsed if value_ratio is not None] + if not valid: + return "1:1" + return min(valid, key=lambda pair: abs(pair[1] - ratio))[0] + + +def _image_size_for_ratio(ratio: str) -> str: + return _IMAGE_SIZE_BY_RATIO.get(ratio, "square_hd") + + +def _parse_ratio(value: str) -> float | None: + try: + left, right = value.split(":", 1) + denominator = float(right) + if denominator == 0: + return None + return float(left) / denominator + except (ValueError, AttributeError): + return None + + +def _parse_retry_after(value: str | None) -> float | None: + if not value: + return None + try: + return float(value) + except ValueError: + return None + + +def _retry_delay(response: requests.Response) -> float: + retry_after = _parse_retry_after(response.headers.get("Retry-After")) + return min(retry_after if retry_after is not None else _POLL_INTERVAL, 60.0) + + +__all__ = ["FalProvider"] diff --git a/invokeai/backend/model_manager/starter_models.py b/invokeai/backend/model_manager/starter_models.py index eb8812f02f5..f82de10877b 100644 --- a/invokeai/backend/model_manager/starter_models.py +++ b/invokeai/backend/model_manager/starter_models.py @@ -2278,9 +2278,94 @@ def _gemini_3_resolution_presets( ) # endregion +FAL_IMAGE_ASPECT_RATIOS = ["1:1", "4:3", "3:4", "16:9", "9:16"] +FAL_IMAGE_ASPECT_RATIO_SIZES = { + "1:1": ExternalImageSize(width=1024, height=1024), + "4:3": ExternalImageSize(width=1152, height=864), + "3:4": ExternalImageSize(width=864, height=1152), + "16:9": ExternalImageSize(width=1280, height=720), + "9:16": ExternalImageSize(width=720, height=1280), +} + +fal_flux_schnell = StarterModel( + name="FLUX.1 [schnell] (fal.ai)", + base=BaseModelType.External, + source="external://fal/fal-ai/flux/schnell", + description="fal.ai-hosted FLUX.1 [schnell] image generation. Requires a fal.ai API key; usage may incur provider-side costs.", + type=ModelType.ExternalImageGenerator, + format=ModelFormat.ExternalApi, + capabilities=ExternalModelCapabilities( + modes=["txt2img"], + supports_negative_prompt=False, + supports_seed=True, + max_images_per_request=4, + allowed_aspect_ratios=FAL_IMAGE_ASPECT_RATIOS, + aspect_ratio_sizes=FAL_IMAGE_ASPECT_RATIO_SIZES, + ), + default_settings=ExternalApiModelDefaultSettings(width=1024, height=1024, num_images=1), +) +fal_flux_dev = StarterModel( + name="FLUX.1 [dev] (fal.ai)", + base=BaseModelType.External, + source="external://fal/fal-ai/flux/dev", + description="fal.ai-hosted FLUX.1 [dev] image generation. Requires a fal.ai API key; usage may incur provider-side costs.", + type=ModelType.ExternalImageGenerator, + format=ModelFormat.ExternalApi, + capabilities=ExternalModelCapabilities( + modes=["txt2img"], + supports_negative_prompt=False, + supports_seed=True, + max_images_per_request=4, + allowed_aspect_ratios=FAL_IMAGE_ASPECT_RATIOS, + aspect_ratio_sizes=FAL_IMAGE_ASPECT_RATIO_SIZES, + ), + default_settings=ExternalApiModelDefaultSettings(width=1024, height=1024, num_images=1), +) +fal_flux_kontext = StarterModel( + name="FLUX.1 Kontext [pro] (fal.ai)", + base=BaseModelType.External, + source="external://fal/fal-ai/flux-pro/kontext", + description="fal.ai-hosted FLUX.1 Kontext [pro] image editing. Requires a fal.ai API key; usage may incur provider-side costs.", + type=ModelType.ExternalImageGenerator, + format=ModelFormat.ExternalApi, + capabilities=ExternalModelCapabilities( + modes=["img2img"], + supports_negative_prompt=False, + supports_seed=True, + max_images_per_request=4, + allowed_aspect_ratios=FAL_IMAGE_ASPECT_RATIOS, + aspect_ratio_sizes=FAL_IMAGE_ASPECT_RATIO_SIZES, + input_image_required_for=["img2img"], + ), + default_settings=ExternalApiModelDefaultSettings(width=1024, height=1024, num_images=1), +) +fal_flux_fill = StarterModel( + name="FLUX.1 Fill (fal.ai)", + base=BaseModelType.External, + source="external://fal/fal-ai/flux-lora-fill", + description="fal.ai-hosted FLUX Fill image inpainting. Requires a fal.ai API key; usage may incur provider-side costs.", + type=ModelType.ExternalImageGenerator, + format=ModelFormat.ExternalApi, + capabilities=ExternalModelCapabilities( + modes=["inpaint"], + supports_negative_prompt=False, + supports_seed=True, + max_images_per_request=4, + allowed_aspect_ratios=FAL_IMAGE_ASPECT_RATIOS, + aspect_ratio_sizes=FAL_IMAGE_ASPECT_RATIO_SIZES, + mask_format="binary", + input_image_required_for=["inpaint"], + ), + default_settings=ExternalApiModelDefaultSettings(width=1024, height=1024, num_images=1), +) + # List of starter models, displayed on the frontend. # The order/sort of this list is not changed by the frontend - set it how you want it here. STARTER_MODELS: list[StarterModel] = [ + fal_flux_schnell, + fal_flux_dev, + fal_flux_kontext, + fal_flux_fill, flux_kontext_quantized, flux_schnell_quantized, flux_dev_quantized, diff --git a/tests/app/invocations/test_external_image_generation.py b/tests/app/invocations/test_external_image_generation.py index 4247a366871..d80830b58b6 100644 --- a/tests/app/invocations/test_external_image_generation.py +++ b/tests/app/invocations/test_external_image_generation.py @@ -4,7 +4,10 @@ import pytest from PIL import Image -from invokeai.app.invocations.external_image_generation import OpenAIImageGenerationInvocation +from invokeai.app.invocations.external_image_generation import ( + FalImageGenerationInvocation, + OpenAIImageGenerationInvocation, +) from invokeai.app.invocations.fields import ImageField from invokeai.app.invocations.model import ModelIdentifierField from invokeai.app.services.external_generation.external_generation_common import ( @@ -86,6 +89,24 @@ def test_provider_specific_external_invocation_rejects_wrong_provider() -> None: invocation.invoke(context) +def test_fal_invocation_requires_fal_model() -> None: + model_config = _build_model().model_copy(update={"provider_id": "fal", "provider_model_id": "fal-ai/flux/schnell"}) + model_field = ModelIdentifierField.from_config(model_config) + generated_image = Image.new("RGB", (16, 16), color="black") + context = _build_context(model_config, generated_image) + + invocation = FalImageGenerationInvocation( + id="fal_node", + model=model_field, + mode="txt2img", + prompt="A prompt", + ) + + invocation.invoke(context) + + assert context._services.external_generation.generate.call_args[0][0].model.provider_id == "fal" + + def test_external_graph_execution_state_runs_node() -> None: model_config = _build_model() model_field = ModelIdentifierField.from_config(model_config) diff --git a/tests/app/routers/test_app_info.py b/tests/app/routers/test_app_info.py index 4ca610a0a43..8c8aa80d95d 100644 --- a/tests/app/routers/test_app_info.py +++ b/tests/app/routers/test_app_info.py @@ -62,6 +62,8 @@ def test_get_external_provider_statuses(monkeypatch: Any, mock_invoker: Invoker, def test_external_provider_config_update_and_reset(monkeypatch: Any, mock_invoker: Invoker, client: TestClient) -> None: + monkeypatch.delenv("FAL_KEY", raising=False) + monkeypatch.delenv("FAL_API_KEY", raising=False) mock_store = Mock() mock_store.search_by_attr.return_value = [] mock_install = Mock() @@ -72,7 +74,7 @@ def test_external_provider_config_update_and_reset(monkeypatch: Any, mock_invoke monkeypatch.setattr("invokeai.app.api.routers.app_info.ApiDependencies", MockApiDependencies(mock_invoker)) monkeypatch.setattr("invokeai.app.api.auth_dependencies.ApiDependencies", MockApiDependencies(mock_invoker)) - for provider_id in ("gemini", "openai"): + for provider_id in ("fal", "gemini", "openai"): response = client.delete(f"/api/v1/app/external_providers/config/{provider_id}") assert response.status_code == 200 @@ -82,6 +84,9 @@ def test_external_provider_config_update_and_reset(monkeypatch: Any, mock_invoke openai_config = _get_provider_config(payload, "openai") assert openai_config["api_key_configured"] is False assert openai_config["base_url"] is None + fal_config = _get_provider_config(payload, "fal") + assert fal_config["api_key_configured"] is False + assert fal_config["base_url"] is None response = client.post( "/api/v1/app/external_providers/config/openai", @@ -99,6 +104,15 @@ def test_external_provider_config_update_and_reset(monkeypatch: Any, mock_invoke assert openai_config["api_key_configured"] is True assert openai_config["base_url"] == "https://api.openai.test" + response = client.post( + "/api/v1/app/external_providers/config/fal", + json={"api_key": "fal-key", "base_url": "https://queue.fal.test"}, + ) + assert response.status_code == 200 + fal_config = response.json() + assert fal_config["api_key_configured"] is True + assert fal_config["base_url"] == "https://queue.fal.test" + config_path = get_config().config_file_path api_keys_path = get_config().api_keys_file_path file_config = load_and_migrate_config(config_path) @@ -116,6 +130,12 @@ def test_external_provider_config_update_and_reset(monkeypatch: Any, mock_invoke assert payload["api_key_configured"] is False assert payload["base_url"] is None + response = client.delete("/api/v1/app/external_providers/config/fal") + assert response.status_code == 200 + payload = response.json() + assert payload["api_key_configured"] is False + assert payload["base_url"] is None + file_config = load_and_migrate_config(config_path) api_keys = load_external_api_keys(api_keys_path) assert file_config.external_openai_api_key is None @@ -123,6 +143,22 @@ def test_external_provider_config_update_and_reset(monkeypatch: Any, mock_invoke assert "external_openai_api_key" not in config_path.read_text() assert "external_openai_api_key" not in api_keys assert "external_openai_base_url" not in api_keys + assert "external_fal_api_key" not in api_keys + assert "external_fal_base_url" not in api_keys + + +def test_fal_external_provider_config_reports_environment_key( + monkeypatch: Any, mock_invoker: Invoker, client: TestClient +) -> None: + monkeypatch.setenv("FAL_KEY", "environment-key") + monkeypatch.setattr("invokeai.app.api.routers.app_info.ApiDependencies", MockApiDependencies(mock_invoker)) + monkeypatch.setattr("invokeai.app.api.auth_dependencies.ApiDependencies", MockApiDependencies(mock_invoker)) + + response = client.get("/api/v1/app/external_providers/config") + + assert response.status_code == 200 + fal_config = _get_provider_config(response.json(), "fal") + assert fal_config["api_key_configured"] is True def test_reset_external_provider_config_removes_provider_models( diff --git a/tests/app/services/external_generation/test_fal_provider.py b/tests/app/services/external_generation/test_fal_provider.py new file mode 100644 index 00000000000..3709beb4e05 --- /dev/null +++ b/tests/app/services/external_generation/test_fal_provider.py @@ -0,0 +1,334 @@ +import io +import logging +from collections.abc import Iterator +from typing import Any + +import pytest +from PIL import Image + +from invokeai.app.services.config.config_default import InvokeAIAppConfig +from invokeai.app.services.external_generation.errors import ExternalProviderRequestError +from invokeai.app.services.external_generation.external_generation_common import ( + ExternalGenerationRequest, +) +from invokeai.app.services.external_generation.providers.fal import FalProvider +from invokeai.backend.model_manager.configs.external_api import ( + ExternalApiModelConfig, + ExternalImageSize, + ExternalModelCapabilities, +) + + +class DummyResponse: + def __init__( + self, + *, + ok: bool = True, + status_code: int = 200, + json_data: dict[str, Any] | None = None, + content: bytes = b"", + text: str = "", + headers: dict[str, str] | None = None, + ) -> None: + self.ok = ok + self.status_code = status_code + self._json_data = json_data or {} + self.content = content + self.text = text + self.headers = headers or {} + + def json(self) -> dict[str, Any]: + return self._json_data + + def iter_content(self, chunk_size: int) -> Iterator[bytes]: + del chunk_size + yield self.content + + def __enter__(self) -> "DummyResponse": + return self + + def __exit__(self, *args: object) -> None: + return None + + +def _png_bytes(color: str = "red") -> bytes: + image = Image.new("RGB", (2, 2), color=color) + buffer = io.BytesIO() + image.save(buffer, format="PNG") + return buffer.getvalue() + + +def _model(model_id: str, *, modes: list[str]) -> ExternalApiModelConfig: + return ExternalApiModelConfig( + key="fal-test", + name="fal test", + provider_id="fal", + provider_model_id=model_id, + capabilities=ExternalModelCapabilities( + modes=modes, # type: ignore[arg-type] + supports_seed=True, + max_images_per_request=4, + allowed_aspect_ratios=["1:1", "4:3", "3:4", "16:9", "9:16"], + aspect_ratio_sizes={ + "1:1": ExternalImageSize(width=1024, height=1024), + "4:3": ExternalImageSize(width=1152, height=864), + "3:4": ExternalImageSize(width=864, height=1152), + "16:9": ExternalImageSize(width=1280, height=720), + "9:16": ExternalImageSize(width=720, height=1280), + }, + ), + ) + + +def _request( + model: ExternalApiModelConfig, + *, + mode: str = "txt2img", + init_image: Image.Image | None = None, + mask_image: Image.Image | None = None, +) -> ExternalGenerationRequest: + return ExternalGenerationRequest( + model=model, + mode=mode, # type: ignore[arg-type] + prompt="A test prompt", + seed=123, + num_images=2, + width=1024, + height=1024, + image_size=None, + init_image=init_image, + mask_image=mask_image, + reference_images=[], + metadata=None, + ) + + +def test_fal_provider_reports_configuration_from_api_key(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.delenv("FAL_KEY", raising=False) + monkeypatch.delenv("FAL_API_KEY", raising=False) + configured = FalProvider(InvokeAIAppConfig(external_fal_api_key="test-key"), logging.getLogger("test")) + unconfigured = FalProvider(InvokeAIAppConfig(), logging.getLogger("test")) + + assert configured.is_configured() is True + assert unconfigured.is_configured() is False + + +def test_fal_provider_accepts_official_environment_key_names(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.delenv("FAL_KEY", raising=False) + monkeypatch.setenv("FAL_API_KEY", "legacy-key") + assert FalProvider(InvokeAIAppConfig(), logging.getLogger("test")).is_configured() is True + + monkeypatch.setenv("FAL_KEY", "official-key") + assert FalProvider(InvokeAIAppConfig(), logging.getLogger("test")).is_configured() is True + + +def test_fal_provider_submits_queue_polls_and_downloads_images(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key", external_fal_base_url="https://queue.test") + provider = FalProvider(config, logging.getLogger("test")) + request = _request(_model("fal-ai/flux/schnell", modes=["txt2img"])) + captured: dict[str, Any] = {} + output_bytes = _png_bytes("green") + + def fake_post(url: str, headers: dict[str, str], json: dict[str, Any], timeout: int) -> DummyResponse: + captured["post_url"] = url + captured["post_headers"] = headers + captured["post_json"] = json + captured["post_timeout"] = timeout + return DummyResponse(json_data={"request_id": "request-1"}) + + def fake_get(url: str, headers: dict[str, str], timeout: int, stream: bool = False) -> DummyResponse: + del headers, timeout + if url.endswith("/status"): + return DummyResponse(json_data={"status": "COMPLETED"}) + if "/requests/request-1" in url: + return DummyResponse(json_data={"images": [{"url": "https://cdn.test/result.png"}], "seed": 777}) + assert stream is True + return DummyResponse(content=output_bytes) + + monkeypatch.setattr("requests.post", fake_post) + monkeypatch.setattr("requests.get", fake_get) + + result = provider.generate(request) + + assert captured["post_url"] == "https://queue.test/fal-ai/flux/schnell" + assert captured["post_headers"] == {"Authorization": "Key fal-key", "Content-Type": "application/json"} + assert captured["post_json"] == { + "prompt": request.prompt, + "image_size": "square_hd", + "num_images": 2, + "seed": 123, + } + assert result.provider_request_id == "request-1" + assert result.seed_used == 777 + assert result.images[0].image.size == (2, 2) + assert result.images[0].seed == 777 + + +def test_fal_provider_uploads_kontext_input_and_uses_image_url(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key", external_fal_base_url="https://queue.test") + provider = FalProvider(config, logging.getLogger("test")) + request = _request( + _model("fal-ai/flux-pro/kontext", modes=["img2img"]), + mode="img2img", + init_image=Image.new("RGB", (2, 2), color="blue"), + ) + post_calls: list[dict[str, Any]] = [] + put_calls: list[dict[str, Any]] = [] + + def fake_post(url: str, headers: dict[str, str], json: dict[str, Any], timeout: int) -> DummyResponse: + post_calls.append({"url": url, "headers": headers, "json": json, "timeout": timeout}) + if "/storage/upload/initiate" in url: + return DummyResponse( + json_data={ + "file_url": "https://cdn.test/input.png", + "upload_url": "https://upload.test/input", + } + ) + return DummyResponse(json_data={"request_id": "request-2"}) + + def fake_put(url: str, data: bytes, headers: dict[str, str], timeout: int) -> DummyResponse: + put_calls.append({"url": url, "data": data, "headers": headers, "timeout": timeout}) + return DummyResponse() + + def fake_get(url: str, headers: dict[str, str], timeout: int, stream: bool = False) -> DummyResponse: + del headers, timeout + if url.endswith("/status"): + return DummyResponse(json_data={"status": "COMPLETED"}) + if "/requests/request-2" in url: + return DummyResponse(json_data={"images": [{"url": "https://cdn.test/result.png"}], "seed": 123}) + assert stream is True + return DummyResponse(content=_png_bytes("green")) + + monkeypatch.setattr("requests.post", fake_post) + monkeypatch.setattr("requests.put", fake_put) + monkeypatch.setattr("requests.get", fake_get) + + provider.generate(request) + + assert post_calls[0]["url"] == "https://rest.fal.ai/storage/upload/initiate?storage_type=fal-cdn-v3" + assert post_calls[0]["json"] == {"file_name": "image.png", "content_type": "image/png"} + assert put_calls[0]["url"] == "https://upload.test/input" + assert put_calls[0]["headers"] == {"Content-Type": "image/png"} + assert post_calls[1]["url"] == "https://queue.test/fal-ai/flux-pro/kontext" + assert post_calls[1]["json"] == { + "prompt": request.prompt, + "image_url": "https://cdn.test/input.png", + "aspect_ratio": "1:1", + "num_images": 2, + "seed": 123, + } + + +def test_fal_provider_inverts_invoke_mask_for_flux_fill(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key", external_fal_base_url="https://queue.test") + provider = FalProvider(config, logging.getLogger("test")) + mask = Image.new("L", (2, 1)) + mask.putdata([0, 255]) + request = _request( + _model("fal-ai/flux-lora-fill", modes=["inpaint"]), + mode="inpaint", + init_image=Image.new("RGB", (2, 1), color="blue"), + mask_image=mask, + ) + uploads: dict[str, bytes] = {} + queue_payload: dict[str, Any] = {} + upload_index = 0 + + def fake_post(url: str, headers: dict[str, str], json: dict[str, Any], timeout: int) -> DummyResponse: + nonlocal upload_index + del headers, timeout + if "/storage/upload/initiate" in url: + upload_index += 1 + name = "image" if upload_index == 1 else "mask" + return DummyResponse( + json_data={ + "file_url": f"https://cdn.test/{name}.png", + "upload_url": f"https://upload.test/{name}", + } + ) + queue_payload.update(json) + return DummyResponse(json_data={"request_id": "request-3"}) + + def fake_put(url: str, data: bytes, headers: dict[str, str], timeout: int) -> DummyResponse: + del headers, timeout + uploads[url.rsplit("/", 1)[-1]] = data + return DummyResponse() + + def fake_get(url: str, headers: dict[str, str], timeout: int, stream: bool = False) -> DummyResponse: + del headers, timeout + if url.endswith("/status"): + return DummyResponse(json_data={"status": "COMPLETED"}) + if "/requests/request-3" in url: + return DummyResponse(json_data={"images": [{"url": "https://cdn.test/result.png"}], "seed": 123}) + assert stream is True + return DummyResponse(content=_png_bytes("green")) + + monkeypatch.setattr("requests.post", fake_post) + monkeypatch.setattr("requests.put", fake_put) + monkeypatch.setattr("requests.get", fake_get) + + provider.generate(request) + + uploaded_mask = Image.open(io.BytesIO(uploads["mask"])).convert("L") + assert list(uploaded_mask.getdata()) == [255, 0] + assert queue_payload == { + "prompt": request.prompt, + "image_size": "square_hd", + "num_images": 2, + "seed": 123, + "image_url": "https://cdn.test/image.png", + "mask_url": "https://cdn.test/mask.png", + "paste_back": True, + "resize_to_original": True, + } + + +def test_fal_provider_retries_poll_rate_limit_without_resubmitting(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key", external_fal_base_url="https://queue.test") + provider = FalProvider(config, logging.getLogger("test")) + request = _request(_model("fal-ai/flux/schnell", modes=["txt2img"])) + submit_count = 0 + status_count = 0 + + def fake_post(*args: Any, **kwargs: Any) -> DummyResponse: + nonlocal submit_count + del args, kwargs + submit_count += 1 + return DummyResponse(json_data={"request_id": "request-4"}) + + def fake_get(url: str, headers: dict[str, str], timeout: int, stream: bool = False) -> DummyResponse: + nonlocal status_count + del headers, timeout + if url.endswith("/status"): + status_count += 1 + if status_count == 1: + return DummyResponse(ok=False, status_code=429, headers={"Retry-After": "1"}) + return DummyResponse(json_data={"status": "COMPLETED"}) + if "/requests/request-4" in url: + return DummyResponse(json_data={"images": [{"url": "https://cdn.test/result.png"}], "seed": 123}) + assert stream is True + return DummyResponse(content=_png_bytes("green")) + + monkeypatch.setattr("requests.post", fake_post) + monkeypatch.setattr("requests.get", fake_get) + monkeypatch.setattr("invokeai.app.services.external_generation.providers.fal.time.sleep", lambda _: None) + + provider.generate(request) + + assert submit_count == 1 + assert status_count == 2 + + +def test_fal_provider_reports_queue_error(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key") + provider = FalProvider(config, logging.getLogger("test")) + request = _request(_model("fal-ai/flux/schnell", modes=["txt2img"])) + + def fake_post(*args: Any, **kwargs: Any) -> DummyResponse: + del args, kwargs + return DummyResponse(ok=False, status_code=400, text="invalid model input") + + monkeypatch.setattr("requests.post", fake_post) + + with pytest.raises(ExternalProviderRequestError, match="fal.ai request failed"): + provider.generate(request) diff --git a/tests/backend/model_manager/test_starter_models.py b/tests/backend/model_manager/test_starter_models.py index cdcddd495ec..6aa6678edfc 100644 --- a/tests/backend/model_manager/test_starter_models.py +++ b/tests/backend/model_manager/test_starter_models.py @@ -6,6 +6,7 @@ standalone dependencies so installing it also pulls the pieces needed to run it. """ +from invokeai.backend.model_manager.configs.external_api import ExternalApiModelDefaultSettings from invokeai.backend.model_manager.starter_models import ( STARTER_BUNDLES, STARTER_MODELS, @@ -24,6 +25,24 @@ def _krea2_bundle_by_source() -> dict[str, StarterModel]: return {model.source: model for model in bundle.models} +def test_fal_external_models_are_registered_with_canvas_capabilities() -> None: + models = {model.source: model for model in STARTER_MODELS if model.source.startswith("external://fal/")} + + assert set(models) == { + "external://fal/fal-ai/flux/schnell", + "external://fal/fal-ai/flux/dev", + "external://fal/fal-ai/flux-pro/kontext", + "external://fal/fal-ai/flux-lora-fill", + } + assert models["external://fal/fal-ai/flux/schnell"].capabilities.modes == ["txt2img"] + assert models["external://fal/fal-ai/flux-pro/kontext"].capabilities.modes == ["img2img"] + assert models["external://fal/fal-ai/flux-pro/kontext"].capabilities.input_image_required_for == ["img2img"] + fill = models["external://fal/fal-ai/flux-lora-fill"] + assert fill.capabilities.modes == ["inpaint"] + assert fill.capabilities.mask_format == "binary" + assert fill.default_settings == ExternalApiModelDefaultSettings(width=1024, height=1024, num_images=1) + + def test_krea2_bundle_is_registered() -> None: assert BaseModelType.Krea2 in STARTER_BUNDLES assert STARTER_BUNDLES[BaseModelType.Krea2].name == "Krea-2" From cd70d51e50754ac686b7ced216978fe0c3aee172 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Aug 2026 22:29:42 +0300 Subject: [PATCH 3/8] feat: expose fal.ai in canvas model picker --- .../docs/features/External Models/fal.mdx | 61 ++++ .../docs/features/External Models/index.mdx | 6 +- docs/src/generated/settings.json | 22 ++ invokeai/frontend/web/openapi.json | 283 +++++++++++++++++- .../ExternalProvidersForm.tsx | 6 +- .../generation/buildExternalGraph.test.ts | 22 ++ .../graph/generation/buildExternalGraph.ts | 1 + .../frontend/web/src/services/api/schema.ts | 126 +++++++- 8 files changed, 517 insertions(+), 10 deletions(-) create mode 100644 docs/src/content/docs/features/External Models/fal.mdx diff --git a/docs/src/content/docs/features/External Models/fal.mdx b/docs/src/content/docs/features/External Models/fal.mdx new file mode 100644 index 00000000000..8e698cd5c86 --- /dev/null +++ b/docs/src/content/docs/features/External Models/fal.mdx @@ -0,0 +1,61 @@ +--- +title: fal.ai +--- + +Invoke can use fal.ai-hosted image models from the Canvas Image Editor. Requests +run on fal.ai, and fal.ai bills them to your account. + +## Setup + +Configure fal.ai in **Models → Add Model → External Providers**. Paste your +fal.ai API key and save. Invoke stores it in `api_keys.yaml`; the key is not +written to `invokeai.yaml` or shown after saving. + +Manual configuration uses: + +```yaml +# api_keys.yaml +external_fal_api_key: "your-fal-api-key" + +# Optional queue API override, mainly for a compatible proxy +external_fal_base_url: "https://queue.fal.run" +``` + +Restart Invoke after manual configuration. + +## Models + +The provider currently ships these curated models: + +- `fal-ai/flux/schnell` — text to image +- `fal-ai/flux/dev` — text to image +- `fal-ai/flux-pro/kontext` — image to image and semantic edits +- `fal-ai/flux-lora-fill` — masked inpainting + +When the API key is configured, Invoke adds these external model references to +the model database. No model weights are downloaded. + +## Canvas + +1. Open **Canvas**. +2. Select one of the fal.ai models in the model picker. +3. Use normal generation for FLUX Schnell or FLUX Dev. +4. Use **img2img** with an existing canvas image for Kontext. +5. Draw an inpaint mask and choose **inpaint** with FLUX Fill. +6. Press **Invoke**. The image is uploaded to fal.ai, processed remotely, and +the result is imported into the Invoke gallery. + +Canvas settings are constrained by each model's capabilities. For example, +Kontext requires an input image, while Fill requires both an input image and a +mask. The provider converts Invoke's white-preserve/black-edit canvas mask to +the white-edit format expected by fal.ai. + +## Costs and limits + +Every generation, upload, and result download uses remote services. Check the +current model pricing and limits on its fal.ai model page before invoking. +Automated tests do not submit inference requests. + +- https://fal.ai/models/fal-ai/flux/schnell +- https://fal.ai/models/fal-ai/flux-pro/kontext +- https://fal.ai/models/fal-ai/flux-lora-fill diff --git a/docs/src/content/docs/features/External Models/index.mdx b/docs/src/content/docs/features/External Models/index.mdx index 358b68fe68e..99895fb096c 100644 --- a/docs/src/content/docs/features/External Models/index.mdx +++ b/docs/src/content/docs/features/External Models/index.mdx @@ -12,7 +12,7 @@ External models appear in the model picker alongside locally installed models. G ## Supported Providers -- [Google Gemini](/features/external-models/gemini/) — Gemini 2.5 Flash Image, Gemini 3 Pro Image Preview, Gemini 3.1 Flash Image Preview +- [fal.ai](/features/external-models/fal/) — FLUX.1 [schnell], FLUX.1 [dev], FLUX.1 Kontext [pro], FLUX.1 Fill - [OpenAI](/features/external-models/openai/) — GPT Image 1 / 1.5 / 1-mini, DALL·E 3 - [BytePlus Seedream](/features/external-models/seedream/) — Seedream 5.0, 5.0 Lite, 4.5, 4.0 - [Alibaba Cloud DashScope](/features/external-models/alibabacloud/) — Qwen Image 2.0 / 2.0 Pro / Max / Edit Max, Wan 2.6 T2I @@ -23,10 +23,12 @@ External provider credentials are stored in a dedicated `api_keys.yaml` file alo ```yaml # api_keys.yaml +external_fal_api_key: "your-fal-api-key" external_gemini_api_key: "your-gemini-api-key" external_openai_api_key: "your-openai-api-key" # Optional: override the provider base URL (e.g. for a compatible proxy or regional endpoint) +external_fal_base_url: "https://queue.fal.run" external_gemini_base_url: "https://generativelanguage.googleapis.com" external_openai_base_url: "https://api.openai.com" ``` @@ -46,7 +48,7 @@ Once installed, external models show up everywhere a model can be selected. Choo Each external model declares its own **capabilities** — for example: -- Which generation modes it supports (`txt2img`, `img2img`). Inpainting is not currently supported by any external provider. +- Which generation modes it supports (`txt2img`, `img2img`, `inpaint`). Support differs by provider and model. - Whether it accepts reference images, and how many. - Which aspect ratios and resolutions it allows. - Whether it supports a negative prompt, seed, or batch size > 1. diff --git a/docs/src/generated/settings.json b/docs/src/generated/settings.json index 5a73c0483af..47787ef7455 100644 --- a/docs/src/generated/settings.json +++ b/docs/src/generated/settings.json @@ -853,6 +853,28 @@ "type": "", "validation": {} }, + { + "category": "EXTERNAL PROVIDERS", + "default": null, + "description": "API key for fal.ai image generation.", + "env_var": "INVOKEAI_EXTERNAL_FAL_API_KEY", + "literal_values": [], + "name": "external_fal_api_key", + "required": false, + "type": "typing.Optional[str]", + "validation": {} + }, + { + "category": "EXTERNAL PROVIDERS", + "default": null, + "description": "Base URL override for fal.ai queue API.", + "env_var": "INVOKEAI_EXTERNAL_FAL_BASE_URL", + "literal_values": [], + "name": "external_fal_base_url", + "required": false, + "type": "typing.Optional[str]", + "validation": {} + }, { "category": "EXTERNAL PROVIDERS", "default": null, diff --git a/invokeai/frontend/web/openapi.json b/invokeai/frontend/web/openapi.json index ccd0f318694..bdda7be2e08 100644 --- a/invokeai/frontend/web/openapi.json +++ b/invokeai/frontend/web/openapi.json @@ -28532,6 +28532,244 @@ "title": "FaceOffOutput", "type": "object" }, + "FalImageGenerationInvocation": { + "category": "image", + "class": "invocation", + "classification": "stable", + "description": "Generate or edit images using a fal.ai-hosted model.", + "node_pack": "invokeai", + "properties": { + "board": { + "anyOf": [ + { + "$ref": "#/components/schemas/BoardField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The board to save the image to", + "field_kind": "internal", + "input": "direct", + "orig_required": false, + "ui_hidden": false + }, + "metadata": { + "anyOf": [ + { + "$ref": "#/components/schemas/MetadataField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional metadata to be saved with the image", + "field_kind": "internal", + "input": "connection", + "orig_required": false, + "ui_hidden": false + }, + "id": { + "description": "The id of this instance of an invocation. Must be unique among all instances of invocations.", + "field_kind": "node_attribute", + "title": "Id", + "type": "string" + }, + "is_intermediate": { + "default": false, + "description": "Whether or not this is an intermediate invocation.", + "field_kind": "node_attribute", + "input": "direct", + "orig_required": true, + "title": "Is Intermediate", + "type": "boolean", + "ui_hidden": false, + "ui_type": "IsIntermediate" + }, + "use_cache": { + "default": true, + "description": "Whether or not to use the cache", + "field_kind": "node_attribute", + "title": "Use Cache", + "type": "boolean" + }, + "model": { + "anyOf": [ + { + "$ref": "#/components/schemas/ModelIdentifierField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Main model (UNet, VAE, CLIP) to load", + "field_kind": "input", + "input": "any", + "orig_required": true, + "ui_model_base": ["external"], + "ui_model_format": ["external_api"], + "ui_model_provider_id": ["fal"], + "ui_model_type": ["external_image_generator"] + }, + "mode": { + "default": "txt2img", + "description": "Generation mode. Not all modes are supported by every model; unsupported modes raise at runtime.", + "enum": ["txt2img", "img2img", "inpaint"], + "field_kind": "input", + "input": "any", + "orig_default": "txt2img", + "orig_required": false, + "title": "Mode", + "type": "string" + }, + "prompt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Prompt", + "field_kind": "input", + "input": "any", + "orig_required": true, + "title": "Prompt" + }, + "seed": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Seed for random number generation", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false, + "title": "Seed" + }, + "num_images": { + "default": 1, + "description": "Number of images to generate", + "exclusiveMinimum": 0, + "field_kind": "input", + "input": "any", + "orig_default": 1, + "orig_required": false, + "title": "Num Images", + "type": "integer" + }, + "width": { + "default": 1024, + "description": "Width of output (px)", + "exclusiveMinimum": 0, + "field_kind": "input", + "input": "any", + "orig_default": 1024, + "orig_required": false, + "title": "Width", + "type": "integer" + }, + "height": { + "default": 1024, + "description": "Height of output (px)", + "exclusiveMinimum": 0, + "field_kind": "input", + "input": "any", + "orig_default": 1024, + "orig_required": false, + "title": "Height", + "type": "integer" + }, + "image_size": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Image size preset (e.g. 1K, 2K, 4K)", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false, + "title": "Image Size" + }, + "init_image": { + "anyOf": [ + { + "$ref": "#/components/schemas/ImageField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Init image for img2img/inpaint", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "mask_image": { + "anyOf": [ + { + "$ref": "#/components/schemas/ImageField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Mask image for inpaint", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "reference_images": { + "default": [], + "description": "Reference images", + "field_kind": "input", + "input": "any", + "items": { + "$ref": "#/components/schemas/ImageField" + }, + "orig_default": [], + "orig_required": false, + "title": "Reference Images", + "type": "array" + }, + "type": { + "const": "fal_image_generation", + "default": "fal_image_generation", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["external", "generation", "fal", "fal.ai"], + "title": "fal.ai Image Generation", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/ImageCollectionOutput" + } + }, "FieldKind": { "description": "The kind of field.\n- `Input`: An input field on a node.\n- `Output`: An output field on a node.\n- `Internal`: A field which is treated as an input, but cannot be used in node definitions. Metadata is\none example. It is provided to nodes via the WithMetadata class, and we want to reserve the field name\n\"metadata\" for this on all nodes. `FieldKind` is used to short-circuit the field name validation logic,\nallowing \"metadata\" for that field.\n- `NodeAttribute`: The field is a node attribute. These are fields which are not inputs or outputs,\nbut which are used to store information about the node. For example, the `id` and `type` fields are node\nattributes.\n\nThe presence of this in `json_schema_extra[\"field_kind\"]` is used when initializing node schemas on app\nstartup, and when generating the OpenAPI schema for the workflow editor.", "enum": ["input", "output", "internal", "node_attribute"], @@ -35215,6 +35453,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalImageGenerationInvocation" + }, { "$ref": "#/components/schemas/FloatBatchInvocation" }, @@ -43753,6 +43994,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalImageGenerationInvocation" + }, { "$ref": "#/components/schemas/FloatBatchInvocation" }, @@ -45104,6 +45348,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalImageGenerationInvocation" + }, { "$ref": "#/components/schemas/FloatBatchInvocation" }, @@ -46061,6 +46308,9 @@ "face_off": { "$ref": "#/components/schemas/FaceOffOutput" }, + "fal_image_generation": { + "$ref": "#/components/schemas/ImageCollectionOutput" + }, "float": { "$ref": "#/components/schemas/FloatOutput" }, @@ -46857,6 +47107,7 @@ "face_identifier", "face_mask_detection", "face_off", + "fal_image_generation", "float", "float_batch", "float_collection", @@ -47372,6 +47623,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalImageGenerationInvocation" + }, { "$ref": "#/components/schemas/FloatBatchInvocation" }, @@ -48432,6 +48686,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalImageGenerationInvocation" + }, { "$ref": "#/components/schemas/FloatBatchInvocation" }, @@ -49784,6 +50041,30 @@ "description": "Enforce strict password requirements. When True, passwords must contain uppercase, lowercase, and numbers. When False (default), any password is accepted but its strength (weak/moderate/strong) is reported to the user.", "default": false }, + "external_fal_api_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "External Fal Api Key", + "description": "API key for fal.ai image generation." + }, + "external_fal_base_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "External Fal Base Url", + "description": "Base URL override for fal.ai queue API." + }, "external_alibabacloud_api_key": { "anyOf": [ { @@ -49884,7 +50165,7 @@ "additionalProperties": false, "type": "object", "title": "InvokeAIAppConfig", - "description": "Invoke's global app configuration.\n\nTypically, you won't need to interact with this class directly. Instead, use the `get_config` function from `invokeai.app.services.config` to get a singleton config object.\n\nAttributes:\n host: IP address to bind to. Use `0.0.0.0` to serve to your local network.\n port: Port to bind to.\n allow_origins: Allowed CORS origins.\n allow_credentials: Allow CORS credentials.\n allow_methods: Methods allowed for CORS.\n allow_headers: Headers allowed for CORS.\n ssl_certfile: SSL certificate file for HTTPS. See https://www.uvicorn.dev/settings/#https.\n ssl_keyfile: SSL key file for HTTPS. See https://www.uvicorn.dev/settings/#https.\n log_tokenization: Enable logging of parsed prompt tokens.\n patchmatch: Enable patchmatch inpaint code.\n models_dir: Path to the models directory.\n convert_cache_dir: Path to the converted models cache directory (DEPRECATED, but do not delete because it is needed for migration from previous versions).\n download_cache_dir: Path to the directory that contains dynamically downloaded models.\n legacy_conf_dir: Path to directory of legacy checkpoint config files.\n db_dir: Path to InvokeAI databases directory.\n outputs_dir: Path to directory for outputs.\n image_subfolder_strategy: Strategy for organizing images into subfolders. 'flat' stores all images in a single folder. 'date' organizes by YYYY/MM/DD. 'type' organizes by image category. 'hash' uses first 2 characters of UUID for filesystem performance.
Valid values: `flat`, `date`, `type`, `hash`\n custom_nodes_dir: Path to directory for custom nodes.\n style_presets_dir: Path to directory for style presets.\n workflow_thumbnails_dir: Path to directory for workflow thumbnails.\n log_handlers: Log handler. Valid options are \"console\", \"file=\", \"syslog=path|address:host:port\", \"http=\".\n log_format: Log format. Use \"plain\" for text-only, \"color\" for colorized output, \"legacy\" for 2.3-style logging and \"syslog\" for syslog-style.
Valid values: `plain`, `color`, `syslog`, `legacy`\n log_level: Emit logging messages at this level or higher.
Valid values: `debug`, `info`, `warning`, `error`, `critical`\n log_sql: Log SQL queries. `log_level` must be `debug` for this to do anything. Extremely verbose.\n log_level_network: Log level for network-related messages. 'info' and 'debug' are very verbose.
Valid values: `debug`, `info`, `warning`, `error`, `critical`\n use_memory_db: Use in-memory database. Useful for development.\n dev_reload: Automatically reload when Python sources are changed. Does not reload node definitions.\n profile_graphs: Enable graph profiling using `cProfile`.\n profile_prefix: An optional prefix for profile output files.\n profiles_dir: Path to profiles output directory.\n max_cache_ram_gb: The maximum amount of CPU RAM to use for model caching in GB. If unset, the limit will be configured based on the available RAM. In most cases, it is recommended to leave this unset.\n max_cache_vram_gb: The amount of VRAM to use for model caching in GB. If unset, the limit will be configured based on the available VRAM and the device_working_mem_gb. In most cases, it is recommended to leave this unset.\n log_memory_usage: If True, a memory snapshot will be captured before and after every model cache operation, and the result will be logged (at debug level). There is a time cost to capturing the memory snapshots, so it is recommended to only enable this feature if you are actively inspecting the model cache's behaviour.\n model_cache_keep_alive_min: How long to keep models in cache after last use, in minutes. A value of 0 (the default) means models are kept in cache indefinitely. If no model generations occur within the timeout period, the model cache is cleared using the same logic as the 'Clear Model Cache' button.\n device_working_mem_gb: The amount of working memory to keep available on the compute device (in GB). Has no effect if running on CPU. If you are experiencing OOM errors, try increasing this value.\n enable_partial_loading: Enable partial loading of models. This enables models to run with reduced VRAM requirements (at the cost of slower speed) by streaming the model from RAM to VRAM as its used. In some edge cases, partial loading can cause models to run more slowly if they were previously being fully loaded into VRAM.\n keep_ram_copy_of_weights: Whether to keep a full RAM copy of a model's weights when the model is loaded in VRAM. Keeping a RAM copy increases average RAM usage, but speeds up model switching and LoRA patching (assuming there is sufficient RAM). Set this to False if RAM pressure is consistently high.\n ram: DEPRECATED: This setting is no longer used. It has been replaced by `max_cache_ram_gb`, but most users will not need to use this config since automatic cache size limits should work well in most cases. This config setting will be removed once the new model cache behavior is stable.\n vram: DEPRECATED: This setting is no longer used. It has been replaced by `max_cache_vram_gb`, but most users will not need to use this config since automatic cache size limits should work well in most cases. This config setting will be removed once the new model cache behavior is stable.\n lazy_offload: DEPRECATED: This setting is no longer used. Lazy-offloading is enabled by default. This config setting will be removed once the new model cache behavior is stable.\n pytorch_cuda_alloc_conf: Configure the Torch CUDA memory allocator. This will impact peak reserved VRAM usage and performance. Setting to \"backend:cudaMallocAsync\" works well on many systems. The optimal configuration is highly dependent on the system configuration (device type, VRAM, CUDA driver version, etc.), so must be tuned experimentally.\n device: Preferred execution device. `auto` will choose the device depending on the hardware platform and the installed torch capabilities.
Valid values: `auto`, `cpu`, `cuda`, `mps`, `xpu`, `cuda:N`, `xpu:N` (where N is a device number)\n precision: Floating point precision. `float16` will consume half the memory of `float32` but produce slightly lower-quality images. The `auto` setting will guess the proper precision based on your video card and operating system.
Valid values: `auto`, `float16`, `bfloat16`, `float32`\n sequential_guidance: Whether to calculate guidance in serial instead of in parallel, lowering memory requirements.\n wan_memory_optimization: Enable experimental Wan memory optimizations at the cost of slower generation.\n pid_memory_optimization: Enable experimental PiD decode memory optimizations. Roughly halves the peak activation memory of a PiD decode; in exchange the decoded image changes slightly, because neither the chunked pixel pathway nor the float32 sampler intermediates are bit-exact with the default path.\n attention_type: Attention type.
Valid values: `auto`, `normal`, `xformers`, `sliced`, `torch-sdp`\n attention_slice_size: Slice size, valid when attention_type==\"sliced\".
Valid values: `auto`, `balanced`, `max`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`\n force_tiled_decode: Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty).\n pil_compress_level: The compress_level setting of PIL.Image.save(), used for PNG encoding. All settings are lossless. 0 = no compression, 1 = fastest with slightly larger filesize, 9 = slowest with smallest filesize. 1 is typically the best setting.\n max_queue_size: Maximum number of items in the session queue.\n session_queue_mode: Session queue mode. Use 'FIFO' for traditional first-in-first-out, or 'round_robin' to serve each user's jobs in turn. In single-user mode, FIFO is always used regardless of this setting.
Valid values: `FIFO`, `round_robin`\n clear_queue_on_startup: Empties session queue on startup. If true, disables `max_queue_history`.\n max_queue_history: Keep the last N completed, failed, and canceled queue items. Older items are deleted on startup. Set to 0 to prune all terminal items. Ignored if `clear_queue_on_startup` is true.\n allow_nodes: List of nodes to allow. Omit to allow all.\n deny_nodes: List of nodes to deny. Omit to deny none.\n node_cache_size: How many cached nodes to keep in memory.\n hashing_algorithm: Model hashing algorthim for model installs. 'blake3_multi' is best for SSDs. 'blake3_single' is best for spinning disk HDDs. 'random' disables hashing, instead assigning a UUID to models. Useful when using a memory db to reduce model installation time, or if you don't care about storing stable hashes for models. Alternatively, any other hashlib algorithm is accepted, though these are not nearly as performant as blake3.
Valid values: `blake3_multi`, `blake3_single`, `random`, `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`, `blake2b`, `blake2s`, `sha3_224`, `sha3_256`, `sha3_384`, `sha3_512`, `shake_128`, `shake_256`\n remote_api_tokens: List of regular expression and token pairs used when downloading models from URLs. The download URL is tested against the regex, and if it matches, the token is provided in as a Bearer token.\n scan_models_on_startup: Scan the models directory on startup, registering orphaned models. This is typically only used in conjunction with `use_memory_db` for testing purposes.\n allow_private_download_urls: Allow the download queue to fetch from loopback, link-local and private-network addresses. Disabled by default so that a download URL cannot be used to reach services that are only reachable from the server. Enable this only if you install models from a mirror on your own network.\n download_proxy: Optional HTTP proxy for model downloads. The proxy must enforce the public-address policy because proxy-side DNS cannot be checked by InvokeAI.\n unsafe_disable_picklescan: UNSAFE. Disable the picklescan security check during model installation. Recommended only for development and testing purposes. This will allow arbitrary code execution during model installation, so should never be used in production.\n allow_unknown_models: Allow installation of models that we are unable to identify. If enabled, models will be marked as `unknown` in the database, and will not have any metadata associated with them. If disabled, unknown models will be rejected during installation.\n multiuser: Enable multiuser support. When disabled, the application runs in single-user mode using a default system account with administrator privileges. When enabled, requires user authentication and authorization.\n strict_password_checking: Enforce strict password requirements. When True, passwords must contain uppercase, lowercase, and numbers. When False (default), any password is accepted but its strength (weak/moderate/strong) is reported to the user.\n external_alibabacloud_api_key: API key for Alibaba Cloud DashScope image generation.\n external_alibabacloud_base_url: Base URL override for Alibaba Cloud DashScope image generation.\n external_gemini_api_key: API key for Gemini image generation.\n external_openai_api_key: API key for OpenAI image generation.\n external_gemini_base_url: Base URL override for Gemini image generation.\n external_openai_base_url: Base URL override for OpenAI image generation.\n external_seedream_api_key: API key for Seedream image generation.\n external_seedream_base_url: Base URL override for Seedream image generation.\n base_url: Public base path when running behind a reverse proxy under a sub-path, e.g. `/invoke`. Set only when the proxy PRESERVES the sub-path (the backend receives `/invoke/api/...`). Leave unset when the proxy strips the sub-path or when serving at the domain root.\n forwarded_allow_ips: Comma-separated list of IPs (or `*`) allowed to set X-Forwarded-* headers. Set to the reverse proxy's IP. Only used when `base_url` is set.\n http_compression_level: Compression level for gzipped HTTP API responses. 0 disables response compression entirely, 1 is fastest, 9 (the default) is smallest. Compression runs on the event loop and blocks the whole server while it works, and level 9 costs about 5.5x the time of level 1 for 0.4 percentage points of extra compression, so lowering this makes the app noticeably more responsive on large libraries. Set to 0 when a reverse proxy already compresses responses." + "description": "Invoke's global app configuration.\n\nTypically, you won't need to interact with this class directly. Instead, use the `get_config` function from `invokeai.app.services.config` to get a singleton config object.\n\nAttributes:\n host: IP address to bind to. Use `0.0.0.0` to serve to your local network.\n port: Port to bind to.\n allow_origins: Allowed CORS origins.\n allow_credentials: Allow CORS credentials.\n allow_methods: Methods allowed for CORS.\n allow_headers: Headers allowed for CORS.\n ssl_certfile: SSL certificate file for HTTPS. See https://www.uvicorn.dev/settings/#https.\n ssl_keyfile: SSL key file for HTTPS. See https://www.uvicorn.dev/settings/#https.\n log_tokenization: Enable logging of parsed prompt tokens.\n patchmatch: Enable patchmatch inpaint code.\n models_dir: Path to the models directory.\n convert_cache_dir: Path to the converted models cache directory (DEPRECATED, but do not delete because it is needed for migration from previous versions).\n download_cache_dir: Path to the directory that contains dynamically downloaded models.\n legacy_conf_dir: Path to directory of legacy checkpoint config files.\n db_dir: Path to InvokeAI databases directory.\n outputs_dir: Path to directory for outputs.\n image_subfolder_strategy: Strategy for organizing images into subfolders. 'flat' stores all images in a single folder. 'date' organizes by YYYY/MM/DD. 'type' organizes by image category. 'hash' uses first 2 characters of UUID for filesystem performance.
Valid values: `flat`, `date`, `type`, `hash`\n custom_nodes_dir: Path to directory for custom nodes.\n style_presets_dir: Path to directory for style presets.\n workflow_thumbnails_dir: Path to directory for workflow thumbnails.\n log_handlers: Log handler. Valid options are \"console\", \"file=\", \"syslog=path|address:host:port\", \"http=\".\n log_format: Log format. Use \"plain\" for text-only, \"color\" for colorized output, \"legacy\" for 2.3-style logging and \"syslog\" for syslog-style.
Valid values: `plain`, `color`, `syslog`, `legacy`\n log_level: Emit logging messages at this level or higher.
Valid values: `debug`, `info`, `warning`, `error`, `critical`\n log_sql: Log SQL queries. `log_level` must be `debug` for this to do anything. Extremely verbose.\n log_level_network: Log level for network-related messages. 'info' and 'debug' are very verbose.
Valid values: `debug`, `info`, `warning`, `error`, `critical`\n use_memory_db: Use in-memory database. Useful for development.\n dev_reload: Automatically reload when Python sources are changed. Does not reload node definitions.\n profile_graphs: Enable graph profiling using `cProfile`.\n profile_prefix: An optional prefix for profile output files.\n profiles_dir: Path to profiles output directory.\n max_cache_ram_gb: The maximum amount of CPU RAM to use for model caching in GB. If unset, the limit will be configured based on the available RAM. In most cases, it is recommended to leave this unset.\n max_cache_vram_gb: The amount of VRAM to use for model caching in GB. If unset, the limit will be configured based on the available VRAM and the device_working_mem_gb. In most cases, it is recommended to leave this unset.\n log_memory_usage: If True, a memory snapshot will be captured before and after every model cache operation, and the result will be logged (at debug level). There is a time cost to capturing the memory snapshots, so it is recommended to only enable this feature if you are actively inspecting the model cache's behaviour.\n model_cache_keep_alive_min: How long to keep models in cache after last use, in minutes. A value of 0 (the default) means models are kept in cache indefinitely. If no model generations occur within the timeout period, the model cache is cleared using the same logic as the 'Clear Model Cache' button.\n device_working_mem_gb: The amount of working memory to keep available on the compute device (in GB). Has no effect if running on CPU. If you are experiencing OOM errors, try increasing this value.\n enable_partial_loading: Enable partial loading of models. This enables models to run with reduced VRAM requirements (at the cost of slower speed) by streaming the model from RAM to VRAM as its used. In some edge cases, partial loading can cause models to run more slowly if they were previously being fully loaded into VRAM.\n keep_ram_copy_of_weights: Whether to keep a full RAM copy of a model's weights when the model is loaded in VRAM. Keeping a RAM copy increases average RAM usage, but speeds up model switching and LoRA patching (assuming there is sufficient RAM). Set this to False if RAM pressure is consistently high.\n ram: DEPRECATED: This setting is no longer used. It has been replaced by `max_cache_ram_gb`, but most users will not need to use this config since automatic cache size limits should work well in most cases. This config setting will be removed once the new model cache behavior is stable.\n vram: DEPRECATED: This setting is no longer used. It has been replaced by `max_cache_vram_gb`, but most users will not need to use this config since automatic cache size limits should work well in most cases. This config setting will be removed once the new model cache behavior is stable.\n lazy_offload: DEPRECATED: This setting is no longer used. Lazy-offloading is enabled by default. This config setting will be removed once the new model cache behavior is stable.\n pytorch_cuda_alloc_conf: Configure the Torch CUDA memory allocator. This will impact peak reserved VRAM usage and performance. Setting to \"backend:cudaMallocAsync\" works well on many systems. The optimal configuration is highly dependent on the system configuration (device type, VRAM, CUDA driver version, etc.), so must be tuned experimentally.\n device: Preferred execution device. `auto` will choose the device depending on the hardware platform and the installed torch capabilities.
Valid values: `auto`, `cpu`, `cuda`, `mps`, `xpu`, `cuda:N`, `xpu:N` (where N is a device number)\n precision: Floating point precision. `float16` will consume half the memory of `float32` but produce slightly lower-quality images. The `auto` setting will guess the proper precision based on your video card and operating system.
Valid values: `auto`, `float16`, `bfloat16`, `float32`\n sequential_guidance: Whether to calculate guidance in serial instead of in parallel, lowering memory requirements.\n wan_memory_optimization: Enable experimental Wan memory optimizations at the cost of slower generation.\n pid_memory_optimization: Enable experimental PiD decode memory optimizations. Roughly halves the peak activation memory of a PiD decode; in exchange the decoded image changes slightly, because neither the chunked pixel pathway nor the float32 sampler intermediates are bit-exact with the default path.\n attention_type: Attention type.
Valid values: `auto`, `normal`, `xformers`, `sliced`, `torch-sdp`\n attention_slice_size: Slice size, valid when attention_type==\"sliced\".
Valid values: `auto`, `balanced`, `max`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`\n force_tiled_decode: Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty).\n pil_compress_level: The compress_level setting of PIL.Image.save(), used for PNG encoding. All settings are lossless. 0 = no compression, 1 = fastest with slightly larger filesize, 9 = slowest with smallest filesize. 1 is typically the best setting.\n max_queue_size: Maximum number of items in the session queue.\n session_queue_mode: Session queue mode. Use 'FIFO' for traditional first-in-first-out, or 'round_robin' to serve each user's jobs in turn. In single-user mode, FIFO is always used regardless of this setting.
Valid values: `FIFO`, `round_robin`\n clear_queue_on_startup: Empties session queue on startup. If true, disables `max_queue_history`.\n max_queue_history: Keep the last N completed, failed, and canceled queue items. Older items are deleted on startup. Set to 0 to prune all terminal items. Ignored if `clear_queue_on_startup` is true.\n allow_nodes: List of nodes to allow. Omit to allow all.\n deny_nodes: List of nodes to deny. Omit to deny none.\n node_cache_size: How many cached nodes to keep in memory.\n hashing_algorithm: Model hashing algorthim for model installs. 'blake3_multi' is best for SSDs. 'blake3_single' is best for spinning disk HDDs. 'random' disables hashing, instead assigning a UUID to models. Useful when using a memory db to reduce model installation time, or if you don't care about storing stable hashes for models. Alternatively, any other hashlib algorithm is accepted, though these are not nearly as performant as blake3.
Valid values: `blake3_multi`, `blake3_single`, `random`, `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`, `blake2b`, `blake2s`, `sha3_224`, `sha3_256`, `sha3_384`, `sha3_512`, `shake_128`, `shake_256`\n remote_api_tokens: List of regular expression and token pairs used when downloading models from URLs. The download URL is tested against the regex, and if it matches, the token is provided in as a Bearer token.\n scan_models_on_startup: Scan the models directory on startup, registering orphaned models. This is typically only used in conjunction with `use_memory_db` for testing purposes.\n allow_private_download_urls: Allow the download queue to fetch from loopback, link-local and private-network addresses. Disabled by default so that a download URL cannot be used to reach services that are only reachable from the server. Enable this only if you install models from a mirror on your own network.\n download_proxy: Optional HTTP proxy for model downloads. The proxy must enforce the public-address policy because proxy-side DNS cannot be checked by InvokeAI.\n unsafe_disable_picklescan: UNSAFE. Disable the picklescan security check during model installation. Recommended only for development and testing purposes. This will allow arbitrary code execution during model installation, so should never be used in production.\n allow_unknown_models: Allow installation of models that we are unable to identify. If enabled, models will be marked as `unknown` in the database, and will not have any metadata associated with them. If disabled, unknown models will be rejected during installation.\n multiuser: Enable multiuser support. When disabled, the application runs in single-user mode using a default system account with administrator privileges. When enabled, requires user authentication and authorization.\n strict_password_checking: Enforce strict password requirements. When True, passwords must contain uppercase, lowercase, and numbers. When False (default), any password is accepted but its strength (weak/moderate/strong) is reported to the user.\n external_fal_api_key: API key for fal.ai image generation.\n external_fal_base_url: Base URL override for fal.ai queue API.\n external_alibabacloud_api_key: API key for Alibaba Cloud DashScope image generation.\n external_alibabacloud_base_url: Base URL override for Alibaba Cloud DashScope image generation.\n external_gemini_api_key: API key for Gemini image generation.\n external_openai_api_key: API key for OpenAI image generation.\n external_gemini_base_url: Base URL override for Gemini image generation.\n external_openai_base_url: Base URL override for OpenAI image generation.\n external_seedream_api_key: API key for Seedream image generation.\n external_seedream_base_url: Base URL override for Seedream image generation.\n base_url: Public base path when running behind a reverse proxy under a sub-path, e.g. `/invoke`. Set only when the proxy PRESERVES the sub-path (the backend receives `/invoke/api/...`). Leave unset when the proxy strips the sub-path or when serving at the domain root.\n forwarded_allow_ips: Comma-separated list of IPs (or `*`) allowed to set X-Forwarded-* headers. Set to the reverse proxy's IP. Only used when `base_url` is set.\n http_compression_level: Compression level for gzipped HTTP API responses. 0 disables response compression entirely, 1 is fastest, 9 (the default) is smallest. Compression runs on the event loop and blocks the whole server while it works, and level 9 costs about 5.5x the time of level 1 for 0.4 percentage points of extra compression, so lowering this makes the app noticeably more responsive on large libraries. Set to 0 when a reverse proxy already compresses responses." }, "InvokeAIAppConfigWithSetFields": { "properties": { diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx index b4bbe8d6335..4ae2d4a3fa0 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx @@ -21,7 +21,7 @@ import type { ChangeEvent } from 'react'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { IconType } from 'react-icons'; -import { PiCheckBold, PiWarningBold } from 'react-icons/pi'; +import { PiCheckBold, PiCloudLightningBold, PiWarningBold } from 'react-icons/pi'; import { SiAlibabacloud, SiBytedance, SiGooglegemini, SiOpenai } from 'react-icons/si'; import { useGetExternalProviderConfigsQuery, @@ -31,12 +31,14 @@ import { import { useGetStarterModelsQuery } from 'services/api/endpoints/models'; import type { ExternalProviderConfig, StarterModel } from 'services/api/types'; -const PROVIDER_SORT_ORDER = ['gemini', 'openai', 'seedream', 'alibabacloud']; +const PROVIDER_SORT_ORDER = ['fal', 'gemini', 'openai', 'seedream', 'alibabacloud']; function resolveProviderIcon(providerId: string): IconType | null { const provider = providerId.toLowerCase(); switch (provider) { + case 'fal': + return PiCloudLightningBold; case 'openai': return SiOpenai; case 'gemini': diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.test.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.test.ts index f1fa54b4e0b..2f143306055 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.test.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.test.ts @@ -182,6 +182,28 @@ describe('buildExternalGraph', () => { expect(externalNode?.type).toBe('gemini_image_generation'); }); + it('uses the fal.ai invocation for fal models', async () => { + mockModelConfig = createExternalModel({ + provider_id: 'fal', + provider_model_id: 'fal-ai/flux/schnell', + path: 'external://fal/fal-ai/flux/schnell', + source: 'external://fal/fal-ai/flux/schnell', + hash: 'external:fal:fal-ai/flux/schnell', + }); + + const { g } = await buildExternalGraph({ + generationMode: 'txt2img', + state: {} as RootState, + manager: null, + }); + + const graph = g.getGraph(); + const externalNode = Object.values(graph.nodes).find((node) => node.type === 'fal_image_generation'); + + expect(externalNode).toBeDefined(); + expect(externalNode?.type).toBe('fal_image_generation'); + }); + it('throws when mode is unsupported', async () => { const modelConfig = createExternalModel({ capabilities: { diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.ts index 6e7f12cabe3..eabda714277 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.ts @@ -23,6 +23,7 @@ import { import { assert } from 'tsafe'; const EXTERNAL_PROVIDER_NODE_TYPES = { + fal: 'fal_image_generation', alibabacloud: 'alibabacloud_image_generation', gemini: 'gemini_image_generation', openai: 'openai_image_generation', diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index c19832d09a1..d3cd937de3d 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -11337,6 +11337,109 @@ export type components = { */ y: number; }; + /** + * fal.ai Image Generation + * @description Generate or edit images using a fal.ai-hosted model. + */ + FalImageGenerationInvocation: { + /** + * @description The board to save the image to + * @default null + */ + board?: components["schemas"]["BoardField"] | null; + /** + * @description Optional metadata to be saved with the image + * @default null + */ + metadata?: components["schemas"]["MetadataField"] | null; + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** + * @description Main model (UNet, VAE, CLIP) to load + * @default null + */ + model?: components["schemas"]["ModelIdentifierField"] | null; + /** + * Mode + * @description Generation mode. Not all modes are supported by every model; unsupported modes raise at runtime. + * @default txt2img + * @enum {string} + */ + mode?: "txt2img" | "img2img" | "inpaint"; + /** + * Prompt + * @description Prompt + * @default null + */ + prompt?: string | null; + /** + * Seed + * @description Seed for random number generation + * @default null + */ + seed?: number | null; + /** + * Num Images + * @description Number of images to generate + * @default 1 + */ + num_images?: number; + /** + * Width + * @description Width of output (px) + * @default 1024 + */ + width?: number; + /** + * Height + * @description Height of output (px) + * @default 1024 + */ + height?: number; + /** + * Image Size + * @description Image size preset (e.g. 1K, 2K, 4K) + * @default null + */ + image_size?: string | null; + /** + * @description Init image for img2img/inpaint + * @default null + */ + init_image?: components["schemas"]["ImageField"] | null; + /** + * @description Mask image for inpaint + * @default null + */ + mask_image?: components["schemas"]["ImageField"] | null; + /** + * Reference Images + * @description Reference images + * @default [] + */ + reference_images?: components["schemas"]["ImageField"][]; + /** + * type + * @default fal_image_generation + * @constant + */ + type: "fal_image_generation"; + }; /** * FieldKind * @description The kind of field. @@ -14653,7 +14756,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; }; /** * Edges @@ -18478,7 +18581,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -18542,7 +18645,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -18630,6 +18733,7 @@ export type components = { face_identifier: components["schemas"]["ImageOutput"]; face_mask_detection: components["schemas"]["FaceMaskOutput"]; face_off: components["schemas"]["FaceOffOutput"]; + fal_image_generation: components["schemas"]["ImageCollectionOutput"]; float: components["schemas"]["FloatOutput"]; float_batch: components["schemas"]["FloatOutput"]; float_collection: components["schemas"]["FloatCollectionOutput"]; @@ -18926,7 +19030,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -19007,7 +19111,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -19087,6 +19191,8 @@ export type components = { * allow_unknown_models: Allow installation of models that we are unable to identify. If enabled, models will be marked as `unknown` in the database, and will not have any metadata associated with them. If disabled, unknown models will be rejected during installation. * multiuser: Enable multiuser support. When disabled, the application runs in single-user mode using a default system account with administrator privileges. When enabled, requires user authentication and authorization. * strict_password_checking: Enforce strict password requirements. When True, passwords must contain uppercase, lowercase, and numbers. When False (default), any password is accepted but its strength (weak/moderate/strong) is reported to the user. + * external_fal_api_key: API key for fal.ai image generation. + * external_fal_base_url: Base URL override for fal.ai queue API. * external_alibabacloud_api_key: API key for Alibaba Cloud DashScope image generation. * external_alibabacloud_base_url: Base URL override for Alibaba Cloud DashScope image generation. * external_gemini_api_key: API key for Gemini image generation. @@ -19548,6 +19654,16 @@ export type components = { * @default false */ strict_password_checking?: boolean; + /** + * External Fal Api Key + * @description API key for fal.ai image generation. + */ + external_fal_api_key?: string | null; + /** + * External Fal Base Url + * @description Base URL override for fal.ai queue API. + */ + external_fal_base_url?: string | null; /** * External Alibabacloud Api Key * @description API key for Alibaba Cloud DashScope image generation. From 53a229370384d0e58eb503e088381d94bc04136f Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Aug 2026 22:51:55 +0300 Subject: [PATCH 4/8] chore: remove internal implementation plan from PR --- .../plans/2026-08-27-fal-external-provider.md | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 docs/plans/2026-08-27-fal-external-provider.md diff --git a/docs/plans/2026-08-27-fal-external-provider.md b/docs/plans/2026-08-27-fal-external-provider.md deleted file mode 100644 index 1b89e5b35f8..00000000000 --- a/docs/plans/2026-08-27-fal-external-provider.md +++ /dev/null @@ -1,56 +0,0 @@ -# fal.ai External Provider Implementation Plan - -**Goal:** Add fal.ai as a native InvokeAI external image provider usable from the Canvas Image Editor. - -**Architecture:** Reuse InvokeAI's existing `ExternalProvider`, external model records, starter model synchronization, and Canvas external graph. Add one REST queue adapter using fal.ai's upload and queue APIs. Ship curated image models with accurate capabilities: Flux Schnell/Dev for txt2img, Flux Kontext Pro for img2img, and Flux Fill for inpaint. Keep generic/video support outside this PR. - -**Tech Stack:** Python 3.11+, requests, Pydantic settings, InvokeAI external generation service, React/TypeScript frontend, Vitest/Pytest. - -## Global Constraints - -- Do not submit billable fal.ai inference jobs in automated tests. -- Store provider credentials through InvokeAI's external provider secret handling; never log or persist raw credentials in normal config. -- Use only existing runtime dependencies; `requests` already belongs to InvokeAI. -- Preserve Canvas model capability filtering and external model installation behavior. -- Use fal.ai queue REST endpoints and fal CDN upload REST endpoints, not a new Python client dependency. -- Keep current standalone custom-node integration separate; native provider covers Canvas image generation/editing only. - -### Task 1: Provider contract and configuration - -**Files:** `invokeai/app/services/config/config_default.py`, `invokeai/app/api/dependencies.py`, `invokeai/app/api/routers/app_info.py`, `invokeai/app/services/external_generation/providers/__init__.py`, tests for config/API/provider registration. - -- [x] Add `external_fal_api_key` and `external_fal_base_url` to provider config fields and API mapping. -- [x] Register `FalProvider` in service construction and export it. -- [x] Add tests proving fal appears in provider config/status APIs and secret redaction remains intact. - -### Task 2: fal.ai REST adapter - -**Files:** `invokeai/app/services/external_generation/providers/fal.py`, `tests/app/services/external_generation/test_fal_provider.py`. - -- [x] Write failing tests for configuration, queue submission, status polling, result parsing, image upload, Flux payload mapping, Kontext payload mapping, Fill mask inversion, HTTP errors, rate limits, and download size limits. -- [x] Implement upload initiation (`rest.fal.ai/storage/upload/initiate`), PUT upload, queue submit/status/result calls, bounded polling, HTTPS image download, and model-specific payload builders. -- [x] Parse fal image URL outputs and provider seed/request metadata without exposing credentials. - -### Task 3: Native invocation and curated models - -**Files:** `invokeai/app/invocations/external_image_generation.py`, `invokeai/backend/model_manager/starter_models.py`, `tests/app/invocations/test_external_image_generation.py`, `tests/backend/model_manager/test_starter_models.py` or focused tests. - -- [x] Add `FalImageGenerationInvocation` with provider filter `fal`. -- [x] Add starter models for `fal-ai/flux/schnell`, `fal-ai/flux/dev`, `fal-ai/flux-pro/kontext`, and `fal-ai/flux-lora-fill` with accurate modes, image requirements, aspect ratios, seed/batch capabilities, and default settings. -- [x] Ensure external starter sync installs these models after fal credentials are configured. - -### Task 4: Canvas and frontend contract - -**Files:** `invokeai/frontend/web/src/features/nodes/util/graph/generation/buildExternalGraph.ts`, `invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx`, locale files, generated OpenAPI/type files, frontend tests. - -- [x] Map provider `fal` to `fal_image_generation` in Canvas graph construction. -- [x] Add fal provider ordering/icon fallback and localized provider wording. -- [x] Regenerate OpenAPI/type artifacts and test that the generated graph uses fal node for txt2img/img2img/inpaint. - -### Task 5: Documentation, validation, and PR - -**Files:** `docs/src/content/docs/features/External Models/index.mdx`, new fal provider docs, changelog/PR description as appropriate. - -- [ ] Document setup, supported models, Canvas usage, API cost warning, and current scope. -- [ ] Run focused Python tests, frontend tests/typecheck, ruff, OpenAPI/typegen checks, and a server smoke test without inference. -- [ ] Create fork, push branch, open PR with test evidence and explicit note that no paid inference was submitted. From 7f6600ad13bc86a51932dc62bde28da9dd13feb2 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Aug 2026 23:16:15 +0300 Subject: [PATCH 5/8] feat: add fal.ai catalog and schema normalization --- .../providers/fal_catalog.py | 323 ++++++++++++++++++ .../external_generation/test_fal_catalog.py | 138 ++++++++ 2 files changed, 461 insertions(+) create mode 100644 invokeai/app/services/external_generation/providers/fal_catalog.py create mode 100644 tests/app/services/external_generation/test_fal_catalog.py diff --git a/invokeai/app/services/external_generation/providers/fal_catalog.py b/invokeai/app/services/external_generation/providers/fal_catalog.py new file mode 100644 index 00000000000..b5c6c4cded7 --- /dev/null +++ b/invokeai/app/services/external_generation/providers/fal_catalog.py @@ -0,0 +1,323 @@ +from __future__ import annotations + +import copy +import os +from dataclasses import dataclass +from enum import StrEnum +from typing import Any + +import requests + +from invokeai.app.services.external_generation.errors import ExternalProviderRateLimitError, ExternalProviderRequestError + +_DEFAULT_CATALOG_URL = "https://api.fal.ai" +_DEFAULT_SCHEMA_URL = "https://fal.ai/api/openapi/queue/openapi.json" +_CATALOG_TIMEOUT = 30 +_MAX_PAGE_SIZE = 100 + + +class FalEndpointKind(StrEnum): + TEXT_TO_IMAGE = "text-to-image" + IMAGE_TO_IMAGE = "image-to-image" + INPAINT = "inpaint" + UPSCALE = "upscale" + TEXT_TO_VIDEO = "text-to-video" + IMAGE_TO_VIDEO = "image-to-video" + VIDEO_TO_VIDEO = "video-to-video" + AUDIO = "audio" + GENERIC = "generic" + + +@dataclass(frozen=True) +class FalCatalogModel: + endpoint_id: str + display_name: str + description: str + category: str + model_url: str | None + thumbnail_url: str | None + tags: tuple[str, ...] + + +@dataclass(frozen=True) +class FalCatalogPage: + models: list[FalCatalogModel] + next_cursor: str | None + has_more: bool + + +@dataclass(frozen=True) +class FalEndpointSchema: + endpoint_id: str + kind: FalEndpointKind + output_kind: FalEndpointKind + category: str + input_schema: dict[str, Any] + output_schema: dict[str, Any] + common_fields: dict[str, str] + public_properties: tuple[str, ...] + + +class FalCatalogClient: + """Read fal.ai's model catalog and per-endpoint OpenAPI schemas.""" + + def __init__( + self, + api_key: str, + *, + catalog_url: str = _DEFAULT_CATALOG_URL, + schema_url: str = _DEFAULT_SCHEMA_URL, + ) -> None: + self._api_key = api_key + self._catalog_url = catalog_url.rstrip("/") + self._schema_url = schema_url + + def list_models( + self, + *, + limit: int = 50, + cursor: str | None = None, + search: str | None = None, + ) -> FalCatalogPage: + params: dict[str, Any] = {"limit": min(max(limit, 1), _MAX_PAGE_SIZE)} + if cursor: + params["cursor"] = cursor + if search: + params["search"] = search + + response = self._get(f"{self._catalog_url}/v1/models", params=params) + payload = self._parse_object(response, "fal.ai catalog response") + raw_models = payload.get("models") + if not isinstance(raw_models, list): + raise ExternalProviderRequestError("fal.ai catalog response missing models") + + models: list[FalCatalogModel] = [] + for raw_model in raw_models: + if not isinstance(raw_model, dict): + continue + endpoint_id = raw_model.get("endpoint_id") + metadata = raw_model.get("metadata") + if not isinstance(endpoint_id, str) or not endpoint_id or not isinstance(metadata, dict): + continue + models.append( + FalCatalogModel( + endpoint_id=endpoint_id, + display_name=_string_or_default(metadata.get("display_name"), endpoint_id.rsplit("/", 1)[-1]), + description=_string_or_default(metadata.get("description"), ""), + category=_string_or_default(metadata.get("category"), "generic"), + model_url=_optional_string(metadata.get("model_url")), + thumbnail_url=_optional_string(metadata.get("thumbnail_url")), + tags=tuple(value for value in metadata.get("tags", []) if isinstance(value, str)), + ) + ) + + next_cursor = payload.get("next_cursor") + return FalCatalogPage( + models=models, + next_cursor=next_cursor if isinstance(next_cursor, str) and next_cursor else None, + has_more=bool(payload.get("has_more")), + ) + + def get_schema(self, endpoint_id: str) -> FalEndpointSchema: + if not endpoint_id or endpoint_id.startswith("/") or ".." in endpoint_id.split("/"): + raise ExternalProviderRequestError("fal.ai catalog endpoint ID is invalid") + response = self._get(self._schema_url, params={"endpoint_id": endpoint_id}) + payload = self._parse_object(response, "fal.ai catalog schema response") + return normalize_openapi_schema(endpoint_id, payload) + + def _get(self, url: str, *, params: dict[str, Any]) -> requests.Response: + try: + response = requests.get( + url, + headers={"Authorization": f"Key {self._api_key}"}, + params=params, + timeout=_CATALOG_TIMEOUT, + ) + except requests.RequestException as exc: + raise ExternalProviderRequestError(f"fal.ai catalog network request failed: {exc}") from exc + if response.status_code == 429: + retry_after = _parse_retry_after(response.headers.get("Retry-After")) + raise ExternalProviderRateLimitError("fal.ai catalog rate limit exceeded", retry_after=retry_after) + if not response.ok: + raise ExternalProviderRequestError( + f"fal.ai catalog request failed with status {response.status_code}: {response.text}" + ) + return response + + @staticmethod + def _parse_object(response: requests.Response, label: str) -> dict[str, Any]: + try: + payload = response.json() + except ValueError as exc: + raise ExternalProviderRequestError(f"{label} was not valid JSON") from exc + if not isinstance(payload, dict): + raise ExternalProviderRequestError(f"{label} was not a JSON object") + return payload + + +def normalize_openapi_schema(endpoint_id: str, document: dict[str, Any]) -> FalEndpointSchema: + """Extract safe request/output metadata from one fal.ai queue OpenAPI document.""" + components = document.get("components", {}).get("schemas", {}) + if not isinstance(components, dict): + components = {} + + metadata = document.get("info", {}).get("x-fal-metadata", {}) + if not isinstance(metadata, dict): + metadata = {} + category = _string_or_default(metadata.get("category"), "generic") + + paths = document.get("paths") + if not isinstance(paths, dict): + raise ExternalProviderRequestError("fal.ai catalog schema response missing paths") + operation = next( + ( + item.get("post") + for path, item in paths.items() + if isinstance(path, str) and "/requests/" not in path and isinstance(item, dict) and isinstance(item.get("post"), dict) + ), + None, + ) + if not isinstance(operation, dict): + raise ExternalProviderRequestError("fal.ai catalog schema response missing queue POST operation") + + request_schema = _resolve_schema( + operation.get("requestBody", {}).get("content", {}).get("application/json", {}).get("schema"), components + ) + if request_schema.get("type") != "object" or not isinstance(request_schema.get("properties"), dict): + raise ExternalProviderRequestError("fal.ai catalog endpoint has no object input schema") + + output_schema = _find_output_schema(components) + kind = classify_endpoint(category, request_schema, endpoint_id=endpoint_id) + output_kind = _classify_output_schema(output_schema, fallback=kind) + properties = request_schema["properties"] + public_properties = tuple( + name for name, value in properties.items() if isinstance(name, str) and isinstance(value, dict) and not value.get("writeOnly") + ) + + return FalEndpointSchema( + endpoint_id=endpoint_id, + kind=kind, + output_kind=output_kind, + category=category, + input_schema=request_schema, + output_schema=output_schema, + common_fields=_find_common_fields(properties), + public_properties=public_properties, + ) + + +def classify_endpoint(category: str, schema: dict[str, Any], *, endpoint_id: str = "") -> FalEndpointKind: + normalized = category.strip().lower().replace("_", "-") + endpoint = endpoint_id.lower() + if "upscal" in normalized or "upscal" in endpoint: + return FalEndpointKind.UPSCALE + if normalized in {"text-to-image", "text2image", "text-to-img"}: + return FalEndpointKind.TEXT_TO_IMAGE + if normalized in {"image-to-image", "image-editing", "image-edit", "inpainting", "inpaint"}: + return FalEndpointKind.INPAINT if "inpaint" in normalized or "fill" in endpoint else FalEndpointKind.IMAGE_TO_IMAGE + if normalized in {"text-to-video", "text2video"}: + return FalEndpointKind.TEXT_TO_VIDEO + if normalized in {"image-to-video", "image2video"}: + return FalEndpointKind.IMAGE_TO_VIDEO + if normalized in {"video-to-video", "video2video", "video-editing", "video-edit"}: + return FalEndpointKind.VIDEO_TO_VIDEO + if normalized.startswith("audio") or normalized.endswith("-to-audio"): + return FalEndpointKind.AUDIO + properties = schema.get("properties", {}) + if isinstance(properties, dict) and any("video" in str(name).lower() for name in properties): + return FalEndpointKind.IMAGE_TO_VIDEO + return FalEndpointKind.GENERIC + + +def _find_output_schema(components: dict[str, Any]) -> dict[str, Any]: + for name, schema in components.items(): + if isinstance(name, str) and name.lower().endswith("output") and isinstance(schema, dict): + resolved = _resolve_schema(schema, components) + if resolved.get("type") == "object": + return resolved + return {} + + +def _classify_output_schema(schema: dict[str, Any], *, fallback: FalEndpointKind) -> FalEndpointKind: + properties = schema.get("properties", {}) + if not isinstance(properties, dict): + return fallback + names = " ".join(str(name).lower() for name in properties) + if "video" in names: + return FalEndpointKind.IMAGE_TO_VIDEO + if "audio" in names or "speech" in names: + return FalEndpointKind.AUDIO + if "image" in names: + return FalEndpointKind.IMAGE_TO_IMAGE + return fallback + + +def _find_common_fields(properties: dict[str, Any]) -> dict[str, str]: + aliases = { + "prompt": ("prompt", "text", "input_text"), + "negative_prompt": ("negative_prompt", "negative_prompt_text"), + "init_image": ( + "image_url", + "image_urls", + "input_image_url", + "input_image", + "start_image_url", + "first_frame_url", + ), + "mask_image": ("mask_url", "mask_image_url", "mask"), + "init_video": ("video_url", "video_urls", "input_video_url"), + "seed": ("seed",), + "num_images": ("num_images", "num_outputs", "num_inference_images"), + "width": ("width", "output_width"), + "height": ("height", "output_height"), + "aspect_ratio": ("aspect_ratio",), + "image_size": ("image_size", "resolution", "output_size"), + "duration": ("duration", "video_length", "num_frames"), + "fps": ("fps", "frame_rate"), + } + return { + common_name: next((candidate for candidate in candidates if candidate in properties), "") + for common_name, candidates in aliases.items() + if any(candidate in properties for candidate in candidates) + } + + +def _resolve_schema(schema: Any, components: dict[str, Any]) -> dict[str, Any]: + if not isinstance(schema, dict): + return {} + resolved = copy.deepcopy(schema) + reference = resolved.pop("$ref", None) + if isinstance(reference, str) and reference.startswith("#/components/schemas/"): + target = components.get(reference.removeprefix("#/components/schemas/")) + if isinstance(target, dict): + resolved = _resolve_schema(target, components) + resolved.update({key: value for key, value in schema.items() if key != "$ref"}) + return resolved + + +def _string_or_default(value: Any, default: str) -> str: + return value if isinstance(value, str) and value else default + + +def _optional_string(value: Any) -> str | None: + return value if isinstance(value, str) and value else None + + +def _parse_retry_after(value: str | None) -> float | None: + if not value: + return None + try: + return float(value) + except ValueError: + return None + + +__all__ = [ + "FalCatalogClient", + "FalCatalogModel", + "FalCatalogPage", + "FalEndpointKind", + "FalEndpointSchema", + "classify_endpoint", + "normalize_openapi_schema", +] diff --git a/tests/app/services/external_generation/test_fal_catalog.py b/tests/app/services/external_generation/test_fal_catalog.py new file mode 100644 index 00000000000..b21df6f8174 --- /dev/null +++ b/tests/app/services/external_generation/test_fal_catalog.py @@ -0,0 +1,138 @@ +from typing import Any + +import pytest + +from invokeai.app.services.external_generation.errors import ExternalProviderRequestError +from invokeai.app.services.external_generation.providers.fal_catalog import ( + FalCatalogClient, + FalEndpointKind, + classify_endpoint, + normalize_openapi_schema, +) + + +class DummyResponse: + def __init__(self, *, json_data: dict[str, Any], status_code: int = 200, text: str = "") -> None: + self.status_code = status_code + self.ok = status_code < 400 + self._json_data = json_data + self.text = text + self.headers: dict[str, str] = {} + + def json(self) -> dict[str, Any]: + return self._json_data + + +def _schema() -> dict[str, Any]: + return { + "openapi": "3.0.4", + "info": { + "title": "Queue OpenAPI for fal-ai/test", + "x-fal-metadata": { + "endpointId": "fal-ai/test", + "category": "image-to-video", + "about": "test endpoint", + }, + }, + "paths": { + "/fal-ai/test": { + "post": { + "requestBody": { + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TestInput"}}} + }, + "responses": { + "200": { + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TestOutput"}}} + } + }, + } + } + }, + "components": { + "schemas": { + "TestInput": { + "type": "object", + "required": ["prompt", "start_image_url"], + "properties": { + "prompt": {"type": "string", "description": "Motion prompt"}, + "start_image_url": {"type": "string", "format": "uri"}, + "duration": {"type": "string", "enum": ["5", "10"], "default": "5"}, + "secret": {"type": "string", "writeOnly": True}, + }, + }, + "TestOutput": { + "type": "object", + "properties": {"video": {"type": "object", "properties": {"url": {"type": "string"}}}}, + }, + } + }, + } + + +def test_normalize_openapi_schema_resolves_refs_and_common_aliases() -> None: + normalized = normalize_openapi_schema("fal-ai/test", _schema()) + + assert normalized.endpoint_id == "fal-ai/test" + assert normalized.kind is FalEndpointKind.IMAGE_TO_VIDEO + assert normalized.input_schema["required"] == ["prompt", "start_image_url"] + assert normalized.input_schema["properties"]["duration"]["enum"] == ["5", "10"] + assert normalized.common_fields == {"prompt": "prompt", "init_image": "start_image_url", "duration": "duration"} + assert normalized.output_kind is FalEndpointKind.IMAGE_TO_VIDEO + assert "secret" not in normalized.public_properties + + +def test_classify_endpoint_keeps_unknown_categories_generic() -> None: + assert classify_endpoint("speech-to-text", {}) is FalEndpointKind.GENERIC + assert classify_endpoint("text-to-image", {}) is FalEndpointKind.TEXT_TO_IMAGE + assert classify_endpoint("upscaling", {}) is FalEndpointKind.UPSCALE + + +def test_catalog_client_lists_pages_and_fetches_schema(monkeypatch: pytest.MonkeyPatch) -> None: + calls: list[tuple[str, dict[str, Any]]] = [] + + def fake_get(url: str, **kwargs: Any) -> DummyResponse: + calls.append((url, kwargs)) + if url.endswith("/v1/models"): + return DummyResponse( + json_data={ + "models": [ + { + "endpoint_id": "fal-ai/test", + "metadata": { + "display_name": "Test model", + "category": "image-to-video", + "description": "A test model", + "tags": ["video"], + "thumbnail_url": "https://cdn.test/thumb.jpg", + }, + } + ], + "next_cursor": "next", + "has_more": True, + } + ) + return DummyResponse(json_data=_schema()) + + monkeypatch.setattr("requests.get", fake_get) + client = FalCatalogClient("test-key") + + page = client.list_models(limit=10, cursor="old", search="test") + schema = client.get_schema("fal-ai/test") + + assert page.next_cursor == "next" + assert page.has_more is True + assert page.models[0].endpoint_id == "fal-ai/test" + assert page.models[0].display_name == "Test model" + assert schema.kind is FalEndpointKind.IMAGE_TO_VIDEO + assert calls[0][0] == "https://api.fal.ai/v1/models" + assert calls[0][1]["params"] == {"limit": 10, "cursor": "old", "search": "test"} + assert calls[1][0] == "https://fal.ai/api/openapi/queue/openapi.json" + assert calls[1][1]["params"] == {"endpoint_id": "fal-ai/test"} + + +def test_catalog_client_rejects_non_object_schema(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr("requests.get", lambda *args, **kwargs: DummyResponse(json_data={"models": []})) + client = FalCatalogClient("test-key") + + with pytest.raises(ExternalProviderRequestError, match="catalog"): + client.get_schema("fal-ai/bad") From 86c9faadf7c21ba0719bd3d457c36772b7bcff61 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Aug 2026 23:46:40 +0300 Subject: [PATCH 6/8] feat: expose schema-driven fal.ai media endpoints --- invokeai/app/api/routers/app_info.py | 227 +++++++++++++++++- .../invocations/external_media_generation.py | 36 +++ .../external_generation_base.py | 8 + .../external_generation_default.py | 12 + .../external_generation/providers/fal.py | 133 ++++++++-- .../app/invocations/test_fal_generic_media.py | 35 +++ tests/app/routers/test_app_info.py | 155 ++++++++++++ .../external_generation/test_fal_provider.py | 78 +++++- 8 files changed, 663 insertions(+), 21 deletions(-) create mode 100644 invokeai/app/invocations/external_media_generation.py create mode 100644 tests/app/invocations/test_fal_generic_media.py diff --git a/invokeai/app/api/routers/app_info.py b/invokeai/app/api/routers/app_info.py index ee091398c37..5413c7fbc78 100644 --- a/invokeai/app/api/routers/app_info.py +++ b/invokeai/app/api/routers/app_info.py @@ -25,9 +25,17 @@ load_external_api_keys, ) from invokeai.app.services.external_generation.external_generation_common import ExternalProviderStatus +from invokeai.app.services.external_generation.providers.fal_catalog import ( + FalCatalogClient, + FalEndpointKind, + FalEndpointSchema, + classify_endpoint, +) from invokeai.app.services.invocation_cache.invocation_cache_common import InvocationCacheStatus -from invokeai.app.services.model_records.model_records_base import UnknownModelException +from invokeai.app.services.model_install.model_install_common import ModelInstallJob +from invokeai.app.services.model_records.model_records_base import ModelRecordChanges, UnknownModelException from invokeai.backend.image_util.infill_methods.patchmatch import PatchMatch +from invokeai.backend.model_manager.configs.external_api import ExternalApiModelConfig, ExternalModelCapabilities from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType from invokeai.backend.util.devices import TorchDevice from invokeai.backend.util.logging import logging @@ -101,6 +109,39 @@ class ExternalProviderConfigModel(BaseModel): base_url: str | None = Field(default=None, description="Optional base URL override") +class FalCatalogModelResponse(BaseModel): + endpoint_id: str + display_name: str + description: str + category: str + kind: FalEndpointKind + model_url: str | None + thumbnail_url: str | None + tags: list[str] + installed: bool + + +class FalCatalogResponse(BaseModel): + models: list[FalCatalogModelResponse] + next_cursor: str | None + has_more: bool + + +class FalEndpointSchemaResponse(BaseModel): + endpoint_id: str + kind: FalEndpointKind + output_kind: FalEndpointKind + category: str + input_schema: dict[str, Any] + output_schema: dict[str, Any] + common_fields: dict[str, str] + public_properties: list[str] + + +class FalModelInstallRequest(BaseModel): + endpoint_id: str = Field(min_length=1, max_length=512, description="fal.ai endpoint identifier") + + EXTERNAL_PROVIDER_FIELDS: dict[str, tuple[str, str]] = { "fal": ("external_fal_api_key", "external_fal_base_url"), "alibabacloud": ("external_alibabacloud_api_key", "external_alibabacloud_base_url"), @@ -515,3 +556,187 @@ def disable_invocation_cache(current_admin: AdminUserOrDefault) -> None: def get_invocation_cache_status(current_admin: AdminUserOrDefault) -> InvocationCacheStatus: """Clears the invocation cache""" return ApiDependencies.invoker.services.invocation_cache.get_status() + + +@app_router.get( + "/external_providers/fal/models", + operation_id="list_fal_models", + status_code=200, + response_model=FalCatalogResponse, +) +def list_fal_models( + _: AdminUserOrDefault, + limit: int = 50, + cursor: str | None = None, + search: str | None = None, +) -> FalCatalogResponse: + client = _get_fal_catalog_client() + try: + page = client.list_models(limit=limit, cursor=cursor, search=search) + except Exception as exc: + _raise_fal_catalog_http_error(exc) + installed = _get_installed_fal_models() + return FalCatalogResponse( + models=[ + FalCatalogModelResponse( + endpoint_id=model.endpoint_id, + display_name=model.display_name, + description=model.description, + category=model.category, + kind=classify_endpoint(model.category, {}, endpoint_id=model.endpoint_id), + model_url=model.model_url, + thumbnail_url=model.thumbnail_url, + tags=list(model.tags), + installed=model.endpoint_id in installed, + ) + for model in page.models + ], + next_cursor=page.next_cursor, + has_more=page.has_more, + ) + + +@app_router.get( + "/external_providers/fal/models/{endpoint_id:path}/schema", + operation_id="get_fal_model_schema", + status_code=200, + response_model=FalEndpointSchemaResponse, +) +def get_fal_model_schema( + _: AdminUserOrDefault, + endpoint_id: str = Path(description="fal.ai endpoint identifier"), +) -> FalEndpointSchemaResponse: + client = _get_fal_catalog_client() + try: + schema = client.get_schema(endpoint_id) + except Exception as exc: + _raise_fal_catalog_http_error(exc) + return _fal_schema_to_response(schema) + + +@app_router.post( + "/external_providers/fal/models/install", + operation_id="install_fal_model", + status_code=201, + response_model=ModelInstallJob, +) +def install_fal_model( + _: AdminUserOrDefault, + request: FalModelInstallRequest, +) -> ModelInstallJob: + client = _get_fal_catalog_client() + try: + schema = client.get_schema(request.endpoint_id) + except Exception as exc: + _raise_fal_catalog_http_error(exc) + + if schema.kind not in _FAL_NATIVE_IMAGE_KINDS: + raise HTTPException( + status_code=422, + detail=( + f"fal.ai endpoint '{request.endpoint_id}' is {schema.kind.value}; " + "use the fal.ai generic media invocation for this endpoint" + ), + ) + + config = ModelRecordChanges( + name=f"fal.ai {request.endpoint_id}", + description=f"Dynamic fal.ai endpoint ({schema.category}).", + provider_id="fal", + provider_model_id=request.endpoint_id, + source_url=f"https://fal.ai/models/{request.endpoint_id}", + capabilities=_fal_capabilities_from_schema(schema), + ) + try: + return ApiDependencies.invoker.services.model_manager.install.heuristic_import( + source=f"external://fal/{request.endpoint_id}", + config=config, + ) + except Exception as exc: + raise HTTPException(status_code=409, detail=f"Unable to install fal.ai model: {exc}") from exc + + +_FAL_NATIVE_IMAGE_KINDS = { + FalEndpointKind.TEXT_TO_IMAGE, + FalEndpointKind.IMAGE_TO_IMAGE, + FalEndpointKind.INPAINT, + FalEndpointKind.UPSCALE, +} + + +def _fal_capabilities_from_schema(schema: FalEndpointSchema) -> ExternalModelCapabilities: + if schema.kind is FalEndpointKind.TEXT_TO_IMAGE: + modes = ["txt2img"] + elif schema.kind is FalEndpointKind.INPAINT: + modes = ["inpaint"] + else: + modes = ["img2img"] + + properties = schema.input_schema.get("properties", {}) + if not isinstance(properties, dict): + properties = {} + ratios = properties.get(schema.common_fields.get("aspect_ratio", ""), {}) + allowed_ratios = ratios.get("enum") if isinstance(ratios, dict) else None + if not isinstance(allowed_ratios, list) or not all(isinstance(value, str) for value in allowed_ratios): + allowed_ratios = None + + num_images_name = schema.common_fields.get("num_images", "") + num_images_schema = properties.get(num_images_name, {}) + maximum = num_images_schema.get("maximum") if isinstance(num_images_schema, dict) else None + max_images = maximum if isinstance(maximum, int) and maximum > 0 else None + + return ExternalModelCapabilities( + modes=modes, # type: ignore[arg-type] + supports_reference_images="image_urls" in schema.common_fields.get("init_image", ""), + supports_negative_prompt="negative_prompt" in schema.common_fields, + supports_seed="seed" in schema.common_fields, + max_images_per_request=max_images, + allowed_aspect_ratios=allowed_ratios, + mask_format="binary" if "mask_image" in schema.common_fields else "none", + input_image_required_for=[modes[0]] if modes[0] != "txt2img" else None, # type: ignore[list-item] + ) + + +def _get_fal_catalog_client() -> FalCatalogClient: + config = get_config() + api_key = config.external_fal_api_key or os.getenv("FAL_KEY") or os.getenv("FAL_API_KEY") + if not api_key: + raise HTTPException(status_code=409, detail="fal.ai API key is not configured") + return FalCatalogClient(api_key) + + +def _get_installed_fal_models() -> set[str]: + models = ApiDependencies.invoker.services.model_manager.store.search_by_attr( + base_model=BaseModelType.External, + model_type=ModelType.ExternalImageGenerator, + ) + return { + model.provider_model_id + for model in models + if isinstance(model, ExternalApiModelConfig) + and model.provider_id == "fal" + and model.provider_model_id + } + + +def _fal_schema_to_response(schema: FalEndpointSchema) -> FalEndpointSchemaResponse: + return FalEndpointSchemaResponse( + endpoint_id=schema.endpoint_id, + kind=schema.kind, + output_kind=schema.output_kind, + category=schema.category, + input_schema=schema.input_schema, + output_schema=schema.output_schema, + common_fields=schema.common_fields, + public_properties=list(schema.public_properties), + ) + + +def _raise_fal_catalog_http_error(exc: Exception) -> None: + from invokeai.app.services.external_generation.errors import ExternalProviderRateLimitError, ExternalProviderRequestError + + if isinstance(exc, ExternalProviderRateLimitError): + raise HTTPException(status_code=429, detail=str(exc)) from exc + if isinstance(exc, ExternalProviderRequestError): + raise HTTPException(status_code=502, detail=str(exc)) from exc + raise HTTPException(status_code=502, detail="fal.ai catalog request failed") from exc diff --git a/invokeai/app/invocations/external_media_generation.py b/invokeai/app/invocations/external_media_generation.py new file mode 100644 index 00000000000..7c2949b19cf --- /dev/null +++ b/invokeai/app/invocations/external_media_generation.py @@ -0,0 +1,36 @@ +import json +from typing import Any + +from invokeai.app.invocations.baseinvocation import BaseInvocation, invocation +from invokeai.app.invocations.fields import InputField +from invokeai.app.invocations.primitives import StringOutput +from invokeai.app.services.shared.invocation_context import InvocationContext + + +@invocation( + "fal_generic_media", + title="fal.ai Generic Media", + tags=["external", "generation", "fal", "fal.ai", "generic"], + category="media", + version="1.0.0", +) +class FalGenericMediaInvocation(BaseInvocation): + """Submit arbitrary JSON to any fal.ai endpoint and return its raw JSON result.""" + + model_id: str = InputField(description="fal.ai endpoint ID, for example fal-ai/kling-video/v3/pro/text-to-video") + input_json: str = InputField(default="{}", description="JSON object sent to the fal.ai endpoint") + + def invoke(self, context: InvocationContext) -> StringOutput: + try: + payload = json.loads(self.input_json) + except json.JSONDecodeError as exc: + raise ValueError(f"fal.ai input_json is not valid JSON: {exc.msg}") from exc + if not isinstance(payload, dict): + raise ValueError("fal.ai input_json must be a JSON object") + + result: dict[str, Any] = context._services.external_generation.generate_generic( + provider_id="fal", + model_id=self.model_id, + payload=payload, + ) + return StringOutput(value=json.dumps(result, ensure_ascii=False, sort_keys=True)) diff --git a/invokeai/app/services/external_generation/external_generation_base.py b/invokeai/app/services/external_generation/external_generation_base.py index 2145ff5ca42..bd9eae2acef 100644 --- a/invokeai/app/services/external_generation/external_generation_base.py +++ b/invokeai/app/services/external_generation/external_generation_base.py @@ -26,6 +26,10 @@ def is_configured(self) -> bool: def generate(self, request: ExternalGenerationRequest) -> ExternalGenerationResult: raise NotImplementedError + def generate_generic(self, model_id: str, payload: dict[str, object]) -> dict[str, object]: + """Submit provider-specific JSON for endpoints outside normalized image generation.""" + raise NotImplementedError(f"Provider '{self.provider_id}' does not support generic media generation") + def get_status(self) -> ExternalProviderStatus: return ExternalProviderStatus(provider_id=self.provider_id, configured=self.is_configured()) @@ -38,3 +42,7 @@ def generate(self, request: ExternalGenerationRequest) -> ExternalGenerationResu @abstractmethod def get_provider_statuses(self) -> dict[str, ExternalProviderStatus]: raise NotImplementedError + + @abstractmethod + def generate_generic(self, provider_id: str, model_id: str, payload: dict[str, object]) -> dict[str, object]: + raise NotImplementedError diff --git a/invokeai/app/services/external_generation/external_generation_default.py b/invokeai/app/services/external_generation/external_generation_default.py index d6a266753b3..05e64d63f81 100644 --- a/invokeai/app/services/external_generation/external_generation_default.py +++ b/invokeai/app/services/external_generation/external_generation_default.py @@ -13,6 +13,7 @@ ExternalProviderNotConfiguredError, ExternalProviderNotFoundError, ExternalProviderRateLimitError, + ExternalProviderRequestError, ) from invokeai.app.services.external_generation.external_generation_base import ( ExternalGenerationServiceBase, @@ -91,6 +92,17 @@ def _generate_with_retry( def get_provider_statuses(self) -> dict[str, ExternalProviderStatus]: return {provider_id: provider.get_status() for provider_id, provider in self._providers.items()} + def generate_generic(self, provider_id: str, model_id: str, payload: dict[str, object]) -> dict[str, object]: + provider = self._providers.get(provider_id) + if provider is None: + raise ExternalProviderRequestError(f"No external provider registered for '{provider_id}'") + if not provider.is_configured(): + raise ExternalProviderRequestError(f"Provider '{provider_id}' is missing credentials") + try: + return provider.generate_generic(model_id, payload) + except NotImplementedError as exc: + raise ExternalProviderRequestError(str(exc)) from exc + def _validate_request(self, request: ExternalGenerationRequest) -> None: capabilities = request.model.capabilities diff --git a/invokeai/app/services/external_generation/providers/fal.py b/invokeai/app/services/external_generation/providers/fal.py index 61137c55ac0..c5d7672099f 100644 --- a/invokeai/app/services/external_generation/providers/fal.py +++ b/invokeai/app/services/external_generation/providers/fal.py @@ -4,6 +4,7 @@ import io import os import time +from logging import Logger from typing import Any import requests @@ -15,6 +16,7 @@ ExternalProviderRequestError, ) from invokeai.app.services.external_generation.external_generation_base import ExternalProvider +from invokeai.app.services.external_generation.providers.fal_catalog import FalCatalogClient, FalEndpointSchema from invokeai.app.services.external_generation.external_generation_common import ( ExternalGeneratedImage, ExternalGenerationRequest, @@ -48,6 +50,10 @@ class FalProvider(ExternalProvider): provider_id = "fal" + def __init__(self, app_config: InvokeAIAppConfig, logger: Logger) -> None: + super().__init__(app_config, logger) + self._schema_cache: dict[str, FalEndpointSchema] = {} + def is_configured(self) -> bool: return bool(self._api_key()) @@ -65,8 +71,28 @@ def generate(self, request: ExternalGenerationRequest) -> ExternalGenerationResu mask = ImageOps.invert(request.mask_image.convert("L")) mask_url = self._upload_image(mask, "mask.png", headers) - payload = self._build_payload(request, image_url=image_url, mask_url=mask_url) model_id = request.model.provider_model_id + schema = self._get_schema(model_id) + payload = ( + build_schema_payload(request, schema, image_url=image_url, mask_url=mask_url) + if schema is not None + else self._build_payload(request, image_url=image_url, mask_url=mask_url) + ) + result_payload, request_id = self._submit_queue(model_id, payload, headers) + return self._parse_result(result_payload, request, request_id=request_id) + + def generate_generic(self, model_id: str, payload: dict[str, Any]) -> dict[str, Any]: + """Submit arbitrary JSON to a fal.ai endpoint and return its raw result.""" + api_key = self._api_key() + if not api_key: + raise ExternalProviderRequestError("fal.ai API key is not configured") + headers = {"Authorization": f"Key {api_key}", "Content-Type": "application/json"} + result, _ = self._submit_queue(model_id, payload, headers) + return result + + def _submit_queue( + self, model_id: str, payload: dict[str, Any], headers: dict[str, str] + ) -> tuple[dict[str, Any], str | None]: queue_url = f"{self._queue_base_url}/{model_id}" submit_response = self._request( "POST", @@ -80,12 +106,21 @@ def generate(self, request: ExternalGenerationRequest) -> ExternalGenerationResu request_id = submitted.get("request_id") if not isinstance(request_id, str) or not request_id: - if self._has_images(submitted): - return self._parse_result(submitted, request, request_id=None) - raise ExternalProviderRequestError("fal.ai queue response missing request_id") + return submitted, None + return self._wait_for_result(model_id, request_id, headers), request_id - result_payload = self._wait_for_result(model_id, request_id, headers) - return self._parse_result(result_payload, request, request_id=request_id) + def _get_schema(self, model_id: str) -> FalEndpointSchema | None: + if model_id in _FLUX_FILL_MODELS | _FLUX_KONTEXT_MODELS | _FLUX_TEXT_MODELS: + return None + cached = self._schema_cache.get(model_id) + if cached is not None: + return cached + api_key = self._api_key() + if not api_key: + return None + schema = FalCatalogClient(api_key).get_schema(model_id) + self._schema_cache[model_id] = schema + return schema def _api_key(self) -> str | None: return self._app_config.external_fal_api_key or os.getenv("FAL_KEY") or os.getenv("FAL_API_KEY") @@ -135,8 +170,8 @@ def _build_payload( payload["image_size"] = _image_size_for_ratio(ratio) return payload - # Unknown external models get conservative common arguments. Curated models above - # use exact schemas; custom external model records can still use txt2img safely. + # Unknown models are schema-driven. This branch is retained for callers that use the provider + # directly with a model whose schema cannot be fetched yet. if image_url is not None: payload["image_url"] = image_url if mask_url is not None: @@ -216,18 +251,12 @@ def _parse_result( *, request_id: str | None, ) -> ExternalGenerationResult: - image_items = payload.get("images") - if not isinstance(image_items, list): - data_items = payload.get("data") - image_items = data_items if isinstance(data_items, list) else [] - + image_items = _extract_image_items(payload) seed_value = payload.get("seed") seed = seed_value if isinstance(seed_value, int) else request.seed images: list[ExternalGeneratedImage] = [] for item in image_items: - if not isinstance(item, dict): - continue - url = item.get("url") or item.get("image_url") + url = item if isinstance(item, str) else item.get("url") or item.get("image_url") if isinstance(url, str) and url: images.append(ExternalGeneratedImage(image=self._download_image(url), seed=seed)) @@ -274,8 +303,7 @@ def _download_image(self, url: str) -> PILImageType: @staticmethod def _has_images(payload: dict[str, Any]) -> bool: - images = payload.get("images") - return isinstance(images, list) and bool(images) + return bool(_extract_image_items(payload)) @staticmethod def _parse_json(response: requests.Response, label: str) -> dict[str, Any]: @@ -311,6 +339,21 @@ def _raise_for_response(response: requests.Response, operation: str) -> None: raise ExternalProviderRequestError(f"{operation} failed with status {response.status_code}: {response.text}") +def _extract_image_items(payload: dict[str, Any]) -> list[Any]: + for key in ("images", "data"): + value = payload.get(key) + if isinstance(value, list) and value: + return value + for key in ("image", "image_url"): + value = payload.get(key) + if isinstance(value, (str, dict)): + return [value] + image_urls = payload.get("image_urls") + if isinstance(image_urls, list): + return image_urls + return [] + + def _encode_png(image: PILImageType) -> bytes: buffer = io.BytesIO() image.save(buffer, format="PNG") @@ -358,4 +401,56 @@ def _retry_delay(response: requests.Response) -> float: return min(retry_after if retry_after is not None else _POLL_INTERVAL, 60.0) -__all__ = ["FalProvider"] +def build_schema_payload( + request: ExternalGenerationRequest, + schema: FalEndpointSchema, + *, + image_url: str | None, + mask_url: str | None, +) -> dict[str, Any]: + """Build payload for one endpoint using only fields declared by its OpenAPI schema.""" + properties = schema.input_schema.get("properties", {}) + if not isinstance(properties, dict): + properties = {} + advanced = request.provider_options.get("advanced", {}) if request.provider_options else {} + payload = { + name: value + for name, value in advanced.items() + if name in schema.public_properties and name in properties + } if isinstance(advanced, dict) else {} + + ratio = _select_aspect_ratio(request.width, request.height, request.model.capabilities.allowed_aspect_ratios) + common_values: dict[str, Any] = { + "prompt": request.prompt, + "seed": request.seed, + "num_images": request.num_images if request.num_images > 1 else None, + "width": request.width, + "height": request.height, + "aspect_ratio": ratio, + "image_size": request.image_size or _image_size_for_ratio(ratio), + "init_image": image_url, + "mask_image": mask_url, + } + for common_name, value in common_values.items(): + field_name = schema.common_fields.get(common_name) + if not field_name or value is None: + continue + property_schema = properties.get(field_name) + if not isinstance(property_schema, dict): + continue + if common_name == "image_size" and not _value_is_allowed(value, property_schema): + continue + if common_name == "aspect_ratio" and not _value_is_allowed(value, property_schema): + continue + if common_name in {"init_image", "mask_image"} and property_schema.get("type") == "array": + value = [value] + payload[field_name] = value + return payload + + +def _value_is_allowed(value: Any, property_schema: dict[str, Any]) -> bool: + allowed = property_schema.get("enum") + return not isinstance(allowed, list) or value in allowed + + +__all__ = ["FalProvider", "build_schema_payload"] diff --git a/tests/app/invocations/test_fal_generic_media.py b/tests/app/invocations/test_fal_generic_media.py new file mode 100644 index 00000000000..38af6260d3b --- /dev/null +++ b/tests/app/invocations/test_fal_generic_media.py @@ -0,0 +1,35 @@ +from unittest.mock import MagicMock + +import pytest + +from invokeai.app.invocations.external_media_generation import FalGenericMediaInvocation + + +def test_fal_generic_media_invocation_submits_declared_json_and_returns_raw_result() -> None: + context = MagicMock() + context._services.external_generation.generate_generic.return_value = { + "video": {"url": "https://cdn.test/video.mp4"}, + "seed": 7, + } + invocation = FalGenericMediaInvocation( + id="fal_generic", + model_id="fal-ai/video", + input_json='{"prompt": "A moving test", "duration": "5"}', + ) + + output = invocation.invoke(context) + + context._services.external_generation.generate_generic.assert_called_once_with( + provider_id="fal", + model_id="fal-ai/video", + payload={"prompt": "A moving test", "duration": "5"}, + ) + assert output.value == '{"seed": 7, "video": {"url": "https://cdn.test/video.mp4"}}' + + +def test_fal_generic_media_invocation_rejects_non_object_json() -> None: + context = MagicMock() + invocation = FalGenericMediaInvocation(id="fal_generic", model_id="fal-ai/video", input_json="[]") + + with pytest.raises(ValueError, match="JSON object"): + invocation.invoke(context) diff --git a/tests/app/routers/test_app_info.py b/tests/app/routers/test_app_info.py index 8c8aa80d95d..cebbf813ced 100644 --- a/tests/app/routers/test_app_info.py +++ b/tests/app/routers/test_app_info.py @@ -497,5 +497,160 @@ def test_reset_external_provider_config_rejects_non_admin_users( assert response.json()["detail"] == "Admin privileges required" +def test_list_fal_catalog_models_without_exposing_credentials( + monkeypatch: Any, mock_invoker: Invoker, client: TestClient +) -> None: + monkeypatch.setenv("FAL_KEY", "secret-key") + mock_store = Mock() + mock_store.search_by_attr.return_value = [] + mock_invoker.services.model_manager = Mock(store=mock_store) + monkeypatch.setattr("invokeai.app.api.routers.app_info.ApiDependencies", MockApiDependencies(mock_invoker)) + monkeypatch.setattr("invokeai.app.api.auth_dependencies.ApiDependencies", MockApiDependencies(mock_invoker)) + + class FakeCatalogClient: + def __init__(self, api_key: str) -> None: + assert api_key == "secret-key" + + def list_models(self, **kwargs: Any) -> Any: + from invokeai.app.services.external_generation.providers.fal_catalog import FalCatalogModel, FalCatalogPage + + return FalCatalogPage( + models=[ + FalCatalogModel( + endpoint_id="fal-ai/test", + display_name="Test model", + description="Safe description", + category="text-to-image", + model_url="https://fal.ai/models/fal-ai/test", + thumbnail_url="https://cdn.test/thumb.jpg", + tags=("image",), + ) + ], + next_cursor="next", + has_more=True, + ) + + monkeypatch.setattr(app_info, "FalCatalogClient", FakeCatalogClient) + response = client.get("/api/v1/app/external_providers/fal/models?limit=10&search=test") + + assert response.status_code == 200 + assert response.json() == { + "models": [ + { + "endpoint_id": "fal-ai/test", + "display_name": "Test model", + "description": "Safe description", + "category": "text-to-image", + "kind": "text-to-image", + "model_url": "https://fal.ai/models/fal-ai/test", + "thumbnail_url": "https://cdn.test/thumb.jpg", + "tags": ["image"], + "installed": False, + } + ], + "next_cursor": "next", + "has_more": True, + } + assert "secret-key" not in response.text + + +def test_get_fal_endpoint_schema_requires_configured_key( + monkeypatch: Any, mock_invoker: Invoker, client: TestClient +) -> None: + monkeypatch.delenv("FAL_KEY", raising=False) + monkeypatch.delenv("FAL_API_KEY", raising=False) + monkeypatch.setattr("invokeai.app.api.routers.app_info.ApiDependencies", MockApiDependencies(mock_invoker)) + monkeypatch.setattr("invokeai.app.api.auth_dependencies.ApiDependencies", MockApiDependencies(mock_invoker)) + + response = client.get("/api/v1/app/external_providers/fal/models/fal-ai/test/schema") + + assert response.status_code == 409 + assert response.json()["detail"] == "fal.ai API key is not configured" + + +def test_install_fal_image_model_from_catalog_schema( + monkeypatch: Any, mock_invoker: Invoker, client: TestClient +) -> None: + monkeypatch.setenv("FAL_KEY", "secret-key") + schema = _fake_fal_schema("fal-ai/test", "text-to-image") + + class FakeCatalogClient: + def __init__(self, api_key: str) -> None: + assert api_key == "secret-key" + + def get_schema(self, endpoint_id: str) -> Any: + assert endpoint_id == "fal-ai/test" + return schema + + install = Mock() + mock_invoker.services.model_manager = Mock(install=install, store=Mock()) + monkeypatch.setattr(app_info, "FalCatalogClient", FakeCatalogClient) + monkeypatch.setattr("invokeai.app.api.routers.app_info.ApiDependencies", MockApiDependencies(mock_invoker)) + monkeypatch.setattr("invokeai.app.api.auth_dependencies.ApiDependencies", MockApiDependencies(mock_invoker)) + + from invokeai.app.services.model_install.model_install_common import ExternalModelSource, ModelInstallJob + + install.heuristic_import.return_value = ModelInstallJob( + id=1, + source=ExternalModelSource(provider_id="fal", provider_model_id="fal-ai/test"), + local_path=".", + ) + response = client.post("/api/v1/app/external_providers/fal/models/install", json={"endpoint_id": "fal-ai/test"}) + + assert response.status_code == 201 + install.heuristic_import.assert_called_once() + call = install.heuristic_import.call_args.kwargs + assert call["source"] == "external://fal/fal-ai/test" + assert call["config"].provider_id == "fal" + assert call["config"].provider_model_id == "fal-ai/test" + assert call["config"].capabilities.modes == ["txt2img"] + + +def test_install_fal_video_model_requires_generic_media_node( + monkeypatch: Any, mock_invoker: Invoker, client: TestClient +) -> None: + monkeypatch.setenv("FAL_KEY", "secret-key") + schema = _fake_fal_schema("fal-ai/video", "image-to-video") + + class FakeCatalogClient: + def __init__(self, api_key: str) -> None: + del api_key + + def get_schema(self, endpoint_id: str) -> Any: + del endpoint_id + return schema + + monkeypatch.setattr(app_info, "FalCatalogClient", FakeCatalogClient) + monkeypatch.setattr("invokeai.app.api.routers.app_info.ApiDependencies", MockApiDependencies(mock_invoker)) + monkeypatch.setattr("invokeai.app.api.auth_dependencies.ApiDependencies", MockApiDependencies(mock_invoker)) + + response = client.post("/api/v1/app/external_providers/fal/models/install", json={"endpoint_id": "fal-ai/video"}) + + assert response.status_code == 422 + assert "generic media" in response.json()["detail"] + + +def _fake_fal_schema(endpoint_id: str, category: str) -> Any: + from invokeai.app.services.external_generation.providers.fal_catalog import ( + FalEndpointKind, + FalEndpointSchema, + ) + + kind = { + "text-to-image": FalEndpointKind.TEXT_TO_IMAGE, + "image-to-video": FalEndpointKind.IMAGE_TO_VIDEO, + }[category] + return FalEndpointSchema( + endpoint_id=endpoint_id, + kind=kind, + output_kind=kind, + category=category, + input_schema={"type": "object", "properties": {"prompt": {"type": "string"}}}, + output_schema={}, + common_fields={"prompt": "prompt"}, + public_properties=("prompt",), + ) + + def _get_provider_config(payload: list[dict[str, Any]], provider_id: str) -> dict[str, Any]: return next(item for item in payload if item["provider_id"] == provider_id) diff --git a/tests/app/services/external_generation/test_fal_provider.py b/tests/app/services/external_generation/test_fal_provider.py index 3709beb4e05..7c9c41971b0 100644 --- a/tests/app/services/external_generation/test_fal_provider.py +++ b/tests/app/services/external_generation/test_fal_provider.py @@ -11,7 +11,8 @@ from invokeai.app.services.external_generation.external_generation_common import ( ExternalGenerationRequest, ) -from invokeai.app.services.external_generation.providers.fal import FalProvider +from invokeai.app.services.external_generation.providers.fal import FalProvider, build_schema_payload +from invokeai.app.services.external_generation.providers.fal_catalog import FalEndpointKind, FalEndpointSchema from invokeai.backend.model_manager.configs.external_api import ( ExternalApiModelConfig, ExternalImageSize, @@ -86,6 +87,7 @@ def _request( mode: str = "txt2img", init_image: Image.Image | None = None, mask_image: Image.Image | None = None, + provider_options: dict[str, Any] | None = None, ) -> ExternalGenerationRequest: return ExternalGenerationRequest( model=model, @@ -100,9 +102,40 @@ def _request( mask_image=mask_image, reference_images=[], metadata=None, + provider_options=provider_options, ) +def test_build_schema_payload_allows_declared_advanced_fields_and_overrides_common_values() -> None: + schema = FalEndpointSchema( + endpoint_id="fal-ai/custom", + kind=FalEndpointKind.TEXT_TO_IMAGE, + output_kind=FalEndpointKind.IMAGE_TO_IMAGE, + category="text-to-image", + input_schema={ + "type": "object", + "properties": { + "prompt": {"type": "string"}, + "aspect_ratio": {"type": "string", "enum": ["1:1", "16:9"]}, + "seed": {"type": "integer"}, + "style": {"type": "string"}, + "write_only_secret": {"type": "string", "writeOnly": True}, + }, + }, + output_schema={}, + common_fields={"prompt": "prompt", "aspect_ratio": "aspect_ratio", "seed": "seed"}, + public_properties=("prompt", "aspect_ratio", "seed", "style"), + ) + request = _request( + _model("fal-ai/custom", modes=["txt2img"]), + provider_options={"advanced": {"style": "cinematic", "seed": 999, "write_only_secret": "nope"}}, + ) + + payload = build_schema_payload(request, schema, image_url=None, mask_url=None) + + assert payload == {"style": "cinematic", "prompt": "A test prompt", "aspect_ratio": "1:1", "seed": 123} + + def test_fal_provider_reports_configuration_from_api_key(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.delenv("FAL_KEY", raising=False) monkeypatch.delenv("FAL_API_KEY", raising=False) @@ -319,6 +352,49 @@ def fake_get(url: str, headers: dict[str, str], timeout: int, stream: bool = Fal assert status_count == 2 +def test_fal_provider_parses_single_image_output_shape(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key") + provider = FalProvider(config, logging.getLogger("test")) + request = _request(_model("fal-ai/upscale", modes=["img2img"]), mode="img2img") + monkeypatch.setattr(provider, "_download_image", lambda url: Image.new("RGB", (3, 3), color="green")) + + result = provider._parse_result( + {"image": {"url": "https://cdn.test/upscaled.png"}, "seed": 22}, + request, + request_id="upscale-1", + ) + + assert result.provider_request_id == "upscale-1" + assert result.images[0].image.size == (3, 3) + assert result.seed_used == 22 + + +def test_fal_provider_generic_media_returns_raw_video_result_without_downloading(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key", external_fal_base_url="https://queue.test") + provider = FalProvider(config, logging.getLogger("test")) + post_payload: dict[str, Any] = {} + + def fake_post(url: str, headers: dict[str, str], json: dict[str, Any], timeout: int) -> DummyResponse: + del headers, timeout + assert url == "https://queue.test/fal-ai/video" + post_payload.update(json) + return DummyResponse(json_data={"request_id": "video-request"}) + + def fake_get(url: str, headers: dict[str, str], timeout: int, stream: bool = False) -> DummyResponse: + del headers, timeout, stream + if url.endswith("/status"): + return DummyResponse(json_data={"status": "COMPLETED"}) + return DummyResponse(json_data={"video": {"url": "https://cdn.test/video.mp4"}, "seed": 99}) + + monkeypatch.setattr("requests.post", fake_post) + monkeypatch.setattr("requests.get", fake_get) + + result = provider.generate_generic("fal-ai/video", {"prompt": "A moving test"}) + + assert post_payload == {"prompt": "A moving test"} + assert result == {"video": {"url": "https://cdn.test/video.mp4"}, "seed": 99} + + def test_fal_provider_reports_queue_error(monkeypatch: pytest.MonkeyPatch) -> None: config = InvokeAIAppConfig(external_fal_api_key="fal-key") provider = FalProvider(config, logging.getLogger("test")) From a36a75abb7b03441e031e9aba8b461c70597be01 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 Aug 2026 01:26:06 +0300 Subject: [PATCH 7/8] feat: expose schema-driven fal.ai media endpoints --- .../docs/features/External Models/fal.mdx | 31 +- invokeai/app/api/routers/app_info.py | 41 +- .../invocations/external_image_generation.py | 8 + .../invocations/external_media_generation.py | 27 +- .../external_generation_base.py | 25 +- .../external_generation_default.py | 24 +- .../external_generation/providers/fal.py | 130 ++++- .../providers/fal_catalog.py | 62 +- .../model_install/model_install_default.py | 2 + .../model_records/model_records_base.py | 5 + invokeai/frontend/web/openapi.json | 530 ++++++++++++++++++ invokeai/frontend/web/public/locales/en.json | 9 + invokeai/frontend/web/public/locales/ru.json | 9 + .../ExternalProvidersForm.tsx | 121 +++- .../ExternalProviders/falCatalog.test.ts | 31 + .../ExternalProviders/falCatalog.ts | 5 + .../web/src/services/api/endpoints/appInfo.ts | 32 ++ .../frontend/web/src/services/api/schema.ts | 297 +++++++++- .../frontend/web/src/services/api/types.ts | 1 + .../test_external_image_generation.py | 20 + .../app/invocations/test_fal_generic_media.py | 27 + tests/app/routers/test_app_info.py | 16 +- .../external_generation/test_fal_catalog.py | 42 +- .../external_generation/test_fal_provider.py | 100 +++- .../model_install/test_model_install.py | 30 +- 25 files changed, 1568 insertions(+), 57 deletions(-) create mode 100644 invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.test.ts create mode 100644 invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.ts diff --git a/docs/src/content/docs/features/External Models/fal.mdx b/docs/src/content/docs/features/External Models/fal.mdx index 8e698cd5c86..135b4da5339 100644 --- a/docs/src/content/docs/features/External Models/fal.mdx +++ b/docs/src/content/docs/features/External Models/fal.mdx @@ -25,15 +25,35 @@ Restart Invoke after manual configuration. ## Models -The provider currently ships these curated models: +Invoke exposes two fal.ai model paths: + +- **Native Canvas models** — image endpoints can be searched in the fal.ai + catalog and installed into Invoke's External Models list. Their endpoint + schema determines supported modes and common fields. +- **Generic media endpoints** — every catalog endpoint can be called from the + `fal.ai Generic Media` node with its raw JSON schema. This covers text/video + generation, image-to-video, video-to-video, upscaling, audio, speech, 3D, + and new endpoints that fal.ai adds later. + +The provider keeps these curated image presets for quick setup: - `fal-ai/flux/schnell` — text to image - `fal-ai/flux/dev` — text to image - `fal-ai/flux-pro/kontext` — image to image and semantic edits - `fal-ai/flux-lora-fill` — masked inpainting -When the API key is configured, Invoke adds these external model references to -the model database. No model weights are downloaded. +Use **Refresh** in the fal.ai catalog to load current endpoint metadata. No +model weights are downloaded; installed entries are lightweight external +references. + +## Generic media workflows + +Add the `fal.ai Generic Media` node in Workflow Editor. Set `model_id` to any +fal.ai endpoint and paste the endpoint's JSON input into `input_json`. Local +images, masks, and videos can be connected to the node and referenced with +`${image_url}`, `${mask_url}`, and `${video_url}` placeholders. The node +returns raw JSON, so endpoint-specific outputs remain available without +waiting for a new Invoke release. ## Canvas @@ -56,6 +76,5 @@ Every generation, upload, and result download uses remote services. Check the current model pricing and limits on its fal.ai model page before invoking. Automated tests do not submit inference requests. -- https://fal.ai/models/fal-ai/flux/schnell -- https://fal.ai/models/fal-ai/flux-pro/kontext -- https://fal.ai/models/fal-ai/flux-lora-fill +- https://fal.ai/models +- https://fal.ai/docs/model-apis diff --git a/invokeai/app/api/routers/app_info.py b/invokeai/app/api/routers/app_info.py index 5413c7fbc78..826015ee186 100644 --- a/invokeai/app/api/routers/app_info.py +++ b/invokeai/app/api/routers/app_info.py @@ -9,7 +9,7 @@ import torch import yaml -from fastapi import Body, HTTPException, Path +from fastapi import Body, HTTPException, Path, Query from fastapi.routing import APIRouter from pydantic import BaseModel, Field, field_validator, model_validator @@ -35,7 +35,11 @@ from invokeai.app.services.model_install.model_install_common import ModelInstallJob from invokeai.app.services.model_records.model_records_base import ModelRecordChanges, UnknownModelException from invokeai.backend.image_util.infill_methods.patchmatch import PatchMatch -from invokeai.backend.model_manager.configs.external_api import ExternalApiModelConfig, ExternalModelCapabilities +from invokeai.backend.model_manager.configs.external_api import ( + ExternalApiModelConfig, + ExternalModelCapabilities, + ExternalModelPanelSchema, +) from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType from invokeai.backend.util.devices import TorchDevice from invokeai.backend.util.logging import logging @@ -566,9 +570,9 @@ def get_invocation_cache_status(current_admin: AdminUserOrDefault) -> Invocation ) def list_fal_models( _: AdminUserOrDefault, - limit: int = 50, - cursor: str | None = None, - search: str | None = None, + limit: int = Query(default=50, ge=1, le=100), + cursor: str | None = Query(default=None, max_length=4096), + search: str | None = Query(default=None, max_length=200), ) -> FalCatalogResponse: client = _get_fal_catalog_client() try: @@ -646,6 +650,7 @@ def install_fal_model( provider_model_id=request.endpoint_id, source_url=f"https://fal.ai/models/{request.endpoint_id}", capabilities=_fal_capabilities_from_schema(schema), + panel_schema=_fal_panel_schema_from_schema(schema), ) try: return ApiDependencies.invoker.services.model_manager.install.heuristic_import( @@ -664,6 +669,16 @@ def install_fal_model( } +def _fal_panel_schema_from_schema(schema: FalEndpointSchema) -> ExternalModelPanelSchema: + prompts = [{"name": "reference_images"}] if "reference_images" in schema.common_fields else [] + image_controls: list[dict[str, str]] = [] + if any(name in schema.common_fields for name in ("width", "height", "aspect_ratio", "image_size")): + image_controls.append({"name": "dimensions"}) + if "seed" in schema.common_fields: + image_controls.append({"name": "seed"}) + return ExternalModelPanelSchema(prompts=prompts, image=image_controls) + + def _fal_capabilities_from_schema(schema: FalEndpointSchema) -> ExternalModelCapabilities: if schema.kind is FalEndpointKind.TEXT_TO_IMAGE: modes = ["txt2img"] @@ -684,10 +699,15 @@ def _fal_capabilities_from_schema(schema: FalEndpointSchema) -> ExternalModelCap num_images_schema = properties.get(num_images_name, {}) maximum = num_images_schema.get("maximum") if isinstance(num_images_schema, dict) else None max_images = maximum if isinstance(maximum, int) and maximum > 0 else None + reference_name = schema.common_fields.get("reference_images", "") + reference_schema = properties.get(reference_name, {}) + max_references = reference_schema.get("maxItems") if isinstance(reference_schema, dict) else None + max_references = max_references if isinstance(max_references, int) and max_references > 0 else None return ExternalModelCapabilities( modes=modes, # type: ignore[arg-type] - supports_reference_images="image_urls" in schema.common_fields.get("init_image", ""), + supports_reference_images="reference_images" in schema.common_fields, + max_reference_images=max_references, supports_negative_prompt="negative_prompt" in schema.common_fields, supports_seed="seed" in schema.common_fields, max_images_per_request=max_images, @@ -713,9 +733,7 @@ def _get_installed_fal_models() -> set[str]: return { model.provider_model_id for model in models - if isinstance(model, ExternalApiModelConfig) - and model.provider_id == "fal" - and model.provider_model_id + if isinstance(model, ExternalApiModelConfig) and model.provider_id == "fal" and model.provider_model_id } @@ -733,7 +751,10 @@ def _fal_schema_to_response(schema: FalEndpointSchema) -> FalEndpointSchemaRespo def _raise_fal_catalog_http_error(exc: Exception) -> None: - from invokeai.app.services.external_generation.errors import ExternalProviderRateLimitError, ExternalProviderRequestError + from invokeai.app.services.external_generation.errors import ( + ExternalProviderRateLimitError, + ExternalProviderRequestError, + ) if isinstance(exc, ExternalProviderRateLimitError): raise HTTPException(status_code=429, detail=str(exc)) from exc diff --git a/invokeai/app/invocations/external_image_generation.py b/invokeai/app/invocations/external_image_generation.py index 88cc772ff0f..6c7f482abf3 100644 --- a/invokeai/app/invocations/external_image_generation.py +++ b/invokeai/app/invocations/external_image_generation.py @@ -363,6 +363,11 @@ class FalImageGenerationInvocation(BaseExternalImageGenerationInvocation): provider_id = "fal" + advanced_options: dict[str, Any] = InputField( + default={}, + description="Additional JSON fields declared by the selected fal.ai endpoint", + ) + model: ModelIdentifierField = InputField( description=FieldDescriptions.main_model, ui_model_base=[BaseModelType.External], @@ -370,3 +375,6 @@ class FalImageGenerationInvocation(BaseExternalImageGenerationInvocation): ui_model_format=[ModelFormat.ExternalApi], ui_model_provider_id=["fal"], ) + + def _build_provider_options(self) -> dict[str, Any] | None: + return {"advanced": self.advanced_options} if self.advanced_options else None diff --git a/invokeai/app/invocations/external_media_generation.py b/invokeai/app/invocations/external_media_generation.py index 7c2949b19cf..b6ef315308d 100644 --- a/invokeai/app/invocations/external_media_generation.py +++ b/invokeai/app/invocations/external_media_generation.py @@ -2,13 +2,13 @@ from typing import Any from invokeai.app.invocations.baseinvocation import BaseInvocation, invocation -from invokeai.app.invocations.fields import InputField +from invokeai.app.invocations.fields import ImageField, InputField, VideoField from invokeai.app.invocations.primitives import StringOutput from invokeai.app.services.shared.invocation_context import InvocationContext @invocation( - "fal_generic_media", + "fal_generic_media_native", title="fal.ai Generic Media", tags=["external", "generation", "fal", "fal.ai", "generic"], category="media", @@ -19,6 +19,16 @@ class FalGenericMediaInvocation(BaseInvocation): model_id: str = InputField(description="fal.ai endpoint ID, for example fal-ai/kling-video/v3/pro/text-to-video") input_json: str = InputField(default="{}", description="JSON object sent to the fal.ai endpoint") + image: ImageField | None = InputField( + default=None, description="Optional local image for ${image_url} placeholders" + ) + mask: ImageField | None = InputField(default=None, description="Optional local mask for ${mask_url} placeholders") + reference_images: list[ImageField] = InputField( + default=[], description="Optional local images for ${image_urls} or ${reference_image_urls} placeholders" + ) + video: VideoField | None = InputField( + default=None, description="Optional local video for ${video_url} placeholders" + ) def invoke(self, context: InvocationContext) -> StringOutput: try: @@ -28,9 +38,22 @@ def invoke(self, context: InvocationContext) -> StringOutput: if not isinstance(payload, dict): raise ValueError("fal.ai input_json must be a JSON object") + media_kwargs: dict[str, Any] = {} + if self.image is not None: + media_kwargs["image"] = context.images.get_pil(self.image.image_name, mode="RGB") + if self.mask is not None: + media_kwargs["mask_image"] = context.images.get_pil(self.mask.image_name, mode="L") + if self.reference_images: + media_kwargs["reference_images"] = [ + context.images.get_pil(field.image_name, mode="RGB") for field in self.reference_images + ] + if self.video is not None: + media_kwargs["video_path"] = context.videos.get_path(self.video.video_name) + result: dict[str, Any] = context._services.external_generation.generate_generic( provider_id="fal", model_id=self.model_id, payload=payload, + **media_kwargs, ) return StringOutput(value=json.dumps(result, ensure_ascii=False, sort_keys=True)) diff --git a/invokeai/app/services/external_generation/external_generation_base.py b/invokeai/app/services/external_generation/external_generation_base.py index bd9eae2acef..c9eb0e31ea7 100644 --- a/invokeai/app/services/external_generation/external_generation_base.py +++ b/invokeai/app/services/external_generation/external_generation_base.py @@ -2,6 +2,8 @@ from abc import ABC, abstractmethod from logging import Logger +from pathlib import Path +from typing import Any from invokeai.app.services.config import InvokeAIAppConfig from invokeai.app.services.external_generation.external_generation_common import ( @@ -26,7 +28,16 @@ def is_configured(self) -> bool: def generate(self, request: ExternalGenerationRequest) -> ExternalGenerationResult: raise NotImplementedError - def generate_generic(self, model_id: str, payload: dict[str, object]) -> dict[str, object]: + def generate_generic( + self, + model_id: str, + payload: dict[str, object], + *, + image: Any = None, + mask_image: Any = None, + reference_images: list[Any] | None = None, + video_path: Path | None = None, + ) -> dict[str, object]: """Submit provider-specific JSON for endpoints outside normalized image generation.""" raise NotImplementedError(f"Provider '{self.provider_id}' does not support generic media generation") @@ -44,5 +55,15 @@ def get_provider_statuses(self) -> dict[str, ExternalProviderStatus]: raise NotImplementedError @abstractmethod - def generate_generic(self, provider_id: str, model_id: str, payload: dict[str, object]) -> dict[str, object]: + def generate_generic( + self, + provider_id: str, + model_id: str, + payload: dict[str, object], + *, + image: Any = None, + mask_image: Any = None, + reference_images: list[Any] | None = None, + video_path: Path | None = None, + ) -> dict[str, object]: raise NotImplementedError diff --git a/invokeai/app/services/external_generation/external_generation_default.py b/invokeai/app/services/external_generation/external_generation_default.py index 05e64d63f81..501da41cc6b 100644 --- a/invokeai/app/services/external_generation/external_generation_default.py +++ b/invokeai/app/services/external_generation/external_generation_default.py @@ -3,7 +3,8 @@ import dataclasses import time from logging import Logger -from typing import TYPE_CHECKING +from pathlib import Path +from typing import TYPE_CHECKING, Any from PIL import Image from PIL.Image import Image as PILImageType @@ -92,14 +93,31 @@ def _generate_with_retry( def get_provider_statuses(self) -> dict[str, ExternalProviderStatus]: return {provider_id: provider.get_status() for provider_id, provider in self._providers.items()} - def generate_generic(self, provider_id: str, model_id: str, payload: dict[str, object]) -> dict[str, object]: + def generate_generic( + self, + provider_id: str, + model_id: str, + payload: dict[str, object], + *, + image: Any = None, + mask_image: Any = None, + reference_images: list[Any] | None = None, + video_path: Path | None = None, + ) -> dict[str, object]: provider = self._providers.get(provider_id) if provider is None: raise ExternalProviderRequestError(f"No external provider registered for '{provider_id}'") if not provider.is_configured(): raise ExternalProviderRequestError(f"Provider '{provider_id}' is missing credentials") try: - return provider.generate_generic(model_id, payload) + return provider.generate_generic( + model_id, + payload, + image=image, + mask_image=mask_image, + reference_images=reference_images, + video_path=video_path, + ) except NotImplementedError as exc: raise ExternalProviderRequestError(str(exc)) from exc diff --git a/invokeai/app/services/external_generation/providers/fal.py b/invokeai/app/services/external_generation/providers/fal.py index c5d7672099f..e5243972a4d 100644 --- a/invokeai/app/services/external_generation/providers/fal.py +++ b/invokeai/app/services/external_generation/providers/fal.py @@ -5,23 +5,25 @@ import os import time from logging import Logger +from pathlib import Path from typing import Any import requests from PIL import Image, ImageOps from PIL.Image import Image as PILImageType +from invokeai.app.services.config import InvokeAIAppConfig from invokeai.app.services.external_generation.errors import ( ExternalProviderRateLimitError, ExternalProviderRequestError, ) from invokeai.app.services.external_generation.external_generation_base import ExternalProvider -from invokeai.app.services.external_generation.providers.fal_catalog import FalCatalogClient, FalEndpointSchema from invokeai.app.services.external_generation.external_generation_common import ( ExternalGeneratedImage, ExternalGenerationRequest, ExternalGenerationResult, ) +from invokeai.app.services.external_generation.providers.fal_catalog import FalCatalogClient, FalEndpointSchema _DEFAULT_QUEUE_URL = "https://queue.fal.run" _UPLOAD_URL = "https://rest.fal.ai/storage/upload/initiate?storage_type=fal-cdn-v3" @@ -63,31 +65,70 @@ def generate(self, request: ExternalGenerationRequest) -> ExternalGenerationResu raise ExternalProviderRequestError("fal.ai API key is not configured") headers = {"Authorization": f"Key {api_key}", "Content-Type": "application/json"} + model_id = request.model.provider_model_id + _validate_endpoint_id(model_id) image_url = None mask_url = None + reference_urls: list[str] = [] if request.init_image is not None: image_url = self._upload_image(request.init_image, "image.png", headers) + for index, reference in enumerate(request.reference_images, start=1): + reference_urls.append(self._upload_image(reference.image, f"reference-{index}.png", headers)) if request.mask_image is not None: mask = ImageOps.invert(request.mask_image.convert("L")) mask_url = self._upload_image(mask, "mask.png", headers) - model_id = request.model.provider_model_id schema = self._get_schema(model_id) payload = ( - build_schema_payload(request, schema, image_url=image_url, mask_url=mask_url) + build_schema_payload( + request, + schema, + image_url=image_url, + mask_url=mask_url, + reference_urls=reference_urls, + ) if schema is not None else self._build_payload(request, image_url=image_url, mask_url=mask_url) ) result_payload, request_id = self._submit_queue(model_id, payload, headers) return self._parse_result(result_payload, request, request_id=request_id) - def generate_generic(self, model_id: str, payload: dict[str, Any]) -> dict[str, Any]: - """Submit arbitrary JSON to a fal.ai endpoint and return its raw result.""" + def generate_generic( + self, + model_id: str, + payload: dict[str, Any], + *, + image: PILImageType | None = None, + mask_image: PILImageType | None = None, + reference_images: list[PILImageType] | None = None, + video_path: Path | None = None, + ) -> dict[str, Any]: + """Submit arbitrary JSON, expanding optional local media placeholders.""" api_key = self._api_key() if not api_key: raise ExternalProviderRequestError("fal.ai API key is not configured") + _validate_endpoint_id(model_id) headers = {"Authorization": f"Key {api_key}", "Content-Type": "application/json"} - result, _ = self._submit_queue(model_id, payload, headers) + media: dict[str, Any] = {} + if image is not None: + media["image_url"] = self._upload_image(image, "image.png", headers) + if mask_image is not None: + media["mask_url"] = self._upload_image(mask_image.convert("L"), "mask.png", headers) + if reference_images: + media["reference_image_urls"] = [ + self._upload_image(image, f"reference-{index}.png", headers) + for index, image in enumerate(reference_images, start=1) + ] + media["image_urls"] = media["reference_image_urls"] + if video_path is not None: + media["video_url"] = self._upload_file( + video_path, + video_path.name or "video.mp4", + "video/mp4", + headers, + ) + expanded_payload = _expand_media_placeholders(payload, media) + result, _ = self._submit_queue(model_id, expanded_payload, headers) return result def _submit_queue( @@ -179,6 +220,43 @@ def _build_payload( payload["image_size"] = _image_size_for_ratio(ratio) return payload + def _upload_file(self, path: Path, filename: str, content_type: str, headers: dict[str, str]) -> str: + if not path.is_file(): + raise ExternalProviderRequestError(f"fal.ai input file does not exist: {path}") + try: + file_size = path.stat().st_size + if file_size > _DOWNLOAD_MAX_BYTES: + raise ExternalProviderRequestError("fal.ai input file exceeds the safety limit") + data = path.read_bytes() + except OSError as exc: + raise ExternalProviderRequestError(f"fal.ai input file could not be read: {exc}") from exc + if len(data) > _DOWNLOAD_MAX_BYTES: + raise ExternalProviderRequestError("fal.ai input file exceeds the safety limit") + + upload_headers = {"Authorization": headers["Authorization"], "Content-Type": "application/json"} + response = self._request( + "POST", + _UPLOAD_URL, + headers=upload_headers, + json={"file_name": filename, "content_type": content_type}, + timeout=_REQUEST_TIMEOUT, + ) + self._raise_for_response(response, "fal.ai upload initiation") + upload = self._parse_json(response, "fal.ai upload initiation response") + file_url = upload.get("file_url") + upload_url = upload.get("upload_url") + if not isinstance(file_url, str) or not file_url or not isinstance(upload_url, str) or not upload_url: + raise ExternalProviderRequestError("fal.ai upload response missing file_url or upload_url") + put_response = self._request( + "PUT", + upload_url, + headers={"Content-Type": content_type}, + data=data, + timeout=_REQUEST_TIMEOUT, + ) + self._raise_for_response(put_response, "fal.ai file upload") + return file_url + def _upload_image(self, image: PILImageType, filename: str, headers: dict[str, str]) -> str: upload_headers = {"Authorization": headers["Authorization"], "Content-Type": "application/json"} response = self._request( @@ -339,6 +417,27 @@ def _raise_for_response(response: requests.Response, operation: str) -> None: raise ExternalProviderRequestError(f"{operation} failed with status {response.status_code}: {response.text}") +def _validate_endpoint_id(model_id: str) -> None: + if not model_id or model_id.startswith("/") or ".." in model_id.split("/"): + raise ExternalProviderRequestError("fal.ai endpoint ID is invalid") + + +def _expand_media_placeholders(value: Any, media: dict[str, Any]) -> Any: + if isinstance(value, dict): + return {key: _expand_media_placeholders(item, media) for key, item in value.items()} + if isinstance(value, list): + return [_expand_media_placeholders(item, media) for item in value] + if not isinstance(value, str): + return value + for name, replacement in media.items(): + if value == "${" + name + "}": + return replacement + for name, replacement in media.items(): + if isinstance(replacement, str): + value = value.replace("${" + name + "}", replacement) + return value + + def _extract_image_items(payload: dict[str, Any]) -> list[Any]: for key in ("images", "data"): value = payload.get(key) @@ -407,17 +506,18 @@ def build_schema_payload( *, image_url: str | None, mask_url: str | None, + reference_urls: list[str] | None = None, ) -> dict[str, Any]: """Build payload for one endpoint using only fields declared by its OpenAPI schema.""" properties = schema.input_schema.get("properties", {}) if not isinstance(properties, dict): properties = {} advanced = request.provider_options.get("advanced", {}) if request.provider_options else {} - payload = { - name: value - for name, value in advanced.items() - if name in schema.public_properties and name in properties - } if isinstance(advanced, dict) else {} + payload = ( + {name: value for name, value in advanced.items() if name in schema.public_properties and name in properties} + if isinstance(advanced, dict) + else {} + ) ratio = _select_aspect_ratio(request.width, request.height, request.model.capabilities.allowed_aspect_ratios) common_values: dict[str, Any] = { @@ -430,6 +530,7 @@ def build_schema_payload( "image_size": request.image_size or _image_size_for_ratio(ratio), "init_image": image_url, "mask_image": mask_url, + "reference_images": ([image_url] if image_url else []) + (reference_urls or []), } for common_name, value in common_values.items(): field_name = schema.common_fields.get(common_name) @@ -442,7 +543,12 @@ def build_schema_payload( continue if common_name == "aspect_ratio" and not _value_is_allowed(value, property_schema): continue - if common_name in {"init_image", "mask_image"} and property_schema.get("type") == "array": + if common_name == "reference_images": + if not value: + continue + if property_schema.get("type") != "array": + value = value[0] + elif common_name in {"init_image", "mask_image"} and property_schema.get("type") == "array": value = [value] payload[field_name] = value return payload diff --git a/invokeai/app/services/external_generation/providers/fal_catalog.py b/invokeai/app/services/external_generation/providers/fal_catalog.py index b5c6c4cded7..2749a1b2c41 100644 --- a/invokeai/app/services/external_generation/providers/fal_catalog.py +++ b/invokeai/app/services/external_generation/providers/fal_catalog.py @@ -1,14 +1,16 @@ from __future__ import annotations import copy -import os from dataclasses import dataclass from enum import StrEnum from typing import Any import requests -from invokeai.app.services.external_generation.errors import ExternalProviderRateLimitError, ExternalProviderRequestError +from invokeai.app.services.external_generation.errors import ( + ExternalProviderRateLimitError, + ExternalProviderRequestError, +) _DEFAULT_CATALOG_URL = "https://api.fal.ai" _DEFAULT_SCHEMA_URL = "https://fal.ai/api/openapi/queue/openapi.json" @@ -79,11 +81,15 @@ def list_models( cursor: str | None = None, search: str | None = None, ) -> FalCatalogPage: - params: dict[str, Any] = {"limit": min(max(limit, 1), _MAX_PAGE_SIZE)} + page_size = min(max(limit, 1), _MAX_PAGE_SIZE) + if search: + return self._search_models(search, limit=page_size, cursor=cursor) + return self._list_models_page(limit=page_size, cursor=cursor) + + def _list_models_page(self, *, limit: int, cursor: str | None) -> FalCatalogPage: + params: dict[str, Any] = {"limit": limit} if cursor: params["cursor"] = cursor - if search: - params["search"] = search response = self._get(f"{self._catalog_url}/v1/models", params=params) payload = self._parse_object(response, "fal.ai catalog response") @@ -118,6 +124,33 @@ def list_models( has_more=bool(payload.get("has_more")), ) + def _search_models(self, search: str, *, limit: int, cursor: str | None) -> FalCatalogPage: + needle = search.casefold().strip() + if not needle: + return self._list_models_page(limit=limit, cursor=cursor) + + matches: list[FalCatalogModel] = [] + next_cursor = cursor + has_more = True + while has_more and len(matches) < limit: + page = self._list_models_page(limit=_MAX_PAGE_SIZE, cursor=next_cursor) + for model in page.models: + haystack = " ".join( + [model.endpoint_id, model.display_name, model.description, model.category, *model.tags] + ).casefold() + if needle in haystack: + matches.append(model) + if len(matches) == limit: + break + has_more = page.has_more and page.next_cursor is not None + next_cursor = page.next_cursor + + return FalCatalogPage( + models=matches, + next_cursor=next_cursor if has_more else None, + has_more=has_more, + ) + def get_schema(self, endpoint_id: str) -> FalEndpointSchema: if not endpoint_id or endpoint_id.startswith("/") or ".." in endpoint_id.split("/"): raise ExternalProviderRequestError("fal.ai catalog endpoint ID is invalid") @@ -173,7 +206,10 @@ def normalize_openapi_schema(endpoint_id: str, document: dict[str, Any]) -> FalE ( item.get("post") for path, item in paths.items() - if isinstance(path, str) and "/requests/" not in path and isinstance(item, dict) and isinstance(item.get("post"), dict) + if isinstance(path, str) + and "/requests/" not in path + and isinstance(item, dict) + and isinstance(item.get("post"), dict) ), None, ) @@ -191,7 +227,9 @@ def normalize_openapi_schema(endpoint_id: str, document: dict[str, Any]) -> FalE output_kind = _classify_output_schema(output_schema, fallback=kind) properties = request_schema["properties"] public_properties = tuple( - name for name, value in properties.items() if isinstance(name, str) and isinstance(value, dict) and not value.get("writeOnly") + name + for name, value in properties.items() + if isinstance(name, str) and isinstance(value, dict) and not value.get("writeOnly") ) return FalEndpointSchema( @@ -214,7 +252,13 @@ def classify_endpoint(category: str, schema: dict[str, Any], *, endpoint_id: str if normalized in {"text-to-image", "text2image", "text-to-img"}: return FalEndpointKind.TEXT_TO_IMAGE if normalized in {"image-to-image", "image-editing", "image-edit", "inpainting", "inpaint"}: - return FalEndpointKind.INPAINT if "inpaint" in normalized or "fill" in endpoint else FalEndpointKind.IMAGE_TO_IMAGE + properties = schema.get("properties", {}) + has_mask = isinstance(properties, dict) and any("mask" in str(name).lower() for name in properties) + return ( + FalEndpointKind.INPAINT + if "inpaint" in normalized or "inpaint" in endpoint or "fill" in endpoint or has_mask + else FalEndpointKind.IMAGE_TO_IMAGE + ) if normalized in {"text-to-video", "text2video"}: return FalEndpointKind.TEXT_TO_VIDEO if normalized in {"image-to-video", "image2video"}: @@ -258,12 +302,12 @@ def _find_common_fields(properties: dict[str, Any]) -> dict[str, str]: "negative_prompt": ("negative_prompt", "negative_prompt_text"), "init_image": ( "image_url", - "image_urls", "input_image_url", "input_image", "start_image_url", "first_frame_url", ), + "reference_images": ("reference_image_urls", "reference_urls", "image_urls"), "mask_image": ("mask_url", "mask_image_url", "mask"), "init_video": ("video_url", "video_urls", "input_video_url"), "seed": ("seed",), diff --git a/invokeai/app/services/model_install/model_install_default.py b/invokeai/app/services/model_install/model_install_default.py index 5b7337d5870..45d8f05c20f 100644 --- a/invokeai/app/services/model_install/model_install_default.py +++ b/invokeai/app/services/model_install/model_install_default.py @@ -1043,10 +1043,12 @@ def _register_external_model(self, job: ModelInstallJob) -> None: key=key, name=name, description=job.config_in.description, + source_url=job.config_in.source_url, provider_id=provider_id, provider_model_id=provider_model_id, capabilities=capabilities, default_settings=default_settings, + panel_schema=job.config_in.panel_schema, source=str(job.source), source_type=MODEL_SOURCE_TO_TYPE_MAP[job.source.__class__], path="", diff --git a/invokeai/app/services/model_records/model_records_base.py b/invokeai/app/services/model_records/model_records_base.py index 41f098addcb..6c281646b9c 100644 --- a/invokeai/app/services/model_records/model_records_base.py +++ b/invokeai/app/services/model_records/model_records_base.py @@ -17,6 +17,7 @@ from invokeai.backend.model_manager.configs.external_api import ( ExternalApiModelDefaultSettings, ExternalModelCapabilities, + ExternalModelPanelSchema, ) from invokeai.backend.model_manager.configs.factory import AnyModelConfig from invokeai.backend.model_manager.configs.lora import LoraModelDefaultSettings @@ -128,6 +129,10 @@ def validate_source_url(cls, v: Any) -> Optional[str]: description="External model capabilities", default=None, ) + panel_schema: Optional[ExternalModelPanelSchema] = Field( + description="External model controls exposed in the frontend", + default=None, + ) cpu_only: Optional[bool] = Field(description="Whether this model should run on CPU only", default=None) # Checkpoint-specific changes diff --git a/invokeai/frontend/web/openapi.json b/invokeai/frontend/web/openapi.json index bdda7be2e08..c20a77d6aa8 100644 --- a/invokeai/frontend/web/openapi.json +++ b/invokeai/frontend/web/openapi.json @@ -9248,6 +9248,179 @@ ] } }, + "/api/v1/app/external_providers/fal/models": { + "get": { + "tags": ["app"], + "summary": "List Fal Models", + "operationId": "list_fal_models", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "default": 50, + "title": "Limit" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "maxLength": 4096 + }, + { + "type": "null" + } + ], + "title": "Cursor" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "maxLength": 200 + }, + { + "type": "null" + } + ], + "title": "Search" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FalCatalogResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/api/v1/app/external_providers/fal/models/{endpoint_id}/schema": { + "get": { + "tags": ["app"], + "summary": "Get Fal Model Schema", + "operationId": "get_fal_model_schema", + "security": [ + { + "HTTPBearer": [] + } + ], + "parameters": [ + { + "name": "endpoint_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "description": "fal.ai endpoint identifier", + "title": "Endpoint Id" + }, + "description": "fal.ai endpoint identifier" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FalEndpointSchemaResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/api/v1/app/external_providers/fal/models/install": { + "post": { + "tags": ["app"], + "summary": "Install Fal Model", + "operationId": "install_fal_model", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FalModelInstallRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelInstallJob" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + } + ] + } + }, "/api/v1/queue/{queue_id}/enqueue_batch": { "post": { "tags": ["queue"], @@ -28532,6 +28705,308 @@ "title": "FaceOffOutput", "type": "object" }, + "FalCatalogModelResponse": { + "properties": { + "endpoint_id": { + "type": "string", + "title": "Endpoint Id" + }, + "display_name": { + "type": "string", + "title": "Display Name" + }, + "description": { + "type": "string", + "title": "Description" + }, + "category": { + "type": "string", + "title": "Category" + }, + "kind": { + "$ref": "#/components/schemas/FalEndpointKind" + }, + "model_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Model Url" + }, + "thumbnail_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Thumbnail Url" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags" + }, + "installed": { + "type": "boolean", + "title": "Installed" + } + }, + "type": "object", + "required": [ + "endpoint_id", + "display_name", + "description", + "category", + "kind", + "model_url", + "thumbnail_url", + "tags", + "installed" + ], + "title": "FalCatalogModelResponse" + }, + "FalCatalogResponse": { + "properties": { + "models": { + "items": { + "$ref": "#/components/schemas/FalCatalogModelResponse" + }, + "type": "array", + "title": "Models" + }, + "next_cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Next Cursor" + }, + "has_more": { + "type": "boolean", + "title": "Has More" + } + }, + "type": "object", + "required": ["models", "next_cursor", "has_more"], + "title": "FalCatalogResponse" + }, + "FalEndpointKind": { + "type": "string", + "enum": [ + "text-to-image", + "image-to-image", + "inpaint", + "upscale", + "text-to-video", + "image-to-video", + "video-to-video", + "audio", + "generic" + ], + "title": "FalEndpointKind" + }, + "FalEndpointSchemaResponse": { + "properties": { + "endpoint_id": { + "type": "string", + "title": "Endpoint Id" + }, + "kind": { + "$ref": "#/components/schemas/FalEndpointKind" + }, + "output_kind": { + "$ref": "#/components/schemas/FalEndpointKind" + }, + "category": { + "type": "string", + "title": "Category" + }, + "input_schema": { + "additionalProperties": true, + "type": "object", + "title": "Input Schema" + }, + "output_schema": { + "additionalProperties": true, + "type": "object", + "title": "Output Schema" + }, + "common_fields": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "title": "Common Fields" + }, + "public_properties": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Public Properties" + } + }, + "type": "object", + "required": [ + "endpoint_id", + "kind", + "output_kind", + "category", + "input_schema", + "output_schema", + "common_fields", + "public_properties" + ], + "title": "FalEndpointSchemaResponse" + }, + "FalGenericMediaInvocation": { + "category": "media", + "class": "invocation", + "classification": "stable", + "description": "Submit arbitrary JSON to any fal.ai endpoint and return its raw JSON result.", + "node_pack": "invokeai", + "properties": { + "id": { + "description": "The id of this instance of an invocation. Must be unique among all instances of invocations.", + "field_kind": "node_attribute", + "title": "Id", + "type": "string" + }, + "is_intermediate": { + "default": false, + "description": "Whether or not this is an intermediate invocation.", + "field_kind": "node_attribute", + "input": "direct", + "orig_required": true, + "title": "Is Intermediate", + "type": "boolean", + "ui_hidden": false, + "ui_type": "IsIntermediate" + }, + "use_cache": { + "default": true, + "description": "Whether or not to use the cache", + "field_kind": "node_attribute", + "title": "Use Cache", + "type": "boolean" + }, + "model_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "fal.ai endpoint ID, for example fal-ai/kling-video/v3/pro/text-to-video", + "field_kind": "input", + "input": "any", + "orig_required": true, + "title": "Model Id" + }, + "input_json": { + "default": "{}", + "description": "JSON object sent to the fal.ai endpoint", + "field_kind": "input", + "input": "any", + "orig_default": "{}", + "orig_required": false, + "title": "Input Json", + "type": "string" + }, + "image": { + "anyOf": [ + { + "$ref": "#/components/schemas/ImageField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional local image for ${image_url} placeholders", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "mask": { + "anyOf": [ + { + "$ref": "#/components/schemas/ImageField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional local mask for ${mask_url} placeholders", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "reference_images": { + "default": [], + "description": "Optional local images for ${image_urls} or ${reference_image_urls} placeholders", + "field_kind": "input", + "input": "any", + "items": { + "$ref": "#/components/schemas/ImageField" + }, + "orig_default": [], + "orig_required": false, + "title": "Reference Images", + "type": "array" + }, + "video": { + "anyOf": [ + { + "$ref": "#/components/schemas/VideoField" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional local video for ${video_url} placeholders", + "field_kind": "input", + "input": "any", + "orig_default": null, + "orig_required": false + }, + "type": { + "const": "fal_generic_media_native", + "default": "fal_generic_media_native", + "field_kind": "node_attribute", + "title": "type", + "type": "string" + } + }, + "required": ["type", "id"], + "tags": ["external", "generation", "fal", "fal.ai", "generic"], + "title": "fal.ai Generic Media", + "type": "object", + "version": "1.0.0", + "output": { + "$ref": "#/components/schemas/StringOutput" + } + }, "FalImageGenerationInvocation": { "category": "image", "class": "invocation", @@ -28753,6 +29228,17 @@ "title": "Reference Images", "type": "array" }, + "advanced_options": { + "additionalProperties": true, + "default": {}, + "description": "Additional JSON fields declared by the selected fal.ai endpoint", + "field_kind": "input", + "input": "any", + "orig_default": {}, + "orig_required": false, + "title": "Advanced Options", + "type": "object" + }, "type": { "const": "fal_image_generation", "default": "fal_image_generation", @@ -28770,6 +29256,20 @@ "$ref": "#/components/schemas/ImageCollectionOutput" } }, + "FalModelInstallRequest": { + "properties": { + "endpoint_id": { + "type": "string", + "maxLength": 512, + "minLength": 1, + "title": "Endpoint Id", + "description": "fal.ai endpoint identifier" + } + }, + "type": "object", + "required": ["endpoint_id"], + "title": "FalModelInstallRequest" + }, "FieldKind": { "description": "The kind of field.\n- `Input`: An input field on a node.\n- `Output`: An output field on a node.\n- `Internal`: A field which is treated as an input, but cannot be used in node definitions. Metadata is\none example. It is provided to nodes via the WithMetadata class, and we want to reserve the field name\n\"metadata\" for this on all nodes. `FieldKind` is used to short-circuit the field name validation logic,\nallowing \"metadata\" for that field.\n- `NodeAttribute`: The field is a node attribute. These are fields which are not inputs or outputs,\nbut which are used to store information about the node. For example, the `id` and `type` fields are node\nattributes.\n\nThe presence of this in `json_schema_extra[\"field_kind\"]` is used when initializing node schemas on app\nstartup, and when generating the OpenAPI schema for the workflow editor.", "enum": ["input", "output", "internal", "node_attribute"], @@ -35453,6 +35953,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalGenericMediaInvocation" + }, { "$ref": "#/components/schemas/FalImageGenerationInvocation" }, @@ -43994,6 +44497,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalGenericMediaInvocation" + }, { "$ref": "#/components/schemas/FalImageGenerationInvocation" }, @@ -45348,6 +45854,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalGenericMediaInvocation" + }, { "$ref": "#/components/schemas/FalImageGenerationInvocation" }, @@ -46308,6 +46817,9 @@ "face_off": { "$ref": "#/components/schemas/FaceOffOutput" }, + "fal_generic_media_native": { + "$ref": "#/components/schemas/StringOutput" + }, "fal_image_generation": { "$ref": "#/components/schemas/ImageCollectionOutput" }, @@ -47107,6 +47619,7 @@ "face_identifier", "face_mask_detection", "face_off", + "fal_generic_media_native", "fal_image_generation", "float", "float_batch", @@ -47623,6 +48136,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalGenericMediaInvocation" + }, { "$ref": "#/components/schemas/FalImageGenerationInvocation" }, @@ -48686,6 +49202,9 @@ { "$ref": "#/components/schemas/FaceOffInvocation" }, + { + "$ref": "#/components/schemas/FalGenericMediaInvocation" + }, { "$ref": "#/components/schemas/FalImageGenerationInvocation" }, @@ -70280,6 +70799,17 @@ ], "description": "External model capabilities" }, + "panel_schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/ExternalModelPanelSchema" + }, + { + "type": "null" + } + ], + "description": "External model controls exposed in the frontend" + }, "cpu_only": { "anyOf": [ { diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c2a4853cc20..d8f59e773b4 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1227,6 +1227,15 @@ "externalResetHelper": "Clear API key and base URL.", "externalProviderSaveFailed": "Failed to save external provider configuration.", "externalProviderResetFailed": "Failed to reset external provider configuration.", + "externalFalCatalogTitle": "fal.ai model catalog", + "externalFalCatalogDescription": "Search fal.ai endpoints. Image endpoints can be installed into Canvas; other media uses the generic workflow node.", + "externalFalCatalogRefresh": "Refresh", + "externalFalCatalogSearch": "Search endpoint or model", + "externalFalCatalogLoadFailed": "Unable to load fal.ai catalog.", + "externalFalCatalogLoading": "Loading fal.ai catalog...", + "externalFalCatalogInstalled": "Installed", + "externalFalCatalogInstall": "Install for Canvas", + "externalFalCatalogGeneric": "Generic workflow", "height": "Height", "huggingFace": "HuggingFace", "huggingFacePlaceholder": "owner/model-name", diff --git a/invokeai/frontend/web/public/locales/ru.json b/invokeai/frontend/web/public/locales/ru.json index d23150a7164..4055c9623b8 100644 --- a/invokeai/frontend/web/public/locales/ru.json +++ b/invokeai/frontend/web/public/locales/ru.json @@ -856,6 +856,15 @@ "externalResetHelper": "Очистить API-ключ и основной URL.", "externalProviderSaveFailed": "Не удалось сохранить конфигурацию внешнего провайдера.", "externalProviderResetFailed": "Не удалось сбросить конфигурацию внешнего провайдера.", + "externalFalCatalogTitle": "Каталог fal.ai", + "externalFalCatalogDescription": "Поиск endpoint fal.ai. Image endpoint можно установить в Canvas; остальные media-функции доступны через generic workflow node.", + "externalFalCatalogRefresh": "Обновить", + "externalFalCatalogSearch": "Поиск endpoint или модели", + "externalFalCatalogLoadFailed": "Не удалось загрузить каталог fal.ai.", + "externalFalCatalogLoading": "Загрузка каталога fal.ai...", + "externalFalCatalogInstalled": "Установлено", + "externalFalCatalogInstall": "Установить в Canvas", + "externalFalCatalogGeneric": "Generic workflow", "hfTokenLabel": "Токен HuggingFace (требуется для некоторых моделей)", "hfTokenHelperText": "Для использования некоторых моделей требуется токен HF. Нажмите здесь, чтобы создать или ввести ваш токен.", "hfTokenInvalid": "Недействительный или отсутствующий HF токен", diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx index 4ae2d4a3fa0..037d74f1c99 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/ExternalProvidersForm.tsx @@ -25,11 +25,15 @@ import { PiCheckBold, PiCloudLightningBold, PiWarningBold } from 'react-icons/pi import { SiAlibabacloud, SiBytedance, SiGooglegemini, SiOpenai } from 'react-icons/si'; import { useGetExternalProviderConfigsQuery, + useInstallFalModelMutation, + useLazyGetFalModelsQuery, useResetExternalProviderConfigMutation, useSetExternalProviderConfigMutation, } from 'services/api/endpoints/appInfo'; import { useGetStarterModelsQuery } from 'services/api/endpoints/models'; -import type { ExternalProviderConfig, StarterModel } from 'services/api/types'; +import type { ExternalProviderConfig, FalCatalogModel, StarterModel } from 'services/api/types'; + +import { isFalNativeCanvasModel } from './falCatalog'; const PROVIDER_SORT_ORDER = ['fal', 'gemini', 'openai', 'seedream', 'alibabacloud']; @@ -347,8 +351,123 @@ const ProviderCard = memo(({ provider, onInstallModels, iconResolver }: Provider + {provider.provider_id === 'fal' && } ); }); ProviderCard.displayName = 'ProviderCard'; + +type FalModelCatalogProps = { + isConfigured: boolean; +}; + +const FalModelCatalog = memo(({ isConfigured }: FalModelCatalogProps) => { + const { t } = useTranslation(); + const toast = useToast(); + const [search, setSearch] = useState(''); + const [fetchModels, { isFetching, isError }] = useLazyGetFalModelsQuery(); + const [models, setModels] = useState([]); + const [nextCursor, setNextCursor] = useState(null); + const [installModel, { isLoading: isInstalling }] = useInstallFalModelMutation(); + + const loadModels = useCallback( + (append: boolean, cursor?: string | null) => { + if (!isConfigured) { + return Promise.resolve(); + } + return fetchModels({ limit: 30, cursor: cursor ?? undefined, search: search.trim() || undefined }) + .unwrap() + .then((result) => { + setModels((current) => (append ? [...current, ...result.models] : result.models)); + setNextCursor(result.next_cursor); + }) + .catch(() => undefined); + }, + [fetchModels, isConfigured, search] + ); + + useEffect(() => { + setModels([]); + setNextCursor(null); + const timer = window.setTimeout(() => void loadModels(false), 300); + return () => window.clearTimeout(timer); + }, [loadModels]); + + const handleInstall = useCallback( + (model: FalCatalogModel) => { + installModel({ endpoint_id: model.endpoint_id }) + .unwrap() + .catch(() => { + toast({ + id: `FAL_MODEL_INSTALL_FAILED_${model.endpoint_id}`, + title: t('modelManager.externalProviderSaveFailed'), + status: 'error', + }); + }); + }, + [installModel, t, toast] + ); + + if (!isConfigured) { + return null; + } + + return ( + + + + {t('modelManager.externalFalCatalogTitle')} + {t('modelManager.externalFalCatalogDescription')} + + + + setSearch(event.target.value)} + /> + {isError && {t('modelManager.externalFalCatalogLoadFailed')}} + {isFetching && models.length === 0 && {t('modelManager.externalFalCatalogLoading')}} + {models.map((model) => { + const isCanvasModel = isFalNativeCanvasModel(model); + return ( + + + + {model.display_name} + {model.kind} + + + {model.endpoint_id} + + + {isCanvasModel ? ( + + ) : ( + {t('modelManager.externalFalCatalogGeneric')} + )} + + ); + })} + {nextCursor && ( + + )} + + ); +}); + +FalModelCatalog.displayName = 'FalModelCatalog'; diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.test.ts b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.test.ts new file mode 100644 index 00000000000..53b53812a44 --- /dev/null +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.test.ts @@ -0,0 +1,31 @@ +import type { FalCatalogModel } from 'services/api/types'; +import { describe, expect, it } from 'vitest'; + +import { isFalNativeCanvasModel } from './falCatalog'; + +const model = (kind: FalCatalogModel['kind']): FalCatalogModel => ({ + endpoint_id: 'fal-ai/test', + display_name: 'Test model', + description: '', + category: kind, + kind, + model_url: null, + thumbnail_url: null, + tags: [], + installed: false, +}); + +describe('fal catalog model capabilities', () => { + it('marks image endpoints as native Canvas-compatible', () => { + expect(isFalNativeCanvasModel(model('text-to-image'))).toBe(true); + expect(isFalNativeCanvasModel(model('image-to-image'))).toBe(true); + expect(isFalNativeCanvasModel(model('inpaint'))).toBe(true); + expect(isFalNativeCanvasModel(model('upscale'))).toBe(true); + }); + + it('keeps video and generic endpoints out of image Canvas picker', () => { + expect(isFalNativeCanvasModel(model('text-to-video'))).toBe(false); + expect(isFalNativeCanvasModel(model('image-to-video'))).toBe(false); + expect(isFalNativeCanvasModel(model('generic'))).toBe(false); + }); +}); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.ts b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.ts new file mode 100644 index 00000000000..90c5996656f --- /dev/null +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ExternalProviders/falCatalog.ts @@ -0,0 +1,5 @@ +import type { FalCatalogModel } from 'services/api/types'; + +const NATIVE_CANVAS_KINDS = new Set(['text-to-image', 'image-to-image', 'inpaint', 'upscale']); + +export const isFalNativeCanvasModel = (model: FalCatalogModel): boolean => NATIVE_CANVAS_KINDS.has(model.kind); diff --git a/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts b/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts index 8a7c6b0448e..4e6708d4f43 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts @@ -116,6 +116,36 @@ export const appInfoApi = api.injectEndpoints({ }), invalidatesTags: ['AppConfig', 'FetchOnReconnect'], }), + getFalModels: build.query< + paths['/api/v1/app/external_providers/fal/models']['get']['responses']['200']['content']['application/json'], + paths['/api/v1/app/external_providers/fal/models']['get']['parameters']['query'] + >({ + query: (query) => ({ + url: buildAppInfoUrl('external_providers/fal/models', query ?? undefined), + method: 'GET', + }), + providesTags: ['FetchOnReconnect'], + }), + getFalModelSchema: build.query< + paths['/api/v1/app/external_providers/fal/models/{endpoint_id}/schema']['get']['responses']['200']['content']['application/json'], + string + >({ + query: (endpoint_id) => ({ + url: buildAppInfoUrl(`external_providers/fal/models/${endpoint_id}/schema`), + method: 'GET', + }), + }), + installFalModel: build.mutation< + paths['/api/v1/app/external_providers/fal/models/install']['post']['responses']['201']['content']['application/json'], + paths['/api/v1/app/external_providers/fal/models/install']['post']['requestBody']['content']['application/json'] + >({ + query: (body) => ({ + url: buildAppInfoUrl('external_providers/fal/models/install'), + method: 'POST', + body, + }), + invalidatesTags: ['FetchOnReconnect'], + }), getInvocationCacheStatus: build.query< paths['/api/v1/app/invocation_cache/status']['get']['responses']['200']['content']['application/json'], void @@ -162,6 +192,8 @@ export const { useGetGenerationDeviceOptionsQuery, useGetExternalProviderStatusesQuery, useGetExternalProviderConfigsQuery, + useLazyGetFalModelsQuery, + useInstallFalModelMutation, useSetExternalProviderConfigMutation, useResetExternalProviderConfigMutation, useUpdateRuntimeConfigMutation, diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index d3cd937de3d..8cf1b4de9cf 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -2239,6 +2239,57 @@ export type paths = { patch?: never; trace?: never; }; + "/api/v1/app/external_providers/fal/models": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List Fal Models */ + get: operations["list_fal_models"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/app/external_providers/fal/models/{endpoint_id}/schema": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get Fal Model Schema */ + get: operations["get_fal_model_schema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/app/external_providers/fal/models/install": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Install Fal Model */ + post: operations["install_fal_model"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/api/v1/queue/{queue_id}/enqueue_batch": { parameters: { query?: never; @@ -11337,6 +11388,125 @@ export type components = { */ y: number; }; + /** FalCatalogModelResponse */ + FalCatalogModelResponse: { + /** Endpoint Id */ + endpoint_id: string; + /** Display Name */ + display_name: string; + /** Description */ + description: string; + /** Category */ + category: string; + kind: components["schemas"]["FalEndpointKind"]; + /** Model Url */ + model_url: string | null; + /** Thumbnail Url */ + thumbnail_url: string | null; + /** Tags */ + tags: string[]; + /** Installed */ + installed: boolean; + }; + /** FalCatalogResponse */ + FalCatalogResponse: { + /** Models */ + models: components["schemas"]["FalCatalogModelResponse"][]; + /** Next Cursor */ + next_cursor: string | null; + /** Has More */ + has_more: boolean; + }; + /** + * FalEndpointKind + * @enum {string} + */ + FalEndpointKind: "text-to-image" | "image-to-image" | "inpaint" | "upscale" | "text-to-video" | "image-to-video" | "video-to-video" | "audio" | "generic"; + /** FalEndpointSchemaResponse */ + FalEndpointSchemaResponse: { + /** Endpoint Id */ + endpoint_id: string; + kind: components["schemas"]["FalEndpointKind"]; + output_kind: components["schemas"]["FalEndpointKind"]; + /** Category */ + category: string; + /** Input Schema */ + input_schema: { + [key: string]: unknown; + }; + /** Output Schema */ + output_schema: { + [key: string]: unknown; + }; + /** Common Fields */ + common_fields: { + [key: string]: string; + }; + /** Public Properties */ + public_properties: string[]; + }; + /** + * fal.ai Generic Media + * @description Submit arbitrary JSON to any fal.ai endpoint and return its raw JSON result. + */ + FalGenericMediaInvocation: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** + * Model Id + * @description fal.ai endpoint ID, for example fal-ai/kling-video/v3/pro/text-to-video + * @default null + */ + model_id?: string | null; + /** + * Input Json + * @description JSON object sent to the fal.ai endpoint + * @default {} + */ + input_json?: string; + /** + * @description Optional local image for ${image_url} placeholders + * @default null + */ + image?: components["schemas"]["ImageField"] | null; + /** + * @description Optional local mask for ${mask_url} placeholders + * @default null + */ + mask?: components["schemas"]["ImageField"] | null; + /** + * Reference Images + * @description Optional local images for ${image_urls} or ${reference_image_urls} placeholders + * @default [] + */ + reference_images?: components["schemas"]["ImageField"][]; + /** + * @description Optional local video for ${video_url} placeholders + * @default null + */ + video?: components["schemas"]["VideoField"] | null; + /** + * type + * @default fal_generic_media_native + * @constant + */ + type: "fal_generic_media_native"; + }; /** * fal.ai Image Generation * @description Generate or edit images using a fal.ai-hosted model. @@ -11433,6 +11603,14 @@ export type components = { * @default [] */ reference_images?: components["schemas"]["ImageField"][]; + /** + * Advanced Options + * @description Additional JSON fields declared by the selected fal.ai endpoint + * @default {} + */ + advanced_options?: { + [key: string]: unknown; + }; /** * type * @default fal_image_generation @@ -11440,6 +11618,14 @@ export type components = { */ type: "fal_image_generation"; }; + /** FalModelInstallRequest */ + FalModelInstallRequest: { + /** + * Endpoint Id + * @description fal.ai endpoint identifier + */ + endpoint_id: string; + }; /** * FieldKind * @description The kind of field. @@ -14756,7 +14942,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + [key: string]: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalGenericMediaInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; }; /** * Edges @@ -18581,7 +18767,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalGenericMediaInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -18645,7 +18831,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalGenericMediaInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -18733,6 +18919,7 @@ export type components = { face_identifier: components["schemas"]["ImageOutput"]; face_mask_detection: components["schemas"]["FaceMaskOutput"]; face_off: components["schemas"]["FaceOffOutput"]; + fal_generic_media_native: components["schemas"]["StringOutput"]; fal_image_generation: components["schemas"]["ImageCollectionOutput"]; float: components["schemas"]["FloatOutput"]; float_batch: components["schemas"]["FloatOutput"]; @@ -19030,7 +19217,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalGenericMediaInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -19111,7 +19298,7 @@ export type components = { * Invocation * @description The ID of the invocation */ - invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; + invocation: components["schemas"]["AddInvocation"] | components["schemas"]["AlibabaCloudImageGenerationInvocation"] | components["schemas"]["AlphaMaskToTensorInvocation"] | components["schemas"]["AnimaDenoiseInvocation"] | components["schemas"]["AnimaDenoiseMetaInvocation"] | components["schemas"]["AnimaImageToLatentsInvocation"] | components["schemas"]["AnimaLLLiteInvocation"] | components["schemas"]["AnimaLatentsToImageInvocation"] | components["schemas"]["AnimaLoRACollectionLoader"] | components["schemas"]["AnimaLoRALoaderInvocation"] | components["schemas"]["AnimaModelLoaderInvocation"] | components["schemas"]["AnimaTextEncoderInvocation"] | components["schemas"]["ApplyMaskTensorToImageInvocation"] | components["schemas"]["ApplyMaskToImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BoundingBoxInvocation"] | components["schemas"]["CLIPSkipInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["CallSavedWorkflowInvocation"] | components["schemas"]["CannyEdgeDetectionInvocation"] | components["schemas"]["CanvasOutputInvocation"] | components["schemas"]["CanvasPasteBackInvocation"] | components["schemas"]["CanvasV2MaskAndCropInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["CogView4DenoiseInvocation"] | components["schemas"]["CogView4ImageToLatentsInvocation"] | components["schemas"]["CogView4LatentsToImageInvocation"] | components["schemas"]["CogView4ModelLoaderInvocation"] | components["schemas"]["CogView4TextEncoderInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ColorMapInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ContentShuffleInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["CreateGradientMaskInvocation"] | components["schemas"]["CropImageToBoundingBoxInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DWOpenposeDetectionInvocation"] | components["schemas"]["DecodeInvisibleWatermarkInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["DenoiseLatentsMetaInvocation"] | components["schemas"]["DepthAnythingDepthEstimationInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ErnieImageDenoiseInvocation"] | components["schemas"]["ErnieImageModelLoaderInvocation"] | components["schemas"]["ErnieImagePromptEnhancerInvocation"] | components["schemas"]["ErnieImageTextEncoderInvocation"] | components["schemas"]["ErnieImageVaeDecodeInvocation"] | components["schemas"]["ExpandMaskWithFadeInvocation"] | components["schemas"]["ExtractVideoRangeInvocation"] | components["schemas"]["FLUXLoRACollectionLoader"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["FalGenericMediaInvocation"] | components["schemas"]["FalImageGenerationInvocation"] | components["schemas"]["FloatBatchInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FloatGenerator"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["Flux2DenoiseInvocation"] | components["schemas"]["Flux2DevLoRACollectionLoader"] | components["schemas"]["Flux2DevLoRALoaderInvocation"] | components["schemas"]["Flux2DevModelLoaderInvocation"] | components["schemas"]["Flux2DevTextEncoderInvocation"] | components["schemas"]["Flux2KleinLoRACollectionLoader"] | components["schemas"]["Flux2KleinLoRALoaderInvocation"] | components["schemas"]["Flux2KleinModelLoaderInvocation"] | components["schemas"]["Flux2KleinTextEncoderInvocation"] | components["schemas"]["Flux2PiDDecodeInvocation"] | components["schemas"]["Flux2VaeDecodeInvocation"] | components["schemas"]["Flux2VaeEncodeInvocation"] | components["schemas"]["FluxControlLoRALoaderInvocation"] | components["schemas"]["FluxControlNetInvocation"] | components["schemas"]["FluxDenoiseInvocation"] | components["schemas"]["FluxDenoiseLatentsMetaInvocation"] | components["schemas"]["FluxFillInvocation"] | components["schemas"]["FluxIPAdapterInvocation"] | components["schemas"]["FluxKontextConcatenateImagesInvocation"] | components["schemas"]["FluxKontextInvocation"] | components["schemas"]["FluxLoRALoaderInvocation"] | components["schemas"]["FluxModelLoaderInvocation"] | components["schemas"]["FluxPiDDecodeInvocation"] | components["schemas"]["FluxReduxInvocation"] | components["schemas"]["FluxTextEncoderInvocation"] | components["schemas"]["FluxVaeDecodeInvocation"] | components["schemas"]["FluxVaeEncodeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["GeminiImageGenerationInvocation"] | components["schemas"]["Gemma2EncoderLoaderInvocation"] | components["schemas"]["GetMaskBoundingBoxInvocation"] | components["schemas"]["GroundingDinoInvocation"] | components["schemas"]["HEDEdgeDetectionInvocation"] | components["schemas"]["HeuristicResizeInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["Ideogram4CaptionBuilderInvocation"] | components["schemas"]["Ideogram4DenoiseInvocation"] | components["schemas"]["Ideogram4LatentsToImageInvocation"] | components["schemas"]["Ideogram4ModelLoaderInvocation"] | components["schemas"]["Ideogram4TextEncoderInvocation"] | components["schemas"]["IfInvocation"] | components["schemas"]["ImageBatchInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImageGenerator"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageMaskToTensorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageNoiseInvocation"] | components["schemas"]["ImagePanelLayoutInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["IntegerBatchInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["IntegerGenerator"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["InvertTensorMaskInvocation"] | components["schemas"]["InvokeAdjustImageHuePlusInvocation"] | components["schemas"]["InvokeEquivalentAchromaticLightnessInvocation"] | components["schemas"]["InvokeImageBlendInvocation"] | components["schemas"]["InvokeImageCompositorInvocation"] | components["schemas"]["InvokeImageDilateOrErodeInvocation"] | components["schemas"]["InvokeImageEnhanceInvocation"] | components["schemas"]["InvokeImageValueThresholdsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["Krea2ConditioningRebalanceInvocation"] | components["schemas"]["Krea2DenoiseInvocation"] | components["schemas"]["Krea2LoRACollectionLoader"] | components["schemas"]["Krea2LoRALoaderInvocation"] | components["schemas"]["Krea2ModelLoaderInvocation"] | components["schemas"]["Krea2SeedVarianceInvocation"] | components["schemas"]["Krea2TextEncoderInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["LineartAnimeEdgeDetectionInvocation"] | components["schemas"]["LineartEdgeDetectionInvocation"] | components["schemas"]["LlavaOnevisionVllmInvocation"] | components["schemas"]["LoRACollectionLoader"] | components["schemas"]["LoRALoaderInvocation"] | components["schemas"]["LoRASelectorInvocation"] | components["schemas"]["MLSDDetectionInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MaskFromIDInvocation"] | components["schemas"]["MaskTensorToImageInvocation"] | components["schemas"]["MediaPipeFaceDetectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["MetadataFieldExtractorInvocation"] | components["schemas"]["MetadataFromImageInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["MetadataItemLinkedInvocation"] | components["schemas"]["MetadataToBoolCollectionInvocation"] | components["schemas"]["MetadataToBoolInvocation"] | components["schemas"]["MetadataToControlnetsInvocation"] | components["schemas"]["MetadataToFloatCollectionInvocation"] | components["schemas"]["MetadataToFloatInvocation"] | components["schemas"]["MetadataToIPAdaptersInvocation"] | components["schemas"]["MetadataToIntegerCollectionInvocation"] | components["schemas"]["MetadataToIntegerInvocation"] | components["schemas"]["MetadataToLorasCollectionInvocation"] | components["schemas"]["MetadataToLorasInvocation"] | components["schemas"]["MetadataToModelInvocation"] | components["schemas"]["MetadataToSDXLLorasInvocation"] | components["schemas"]["MetadataToSDXLModelInvocation"] | components["schemas"]["MetadataToSchedulerInvocation"] | components["schemas"]["MetadataToStringCollectionInvocation"] | components["schemas"]["MetadataToStringInvocation"] | components["schemas"]["MetadataToT2IAdaptersInvocation"] | components["schemas"]["MetadataToVAEInvocation"] | components["schemas"]["ModelIdentifierInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["NormalMapInvocation"] | components["schemas"]["OklabUnsharpMaskInvocation"] | components["schemas"]["OklchImageHueAdjustmentInvocation"] | components["schemas"]["OpenAIImageGenerationInvocation"] | components["schemas"]["PBRMapsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["PasteImageIntoBoundingBoxInvocation"] | components["schemas"]["PiDDecoderLoaderInvocation"] | components["schemas"]["PiDUpscaleInvocation"] | components["schemas"]["PiDiNetEdgeDetectionInvocation"] | components["schemas"]["PromptTemplateInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["QwenImageDenoiseInvocation"] | components["schemas"]["QwenImageImageToLatentsInvocation"] | components["schemas"]["QwenImageLatentsToImageInvocation"] | components["schemas"]["QwenImageLoRACollectionLoader"] | components["schemas"]["QwenImageLoRALoaderInvocation"] | components["schemas"]["QwenImageModelLoaderInvocation"] | components["schemas"]["QwenImagePiDDecodeInvocation"] | components["schemas"]["QwenImageTextEncoderInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RectangleMaskInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["SD3DenoiseInvocation"] | components["schemas"]["SD3ImageToLatentsInvocation"] | components["schemas"]["SD3LatentsToImageInvocation"] | components["schemas"]["SD3PiDDecodeInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLLoRACollectionLoader"] | components["schemas"]["SDXLLoRALoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLPiDDecodeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["SaveImageToFileInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["Sd3ModelLoaderInvocation"] | components["schemas"]["Sd3TextEncoderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SeedreamImageGenerationInvocation"] | components["schemas"]["SegmentAnythingInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["SpandrelImageToImageAutoscaleInvocation"] | components["schemas"]["SpandrelImageToImageInvocation"] | components["schemas"]["StringBatchInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["StringGenerator"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["TextLLMInvocation"] | components["schemas"]["TextLLMWithPresetInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["TiledMultiDiffusionDenoiseLatents"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["VAELoaderInvocation"] | components["schemas"]["VideoConcatInvocation"] | components["schemas"]["VideoFrameExtractInvocation"] | components["schemas"]["VideoInvocation"] | components["schemas"]["WanDenoiseInvocation"] | components["schemas"]["WanI2VIdealDimensionsInvocation"] | components["schemas"]["WanImageToLatentsInvocation"] | components["schemas"]["WanLatentsToImageInvocation"] | components["schemas"]["WanLatentsToVideoInvocation"] | components["schemas"]["WanLoRACollectionLoader"] | components["schemas"]["WanLoRALoaderInvocation"] | components["schemas"]["WanModelLoaderInvocation"] | components["schemas"]["WanRefImageEncoderInvocation"] | components["schemas"]["WanTI2VIdealDimensionsInvocation"] | components["schemas"]["WanTextEncoderInvocation"] | components["schemas"]["WanVideoDenoiseInvocation"] | components["schemas"]["WorkflowReturnGetInvocation"] | components["schemas"]["WorkflowReturnInvocation"] | components["schemas"]["WorkflowReturnValueInvocation"] | components["schemas"]["ZImageControlInvocation"] | components["schemas"]["ZImageDenoiseInvocation"] | components["schemas"]["ZImageDenoiseMetaInvocation"] | components["schemas"]["ZImageImageToLatentsInvocation"] | components["schemas"]["ZImageLatentsToImageInvocation"] | components["schemas"]["ZImageLoRACollectionLoader"] | components["schemas"]["ZImageLoRALoaderInvocation"] | components["schemas"]["ZImageModelLoaderInvocation"] | components["schemas"]["ZImagePiDDecodeInvocation"] | components["schemas"]["ZImageSeedVarianceEnhancerInvocation"] | components["schemas"]["ZImageTextEncoderInvocation"]; /** * Invocation Source Id * @description The ID of the prepared invocation's source node @@ -29359,6 +29546,8 @@ export type components = { provider_model_id?: string | null; /** @description External model capabilities */ capabilities?: components["schemas"]["ExternalModelCapabilities"] | null; + /** @description External model controls exposed in the frontend */ + panel_schema?: components["schemas"]["ExternalModelPanelSchema"] | null; /** * Cpu Only * @description Whether this model should run on CPU only @@ -47180,6 +47369,104 @@ export interface operations { }; }; }; + list_fal_models: { + parameters: { + query?: { + limit?: number; + cursor?: string | null; + search?: string | null; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["FalCatalogResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + get_fal_model_schema: { + parameters: { + query?: never; + header?: never; + path: { + /** @description fal.ai endpoint identifier */ + endpoint_id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["FalEndpointSchemaResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + install_fal_model: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["FalModelInstallRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ModelInstallJob"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; enqueue_batch: { parameters: { query?: never; diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 93589541742..165a0543011 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -58,6 +58,7 @@ export type ExternalProviderConfigUpdate = { api_key?: string; base_url?: string | null; }; +export type FalCatalogModel = S['FalCatalogModelResponse']; export type UpdateModelBody = paths['/api/v2/models/i/{key}']['patch']['requestBody']['content']['application/json']; const zResourceOrigin = z.enum(['internal', 'external']); diff --git a/tests/app/invocations/test_external_image_generation.py b/tests/app/invocations/test_external_image_generation.py index d80830b58b6..8c4141d2675 100644 --- a/tests/app/invocations/test_external_image_generation.py +++ b/tests/app/invocations/test_external_image_generation.py @@ -89,6 +89,26 @@ def test_provider_specific_external_invocation_rejects_wrong_provider() -> None: invocation.invoke(context) +def test_fal_invocation_forwards_advanced_schema_options() -> None: + model_config = _build_model().model_copy(update={"provider_id": "fal", "provider_model_id": "fal-ai/custom"}) + model_field = ModelIdentifierField.from_config(model_config) + generated_image = Image.new("RGB", (16, 16), color="black") + context = _build_context(model_config, generated_image) + + invocation = FalImageGenerationInvocation( + id="fal_node", + model=model_field, + mode="txt2img", + prompt="A prompt", + advanced_options={"style": "cinematic", "num_inference_steps": 4}, + ) + + invocation.invoke(context) + + request = context._services.external_generation.generate.call_args[0][0] + assert request.provider_options == {"advanced": {"style": "cinematic", "num_inference_steps": 4}} + + def test_fal_invocation_requires_fal_model() -> None: model_config = _build_model().model_copy(update={"provider_id": "fal", "provider_model_id": "fal-ai/flux/schnell"}) model_field = ModelIdentifierField.from_config(model_config) diff --git a/tests/app/invocations/test_fal_generic_media.py b/tests/app/invocations/test_fal_generic_media.py index 38af6260d3b..5176f836fec 100644 --- a/tests/app/invocations/test_fal_generic_media.py +++ b/tests/app/invocations/test_fal_generic_media.py @@ -1,8 +1,35 @@ +from pathlib import Path from unittest.mock import MagicMock import pytest +from PIL import Image from invokeai.app.invocations.external_media_generation import FalGenericMediaInvocation +from invokeai.app.invocations.fields import ImageField, VideoField + + +def test_fal_generic_media_invocation_uploads_local_media_fields() -> None: + context = MagicMock() + context.images.get_pil.return_value = Image.new("RGB", (2, 2)) + context.videos.get_path.return_value = Path("/tmp/input.mp4") + context._services.external_generation.generate_generic.return_value = {} + invocation = FalGenericMediaInvocation( + id="fal_generic", + model_id="fal-ai/video", + input_json='{"start_image_url": "${image_url}", "video_url": "${video_url}"}', + image=ImageField(image_name="input.png"), + mask=ImageField(image_name="mask.png"), + reference_images=[ImageField(image_name="ref.png")], + video=VideoField(video_name="input.mp4"), + ) + + invocation.invoke(context) + + call = context._services.external_generation.generate_generic.call_args + assert call.kwargs["image"].size == (2, 2) + assert call.kwargs["mask_image"].size == (2, 2) + assert len(call.kwargs["reference_images"]) == 1 + assert call.kwargs["video_path"] == Path("/tmp/input.mp4") def test_fal_generic_media_invocation_submits_declared_json_and_returns_raw_result() -> None: diff --git a/tests/app/routers/test_app_info.py b/tests/app/routers/test_app_info.py index cebbf813ced..01a8fc9e2fc 100644 --- a/tests/app/routers/test_app_info.py +++ b/tests/app/routers/test_app_info.py @@ -603,7 +603,10 @@ def get_schema(self, endpoint_id: str) -> Any: assert call["source"] == "external://fal/fal-ai/test" assert call["config"].provider_id == "fal" assert call["config"].provider_model_id == "fal-ai/test" + assert call["config"].source_url == "https://fal.ai/models/fal-ai/test" assert call["config"].capabilities.modes == ["txt2img"] + assert call["config"].panel_schema is not None + assert any(control.name == "dimensions" for control in call["config"].panel_schema.image) def test_install_fal_video_model_requires_generic_media_node( @@ -645,10 +648,17 @@ def _fake_fal_schema(endpoint_id: str, category: str) -> Any: kind=kind, output_kind=kind, category=category, - input_schema={"type": "object", "properties": {"prompt": {"type": "string"}}}, + input_schema={ + "type": "object", + "properties": { + "prompt": {"type": "string"}, + "width": {"type": "integer"}, + "height": {"type": "integer"}, + }, + }, output_schema={}, - common_fields={"prompt": "prompt"}, - public_properties=("prompt",), + common_fields={"prompt": "prompt", "width": "width", "height": "height"}, + public_properties=("prompt", "width", "height"), ) diff --git a/tests/app/services/external_generation/test_fal_catalog.py b/tests/app/services/external_generation/test_fal_catalog.py index b21df6f8174..34bd0ffc705 100644 --- a/tests/app/services/external_generation/test_fal_catalog.py +++ b/tests/app/services/external_generation/test_fal_catalog.py @@ -85,6 +85,10 @@ def test_classify_endpoint_keeps_unknown_categories_generic() -> None: assert classify_endpoint("speech-to-text", {}) is FalEndpointKind.GENERIC assert classify_endpoint("text-to-image", {}) is FalEndpointKind.TEXT_TO_IMAGE assert classify_endpoint("upscaling", {}) is FalEndpointKind.UPSCALE + assert ( + classify_endpoint("image-to-image", {"properties": {"image_url": {}, "mask_url": {}}}) + is FalEndpointKind.INPAINT + ) def test_catalog_client_lists_pages_and_fetches_schema(monkeypatch: pytest.MonkeyPatch) -> None: @@ -116,7 +120,7 @@ def fake_get(url: str, **kwargs: Any) -> DummyResponse: monkeypatch.setattr("requests.get", fake_get) client = FalCatalogClient("test-key") - page = client.list_models(limit=10, cursor="old", search="test") + page = client.list_models(limit=10, cursor="old") schema = client.get_schema("fal-ai/test") assert page.next_cursor == "next" @@ -125,11 +129,45 @@ def fake_get(url: str, **kwargs: Any) -> DummyResponse: assert page.models[0].display_name == "Test model" assert schema.kind is FalEndpointKind.IMAGE_TO_VIDEO assert calls[0][0] == "https://api.fal.ai/v1/models" - assert calls[0][1]["params"] == {"limit": 10, "cursor": "old", "search": "test"} + assert calls[0][1]["params"] == {"limit": 10, "cursor": "old"} assert calls[1][0] == "https://fal.ai/api/openapi/queue/openapi.json" assert calls[1][1]["params"] == {"endpoint_id": "fal-ai/test"} +def test_catalog_client_filters_search_across_api_pages(monkeypatch: pytest.MonkeyPatch) -> None: + calls: list[dict[str, Any]] = [] + + def fake_get(url: str, **kwargs: Any) -> DummyResponse: + del url + calls.append(kwargs["params"]) + if len(calls) == 1: + return DummyResponse( + json_data={ + "models": [ + {"endpoint_id": "fal-ai/other", "metadata": {"display_name": "Other"}}, + ], + "next_cursor": "next", + "has_more": True, + } + ) + return DummyResponse( + json_data={ + "models": [ + {"endpoint_id": "fal-ai/flux/schnell", "metadata": {"display_name": "Flux Schnell"}}, + ], + "next_cursor": None, + "has_more": False, + } + ) + + monkeypatch.setattr("requests.get", fake_get) + page = FalCatalogClient("test-key").list_models(limit=1, search="flux") + + assert [model.endpoint_id for model in page.models] == ["fal-ai/flux/schnell"] + assert calls == [{"limit": 100}, {"limit": 100, "cursor": "next"}] + assert page.has_more is False + + def test_catalog_client_rejects_non_object_schema(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr("requests.get", lambda *args, **kwargs: DummyResponse(json_data={"models": []})) client = FalCatalogClient("test-key") diff --git a/tests/app/services/external_generation/test_fal_provider.py b/tests/app/services/external_generation/test_fal_provider.py index 7c9c41971b0..29a59f491eb 100644 --- a/tests/app/services/external_generation/test_fal_provider.py +++ b/tests/app/services/external_generation/test_fal_provider.py @@ -1,3 +1,4 @@ +import dataclasses import io import logging from collections.abc import Iterator @@ -10,6 +11,7 @@ from invokeai.app.services.external_generation.errors import ExternalProviderRequestError from invokeai.app.services.external_generation.external_generation_common import ( ExternalGenerationRequest, + ExternalReferenceImage, ) from invokeai.app.services.external_generation.providers.fal import FalProvider, build_schema_payload from invokeai.app.services.external_generation.providers.fal_catalog import FalEndpointKind, FalEndpointSchema @@ -369,7 +371,95 @@ def test_fal_provider_parses_single_image_output_shape(monkeypatch: pytest.Monke assert result.seed_used == 22 -def test_fal_provider_generic_media_returns_raw_video_result_without_downloading(monkeypatch: pytest.MonkeyPatch) -> None: +def test_fal_provider_generic_media_uploads_local_media_and_expands_placeholders( + monkeypatch: pytest.MonkeyPatch, tmp_path: Any +) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key") + provider = FalProvider(config, logging.getLogger("test")) + video_path = tmp_path / "input.mp4" + video_path.write_bytes(b"video") + captured: dict[str, Any] = {} + + monkeypatch.setattr(provider, "_upload_image", lambda image, filename, headers: "https://cdn.test/image.png") + monkeypatch.setattr( + provider, + "_upload_file", + lambda path, filename, content_type, headers: "https://cdn.test/video.mp4", + ) + + def fake_submit( + model_id: str, payload: dict[str, Any], headers: dict[str, str] + ) -> tuple[dict[str, Any], str | None]: + del model_id, headers + captured.update(payload) + return payload, "request-5" + + monkeypatch.setattr(provider, "_submit_queue", fake_submit) + + result = provider.generate_generic( + "fal-ai/video", + { + "start_image_url": "${image_url}", + "video_url": "${video_url}", + "reference_image_urls": "${reference_image_urls}", + }, + image=Image.new("RGB", (2, 2)), + reference_images=[Image.new("RGB", (2, 2))], + video_path=video_path, + ) + + assert captured == { + "start_image_url": "https://cdn.test/image.png", + "video_url": "https://cdn.test/video.mp4", + "reference_image_urls": ["https://cdn.test/image.png"], + } + assert result == captured + + +def test_fal_provider_schema_payload_maps_init_and_reference_images() -> None: + schema = FalEndpointSchema( + endpoint_id="fal-ai/edit", + kind=FalEndpointKind.IMAGE_TO_IMAGE, + output_kind=FalEndpointKind.IMAGE_TO_IMAGE, + category="image-to-image", + input_schema={ + "type": "object", + "properties": { + "prompt": {"type": "string"}, + "image_urls": {"type": "array", "items": {"type": "string"}}, + }, + }, + output_schema={}, + common_fields={"prompt": "prompt", "reference_images": "image_urls"}, + public_properties=("prompt", "image_urls"), + ) + request = _request(_model("fal-ai/edit", modes=["img2img"]), mode="img2img") + request = dataclasses.replace( + request, + reference_images=[ + ExternalReferenceImage(image=Image.new("RGB", (2, 2))), + ExternalReferenceImage(image=Image.new("RGB", (2, 2))), + ], + ) + + payload = build_schema_payload( + request, + schema, + image_url="https://cdn.test/init.png", + mask_url=None, + reference_urls=["https://cdn.test/ref-1.png", "https://cdn.test/ref-2.png"], + ) + + assert payload["image_urls"] == [ + "https://cdn.test/init.png", + "https://cdn.test/ref-1.png", + "https://cdn.test/ref-2.png", + ] + + +def test_fal_provider_generic_media_returns_raw_video_result_without_downloading( + monkeypatch: pytest.MonkeyPatch, +) -> None: config = InvokeAIAppConfig(external_fal_api_key="fal-key", external_fal_base_url="https://queue.test") provider = FalProvider(config, logging.getLogger("test")) post_payload: dict[str, Any] = {} @@ -395,6 +485,14 @@ def fake_get(url: str, headers: dict[str, str], timeout: int, stream: bool = Fal assert result == {"video": {"url": "https://cdn.test/video.mp4"}, "seed": 99} +def test_fal_provider_rejects_path_traversal_endpoint_id() -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key") + provider = FalProvider(config, logging.getLogger("test")) + + with pytest.raises(ExternalProviderRequestError, match="endpoint ID is invalid"): + provider.generate_generic("fal-ai/../secret", {}) + + def test_fal_provider_reports_queue_error(monkeypatch: pytest.MonkeyPatch) -> None: config = InvokeAIAppConfig(external_fal_api_key="fal-key") provider = FalProvider(config, logging.getLogger("test")) diff --git a/tests/app/services/model_install/test_model_install.py b/tests/app/services/model_install/test_model_install.py index 2b9d04647bc..5150bbe6eca 100644 --- a/tests/app/services/model_install/test_model_install.py +++ b/tests/app/services/model_install/test_model_install.py @@ -39,7 +39,7 @@ ) from invokeai.app.services.model_install.model_install_default import TMPDIR_PREFIX from invokeai.app.services.model_records import ModelRecordChanges, UnknownModelException -from invokeai.backend.model_manager.configs.external_api import ExternalApiModelConfig +from invokeai.backend.model_manager.configs.external_api import ExternalApiModelConfig, ExternalModelPanelSchema from invokeai.backend.model_manager.taxonomy import ( BaseModelType, ModelFormat, @@ -237,6 +237,34 @@ def test_external_install(mm2_installer: ModelInstallServiceBase) -> None: assert job.config_out.source_type == ModelSourceType.External +def test_external_install_preserves_panel_schema(mm2_installer: ModelInstallServiceBase) -> None: + panel_schema = ExternalModelPanelSchema(image=[{"name": "dimensions"}]) + job = mm2_installer.heuristic_import( + "external://fal/fal-ai/test", + config=ModelRecordChanges(panel_schema=panel_schema), + ) + + mm2_installer.wait_for_installs() + + assert job.status == InstallStatus.COMPLETED + assert job.config_out is not None + assert isinstance(job.config_out, ExternalApiModelConfig) + assert job.config_out.panel_schema == panel_schema + + +def test_external_install_preserves_source_url(mm2_installer: ModelInstallServiceBase) -> None: + job = mm2_installer.heuristic_import( + "external://fal/fal-ai/test", + config=ModelRecordChanges(source_url="https://fal.ai/models/fal-ai/test"), + ) + + mm2_installer.wait_for_installs() + + assert job.status == InstallStatus.COMPLETED + assert job.config_out is not None + assert job.config_out.source_url == "https://fal.ai/models/fal-ai/test" + + def test_external_install_is_idempotent(mm2_installer: ModelInstallServiceBase) -> None: first_job = mm2_installer.heuristic_import( "external://openai/gpt-image-1", From 2b52b02156771c40c6d5289ac20ed2ff3312022d Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 Aug 2026 18:34:23 +0300 Subject: [PATCH 8/8] fix: support fal segmentation image outputs --- .../external_generation/providers/fal.py | 25 +++++++++++++++++++ .../providers/fal_catalog.py | 2 ++ .../external_generation/test_fal_catalog.py | 11 ++++++++ .../external_generation/test_fal_provider.py | 18 +++++++++++++ 4 files changed, 56 insertions(+) diff --git a/invokeai/app/services/external_generation/providers/fal.py b/invokeai/app/services/external_generation/providers/fal.py index e5243972a4d..8c602b6ef5c 100644 --- a/invokeai/app/services/external_generation/providers/fal.py +++ b/invokeai/app/services/external_generation/providers/fal.py @@ -450,6 +450,31 @@ def _extract_image_items(payload: dict[str, Any]) -> list[Any]: image_urls = payload.get("image_urls") if isinstance(image_urls, list): return image_urls + + # Segmentation and preprocessing endpoints use named mask/depth/image fields instead of `images`. + items: list[Any] = [] + for key, value in payload.items(): + key_lower = str(key).lower() + if any(term in key_lower for term in ("image", "mask", "depth", "normal", "matte")): + items.extend(_extract_media_items(value)) + return items + + +def _extract_media_items(value: Any) -> list[Any]: + if isinstance(value, str): + return [value] + if isinstance(value, dict): + if isinstance(value.get("url"), str) or isinstance(value.get("image_url"), str): + return [value] + items: list[Any] = [] + for nested in value.values(): + items.extend(_extract_media_items(nested)) + return items + if isinstance(value, list): + items: list[Any] = [] + for nested in value: + items.extend(_extract_media_items(nested)) + return items return [] diff --git a/invokeai/app/services/external_generation/providers/fal_catalog.py b/invokeai/app/services/external_generation/providers/fal_catalog.py index 2749a1b2c41..171a72d1f29 100644 --- a/invokeai/app/services/external_generation/providers/fal_catalog.py +++ b/invokeai/app/services/external_generation/providers/fal_catalog.py @@ -251,6 +251,8 @@ def classify_endpoint(category: str, schema: dict[str, Any], *, endpoint_id: str return FalEndpointKind.UPSCALE if normalized in {"text-to-image", "text2image", "text-to-img"}: return FalEndpointKind.TEXT_TO_IMAGE + if "segment" in normalized or "segment" in endpoint: + return FalEndpointKind.IMAGE_TO_IMAGE if normalized in {"image-to-image", "image-editing", "image-edit", "inpainting", "inpaint"}: properties = schema.get("properties", {}) has_mask = isinstance(properties, dict) and any("mask" in str(name).lower() for name in properties) diff --git a/tests/app/services/external_generation/test_fal_catalog.py b/tests/app/services/external_generation/test_fal_catalog.py index 34bd0ffc705..00a9898ca7b 100644 --- a/tests/app/services/external_generation/test_fal_catalog.py +++ b/tests/app/services/external_generation/test_fal_catalog.py @@ -91,6 +91,17 @@ def test_classify_endpoint_keeps_unknown_categories_generic() -> None: ) +def test_classify_endpoint_keeps_segmentation_out_of_inpaint_mode() -> None: + assert ( + classify_endpoint( + "image-to-image", + {"properties": {"image_url": {}, "min_mask_region_area": {}}}, + endpoint_id="fal-ai/sam2/auto-segment", + ) + is FalEndpointKind.IMAGE_TO_IMAGE + ) + + def test_catalog_client_lists_pages_and_fetches_schema(monkeypatch: pytest.MonkeyPatch) -> None: calls: list[tuple[str, dict[str, Any]]] = [] diff --git a/tests/app/services/external_generation/test_fal_provider.py b/tests/app/services/external_generation/test_fal_provider.py index 29a59f491eb..c861659dd39 100644 --- a/tests/app/services/external_generation/test_fal_provider.py +++ b/tests/app/services/external_generation/test_fal_provider.py @@ -371,6 +371,24 @@ def test_fal_provider_parses_single_image_output_shape(monkeypatch: pytest.Monke assert result.seed_used == 22 +def test_fal_provider_parses_segmentation_mask_output(monkeypatch: pytest.MonkeyPatch) -> None: + config = InvokeAIAppConfig(external_fal_api_key="fal-key") + provider = FalProvider(config, logging.getLogger("test")) + request = _request(_model("fal-ai/sam2/auto-segment", modes=["img2img"]), mode="img2img") + monkeypatch.setattr(provider, "_download_image", lambda url: Image.new("RGB", (3, 3), color="green")) + + result = provider._parse_result( + { + "combined_mask": {"url": "https://cdn.test/combined-mask.png"}, + "individual_masks": [{"url": "https://cdn.test/mask-1.png"}], + }, + request, + request_id="segment-1", + ) + + assert len(result.images) == 2 + + def test_fal_provider_generic_media_uploads_local_media_and_expands_placeholders( monkeypatch: pytest.MonkeyPatch, tmp_path: Any ) -> None: