Supports direct processing of video output and can simultaneously handle workflows with both images and videos.
This commit is contained in:
+111
-126
@@ -1,11 +1,11 @@
|
||||
import requests
|
||||
import time
|
||||
import json
|
||||
from PIL import Image, ImageOps
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
import numpy as np
|
||||
import torch
|
||||
import os # 确保导入 os 库
|
||||
import os
|
||||
|
||||
class ExecuteNode:
|
||||
def __init__(self):
|
||||
@@ -16,30 +16,26 @@ class ExecuteNode:
|
||||
return {
|
||||
"required": {
|
||||
"apiConfig": ("STRUCT",), # 设置节点的输入
|
||||
"nodeInfoList": ("ARRAY", {"default": []}), # NodeInfoList节点的输出
|
||||
},
|
||||
"optional": {
|
||||
"nodeInfoList": ("ARRAY", {"default": []}), # NodeInfoList节点的输出, 设置为可选
|
||||
"run_timeout": ("INT", {"default": 600}), # 最大运行超时时间(秒)
|
||||
"query_interval": ("INT", {"default": 10}), # 查询间隔时间(秒)
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",) # 支持单张和多张图片输出
|
||||
RETURN_NAMES = ("images",) # 定义返回名称,与 ComfyUI 的预期匹配
|
||||
RETURN_TYPES = ("IMAGE", "VIDEO") # 支持单张和多张图片输出,也支持视频
|
||||
RETURN_NAMES = ("images", "videos") # 定义返回名称,与 ComfyUI 的预期匹配
|
||||
|
||||
CATEGORY = "RunningHub"
|
||||
FUNCTION = "process" # 指向 process 方法
|
||||
|
||||
def process(self, apiConfig, nodeInfoList, run_timeout=600, query_interval=2):
|
||||
def process(self, apiConfig, nodeInfoList=None, run_timeout=600, query_interval=2):
|
||||
# Ensure query_interval is not less than 2
|
||||
if query_interval < 2:
|
||||
print("Query interval is too low, setting to minimum value of 2 seconds.")
|
||||
query_interval = 2
|
||||
|
||||
"""
|
||||
该节点通过调用 RunningHub API 创建任务并返回生成的图片链接。
|
||||
"""
|
||||
# 打印请求数据,方便调试
|
||||
print(f"API request data: {apiConfig}")
|
||||
print(f"Node info list: {nodeInfoList}")
|
||||
print(f"Run timeout: {run_timeout} seconds")
|
||||
@@ -49,19 +45,17 @@ class ExecuteNode:
|
||||
account_status = self.check_account_status(apiConfig["apiKey"], apiConfig["base_url"])
|
||||
if int(account_status["currentTaskCounts"]) > 0:
|
||||
print("There are tasks running, waiting for them to finish.")
|
||||
# 等待最多 run_timeout 秒,如果任务未完成,则超时
|
||||
start_time = time.time()
|
||||
while account_status["currentTaskCounts"] > 0 and time.time() - start_time < run_timeout:
|
||||
time.sleep(query_interval) # 每 query_interval 秒查询一次
|
||||
time.sleep(query_interval)
|
||||
account_status = self.check_account_status(apiConfig["apiKey"], apiConfig["base_url"])
|
||||
if int(account_status["currentTaskCounts"]) > 0:
|
||||
raise Exception(f"Timeout: There are still running tasks after {run_timeout} seconds.")
|
||||
|
||||
# Print nodeInfoList for debugging
|
||||
print(f"ExecuteNode NodeInfoList: {nodeInfoList}")
|
||||
|
||||
# 2. 创建任务
|
||||
task_creation_result = self.create_task(apiConfig, nodeInfoList, apiConfig["base_url"])
|
||||
# 2. 创建任务,如果 nodeInfoList 为空则不传递
|
||||
task_creation_result = self.create_task(apiConfig, nodeInfoList or [], apiConfig["base_url"])
|
||||
if task_creation_result["code"] != 0:
|
||||
raise Exception(f"Task creation failed: {task_creation_result['msg']}")
|
||||
|
||||
@@ -73,14 +67,13 @@ class ExecuteNode:
|
||||
task_start_time = time.time()
|
||||
while task_status != "success":
|
||||
print(f"Task still running, checking again in {query_interval} seconds...")
|
||||
time.sleep(query_interval) # 每 query_interval 秒检查一次任务状态
|
||||
time.sleep(query_interval)
|
||||
task_status_result = self.check_task_status(task_id, apiConfig["apiKey"], apiConfig["base_url"])
|
||||
print(f"Task info, taskId: {task_id}, status: {task_status_result}")
|
||||
|
||||
if isinstance(task_status_result, dict):
|
||||
task_status = task_status_result.get("taskStatus", "unknown") # 从结果中获取任务状态
|
||||
task_status = task_status_result.get("taskStatus", "unknown")
|
||||
elif isinstance(task_status_result, list):
|
||||
# 假设任务完成后返回的数据列表表示任务成功
|
||||
task_status = "success"
|
||||
else:
|
||||
task_status = "unknown"
|
||||
@@ -89,13 +82,105 @@ class ExecuteNode:
|
||||
print(f"Task failed or completed with status: {task_status}")
|
||||
break
|
||||
|
||||
# 检查是否超过 run_timeout
|
||||
if time.time() - task_start_time > run_timeout:
|
||||
raise Exception(f"Timeout: Task {task_id} did not complete within {run_timeout} seconds.")
|
||||
|
||||
# 4. 任务完成,处理输出
|
||||
return self.process_task_output(task_id, apiConfig["apiKey"], apiConfig["base_url"])
|
||||
|
||||
def process_task_output(self, task_id, api_key, base_url):
|
||||
"""
|
||||
处理任务输出,返回文件链接。
|
||||
返回图像和视频,若无图像则返回空图像,若无视频则返回空视频。
|
||||
"""
|
||||
task_status_result = self.check_task_status(task_id, api_key, base_url)
|
||||
|
||||
print("Task Status Result:", json.dumps(task_status_result, indent=4, ensure_ascii=False))
|
||||
|
||||
image_urls = []
|
||||
video_urls = []
|
||||
|
||||
# 检查任务是否返回了图像
|
||||
if isinstance(task_status_result, dict):
|
||||
file_url = task_status_result.get("fileUrl")
|
||||
file_type = task_status_result.get("fileType")
|
||||
if file_url and file_type.lower() in ["png", "jpg", "jpeg"]:
|
||||
image_urls.append(file_url)
|
||||
elif file_url and file_type.lower() in ["mp4", "avi", "mov"]:
|
||||
video_urls.append(file_url)
|
||||
elif isinstance(task_status_result, list):
|
||||
for output in task_status_result:
|
||||
if isinstance(output, dict):
|
||||
file_url = output.get("fileUrl")
|
||||
file_type = output.get("fileType")
|
||||
if file_url and file_type.lower() in ["png", "jpg", "jpeg"]:
|
||||
image_urls.append(file_url)
|
||||
elif file_url and file_type.lower() in ["mp4", "avi", "mov"]:
|
||||
video_urls.append(file_url)
|
||||
|
||||
if not image_urls:
|
||||
image_urls = None # No images found, set to None
|
||||
if not video_urls:
|
||||
video_urls = None # No videos found, set to None
|
||||
|
||||
# Download and process images if available
|
||||
image_data_list = []
|
||||
if image_urls:
|
||||
for url in image_urls:
|
||||
print("Downloading image from URL:", url)
|
||||
image_tensor = self.download_image(url)
|
||||
image_data_list.append(image_tensor)
|
||||
|
||||
# 下载视频并保存在本地
|
||||
video_data_list = []
|
||||
if video_urls:
|
||||
for url in video_urls:
|
||||
print("Downloading video from URL:", url)
|
||||
video_path = self.download_video(url)
|
||||
video_data_list.append(video_path)
|
||||
|
||||
print(f"Returning {len(image_data_list)} images and {len(video_data_list)} videos.")
|
||||
return (image_data_list, video_data_list)
|
||||
|
||||
def download_image(self, image_url):
|
||||
"""
|
||||
从 URL 下载图像并转换为适合预览或保存的 torch.Tensor 格式。
|
||||
"""
|
||||
response = requests.get(image_url)
|
||||
|
||||
if response.status_code == 200:
|
||||
img = Image.open(BytesIO(response.content)).convert("RGB")
|
||||
img_array = np.array(img).astype(np.float32) / 255.0
|
||||
img_tensor = torch.from_numpy(img_array)
|
||||
return img_tensor
|
||||
else:
|
||||
raise Exception(f"Failed to download image: {image_url}")
|
||||
|
||||
def download_video(self, video_url):
|
||||
"""
|
||||
从 URL 下载视频并保存到本地。
|
||||
"""
|
||||
response = requests.get(video_url, stream=True)
|
||||
if response.status_code == 200:
|
||||
# 确保保存视频的目录存在
|
||||
output_dir = "output"
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
# 获取视频文件名并保存
|
||||
video_filename = f"RH_output_video_{str(int(time.time()))}.mp4"
|
||||
video_path = os.path.join(output_dir, video_filename)
|
||||
|
||||
with open(video_path, "wb") as f:
|
||||
for chunk in response.iter_content(chunk_size=1024):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
|
||||
print(f"Video saved to {video_path}")
|
||||
return video_path
|
||||
else:
|
||||
raise Exception(f"Failed to download video: {video_url}")
|
||||
|
||||
def check_account_status(self, api_key, base_url):
|
||||
"""
|
||||
查询账户状态,检查是否可以提交新任务
|
||||
@@ -113,7 +198,6 @@ class ExecuteNode:
|
||||
result = response.json()
|
||||
if result["code"] != 0:
|
||||
raise Exception(f"Failed to get account status: {result['msg']}")
|
||||
# 检查并确保 currentTaskCounts 是整数
|
||||
try:
|
||||
current_task_counts = int(result["data"]["currentTaskCounts"])
|
||||
except ValueError:
|
||||
@@ -134,14 +218,7 @@ class ExecuteNode:
|
||||
data = {
|
||||
"workflowId": apiConfig["workflowId"],
|
||||
"apiKey": apiConfig["apiKey"],
|
||||
"nodeInfoList": [
|
||||
{
|
||||
"nodeId": int(nodeInfo["nodeId"]), # 确保 nodeId 为整数类型
|
||||
"fieldName": nodeInfo["fieldName"],
|
||||
"fieldValue": nodeInfo["fieldValue"],
|
||||
}
|
||||
for nodeInfo in nodeInfoList
|
||||
],
|
||||
"nodeInfoList": nodeInfoList, # 如果nodeInfoList为空,传递空列表
|
||||
}
|
||||
|
||||
response = requests.post(url, json=data, headers=headers)
|
||||
@@ -163,7 +240,6 @@ class ExecuteNode:
|
||||
|
||||
response = requests.post(url, json=data, headers=headers)
|
||||
|
||||
# 打印响应以便调试
|
||||
print("Response Status Code:", response.status_code)
|
||||
try:
|
||||
response_json = response.json()
|
||||
@@ -176,114 +252,23 @@ class ExecuteNode:
|
||||
|
||||
result = response.json()
|
||||
|
||||
# 检查是否有数据结果
|
||||
if result.get("data") and isinstance(result["data"], list):
|
||||
if len(result["data"]) > 0:
|
||||
return result["data"] # 返回整个列表,表示任务成功并且有结果
|
||||
return result["data"]
|
||||
else:
|
||||
# data 是空列表,可能是任务还在运行,或出错
|
||||
if result.get("code") != 0:
|
||||
msg = result.get("msg")
|
||||
if msg != "APIKEY_TASK_IS_RUNNING":
|
||||
return {"error": msg} # 出现了错误,返回错误信息
|
||||
return {"error": msg}
|
||||
else:
|
||||
return {"taskStatus": "RUNNING"} # 任务仍在运行
|
||||
return {"taskStatus": "RUNNING"} # 如果没有其他信息,认为任务在运行中
|
||||
return {"taskStatus": "RUNNING"}
|
||||
return {"taskStatus": "RUNNING"}
|
||||
|
||||
# 如果没有 data 字段或 data 不是列表,检查任务状态
|
||||
if result.get("code") != 0:
|
||||
msg = result.get("msg")
|
||||
if msg != "APIKEY_TASK_IS_RUNNING":
|
||||
return {"error": msg} # 返回错误信息
|
||||
return {"error": msg}
|
||||
else:
|
||||
return {"taskStatus": "RUNNING"} # 任务仍在运行
|
||||
return {"taskStatus": "RUNNING"}
|
||||
|
||||
return {"taskStatus": "UNKNOWN_ERROR"}
|
||||
|
||||
def process_task_output(self, task_id, api_key, base_url):
|
||||
"""
|
||||
处理任务输出,返回文件链接。
|
||||
"""
|
||||
task_status_result = self.check_task_status(task_id, api_key, base_url)
|
||||
|
||||
# 记录任务状态结果以了解其结构
|
||||
print("Task Status Result:", json.dumps(task_status_result, indent=4, ensure_ascii=False))
|
||||
|
||||
image_urls = []
|
||||
|
||||
# 确保 task_status_result 是字典或列表
|
||||
if isinstance(task_status_result, dict):
|
||||
# 检查 fileUrl 和 fileType
|
||||
file_url = task_status_result.get("fileUrl")
|
||||
file_type = task_status_result.get("fileType")
|
||||
if file_url and file_type.lower() in ["png", "jpg", "jpeg"]:
|
||||
image_urls.append(file_url)
|
||||
elif isinstance(task_status_result, list):
|
||||
for output in task_status_result:
|
||||
if isinstance(output, dict):
|
||||
file_url = output.get("fileUrl")
|
||||
file_type = output.get("fileType")
|
||||
if file_url and file_type.lower() in ["png", "jpg", "jpeg"]:
|
||||
image_urls.append(file_url)
|
||||
|
||||
if not image_urls:
|
||||
raise Exception("No valid image output found.")
|
||||
|
||||
# 下载并处理所有图像
|
||||
image_data_list = []
|
||||
for url in image_urls:
|
||||
print("Downloading image from URL:", url) # 记录图像 URL
|
||||
image_tensor = self.download_image(url) # 下载并处理图像
|
||||
print("Image downloaded and processed successfully.")
|
||||
|
||||
# 打印张量信息,避免在 uint8 上调用 mean()
|
||||
print(f"Image tensor shape: {image_tensor.shape}")
|
||||
mean_val = image_tensor.mean()
|
||||
print(f"Image tensor min: {image_tensor.min()}, max: {image_tensor.max()}, mean: {mean_val}")
|
||||
|
||||
# 确保返回的是 torch.Tensor
|
||||
if not isinstance(image_tensor, torch.Tensor):
|
||||
raise TypeError(f"Expected torch.Tensor, got {type(image_tensor)}")
|
||||
|
||||
image_data_list.append(image_tensor)
|
||||
|
||||
print(f"Returning {len(image_data_list)} images.")
|
||||
return (image_data_list,) # 返回一个包含图像列表的元组,与 RETURN_TYPES 和 RETURN_NAMES 匹配
|
||||
|
||||
def download_image(self, image_url):
|
||||
"""
|
||||
从 URL 下载图像并转换为适合预览或保存的 torch.Tensor 格式。
|
||||
"""
|
||||
response = requests.get(image_url)
|
||||
|
||||
if response.status_code == 200:
|
||||
img = Image.open(BytesIO(response.content)).convert("RGB")
|
||||
|
||||
# 转换为 numpy 数组并调整数据类型和范围
|
||||
img_array = np.array(img).astype(np.float32) / 255.0 # 归一化到 [0, 1]
|
||||
|
||||
# **保持形状为 [H, W, C],不进行 permute 操作**
|
||||
img_tensor = torch.from_numpy(img_array) # 形状 [H, W, C]
|
||||
|
||||
# 打印图像尺寸
|
||||
print(f"Downloaded image dimensions: {img_tensor.shape}") # 例如 (高度, 宽度, 3)
|
||||
|
||||
return img_tensor
|
||||
|
||||
else:
|
||||
raise Exception(f"Failed to download image: {image_url}")
|
||||
|
||||
def download_video(self, video_url):
|
||||
"""
|
||||
从 URL 下载视频。
|
||||
根据 ComfyUI 的要求实现此方法。
|
||||
"""
|
||||
response = requests.get(video_url, stream=True)
|
||||
if response.status_code == 200:
|
||||
# 示例:将视频保存到临时位置并返回路径或数据
|
||||
video_content = response.content
|
||||
# 您可能需要根据 ComfyUI 的要求处理视频数据
|
||||
# 目前,返回原始字节
|
||||
return video_content
|
||||
else:
|
||||
raise Exception(f"Failed to download video: {video_url}")
|
||||
|
||||
+253
-147
@@ -1,61 +1,7 @@
|
||||
{
|
||||
"last_node_id": 42,
|
||||
"last_link_id": 32,
|
||||
"last_node_id": 44,
|
||||
"last_link_id": 34,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 17,
|
||||
"type": "RH_NodeInfoListNode",
|
||||
"pos": [
|
||||
68,
|
||||
1440
|
||||
],
|
||||
"size": {
|
||||
"0": 330,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "previousNodeInfoList",
|
||||
"type": "ARRAY",
|
||||
"link": null,
|
||||
"label": "previousNodeInfoList",
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"name": "fieldValue",
|
||||
"type": "STRING",
|
||||
"link": 32,
|
||||
"widget": {
|
||||
"name": "fieldValue"
|
||||
},
|
||||
"label": "fieldValue",
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "ARRAY",
|
||||
"type": "ARRAY",
|
||||
"links": [
|
||||
23
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3,
|
||||
"label": "ARRAY"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_NodeInfoListNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
90,
|
||||
"text",
|
||||
"土星环"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"type": "String",
|
||||
@@ -88,96 +34,12 @@
|
||||
"wh32,一个采光很好的房间,中午,女子穿着蕾丝睡衣在床上躺着,正面对着镜头漏出了微笑"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"type": "RH_ExecuteNode",
|
||||
"pos": [
|
||||
526,
|
||||
1477
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "apiConfig",
|
||||
"type": "STRUCT",
|
||||
"link": 20,
|
||||
"label": "apiConfig"
|
||||
},
|
||||
{
|
||||
"name": "nodeInfoList",
|
||||
"type": "ARRAY",
|
||||
"link": 23,
|
||||
"label": "nodeInfoList"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
30
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3,
|
||||
"label": "images"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_ExecuteNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
600,
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "RH_SettingsNode",
|
||||
"pos": [
|
||||
53,
|
||||
1227
|
||||
],
|
||||
"size": [
|
||||
502.2504859687508,
|
||||
137.38932101438627
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRUCT",
|
||||
"type": "STRUCT",
|
||||
"links": [
|
||||
20
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3,
|
||||
"label": "STRUCT"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_SettingsNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"https://www.runninghub.cn",
|
||||
"ed37fbdd79c34a7ca612aedbe5cea13e",
|
||||
"1871595400514633730"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 39,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
887,
|
||||
1224
|
||||
1395,
|
||||
1231
|
||||
],
|
||||
"size": [
|
||||
214.7587890625,
|
||||
@@ -239,16 +101,244 @@
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "AnimateDiff_00002.mp4",
|
||||
"filename": "AnimateDiff_00005.mp4",
|
||||
"subfolder": "",
|
||||
"type": "output",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 24,
|
||||
"workflow": "AnimateDiff_00002.png"
|
||||
"workflow": "AnimateDiff_00005.png"
|
||||
},
|
||||
"muted": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "RH_SettingsNode",
|
||||
"pos": [
|
||||
53,
|
||||
1227
|
||||
],
|
||||
"size": {
|
||||
"0": 502.25048828125,
|
||||
"1": 137.3893280029297
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRUCT",
|
||||
"type": "STRUCT",
|
||||
"links": [
|
||||
20
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3,
|
||||
"label": "STRUCT"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_SettingsNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"https://www.runninghub.cn",
|
||||
"ed37fbdd79c34a7ca612aedbe5cea13e",
|
||||
"1871595400514633730"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"type": "RH_ExecuteNode",
|
||||
"pos": [
|
||||
550,
|
||||
1468
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "apiConfig",
|
||||
"type": "STRUCT",
|
||||
"link": 20,
|
||||
"label": "apiConfig"
|
||||
},
|
||||
{
|
||||
"name": "nodeInfoList",
|
||||
"type": "ARRAY",
|
||||
"link": 23,
|
||||
"label": "nodeInfoList"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
30
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3,
|
||||
"label": "images"
|
||||
},
|
||||
{
|
||||
"name": "videos",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
33
|
||||
],
|
||||
"shape": 3,
|
||||
"label": "videos",
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_ExecuteNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
600,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"type": "RH_NodeInfoListNode",
|
||||
"pos": [
|
||||
82,
|
||||
1435
|
||||
],
|
||||
"size": {
|
||||
"0": 330,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "previousNodeInfoList",
|
||||
"type": "ARRAY",
|
||||
"link": null,
|
||||
"label": "previousNodeInfoList",
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"name": "fieldValue",
|
||||
"type": "STRING",
|
||||
"link": 32,
|
||||
"widget": {
|
||||
"name": "fieldValue"
|
||||
},
|
||||
"label": "fieldValue",
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "ARRAY",
|
||||
"type": "ARRAY",
|
||||
"links": [
|
||||
23
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3,
|
||||
"label": "ARRAY"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_NodeInfoListNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
90,
|
||||
"text",
|
||||
"土星环"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 43,
|
||||
"type": "easy showAnythingLazy",
|
||||
"pos": [
|
||||
943,
|
||||
1509
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 26
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "anything",
|
||||
"type": "*",
|
||||
"link": 33,
|
||||
"label": "anything"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output",
|
||||
"type": "*",
|
||||
"links": [
|
||||
34
|
||||
],
|
||||
"shape": 3,
|
||||
"label": "output",
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "easy showAnythingLazy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 44,
|
||||
"type": "ShowText|pysssss",
|
||||
"pos": [
|
||||
928,
|
||||
1639
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
76
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"link": 34,
|
||||
"widget": {
|
||||
"name": "text"
|
||||
},
|
||||
"label": "文本"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": null,
|
||||
"shape": 6,
|
||||
"label": "字符串"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ShowText|pysssss"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
"output\\RH_output_video_1738854232.mp4"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -283,16 +373,32 @@
|
||||
17,
|
||||
1,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
33,
|
||||
30,
|
||||
1,
|
||||
43,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
34,
|
||||
43,
|
||||
0,
|
||||
44,
|
||||
0,
|
||||
"STRING"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.8769226950000008,
|
||||
"scale": 0.9646149645000006,
|
||||
"offset": [
|
||||
589.8700344728978,
|
||||
-719.2667377838786
|
||||
197.9158053009368,
|
||||
-912.3150194555913
|
||||
]
|
||||
},
|
||||
"ue_links": [],
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
{
|
||||
"last_node_id": 53,
|
||||
"last_link_id": 42,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 9,
|
||||
"type": "RH_SettingsNode",
|
||||
"pos": [
|
||||
66,
|
||||
1357
|
||||
],
|
||||
"size": {
|
||||
"0": 502.25048828125,
|
||||
"1": 137.3893280029297
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRUCT",
|
||||
"type": "STRUCT",
|
||||
"links": [
|
||||
33
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3,
|
||||
"label": "STRUCT"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_SettingsNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"https://www.runninghub.cn",
|
||||
"ed37fbdd79c34a7ca612aedbe5cea13e",
|
||||
"1887510793653780481"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 43,
|
||||
"type": "RH_ExecuteNode",
|
||||
"pos": [
|
||||
635,
|
||||
1367
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "apiConfig",
|
||||
"type": "STRUCT",
|
||||
"link": 33,
|
||||
"label": "apiConfig"
|
||||
},
|
||||
{
|
||||
"name": "nodeInfoList",
|
||||
"type": "ARRAY",
|
||||
"link": null,
|
||||
"label": "nodeInfoList",
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [],
|
||||
"shape": 3,
|
||||
"label": "images",
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "videos",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
36
|
||||
],
|
||||
"shape": 3,
|
||||
"label": "videos",
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "RH_ExecuteNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
600,
|
||||
10
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 44,
|
||||
"type": "easy showAnythingLazy",
|
||||
"pos": [
|
||||
992,
|
||||
1373
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 26
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "anything",
|
||||
"type": "*",
|
||||
"link": 36,
|
||||
"label": "anything"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output",
|
||||
"type": "*",
|
||||
"links": [
|
||||
39
|
||||
],
|
||||
"shape": 3,
|
||||
"label": "output",
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "easy showAnythingLazy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 47,
|
||||
"type": "ShowText|pysssss",
|
||||
"pos": [
|
||||
584,
|
||||
1572
|
||||
],
|
||||
"size": {
|
||||
"0": 347.5731201171875,
|
||||
"1": 242.42494201660156
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"link": 39,
|
||||
"widget": {
|
||||
"name": "text"
|
||||
},
|
||||
"label": "文本"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": null,
|
||||
"shape": 6,
|
||||
"label": "字符串"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ShowText|pysssss"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
"output\\RH_output_video_1738853689.mp4"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
33,
|
||||
9,
|
||||
0,
|
||||
43,
|
||||
0,
|
||||
"STRUCT"
|
||||
],
|
||||
[
|
||||
36,
|
||||
43,
|
||||
1,
|
||||
44,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
39,
|
||||
44,
|
||||
0,
|
||||
47,
|
||||
0,
|
||||
"STRING"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 1.0610764609500007,
|
||||
"offset": [
|
||||
143.41590852037982,
|
||||
-895.2557214802658
|
||||
]
|
||||
},
|
||||
"ue_links": [],
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Reference in New Issue
Block a user