Update image and video workflow nodes
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
import asyncio
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
try:
|
||||
from comfy.model_management import processing_interrupted, InterruptProcessingException
|
||||
INTERRUPT_AVAILABLE = True
|
||||
except Exception:
|
||||
INTERRUPT_AVAILABLE = False
|
||||
processing_interrupted = lambda: False
|
||||
|
||||
class InterruptProcessingException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
SUCCESS_STATUSES = {"succeed", "succeeded", "success", "completed", "done", "finished"}
|
||||
FAILURE_STATUSES = {
|
||||
"fail",
|
||||
"failed",
|
||||
"failure",
|
||||
"error",
|
||||
"expired",
|
||||
"timeout",
|
||||
"timed_out",
|
||||
"cancel",
|
||||
"canceled",
|
||||
"cancelled",
|
||||
"rejected",
|
||||
}
|
||||
|
||||
|
||||
def check_interrupt() -> None:
|
||||
if INTERRUPT_AVAILABLE and processing_interrupted():
|
||||
raise InterruptProcessingException()
|
||||
|
||||
|
||||
async def interruptible_sleep(seconds: float, step: float = 0.2) -> None:
|
||||
elapsed = 0.0
|
||||
while elapsed < seconds:
|
||||
check_interrupt()
|
||||
delay = min(step, seconds - elapsed)
|
||||
await asyncio.sleep(delay)
|
||||
elapsed += delay
|
||||
check_interrupt()
|
||||
|
||||
|
||||
async def run_with_interrupt(coro, step: float = 0.2):
|
||||
task = asyncio.ensure_future(coro)
|
||||
try:
|
||||
while not task.done():
|
||||
check_interrupt()
|
||||
await asyncio.wait({task}, timeout=step)
|
||||
check_interrupt()
|
||||
return await task
|
||||
except InterruptProcessingException:
|
||||
task.cancel()
|
||||
try:
|
||||
await task
|
||||
except BaseException:
|
||||
pass
|
||||
raise
|
||||
|
||||
|
||||
def _as_dict(value: Any) -> Dict[str, Any]:
|
||||
return value if isinstance(value, dict) else {}
|
||||
|
||||
|
||||
def _nested_payloads(payload: Dict[str, Any]):
|
||||
root = _as_dict(payload)
|
||||
data = _as_dict(root.get("data"))
|
||||
inner = _as_dict(data.get("data"))
|
||||
return root, data, inner
|
||||
|
||||
|
||||
def extract_status(payload: Dict[str, Any]) -> str:
|
||||
root, data, inner = _nested_payloads(payload)
|
||||
keys = ("status", "task_status", "state", "task_state")
|
||||
statuses = []
|
||||
for source in (data, inner, root):
|
||||
for key in keys:
|
||||
value = source.get(key)
|
||||
if value is not None and str(value).strip():
|
||||
statuses.append(str(value).strip().lower())
|
||||
for status in statuses:
|
||||
if status in FAILURE_STATUSES or any(
|
||||
token in status for token in ("fail", "error", "reject", "timeout", "cancel")
|
||||
):
|
||||
return status
|
||||
for status in statuses:
|
||||
if status in SUCCESS_STATUSES:
|
||||
return status
|
||||
return statuses[0] if statuses else ""
|
||||
|
||||
|
||||
def extract_progress(payload: Dict[str, Any]) -> int:
|
||||
root, data, inner = _nested_payloads(payload)
|
||||
for source in (data, inner, root):
|
||||
value = source.get("progress")
|
||||
if value is None:
|
||||
continue
|
||||
try:
|
||||
return max(0, min(100, int(float(str(value).strip().rstrip("%")))))
|
||||
except (TypeError, ValueError):
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def extract_error_message(payload: Dict[str, Any], default: str = "未知错误") -> str:
|
||||
root, data, inner = _nested_payloads(payload)
|
||||
keys = (
|
||||
"fail_reason",
|
||||
"failure_reason",
|
||||
"task_status_msg",
|
||||
"status_msg",
|
||||
"error_message",
|
||||
"message",
|
||||
"msg",
|
||||
"reason",
|
||||
"detail",
|
||||
"details",
|
||||
)
|
||||
for source in (data, inner, root):
|
||||
error = source.get("error")
|
||||
if isinstance(error, dict):
|
||||
for key in ("message", "msg", "detail", "reason", "code"):
|
||||
value = error.get(key)
|
||||
if value:
|
||||
return str(value)
|
||||
elif error:
|
||||
return str(error)
|
||||
|
||||
for key in keys:
|
||||
value = source.get(key)
|
||||
if value:
|
||||
return str(value)
|
||||
return default
|
||||
|
||||
|
||||
def extract_video_url(payload: Dict[str, Any]) -> str | None:
|
||||
root, data, inner = _nested_payloads(payload)
|
||||
for source in (data, inner, root):
|
||||
for key in ("video_url", "result_url", "url", "download_url"):
|
||||
value = source.get(key)
|
||||
if value:
|
||||
return str(value)
|
||||
|
||||
result = _as_dict(source.get("result"))
|
||||
for key in ("video_url", "result_url", "url", "download_url"):
|
||||
value = result.get(key)
|
||||
if value:
|
||||
return str(value)
|
||||
|
||||
content = _as_dict(source.get("content"))
|
||||
value = content.get("video_url") or content.get("url")
|
||||
if value:
|
||||
return str(value)
|
||||
|
||||
task_result = _as_dict(source.get("task_result"))
|
||||
videos = task_result.get("videos")
|
||||
if isinstance(videos, list) and videos:
|
||||
first = _as_dict(videos[0])
|
||||
value = first.get("url") or first.get("video_url")
|
||||
if value:
|
||||
return str(value)
|
||||
return None
|
||||
|
||||
|
||||
def is_success_status(status: str) -> bool:
|
||||
return status in SUCCESS_STATUSES
|
||||
|
||||
|
||||
def is_failure_status(status: str, payload: Dict[str, Any] | None = None) -> bool:
|
||||
if status in FAILURE_STATUSES:
|
||||
return True
|
||||
if any(token in status for token in ("fail", "error", "reject", "timeout", "cancel")):
|
||||
return True
|
||||
if payload is None:
|
||||
return False
|
||||
root, data, inner = _nested_payloads(payload)
|
||||
failure_keys = ("error", "fail_reason", "failure_reason", "task_status_msg", "error_message")
|
||||
return any(any(source.get(key) for key in failure_keys) for source in (data, inner, root))
|
||||
Reference in New Issue
Block a user