diff --git a/custom_nodes/CONTRIBUTING.md b/custom_nodes/CONTRIBUTING.md new file mode 100644 index 00000000..048f127e --- /dev/null +++ b/custom_nodes/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Contributing to ComfyUI + +Welcome, and thank you for your interest in contributing to ComfyUI! + +There are several ways in which you can contribute, beyond writing code. The goal of this document is to provide a high-level overview of how you can get involved. + +## Asking Questions + +Have a question? Instead of opening an issue, please ask on [Discord](https://comfy.org/discord) or [Matrix](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) channels. Our team and the community will help you. + +## Providing Feedback + +Your comments and feedback are welcome, and the development team is available via a handful of different channels. + +See the `#bug-report`, `#feature-request` and `#feedback` channels on Discord. + +## Reporting Issues + +Have you identified a reproducible problem in ComfyUI? Do you have a feature request? We want to hear about it! Here's how you can report your issue as effectively as possible. + + +### Look For an Existing Issue + +Before you create a new issue, please do a search in [open issues](https://github.com/comfyanonymous/ComfyUI/issues) to see if the issue or feature request has already been filed. + +If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment: + +* 👍 - upvote +* 👎 - downvote + +If you cannot find an existing issue that describes your bug or feature, create a new issue. We have an issue template in place to organize new issues. + + +### Creating Pull Requests + +* Please refer to the article on [creating pull requests](https://github.com/comfyanonymous/ComfyUI/wiki/How-to-Contribute-Code) and contributing to this project. + + +## Thank You + +Your contributions to open source, large or small, make great projects like this possible. Thank you for taking the time to contribute. diff --git a/flux_style_shaper_api/client_example.py b/flux_style_shaper_api/client_example.py deleted file mode 100644 index 2561fb69..00000000 --- a/flux_style_shaper_api/client_example.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -FLUX风格塑形API的Python客户端示例 -""" - -import requests -import argparse -import os -from datetime import datetime - -def generate_image(server_url, prompt, structure_image_path, style_image_path, depth_strength=15.0, style_strength=0.5): - """ - 调用API生成风格化图像 - - 参数: - server_url (str): API服务器地址 - prompt (str): 文本提示 - structure_image_path (str): 结构图像的路径 - style_image_path (str): 风格图像的路径 - depth_strength (float): 深度强度 - style_strength (float): 风格强度 - - 返回: - str: 生成图像的保存路径 - """ - # API端点 - url = f"{server_url}/generate" - - # 参数 - data = { - "prompt": prompt, - "depth_strength": depth_strength, - "style_strength": style_strength - } - - # 图像文件 - files = { - "structure_image": open(structure_image_path, "rb"), - "style_image": open(style_image_path, "rb") - } - - print(f"正在发送请求到 {url}...") - print(f"参数: 提示词='{prompt}', 深度强度={depth_strength}, 风格强度={style_strength}") - print(f"结构图像: {structure_image_path}") - print(f"风格图像: {style_image_path}") - - try: - # 发送请求 - response = requests.post(url, data=data, files=files) - - # 检查响应 - if response.status_code == 200: - # 生成输出文件名 - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - output_filename = f"生成图像_{timestamp}.png" - - # 保存生成的图像 - with open(output_filename, "wb") as f: - f.write(response.content) - - print(f"成功! 图像已保存到 {output_filename}") - return output_filename - else: - print(f"生成失败: {response.json()}") - return None - except Exception as e: - print(f"请求出错: {e}") - return None - finally: - # 关闭文件 - for f in files.values(): - f.close() - -def main(): - # 解析命令行参数 - parser = argparse.ArgumentParser(description="FLUX风格塑形API客户端") - parser.add_argument("--server", default="http://localhost:8000", help="API服务器地址") - parser.add_argument("--prompt", default="", help="文本提示") - parser.add_argument("--structure", required=True, help="结构图像路径") - parser.add_argument("--style", required=True, help="风格图像路径") - parser.add_argument("--depth-strength", type=float, default=15.0, help="深度强度 (默认: 15.0)") - parser.add_argument("--style-strength", type=float, default=0.5, help="风格强度 (默认: 0.5)") - - args = parser.parse_args() - - # 检查文件是否存在 - if not os.path.exists(args.structure): - print(f"错误: 结构图像文件不存在 {args.structure}") - return - - if not os.path.exists(args.style): - print(f"错误: 风格图像文件不存在 {args.style}") - return - - # 调用API - generate_image( - server_url=args.server, - prompt=args.prompt, - structure_image_path=args.structure, - style_image_path=args.style, - depth_strength=args.depth_strength, - style_strength=args.style_strength - ) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/hook_breaker_ac10a0.py b/hook_breaker_ac10a0.py new file mode 100644 index 00000000..c3e1c063 --- /dev/null +++ b/hook_breaker_ac10a0.py @@ -0,0 +1,17 @@ +# Prevent custom nodes from hooking anything important +import comfy.model_management + +HOOK_BREAK = [(comfy.model_management, "cast_to")] + + +SAVED_FUNCTIONS = [] + + +def save_functions(): + for f in HOOK_BREAK: + SAVED_FUNCTIONS.append((f[0], f[1], getattr(f[0], f[1]))) + + +def restore_functions(): + for f in SAVED_FUNCTIONS: + setattr(f[0], f[1], f[2]) diff --git a/main.py b/main.py index ac9d24b7..f3f56597 100644 --- a/main.py +++ b/main.py @@ -141,7 +141,7 @@ import nodes import comfy.model_management import comfyui_version import app.logger - +import hook_breaker_ac10a0 def cuda_malloc_warning(): device = comfy.model_management.get_torch_device() @@ -215,6 +215,7 @@ def prompt_worker(q, server_instance): comfy.model_management.soft_empty_cache() last_gc_collect = current_time need_gc = False + hook_breaker_ac10a0.restore_functions() async def run(server_instance, address='', port=8188, verbose=True, call_on_start=None): @@ -268,7 +269,9 @@ def start_comfyui(asyncio_loop=None): prompt_server = server.PromptServer(asyncio_loop) q = execution.PromptQueue(prompt_server) + hook_breaker_ac10a0.save_functions() nodes.init_extra_nodes(init_custom_nodes=not args.disable_all_custom_nodes) + hook_breaker_ac10a0.restore_functions() cuda_malloc_warning() diff --git a/requirements.txt b/requirements.txt index a7ba5010..749b20e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,6 @@ transformers==4.51.3 # 用于CLIP模型和文本处理 tokenizers>=0.13.3 sentencepiece safetensors>=0.4.2 -aiohttp>=3.11.8 # 使用更新版本的要求 yarl>=1.18.0 pyyaml Pillow>=9.3.0 # 使用flux版本的最低要求 @@ -46,3 +45,4 @@ addict yapf xformers==0.0.24 diffusers==0.33.1 # 用于Stable Diffusion和ControlNet模型 +aiohttp>=3.11.13 \ No newline at end of file diff --git a/server.py b/server.py index c0fd79ad..08bc2331 100644 --- a/server.py +++ b/server.py @@ -18,6 +18,7 @@ from PIL import Image, ImageOps from PIL.PngImagePlugin import PngInfo from io import BytesIO +import aiohttp from aiohttp import web import logging @@ -579,6 +580,9 @@ class PromptServer(): info['deprecated'] = True if getattr(obj_class, "EXPERIMENTAL", False): info['experimental'] = True + + if hasattr(obj_class, 'API_NODE'): + info['api_node'] = obj_class.API_NODE return info @routes.get("/object_info") @@ -723,13 +727,50 @@ class PromptServer(): # Currently both the old endpoints without prefix and new endpoints with # prefix are supported. api_routes = web.RouteTableDef() + + # 存储已添加的路由,避免重复 + added_routes = set() + for route in self.routes: # Custom nodes might add extra static routes. Only process non-static # routes to add /api prefix. if isinstance(route, web.RouteDef): - api_routes.route(route.method, "/api" + route.path)(route.handler, **route.kwargs) - self.app.add_routes(api_routes) - self.app.add_routes(self.routes) + route_key = f"{route.method}:{route.path}" + if route_key not in added_routes: + api_routes.route(route.method, "/api" + route.path)(route.handler, **route.kwargs) + added_routes.add(route_key) + + # 添加API路由,使用异常处理避免重复路由错误 + try: + self.app.add_routes(api_routes) + except RuntimeError as e: + import logging + logging.warning(f"添加API路由时出错: {e}") + logging.warning("尝试跳过冲突路由继续启动服务...") + # 单个添加路由,跳过冲突的路由 + for route in api_routes: + try: + self.app.router.add_route(route.method, route.path, route.handler, **route.kwargs) + except RuntimeError: + continue + + # 添加主路由,使用相同的异常处理方式 + try: + self.app.add_routes(self.routes) + except RuntimeError as e: + import logging + logging.warning(f"添加主路由时出错: {e}") + for route in self.routes: + if isinstance(route, web.RouteDef): + try: + self.app.router.add_route(route.method, route.path, route.handler, **route.kwargs) + except RuntimeError: + continue + else: + try: + self.app.add_routes([route]) + except RuntimeError: + continue # Add routes from web extensions. for name, dir in nodes.EXTENSION_WEB_DIRS.items(): diff --git a/styles/default.csv b/styles/default.csv new file mode 100644 index 00000000..b7977e59 --- /dev/null +++ b/styles/default.csv @@ -0,0 +1,3 @@ +name,prompt,negative_prompt +❌Low Token,,"embedding:EasyNegative, NSFW, Cleavage, Pubic Hair, Nudity, Naked, censored" +✅Line Art / Manga,"(Anime Scene, Toonshading, Satoshi Kon, Ken Sugimori, Hiromu Arakawa:1.2), (Anime Style, Manga Style:1.3), Low detail, sketch, concept art, line art, webtoon, manhua, hand drawn, defined lines, simple shades, minimalistic, High contrast, Linear compositions, Scalable artwork, Digital art, High Contrast Shadows, glow effects, humorous illustration, big depth of field, Masterpiece, colors, concept art, trending on artstation, Vivid colors, dramatic", diff --git a/优化.md b/优化.md new file mode 100644 index 00000000..23850cb1 --- /dev/null +++ b/优化.md @@ -0,0 +1,19 @@ +1.生成图片后微调 +使用flux-canny 页面上传两张参考图或者色卡(获取色卡,或者其他参数之后重新组织提示词) +调整图片尺寸 +使用flux-redux +2.软装数量的控制 +3.45斜角拍摄 +4.天花板线性射灯的识别率很低 +5.上传四个角度的图片 + +6.45度的构图如何生成 + +https://huggingface.co/spaces/multimodalart/flux-fill-outpaint (在原图上进行填充 内容丰富) + + +Tile 瓷砖生成 + +流程: +1.上传图片(1-4张) 2.选择案例库 3.设计风格微调 4.选择尺寸 宽屏竖屏 5.生成方案(图片出来) +