Compare commits

..

No commits in common. "257e1c6c4008f6fdaf0df42363cc741eea64db23" and "f16b4474a03cacb28a4b0afdae3a449611f2584a" have entirely different histories.

2 changed files with 56 additions and 105 deletions

View File

@ -57,7 +57,7 @@ vol = modal.Volume.from_name("comfy_model", environment_name="dev", create_if_mi
) )
@modal.web_server(8000, startup_timeout=120, label='image-video-agent-1') @modal.web_server(8000, startup_timeout=120, label='image-video-agent-1')
def ui_1(): def ui_1():
process = subprocess.Popen("comfy launch -- --cpu --listen 0.0.0.0 --port 8001", shell=True) process = subprocess.Popen("comfy launch -- --cpu --listen 0.0.0.0 --port 8000", shell=True)
process.wait() process.wait()

View File

@ -1,4 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding:utf-8 -*-
""" """
File img_agent.py File img_agent.py
Author silence Author silence
@ -22,7 +22,7 @@ except ImportError:
import logging import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("ImgSubmitNode") logger = logging.getLogger("ImgSubmitNode_Final")
print("提示: loguru 未安装使用内置logging。建议安装以获得更好的日志体验: pip install loguru") print("提示: loguru 未安装使用内置logging。建议安装以获得更好的日志体验: pip install loguru")
@ -102,12 +102,6 @@ class ImgSubmitNode:
@classmethod @classmethod
def INPUT_TYPES(cls): def INPUT_TYPES(cls):
# 从用户提供的截图中提取的尺寸选项
size_options = [
'2048x2048 (1:1)', '2394x1728 (4:3)', '1728x2394 (3:4)', '2560x1440 (16:9)',
'1440x2560 (9:16)', '2496x1664 (3:2)', '1664x2496 (2:3)', '3024x1296 (21:9)',
'1K', '2K', '4K'
]
return { return {
"required": { "required": {
"model_name_display": (cls.MODEL_DATA["full_display_list"],), "model_name_display": (cls.MODEL_DATA["full_display_list"],),
@ -118,10 +112,6 @@ class ImgSubmitNode:
"optional": { "optional": {
"image": ("IMAGE",), "image": ("IMAGE",),
"image_filename": ("STRING", {"multiline": False, "default": ""}), "image_filename": ("STRING", {"multiline": False, "default": ""}),
"image_urls": (
"STRING", {"multiline": True, "default": "", "placeholder": "单个或多个图片URL用英文逗号隔开..."}),
"num_images": ("INT", {"default": 1, "min": 1, "max": 9, "step": 1}),
"image_size": (size_options, {"default": "2K"}),
} }
} }
@ -144,97 +134,59 @@ class ImgSubmitNode:
logger.info(f"环境: [{environment}], 模型: '{model_name_display}' -> '{tech_name}'") logger.info(f"环境: [{environment}], 模型: '{model_name_display}' -> '{tech_name}'")
return base_url, tech_name return base_url, tech_name
def submit_task(self, model_name_display, prompt, aspect_ratio, environment, def submit_task(self, model_name_display, prompt, aspect_ratio, environment, image_filename=None, image=None):
image_filename=None, image=None, image_urls="", num_images=1, image_size="2K"):
file_obj = None
try: try:
base_url, tech_name = self._get_base_url_and_tech_name(environment, model_name_display) base_url, tech_name = self._get_base_url_and_tech_name(environment, model_name_display)
api_endpoint = f'{base_url}/api/custom/image/submit/task' model_config = self.MODEL_DATA["configs"].get(tech_name)
if not model_config:
raise ValueError(f"无法找到模型 '{tech_name}' 的配置。")
def validate_and_correct_parameter(param_name, user_value, supported_values):
if not supported_values: return user_value
if user_value in supported_values: return user_value
default_value = supported_values[0]
logger.warning(
f"参数警告!模型 '{tech_name}' 不支持 '{param_name}': '{user_value}'"
f"已自动替换为支持的默认值: '{default_value}'。支持的选项: {supported_values}"
)
return default_value
final_ar = validate_and_correct_parameter("宽高比", aspect_ratio, model_config.get("supported_ar", []))
headers = {'accept': 'application/json'} headers = {'accept': 'application/json'}
if "doubao-seedream-4-0" in tech_name: payload = {'prompt': prompt, 'model_name': tech_name, 'aspect_ratio': final_ar,
logger.info(f"检测到豆包模型 '{tech_name}',启用特定提交逻辑。") 'mode': 'turbo', 'webhook_flag': 'false'}
files_to_send = {}
# 从尺寸选项中提取实际值(例如 '2048x2048 (1:1)' -> '2048x2048' file_obj = None
actual_size = image_size.split(' ')[0]
extra_params = {
"sequential_image_generation": "auto",
"size": actual_size,
"max_images": num_images
}
payload = {
'prompt': prompt,
'model_name': tech_name,
'aspect_ratio': aspect_ratio,
'mode': 'turbo',
'webhook_flag': 'false',
'watermark': 'false',
'extra': json.dumps(extra_params)
}
if image_urls and image_urls.strip():
logger.info(f"使用提供的图片URL: {image_urls.strip()}")
image_urls = image_urls.strip()
image_urls = image_urls.strip().replace('\n', ',')
payload['img_list'] = image_urls
else:
logger.info("未提供图片URL将以文生图模式运行。")
logger.info(f"向豆包模型端点 {api_endpoint} 发送请求...")
response = requests.post(
api_endpoint, headers=headers, data=payload, timeout=60
)
if image is not None:
logger.info(f"检测到 IMAGE (Tensor) 输入,优先处理。")
img_tensor = image[0]
img_np = np.clip(255. * img_tensor.cpu().numpy(), 0, 255).astype(np.uint8)
pil_image = Image.fromarray(img_np)
buffer = io.BytesIO()
pil_image.save(buffer, format="PNG")
buffer.seek(0)
files_to_send['img_file'] = ('image_from_workflow.png', buffer, 'image/png')
elif image_filename and image_filename.strip():
logger.info(f"处理文件名: {image_filename}")
full_path = folder_paths.get_full_path("input", image_filename.strip())
if not (full_path and os.path.exists(full_path)):
return (f"错误: 在ComfyUI的input文件夹中未找到文件 '{image_filename}'",)
filename = os.path.basename(full_path)
mime_type, _ = mimetypes.guess_type(full_path) or ('application/octet-stream', None)
file_obj = open(full_path, 'rb')
files_to_send['img_file'] = (filename, file_obj, mime_type)
else: else:
# 原始逻辑,适用于其他所有模型 logger.info("未提供任何图像输入,以纯文本模式运行。")
logger.info(f"使用标准逻辑提交任务到模型 '{tech_name}'")
model_config = self.MODEL_DATA["configs"].get(tech_name)
if not model_config:
raise ValueError(f"无法找到模型 '{tech_name}' 的配置。")
def validate_and_correct_parameter(param_name, user_value, supported_values): api_endpoint = f'{base_url}/api/custom/image/submit/task'
if not supported_values: return user_value logger.info(f"向端点 {api_endpoint} 发送请求...")
if user_value in supported_values: return user_value
default_value = supported_values[0] response = requests.post(
logger.warning( api_endpoint, headers=headers, data=payload, files=files_to_send, timeout=60
f"参数警告!模型 '{tech_name}' 不支持 '{param_name}': '{user_value}'" )
f"已自动替换为支持的默认值: '{default_value}'。支持的选项: {supported_values}"
)
return default_value
final_ar = validate_and_correct_parameter("宽高比", aspect_ratio, model_config.get("supported_ar", []))
payload = {'prompt': prompt, 'model_name': tech_name, 'aspect_ratio': final_ar,
'mode': 'turbo', 'webhook_flag': 'false'}
files_to_send = {}
if image is not None:
logger.info(f"检测到 IMAGE (Tensor) 输入,优先处理。")
img_tensor = image[0]
img_np = np.clip(255. * img_tensor.cpu().numpy(), 0, 255).astype(np.uint8)
pil_image = Image.fromarray(img_np)
buffer = io.BytesIO()
pil_image.save(buffer, format="PNG")
buffer.seek(0)
files_to_send['img_file'] = ('image_from_workflow.png', buffer, 'image/png')
elif image_filename and image_filename.strip():
logger.info(f"处理文件名: {image_filename}")
full_path = folder_paths.get_full_path("input", image_filename.strip())
if not (full_path and os.path.exists(full_path)):
return (f"错误: 在ComfyUI的input文件夹中未找到文件 '{image_filename}'",)
filename = os.path.basename(full_path)
mime_type, _ = mimetypes.guess_type(full_path) or ('application/octet-stream', None)
file_obj = open(full_path, 'rb')
files_to_send['img_file'] = (filename, file_obj, mime_type)
else:
logger.info("未提供任何图像输入,以纯文本模式运行。")
logger.info(f"向标准端点 {api_endpoint} 发送请求...")
response = requests.post(
api_endpoint, headers=headers, data=payload, files=files_to_send, timeout=60
)
response.raise_for_status() response.raise_for_status()
response_json = response.json() response_json = response.json()
logger.info(f"任务提交成功,完整响应: {json.dumps(response_json, indent=2, ensure_ascii=False)}") logger.info(f"任务提交成功,完整响应: {json.dumps(response_json, indent=2, ensure_ascii=False)}")
@ -251,11 +203,10 @@ class ImgSubmitNode:
if file_obj: if file_obj:
file_obj.close() file_obj.close()
# NODE_CLASS_MAPPINGS = {
NODE_CLASS_MAPPINGS = { # "ImgSubmitNode": ImgSubmitNode
"ImgSubmitNode": ImgSubmitNode # }
} #
# NODE_DISPLAY_NAME_MAPPINGS = {
NODE_DISPLAY_NAME_MAPPINGS = { # "ImgSubmitNode": "统一生图任务节点"
"ImgSubmitNode": "提交图片生成" # }
}