commit 05bdcb9d3dfd1d5e5e8792c57bd06699ccd1f6af
Author: raysers <33230373@qq.com>
Date: Fri Oct 4 02:31:59 2024 -0700
Initial commit
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..64e108d
Binary files /dev/null and b/.DS_Store differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..33d2ade
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+
Quick Mflux on Comfyui
+
+
+
English | 中文
+
+
+## Introduction
+Simple use of Mflux in ComfyUI, suitable for users who are not familiar with terminal usage.
+
+## Acknowledgements
+
+Special thanks to the developers of the mflux project, especially the initiator @filipstrand and active contributor @anthonywu, for making it easier and more efficient for Mac users to generate flux model images. Their contributions are truly delightful; appreciate them!
+
+mflux:https://github.com/filipstrand/mflux
+
+I also want to thank @CharafChnioune, the author of MFLUX-WEBUI. I have partially referenced his code, and in accordance with the Apache 2.0 license used in his project, I have added license comments in the referenced sections of my code.
+
+MFLUX-WEBUI:https://github.com/CharafChnioune/MFLUX-WEBUI
+
+## Installation Guide
+1. cd /path/to/your_ComfyUI
+2. Activate your virtual environment
+3. cd custom_nodes
+4. git clone https://github.com/raysers/Mflux-ComfyUI.git
+5. pip install mflux==0.3.0
+6. Restart ComfyUI
+
+## Usage Instructions
+Currently, the functionality is relatively simple and only implements text-to-image generation. To use it, simply create a node named **Quick MFlux Generation** (found under **Mflux/Quick**), and then connect it to the built-in preview or save image nodes in ComfyUI. If the Quick MFlux Generation node is connected to a preview node and you are satisfied with the generated image, you will need to right-click to manually save the final result. If it is connected to a save image node, any generated images will be automatically saved to **ComfyUI/output** by the ComfyUI mechanism. Note that in the Quick MFlux Generation node, the metadata option should be set to true (default is false); if true, the generated image will be saved to **ComfyUI/output/Mflux** along with a JSON file of the same name, containing almost all the generation parameters of that image.
+
+PS: Alternatively, you can directly drag the JSON or PNG workflows from this project into ComfyUI, and they will load automatically.
+
+## Contributions
+I am a novice coder, and this is my first GitHub project. I initially had grand plans, such as implementing mflux's Lora and ControlNet functionalities, and realizing the essence of ComfyUI—splitting nodes to allow users to delve into the underlying logic of flux. However, my limited coding skills have constrained my vision. If anyone with expertise could help implement these, I would be very grateful. Greetings to all!
+
+## License
+I would like to adopt the MIT license, consistent with the mflux project, as a contribution to open source.
\ No newline at end of file
diff --git a/README_zh.md b/README_zh.md
new file mode 100644
index 0000000..2bd7f0a
--- /dev/null
+++ b/README_zh.md
@@ -0,0 +1,40 @@
+Quick Mflux on Comfyui
+
+
+
中文 | English
+
+
+
+# Quick Mflux on Comfyui
+
+## 简介
+Mflux在ComfyUI中的简单使用,适合不太懂得使用终端的用户。
+
+## 特别鸣谢
+
+感谢mflux项目的开发者们,特别是项目发起人 @filipstrand 和活跃贡献者 @anthonywu,是他们让Mac用户实现了更方便高效的flux模型生图,这些贡献着实令人轻松愉悦,谢谢他们!
+
+mflux:https://github.com/filipstrand/mflux
+
+同时感谢MFLUX-WEBUI的作者 @CharafChnioune,我部分参考了他的代码,基于他的项目所使用的Apache 2.0许可证的要求,我在代码中的引用段落添加了许可证注释。
+
+MFLUX-WEBUI:https://github.com/CharafChnioune/MFLUX-WEBUI
+
+## 安装指南
+1. cd /path/to/your_ComfyUI
+2. 激活虚拟环境
+3. cd custom_nodes
+4. git clone https://github.com/raysers/Mflux-ComfyUI.git
+5. pip install mflux==0.3.0
+6. 重启ComfyUI
+
+## 使用说明
+由于目前的功能相对简单,仅仅实现了文生图,因此只需要新建节点 **Quick MFlux Generation**(在 **Mflux/Quick** 下),再连接ComfyUI自带的预览图像或保存图像节点即可。如果 **Quick MFlux Generation** 连接的是预览图像节点,最终生成结果需要右键手动保存;如果是保存图像节点,任何生成图片都将被ComfyUI的机制自动保存到 **ComfyUI/output** 下。需要注意的是 **Quick MFlux Generation** 节点中的metadata选项,如果它是true值(默认false),那么生成的图像将被保存到 **ComfyUI/output/Mflux** 中,同时带有图像同名的json文件,里面包含了该图像的几乎一切生成参数。
+
+或者,您可以直接将本项目中的JSON或PNG工作流拖入ComfyUI,它们将自动加载。
+
+## 贡献
+我是编码新手,这是我的第一个GitHub项目。我原本的规划十分宏大,比如实现mflux的Lora以及ControlNet功能,以及实现ComfyUI的精髓理念——即拆分节点以让用户能够深入了解flux的底层逻辑……但我粗浅的代码能力限制了我的蓝图。如果有高手能够帮忙实现这些,我十分感谢。在此问好。
+
+## 许可证
+我想采用和mflux项目一致的MIT麻省理工许可,也算为开源贡献一份心力吧。
\ No newline at end of file
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..39a8c6b
--- /dev/null
+++ b/__init__.py
@@ -0,0 +1,3 @@
+from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
+
+__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
diff --git a/nodes.py b/nodes.py
new file mode 100644
index 0000000..105b416
--- /dev/null
+++ b/nodes.py
@@ -0,0 +1,162 @@
+import time
+import random
+import os
+import numpy as np
+from mflux.config.model_config import ModelConfig
+from mflux.config.config import Config
+from mflux.flux.flux import Flux1
+from mflux.controlnet.flux_controlnet import Flux1Controlnet
+from pathlib import Path
+from folder_paths import get_filename_list, get_output_directory, models_dir
+from huggingface_hub import snapshot_download
+import torch
+import json
+
+flux_cache = {}
+
+def download_hg_model(model_id, path, exDir="mflux"):
+ model_checkpoint = os.path.join(models_dir, exDir, path)
+ if not os.path.exists(model_checkpoint):
+ print(f"Downloading model {model_id} to {model_checkpoint}...")
+ try:
+ snapshot_download(repo_id=model_id, local_dir=model_checkpoint, local_dir_use_symlinks=False)
+ except Exception as e:
+ print(f"Error downloading model {model_id}: {e}")
+ return None
+ else:
+ print(f"Model {model_id} already exists at {model_checkpoint}. Skipping download.")
+ return model_checkpoint
+
+def load_or_create_flux(model, path, lora_paths, lora_scales, is_controlnet=False):
+ key = (model, path, tuple(lora_paths), tuple(lora_scales), is_controlnet)
+ if key not in flux_cache:
+ FluxClass = Flux1Controlnet if is_controlnet else Flux1
+ flux_cache[key] = FluxClass(
+ model_config=ModelConfig.from_alias(model),
+ local_path=path,
+ lora_paths=lora_paths,
+ lora_scales=lora_scales,
+ )
+ # This code is licensed under the Apache 2.0 License.
+ # Portions of this code are derived from the work of CharafChnioune at https://github.com/CharafChnioune/MFLUX-WEBUI
+ return flux_cache[key]
+
+
+def generate_image(prompt, model, seed, height, width, steps, guidance, path, lora_files, lora_scales_str):
+ lora_paths = lora_files if lora_files else []
+ lora_scales = [float(s.strip()) for s in lora_scales_str.split(",")] if lora_scales_str else []
+
+ seed = random.randint(0, 0xffffffffffffffff) if seed == -1 else int(seed)
+ print(f"Using seed: {seed}")
+
+ flux = load_or_create_flux(model, path if path else None, lora_paths, lora_scales)
+
+ image = flux.generate_image(
+ seed=seed,
+ prompt=prompt,
+ config=Config(
+ num_inference_steps=steps,
+ height=height,
+ width=width,
+ guidance=guidance,
+ ),
+ )
+
+ inner_image = image.image
+
+ inner_image_numpy = np.array(inner_image).astype(np.float32)
+
+ normalized = inner_image_numpy / 255.0
+
+ tensor_image = torch.from_numpy(normalized).permute(2, 0, 1)
+ tensor_image = tensor_image.unsqueeze(0)
+ tensor_image = tensor_image.permute(0, 2, 3, 1)
+
+ return inner_image, tensor_image
+
+class QuickMfluxNode:
+ @classmethod
+ def INPUT_TYPES(cls):
+ return {
+ "required": {
+ "prompt": ("STRING", {"multiline": True, "dynamicPrompts": True, "tooltip": "The text to be encoded.", "default": "Luxury food photograph"}),
+ "model": (["dev", "schnell"], {"default": "schnell"}),
+ "path": (["flux.1-schnell-mflux-4bit", "flux.1-dev-mflux-4bit"], {"default": "flux.1-schnell-mflux-4bit"}),
+ "seed": ("INT", {"default": -1, "min": -1, "max": 0xffffffffffffffff}),
+ "height": ("INT", {"default": 1024, "min": 256, "max": 1024}),
+ "width": ("INT", {"default": 1024, "min": 256, "max": 1024}),
+ "steps": ("INT", {"default": 2, "min": 1}),
+ "guidance": ("FLOAT", {"default": 3.5, "min": 0.0}),
+ "metadata": (["true", "false"], {"default": "false"}),
+ },
+ "optional": {
+ "lora_files": ("LIST", {"default": []}),
+ "lora_scales": ("STRING", {"default": ""}),
+ }
+ }
+
+ RETURN_TYPES = ("IMAGE",)
+ CATEGORY = "Mflux/Quick"
+ FUNCTION = "generate"
+
+ def generate(self, prompt, model, path, seed, height, width, steps, guidance, metadata="false", lora_files=[], lora_scales=""):
+ model_id = f"madroid/{path}"
+ full_model_path = download_hg_model(model_id, path)
+
+ if model == "dev":
+ steps = max(steps, 14)
+ elif model == "schnell":
+ steps = min(max(steps, 2), 4)
+
+ inner_image, tensor_image = generate_image(prompt, model, seed, height, width, steps, guidance, full_model_path, lora_files, lora_scales)
+
+ if metadata == "true":
+ self.save_images([inner_image], prompt, model, path, seed, height, width, steps, guidance)
+
+ print(f"Generated tensor image with shape: {tensor_image.shape}, dtype: {tensor_image.dtype}")
+
+ return (tensor_image,)
+
+ def save_images(self, images, prompt, model, path, seed, height, width, steps, guidance, filename_prefix="Mflux"):
+ output_dir = get_output_directory()
+ mflux_dir = os.path.join(output_dir, "Mflux")
+ os.makedirs(mflux_dir, exist_ok=True)
+
+ results = []
+ existing_files = os.listdir(mflux_dir)
+ existing_count = len([f for f in existing_files if f.startswith(filename_prefix)])
+
+ for (batch_number, img) in enumerate(images):
+ filename = f"{filename_prefix}_{existing_count + batch_number:05}.png"
+ file_path = os.path.join(mflux_dir, filename)
+ img.save(file_path)
+
+ metadata = {
+ "prompt": prompt,
+ "model": model,
+ "path": path,
+ "seed": seed,
+ "height": height,
+ "width": width,
+ "steps": steps,
+ "guidance": guidance,
+ }
+
+ metadata_filename = os.path.join(mflux_dir, f"{filename_prefix}_{existing_count + batch_number:05}.json")
+ with open(metadata_filename, 'w') as metadata_file:
+ json.dump(metadata, metadata_file)
+
+ results.append({
+ "filename": filename,
+ "path": file_path,
+ })
+
+ return results
+
+NODE_CLASS_MAPPINGS = {
+ "QuickMfluxNode": QuickMfluxNode,
+}
+
+NODE_DISPLAY_NAME_MAPPINGS = {
+ "QuickMfluxNode": "Quick MFlux Generation"
+}
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..447af02
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+mflux==0.3.0
\ No newline at end of file