├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── feature_request.yml
└── workflows
│ └── publish.yml
├── README.md
├── __init__.py
├── flow
├── api_handlers.py
├── constants.py
├── downloader.py
├── flow_manager.py
├── flow_node.py
├── route_manager.py
└── server_setup.py
├── pyproject.toml
└── web
├── core
├── content.html
├── css
│ ├── main.css
│ └── themes.css
├── js
│ └── common
│ │ ├── components
│ │ ├── BlobMessageProcessor.js
│ │ ├── CanvasComponent.js
│ │ ├── DataComponent.js
│ │ ├── DimSelector.js
│ │ ├── Dropdown.js
│ │ ├── DropdownStepper.js
│ │ ├── IMessageProcessor.js
│ │ ├── ImageLoader.js
│ │ ├── InputComponent.js
│ │ ├── JSONMessageProcessor.js
│ │ ├── LoraWorkflowManager.js
│ │ ├── MultiComponent.js
│ │ ├── MultiStepper.js
│ │ ├── Seeder.js
│ │ ├── Stepper.js
│ │ ├── ToggleComponent.js
│ │ ├── WorkflowNodeAdder.js
│ │ ├── canvas
│ │ │ ├── CanvasControlsPlugin.js
│ │ │ ├── CanvasLoader.js
│ │ │ ├── CanvasManager.js
│ │ │ ├── CanvasPlugin.js
│ │ │ ├── CanvasScaleForSavePlugin.js
│ │ │ ├── CustomBrushPlugin.js
│ │ │ ├── EventEmitter.js
│ │ │ ├── ImageAdderPlugin.js
│ │ │ ├── ImageCompareSliderPlugin.js
│ │ │ ├── ImageLoaderPlugin.js
│ │ │ ├── MaskBrushPlugin.js
│ │ │ ├── MaskExportUtilities.js
│ │ │ ├── UndoRedoPlugin.js
│ │ │ └── fabric.5.2.4.min.js
│ │ ├── dropdownHandler.js
│ │ ├── footer.js
│ │ ├── header.js
│ │ ├── headerLinker.js
│ │ ├── imageLoaderComp.js
│ │ ├── imagedisplay.js
│ │ ├── messageHandler.js
│ │ ├── mimeTypeDetector.js
│ │ ├── missingPackagesDialog.js
│ │ ├── previewManager.js
│ │ ├── progressbar.js
│ │ ├── utils.js
│ │ ├── webSocketHandler.js
│ │ ├── workflowLoader.js
│ │ └── workflowManager.js
│ │ └── scripts
│ │ ├── ThemeManager.js
│ │ ├── componentTypes.js
│ │ ├── corePath.js
│ │ ├── corePathLinker.js
│ │ ├── favicon.js
│ │ ├── fetchWorkflow.js
│ │ ├── fetchflowConfig.js
│ │ ├── init.js
│ │ ├── injectStylesheet.js
│ │ ├── interactiveUI.js
│ │ ├── nodesscanner.js
│ │ ├── preferences.js
│ │ ├── state.js
│ │ ├── stateManager.js
│ │ ├── stateManagerMain.js
│ │ ├── templates.js
│ │ ├── ui_utils.js
│ │ └── workflowLoader.js
├── loadScripts.js
├── loadScriptsLinker.js
├── main.js
├── media
│ ├── git
│ │ ├── cover_flow.jpg
│ │ ├── flow_1.jpg
│ │ ├── flow_2.jpg
│ │ ├── flow_3.jpg
│ │ ├── flow_4.jpg
│ │ ├── flow_5.jpg
│ │ ├── flow_yt.jpg
│ │ └── patreon.svg
│ └── ui
│ │ ├── area_in_zoom_icon.png
│ │ ├── area_out_zoom_icon.png
│ │ ├── area_zoom_icon.png
│ │ ├── dice.png
│ │ ├── double-face-mask.png
│ │ ├── drop_image_main.png
│ │ ├── drop_image_main2.png
│ │ ├── drop_image_rect.png
│ │ ├── drop_image_rect_no_border.png
│ │ ├── drop_image_rect_no_border_trans.png
│ │ ├── flow_logo.png
│ │ ├── g_flow_logo.png
│ │ ├── i2i.png
│ │ ├── minus_icon_n.png
│ │ ├── paintree.png
│ │ ├── pen_icon.png
│ │ ├── plus_icon_n.png
│ │ ├── r_flow_logo.png
│ │ ├── top-view_30trans.png
│ │ └── update_logo.png
└── templates
│ └── index.html
├── flow
├── conf.json
├── index.html
└── js
│ └── main.js
└── linker
├── app.js
├── componentHandler.js
├── configHandler.js
├── css
└── styles.css
├── defFlowConfig.json
├── defwf.json
├── fileHandler.js
├── flow.html
├── flowConfig.json
├── index.html
├── linker.html
├── media
└── thumbnail.jpg
├── multiComponentHandler.js
├── nodeHandler.js
├── wf.json
└── workflowHandler.js
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Something is not right with the Flow.
3 | title: "[Bug]: "
4 | labels: ["bug-report"]
5 |
6 | body:
7 | - type: checkboxes
8 | attributes:
9 | label: Where is the issue?
10 | description: Is the issue in the "Custom Node 'Flow'" UI, or does it concern a specific flow?
11 | options:
12 | - label: The issue is with the "Custom Node 'Flow'"
13 | - label: The issue is with a specific flow. Please refer to [Flows repository](https://github.com/diStyApps/flows_lib) if the problem lies with a specific flow.
14 | - label: I’m not sure where the issue is
15 |
16 | - type: markdown
17 | attributes:
18 | value: |
19 | *Please provide detailed information to help us resolve the issue. Screenshots and logs are highly appreciated.*
20 |
21 | - type: textarea
22 | id: bug-description
23 | attributes:
24 | label: Bug Description
25 | description: A clear and concise description of the issue you're encountering.
26 | validations:
27 | required: true
28 |
29 | - type: textarea
30 | id: steps
31 | attributes:
32 | label: Step-by-step instructions to reproduce the issue
33 | description: Be as specific as possible.
34 | validations:
35 | required: true
36 |
37 | - type: textarea
38 | id: expected-behavior
39 | attributes:
40 | label: Expected Behavior
41 | description: Describe what you expected to happen.
42 | validations:
43 | required: true
44 |
45 | - type: textarea
46 | id: current-behavior
47 | attributes:
48 | label: Current Behavior
49 | description: Describe what is currently happening instead.
50 | validations:
51 | required: true
52 |
53 | - type: input
54 | id: version
55 | attributes:
56 | label: Flow Version or Commit
57 | description: "Specify the version or commit of Flow you're using. Avoid 'Latest Version'—instead, provide the exact version (e.g., v1.0.1)."
58 | validations:
59 | required: true
60 |
61 | - type: textarea
62 | id: media-logs
63 | attributes:
64 | label: Media and Logs
65 | description: Please provide any relevant media or logs to help diagnose the issue. If the logs are long, consider sharing via Pastebin or a similar service.
66 | render: Shell
67 | validations:
68 | required: true
69 |
70 | - type: textarea
71 | id: additional-info
72 | attributes:
73 | label: Additional Information
74 | description: Include any other relevant information or context that may help.
75 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest an idea for this project
3 | title: "[Feature Request]: "
4 | labels: ["enhancement"]
5 |
6 | body:
7 | - type: checkboxes
8 | attributes:
9 | label: Is there an existing issue for this?
10 | description: Please search to see if an issue already exists for the feature you want, and that it's not implemented in a recent build/commit.
11 | options:
12 | - label: I have searched the existing issues and checked the recent builds/commits
13 | required: true
14 | - type: markdown
15 | attributes:
16 | value: |
17 | *Please fill this form with as much information as possible, provide screenshots and/or illustrations of the feature if possible*
18 | - type: textarea
19 | id: feature
20 | attributes:
21 | label: Summary
22 | description: Briefly describe the new feature you would like to request.
23 | validations:
24 | required: true
25 | - type: textarea
26 | id: workflow
27 | attributes:
28 | label: Description
29 | description: Provide a detailed description of the feature you are suggesting. Explain how it would work, what problem it would solve, and any potential benefits.
30 | value:
31 | validations:
32 | required: true
33 | - type: textarea
34 | id: misc
35 | attributes:
36 | label: Additional information
37 | description: Add any other context or screenshots about the feature request here.
38 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to Comfy registry
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - main
7 | - master
8 | paths:
9 | - "pyproject.toml"
10 |
11 | jobs:
12 | publish-node:
13 | name: Publish Custom Node to registry
14 | runs-on: ubuntu-latest
15 | # if this is a forked repository. Skipping the workflow.
16 | if: github.event.repository.fork == false
17 | steps:
18 | - name: Check out code
19 | uses: actions/checkout@v4
20 | - name: Publish Custom Node
21 | uses: Comfy-Org/publish-node-action@main
22 | with:
23 | ## Add your own personal access token to your Github Repository secrets and reference it here.
24 | personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
17 |
18 |
19 |
20 | [](https://www.patreon.com/distyx)
21 | [](https://discord.com/invite/M3PWExxVbP)
22 | [](https://www.youtube.com/@Flowcomfy/videos)
23 |
24 |
25 |
26 |
27 |
28 |
Flow - Streamlined Way to ComfyUI
29 |
30 |
31 |
Let your creativity flow naturally
32 |
Don't forget to leave a star.
33 |
34 |
35 |
36 | Report Bug
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Table of Contents
45 |
46 |
47 | About The Project
48 |
49 | Installation
50 | Roadmap
51 | Contact
52 | My Other Projects
53 |
54 |
55 |
56 |
57 |
58 |
59 | ## About The Project
60 |
61 | Flow is a custom node designed to provide user-friendly interface for ComfyUI by acting as an alternative user interface for running workflows. It is not a replacement for workflow creation.
62 |
63 | Flow is currently in the early stages of development, so expect bugs and ongoing feature enhancements. With your support and feedback, Flow will settle into a steady stream.
64 |
65 | ### Watch on Youtube
66 |
67 | [](https://www.youtube.com/watch?v=g8zMs2B5tic "Flow")
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | (back to top )
81 |
82 | #### Requirements
83 | - [ComfyUI](https://github.com/comfyanonymous/ComfyUI)
84 | - [ComfyUI-Manager](https://github.com/ltdrdata/ComfyUI-Manager)
85 |
86 |
87 | ## Installation
88 |
89 |
90 | In [ComfyUI](https://github.com/comfyanonymous/ComfyUI) root folder, navigate to the `custom_nodes` folder and run the following command:
91 |
92 | Open the terminal, or in the address bar type CMD to open a command prompt, then run the following command:
93 |
94 | ```bash
95 | git clone https://github.com/diStyApps/ComfyUI-disty-Flow
96 | ```
97 |
98 | To run Flow, navigate to this address in your web browser:
99 |
100 | ```bash
101 | http://127.0.0.1:8188/flow
102 | ```
103 |
104 | (back to top )
105 |
106 |
107 | ## Roadmap
108 |
109 | ### Flow Customization
110 | - [x] Flow Linker
111 | - - [ ] Improved Flow Linker
112 | - Expanded Flow Components
113 | - Enhanced Customization Options
114 |
115 | ### Feature Support
116 | - [x] Canvas / Masking / Inpainting Functionality
117 | - - [x] Improved Canvas / Masking / Inpainting Functionality
118 | - - [ ] Outpainting Functionality
119 | - - Improving Inpainting Functionality
120 |
121 | - [ ] Enhanced Media Handling
122 | - [x] Live Preview
123 | - [ ] Prompt Tracking
124 |
125 | ### UI/UX Enhancements
126 | - [ ] Status Bar Implementation
127 | - [ ] Optimized Menu for Flow Organization
128 | - General User Interface Improvements
129 |
130 | ### Media and Model Management
131 | - [ ] Media Gallery Integration
132 | - [x] Model Gallery Integration
133 | - - Improved Model Gallery
134 | ### Pre-built Flows
135 | - Exclusive Flows for various tasks
136 | - Task-specific Flows
137 | - Continuous updates to support evolving needs
138 |
139 | ### Codebase Improvements
140 | - [ ] Code Optimization and Refactoring
141 | - [ ] Better Error Handling
142 | - [ ] Improved Event Handling
143 |
144 | (back to top )
145 |
146 |
147 | ## Contact
148 |
149 | distty@gmail.com
150 |
151 |
152 | (back to top )
153 |
154 |
155 | ## My Other Projects
156 |
157 | [SEAIT](https://github.com/diStyApps/seait)
158 |
159 | [ComfyUI_FrameMaker](https://github.com/diStyApps/ComfyUI_FrameMaker)
160 |
161 | [VisionCrafter](https://github.com/diStyApps/VisionCrafter)
162 |
163 | [FaceSwapSuite](https://github.com/diStyApps/FaceSwapSuite)
164 |
165 | [VisualClipPicker](https://github.com/diStyApps/VisualClipPicker)
166 |
167 | [Stable-Diffusion-Pickle-Scanner-GUI](https://github.com/diStyApps/Stable-Diffusion-Pickle-Scanner-GUI)
168 |
169 | [Safe-and-Stable-Ckpt2Safetensors-Conversion-Tool-GUI](https://github.com/diStyApps/Safe-and-Stable-Ckpt2Safetensors-Conversion-Tool-GUI)
170 |
171 |
172 | (back to top )
173 |
174 |
175 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | from .flow.flow_node import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
2 | from .flow.constants import WEB_DIRECTORY
3 | from .flow.server_setup import setup_server
4 | setup_server()
5 | __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
6 |
--------------------------------------------------------------------------------
/flow/constants.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import mimetypes
3 | from pathlib import Path
4 | import re
5 | APP_NAME = "Flow"
6 | APP_VERSION = "0.5.2"
7 | FLOWMSG = f"\033[38;5;129mFlow - {APP_VERSION}\033[0m"
8 | APP_CONFIGS = []
9 |
10 | CURRENT_DIR = Path(__file__).parent
11 | ROOT_DIR = CURRENT_DIR.parent
12 | WEBROOT = ROOT_DIR / "web"
13 | CORE_PATH = WEBROOT / "core"
14 | FLOW_PATH = WEBROOT / "flow"
15 | FLOWS_PATH = WEBROOT / "flows"
16 | LINKER_PATH = WEBROOT / "linker"
17 | CUSTOM_THEMES_DIR = WEBROOT / 'custom-themes'
18 | WEB_DIRECTORY = "web/core/js/common/scripts"
19 |
20 | CUSTOM_NODES_DIR = ROOT_DIR.parent
21 | EXTENSION_NODE_MAP_PATH = ROOT_DIR.parent / "ComfyUI-Manager" / "extension-node-map.json"
22 |
23 | FLOWS_DOWNLOAD_PATH = 'https://github.com/diStyApps/flows_lib'
24 |
25 | SAFE_FOLDER_NAME_REGEX = re.compile(r'^[\w\-]+$')
26 | ALLOWED_EXTENSIONS = {'css'}
27 | mimetypes.add_type('application/javascript', '.js')
28 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
29 | logger = logging.getLogger(__name__)
30 | FLOWS_CONFIG_FILE = 'flowConfig.json'
31 | FLOWS_TO_REMOVE = [
32 | "afl_CogVideoX-Fun-i2v-es",
33 | "afl_CogVideoX-Fun-i2v",
34 | "afl_MimicMotioni2v",
35 | "afl_abase",
36 | "afl_abasei2i",
37 | "afl_abasesd35t3v",
38 | "afl_abasevea",
39 | "afl_abaseveai2i",
40 | "afl_base-fluxd_at2i",
41 | "afl_base-fluxdggufi2i",
42 | "afl_base-fluxdgguft2i",
43 | "afl_base-fluxdi2i",
44 | "afl_base-fluxs_ai2t",
45 | "afl_base-fluxsi2i",
46 | "afl_baseAD",
47 | "afl_baseAdLcm",
48 | "afl_cogvidx_at2v",
49 | "afl_cogvidxi2v",
50 | "afl_cogvidxinteri2v",
51 | "afl_flowup",
52 | "afl_flux_dev",
53 | "afl_flux_dev_lora",
54 | "afl_genfill",
55 | "afl_ipivsMorph",
56 | "afl_mochi2v",
57 | "afl_pulid_flux",
58 | "afl_pulid_flux_GGUF",
59 | "afl_reactor"
60 | "5otvy-cogvideox-orbit-left-lora",
61 | "umbi9-hunyuan-text-to-video",
62 | ]
63 |
64 | NODE_CLASS_MAPPINGS = {}
65 | NODE_DISPLAY_NAME_MAPPINGS = {}
66 |
--------------------------------------------------------------------------------
/flow/downloader.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | import tempfile
3 | import shutil
4 | from pathlib import Path
5 | from .constants import FLOWS_DOWNLOAD_PATH, FLOWS_PATH, FLOWS_TO_REMOVE, FLOWMSG, logger
6 |
7 | def download_update_flows() -> None:
8 | try:
9 | for flow in FLOWS_TO_REMOVE:
10 | flow_path = FLOWS_PATH / flow
11 | if flow_path.exists() and flow_path.is_dir():
12 | # logger.info(f"{FLOWMSG}: Removing existing flow directory '{flow}'")
13 | shutil.rmtree(flow_path)
14 | # logger.debug(f"{FLOWMSG}: Successfully removed '{flow}'")
15 |
16 | with tempfile.TemporaryDirectory() as tmpdirname:
17 | temp_repo_path = Path(tmpdirname) / "Flows"
18 | logger.info(f"{FLOWMSG}: Downloading and Upading Flows")
19 |
20 | result = subprocess.run(
21 | ['git', 'clone', FLOWS_DOWNLOAD_PATH, str(temp_repo_path)],
22 | capture_output=True,
23 | text=True
24 | )
25 | if result.returncode != 0:
26 | logger.error(f"{FLOWMSG}: Failed to clone flows repository:\n{result.stderr}")
27 | return
28 | else:
29 | # logger.debug(f"{FLOWMSG}: Successfully cloned flows repository")
30 | pass
31 |
32 | if not FLOWS_PATH.exists():
33 | FLOWS_PATH.mkdir(parents=True)
34 | # logger.debug(f"{FLOWMSG}: Created flows directory at '{FLOWS_PATH}'")
35 |
36 | for item in temp_repo_path.iterdir():
37 | if item.name in ['.git', '.github']:
38 | # logger.debug(f"{FLOWMSG}: Skipping directory '{item.name}'")
39 | continue
40 | dest_item = FLOWS_PATH / item.name
41 | if item.is_dir():
42 | if dest_item.exists():
43 | # logger.info(f"{FLOWMSG}: Updating existing directory '{item.name}'")
44 | _copy_directory(item, dest_item)
45 | else:
46 | shutil.copytree(item, dest_item)
47 | # logger.info(f"{FLOWMSG}: Copied new directory '{item.name}'")
48 | else:
49 | shutil.copy2(item, dest_item)
50 | # logger.info(f"{FLOWMSG}: Copied file '{item.name}'")
51 |
52 | logger.info(f"{FLOWMSG}: Flows have been updated successfully.")
53 | except Exception as e:
54 | logger.error(f"{FLOWMSG}: An error occurred while downloading or updating flows: {e}")
55 |
56 | def _copy_directory(src: Path, dest: Path) -> None:
57 | for item in src.iterdir():
58 | if item.name in ['.git', '.github']:
59 | continue
60 | dest_item = dest / item.name
61 | if item.is_dir():
62 | if not dest_item.exists():
63 | dest_item.mkdir()
64 | _copy_directory(item, dest_item)
65 | else:
66 | shutil.copy2(item, dest_item)
67 |
--------------------------------------------------------------------------------
/flow/flow_manager.py:
--------------------------------------------------------------------------------
1 | import json
2 | from pathlib import Path
3 | from aiohttp import web
4 | from typing import Dict, Any
5 | from .constants import (
6 | FLOWS_PATH, CORE_PATH, LINKER_PATH, FLOW_PATH, APP_CONFIGS, FLOWMSG,FLOWS_CONFIG_FILE, logger
7 | )
8 | from .route_manager import RouteManager
9 | from .api_handlers import (
10 | list_themes_handler, get_theme_css_handler, flow_version_handler,
11 | apps_handler, extension_node_map_handler,
12 | install_package_handler, update_package_handler, uninstall_package_handler,
13 | installed_custom_nodes_handler, preview_flow_handler,
14 | reset_preview_handler, create_flow_handler, update_flow_handler, delete_flow_handler,
15 | set_model_preview_handler,
16 | clear_model_preview_handler,
17 | list_model_previews_handler,
18 | get_model_preview_handler
19 | )
20 |
21 | class FlowManager:
22 | @staticmethod
23 | def setup_app_routes(app: web.Application) -> None:
24 | try:
25 | FlowManager._setup_flows_routes(app)
26 |
27 | FlowManager._setup_core_routes(app)
28 |
29 | FlowManager._setup_api_routes(app)
30 |
31 | FlowManager._setup_additional_routes(app)
32 |
33 | except Exception as e:
34 | logger.error(f"{FLOWMSG}: Failed to set up routes: {e}")
35 |
36 | @staticmethod
37 | def _setup_flows_routes(app: web.Application) -> None:
38 | for flow_dir in filter(lambda d: d.is_dir(), FLOWS_PATH.iterdir()):
39 | conf_file = flow_dir / FLOWS_CONFIG_FILE
40 | if not conf_file.is_file():
41 | # logger.warning(f"{FLOWMSG}: Config file not found in {flow_dir}")
42 | continue
43 |
44 | conf = FlowManager._load_config(conf_file)
45 | flow_url = conf.get('url')
46 | if not flow_url:
47 | logger.warning(f"{FLOWMSG}: Missing 'url' in config for {flow_dir}")
48 | continue
49 |
50 | app.add_routes(RouteManager.create_routes(f"flow/{flow_url}", flow_dir))
51 | APP_CONFIGS.append(conf)
52 |
53 | @staticmethod
54 | def _setup_core_routes(app: web.Application) -> None:
55 | if CORE_PATH.is_dir():
56 | app.router.add_get('/core/css/themes/list', list_themes_handler)
57 | app.router.add_get('/core/css/themes/{filename}', get_theme_css_handler)
58 | app.router.add_static('/core/', path=CORE_PATH, name='core')
59 |
60 | @staticmethod
61 | def _setup_api_routes(app: web.Application) -> None:
62 | api_routes = [
63 | (f'/flow/api/apps', 'GET', apps_handler),
64 | (f'/flow/api/extension-node-map', 'GET', extension_node_map_handler),
65 | (f'/flow/api/install-package', 'POST', install_package_handler),
66 | (f'/flow/api/update-package', 'POST', update_package_handler),
67 | (f'/flow/api/uninstall-package', 'POST', uninstall_package_handler),
68 | (f'/flow/api/flow-version', 'GET', flow_version_handler),
69 | (f'/flow/api/installed-custom-nodes', 'GET', installed_custom_nodes_handler),
70 | (f'/flow/api/preview-flow', 'POST', preview_flow_handler),
71 | (f'/flow/api/reset-preview', 'POST', reset_preview_handler),
72 | (f'/flow/api/create-flow', 'POST', create_flow_handler),
73 | (f'/flow/api/update-flow', 'POST', update_flow_handler),
74 | (f'/flow/api/delete-flow', 'DELETE', delete_flow_handler),
75 | (f'/flow/api/model-preview', 'POST', set_model_preview_handler),
76 | (f'/flow/api/model-preview', 'DELETE', clear_model_preview_handler),
77 | (f'/flow/api/model-previews', 'POST', list_model_previews_handler),
78 | (f'/flow/api/model-preview', 'GET', get_model_preview_handler),
79 | ]
80 |
81 | for path, method, handler in api_routes:
82 | if method == 'GET':
83 | app.router.add_get(path, handler)
84 | elif method == 'POST':
85 | app.router.add_post(path, handler)
86 | elif method == 'DELETE':
87 | app.router.add_delete(path, handler)
88 |
89 | @staticmethod
90 | def _setup_additional_routes(app: web.Application) -> None:
91 | if LINKER_PATH.is_dir():
92 | app.add_routes(RouteManager.create_routes('flow/linker', LINKER_PATH))
93 | if FLOW_PATH.is_dir():
94 | app.add_routes(RouteManager.create_routes('flow', FLOW_PATH))
95 |
96 | @staticmethod
97 | def _load_config(conf_file: Path) -> Dict[str, Any]:
98 | try:
99 | with conf_file.open('r') as f:
100 | return json.load(f)
101 | except json.JSONDecodeError as e:
102 | logger.error(f"{FLOWMSG}: Invalid JSON in {conf_file}: {e}")
103 | return {}
104 | except Exception as e:
105 | logger.error(f"{FLOWMSG}: Error loading config from {conf_file}: {e}")
106 | return {}
107 |
108 |
--------------------------------------------------------------------------------
/flow/flow_node.py:
--------------------------------------------------------------------------------
1 | class Flow:
2 | def __init__(self):
3 | pass
4 |
5 | @classmethod
6 | def INPUT_TYPES(s):
7 | return {
8 | "required": {
9 | },
10 | }
11 |
12 | RETURN_TYPES = ("Flow",)
13 | FUNCTION = "flow"
14 | CATEGORY = '🅓 diSty/Flow'
15 | def flow(self):
16 | return "Flow"
17 |
18 | NODE_CLASS_MAPPINGS = {
19 | "Flow": Flow
20 | }
21 |
22 | NODE_DISPLAY_NAME_MAPPINGS = {
23 | "Flow": "Flow"
24 | }
--------------------------------------------------------------------------------
/flow/route_manager.py:
--------------------------------------------------------------------------------
1 | from aiohttp import web
2 | from pathlib import Path
3 |
4 | class RouteManager:
5 |
6 | @staticmethod
7 | def create_routes(base_path: str, app_dir: Path) -> web.RouteTableDef:
8 | routes = web.RouteTableDef()
9 | index_html = app_dir / 'index.html'
10 |
11 | @routes.get(f"/{base_path}")
12 | async def serve_html(request: web.Request) -> web.FileResponse:
13 | return web.FileResponse(index_html)
14 |
15 | for static_dir in ['css', 'js', 'media']:
16 | static_path = app_dir / static_dir
17 | if static_path.is_dir():
18 | routes.static(f"/{static_dir}/", path=static_path)
19 |
20 | routes.static(f"/{base_path}/", path=app_dir, show_index=False)
21 | return routes
22 |
--------------------------------------------------------------------------------
/flow/server_setup.py:
--------------------------------------------------------------------------------
1 | from aiohttp import web
2 | import server
3 | from .flow_manager import FlowManager
4 | from .downloader import download_update_flows
5 | from .constants import FLOWMSG, logger
6 |
7 | def setup_server() -> None:
8 | try:
9 | server_instance = server.PromptServer.instance
10 | except Exception as e:
11 | logger.error(f"{FLOWMSG}: Failed to get server instance: {e}")
12 | return
13 |
14 | download_update_flows()
15 |
16 | try:
17 | FlowManager.setup_app_routes(server_instance.app)
18 | except Exception as e:
19 | logger.error(f"{FLOWMSG}: Failed to set up app routes: {e}")
20 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "comfyui-disty-flow"
3 | description = "Flow is a custom node designed to provide a more user-friendly interface for ComfyUI by acting as an alternative user interface for running workflows. It is not a replacement for workflow creation.\nFlow is currently in the early stages of development, so expect bugs and ongoing feature enhancements. With your support and feedback, Flow will settle into a steady stream."
4 | version = "0.5.2"
5 | license = {file = "LICENSE"}
6 |
7 | [project.urls]
8 | Repository = "https://github.com/diStyApps/ComfyUI-disty-Flow"
9 | # Used by Comfy Registry https://comfyregistry.org
10 |
11 | [tool.comfy]
12 | PublisherId = "disty"
13 | DisplayName = "ComfyUI-disty-Flow"
14 | Icon = ""
15 |
--------------------------------------------------------------------------------
/web/core/content.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
32 |
33 |
47 |
48 |
49 |
50 |