feat: add image-list return format and quality controls

This commit is contained in:
Robert Wojciechowski
2026-10-14 00:44:45 +00:00
parent b14c51c365
commit 2df73e4b9f
10 changed files with 522 additions and 18 deletions
+2
View File
@@ -5,6 +5,7 @@ from aiohttp import web
import server
from ..image_list.runtime import (
IMAGE_TRANSFER_FORMATS,
MAX_REQUEST_BYTES,
PROTOCOL_VERSION,
decode_result,
@@ -39,6 +40,7 @@ async def image_list_capabilities_endpoint(_request):
"protocol_version": PROTOCOL_VERSION,
"node_ids": ["DistributedImageListStart", "DistributedImageListEnd"],
"transport": "typed-float-tensor-json-v1",
"image_transfer_formats": list(IMAGE_TRANSFER_FORMATS),
})
+21 -1
View File
@@ -188,7 +188,8 @@ async def dispatch_worker_prompt(
return prompt_id if return_prompt_id else None
async def preflight_image_list_workers(workers, require_idle=True, timeout=3.0):
async def preflight_image_list_workers(workers, require_idle=True, timeout=3.0, *,
required_transfer_formats=()):
"""Require protocol/node support and report which direct workers are idle.
This performs read-only GETs only; it never submits a prompt or contacts a
@@ -196,6 +197,14 @@ async def preflight_image_list_workers(workers, require_idle=True, timeout=3.0):
"""
if not workers:
raise RuntimeError("Distributed Image List requires at least one selected direct worker")
if (not isinstance(required_transfer_formats, (list, tuple, set, frozenset))
or any(type(fmt) is not str for fmt in required_transfer_formats)):
raise ValueError("required_transfer_formats must contain image transfer format names")
required_formats = set(required_transfer_formats) - {"exact"}
if required_formats:
from ...serverless_bridge.image_transfer import validate_options
for fmt in required_formats:
validate_options(fmt)
session = await get_client_session()
required_nodes = {"DistributedImageListStart", "DistributedImageListEnd"}
semaphore = asyncio.Semaphore(8)
@@ -242,6 +251,17 @@ async def preflight_image_list_workers(workers, require_idle=True, timeout=3.0):
"upgrade that worker before running this feature; no work was submitted"
)
if required_formats:
advertised = capability.get("image_transfer_formats")
if (not isinstance(advertised, list)
or any(type(fmt) is not str for fmt in advertised)
or not required_formats.issubset(advertised)):
raise RuntimeError(
f"Image-list worker {worker_id} lacks required image_transfer_formats "
f"{sorted(required_formats)}; upgrade that worker before compressed IMAGE returns; "
"no work was submitted"
)
check = "queue"
queue_url = build_worker_url(worker, "/queue")
async with session.get(queue_url, timeout=aiohttp.ClientTimeout(total=timeout)) as response:
+11 -1
View File
@@ -361,6 +361,14 @@ async def orchestrate_distributed_execution(
"DistributedMediaCollector or Ultimate SD Upscale nodes in one prompt"
)
validate_image_list_regions(prompt_obj, explicit_targets=True)
from ..serverless_bridge.image_transfer import DEFAULT_FORMAT, DEFAULT_QUALITY, validate_options
required_transfer_formats = set()
for end_id in prompt_index.nodes_for_class("DistributedImageListEnd"):
end_inputs = prompt_obj[end_id].get("inputs", {})
fmt, _ = validate_options(end_inputs.get("transfer_format", DEFAULT_FORMAT),
end_inputs.get("transfer_quality", DEFAULT_QUALITY))
if fmt != DEFAULT_FORMAT:
required_transfer_formats.add(fmt)
workers = _resolve_direct_workers_for_image_list(config, requested_ids)
if _has_selected_serverless_workers(config, requested_ids):
from ..image_list.serverless import resolve_serverless_workers
@@ -421,7 +429,9 @@ async def orchestrate_distributed_execution(
"No selected worker is reachable for Distributed Image List in orchestrator-only mode"
)
direct_workers = [worker for worker in active_workers if worker.get("type") != "serverless"]
idle_ids = (await preflight_image_list_workers(direct_workers, require_idle=delegate_master)
transfer_kwargs = ({"required_transfer_formats": sorted(required_transfer_formats)}
if required_transfer_formats else {})
idle_ids = (await preflight_image_list_workers(direct_workers, require_idle=delegate_master, **transfer_kwargs)
if direct_workers else {})
active_workers = [worker for worker in active_workers
if worker.get("type") == "serverless" or worker["id"] in idle_ids]