Emmanuel Durand commited on
Commit
a2f1ee5
·
1 Parent(s): b463267

Basic setup

Browse files
Files changed (4) hide show
  1. .gitignore +1 -0
  2. README.md +2 -0
  3. app.py +204 -0
  4. requirements.txt +25 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ *.swp
README.md CHANGED
@@ -10,3 +10,5 @@ pinned: false
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
13
+
14
+ Built using [this guide](https://huggingface.co/blog/run-comfyui-workflows-on-spaces)
app.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import random
4
+ import sys
5
+ from typing import Sequence, Mapping, Any, Union
6
+ import torch
7
+ from huggingface_hub import hf_hub_download
8
+ import spaces
9
+
10
+ hf_hub_download(repo_id="stable-diffusion-v1-5/stable-diffusion-v1-5", filename="v1-5-pruned-emaonly.ckpt", local_dir="models/checkpoints")
11
+
12
+ def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
13
+ """Returns the value at the given index of a sequence or mapping.
14
+
15
+ If the object is a sequence (like list or string), returns the value at the given index.
16
+ If the object is a mapping (like a dictionary), returns the value at the index-th key.
17
+
18
+ Some return a dictionary, in these cases, we look for the "results" key
19
+
20
+ Args:
21
+ obj (Union[Sequence, Mapping]): The object to retrieve the value from.
22
+ index (int): The index of the value to retrieve.
23
+
24
+ Returns:
25
+ Any: The value at the given index.
26
+
27
+ Raises:
28
+ IndexError: If the index is out of bounds for the object and the object is not a mapping.
29
+ """
30
+ try:
31
+ return obj[index]
32
+ except KeyError:
33
+ return obj["result"][index]
34
+
35
+
36
+ def find_path(name: str, path: str = None) -> str:
37
+ """
38
+ Recursively looks at parent folders starting from the given path until it finds the given name.
39
+ Returns the path as a Path object if found, or None otherwise.
40
+ """
41
+ # If no path is given, use the current working directory
42
+ if path is None:
43
+ path = os.getcwd()
44
+
45
+ # Check if the current directory contains the name
46
+ if name in os.listdir(path):
47
+ path_name = os.path.join(path, name)
48
+ print(f"{name} found: {path_name}")
49
+ return path_name
50
+
51
+ # Get the parent directory
52
+ parent_directory = os.path.dirname(path)
53
+
54
+ # If the parent directory is the same as the current directory, we've reached the root and stop the search
55
+ if parent_directory == path:
56
+ return None
57
+
58
+ # Recursively call the function with the parent directory
59
+ return find_path(name, parent_directory)
60
+
61
+
62
+ def add_comfyui_directory_to_sys_path() -> None:
63
+ """
64
+ Add 'ComfyUI' to the sys.path
65
+ """
66
+ comfyui_path = find_path("ComfyUI")
67
+ if comfyui_path is not None and os.path.isdir(comfyui_path):
68
+ sys.path.append(comfyui_path)
69
+ print(f"'{comfyui_path}' added to sys.path")
70
+
71
+
72
+ def add_extra_model_paths() -> None:
73
+ """
74
+ Parse the optional extra_model_paths.yaml file and add the parsed paths to the sys.path.
75
+ """
76
+ try:
77
+ from main import load_extra_path_config
78
+ except ImportError:
79
+ print(
80
+ "Could not import load_extra_path_config from main.py. Looking in utils.extra_config instead."
81
+ )
82
+ from utils.extra_config import load_extra_path_config
83
+
84
+ extra_model_paths = find_path("extra_model_paths.yaml")
85
+
86
+ if extra_model_paths is not None:
87
+ load_extra_path_config(extra_model_paths)
88
+ else:
89
+ print("Could not find the extra_model_paths config file.")
90
+
91
+
92
+ add_comfyui_directory_to_sys_path()
93
+ add_extra_model_paths()
94
+
95
+
96
+ def import_custom_nodes() -> None:
97
+ """Find all custom nodes in the custom_nodes folder and add those node objects to NODE_CLASS_MAPPINGS
98
+
99
+ This function sets up a new asyncio event loop, initializes the PromptServer,
100
+ creates a PromptQueue, and initializes the custom nodes.
101
+ """
102
+ import asyncio
103
+ import execution
104
+ from nodes import init_extra_nodes
105
+ import server
106
+
107
+ # Creating a new event loop and setting it as the default loop
108
+ loop = asyncio.new_event_loop()
109
+ asyncio.set_event_loop(loop)
110
+
111
+ # Creating an instance of PromptServer with the loop
112
+ server_instance = server.PromptServer(loop)
113
+ execution.PromptQueue(server_instance)
114
+
115
+ # Initializing custom nodes
116
+ init_extra_nodes()
117
+
118
+
119
+ from nodes import NODE_CLASS_MAPPINGS
120
+
121
+
122
+ @spaces.GPU(duration=15)
123
+ def generate_image(prompt):
124
+ import_custom_nodes()
125
+ with torch.inference_mode():
126
+ checkpointloadersimple = NODE_CLASS_MAPPINGS["CheckpointLoaderSimple"]()
127
+ checkpointloadersimple_4 = checkpointloadersimple.load_checkpoint(
128
+ ckpt_name="SD1.5/v1-5-pruned-emaonly.ckpt"
129
+ )
130
+
131
+ emptylatentimage = NODE_CLASS_MAPPINGS["EmptyLatentImage"]()
132
+ emptylatentimage_5 = emptylatentimage.generate(
133
+ width=512, height=512, batch_size=1
134
+ )
135
+
136
+ cliptextencode = NODE_CLASS_MAPPINGS["CLIPTextEncode"]()
137
+ cliptextencode_6 = cliptextencode.encode(
138
+ text=prompt,
139
+ clip=get_value_at_index(checkpointloadersimple_4, 1),
140
+ )
141
+
142
+ cliptextencode_7 = cliptextencode.encode(
143
+ text="text, watermark", clip=get_value_at_index(checkpointloadersimple_4, 1)
144
+ )
145
+
146
+ ksampler = NODE_CLASS_MAPPINGS["KSampler"]()
147
+ vaedecode = NODE_CLASS_MAPPINGS["VAEDecode"]()
148
+ saveimage = NODE_CLASS_MAPPINGS["SaveImage"]()
149
+
150
+ for q in range(1):
151
+ ksampler_3 = ksampler.sample(
152
+ seed=random.randint(1, 2**64),
153
+ steps=20,
154
+ cfg=8,
155
+ sampler_name="euler",
156
+ scheduler="normal",
157
+ denoise=1,
158
+ model=get_value_at_index(checkpointloadersimple_4, 0),
159
+ positive=get_value_at_index(cliptextencode_6, 0),
160
+ negative=get_value_at_index(cliptextencode_7, 0),
161
+ latent_image=get_value_at_index(emptylatentimage_5, 0),
162
+ )
163
+
164
+ vaedecode_8 = vaedecode.decode(
165
+ samples=get_value_at_index(ksampler_3, 0),
166
+ vae=get_value_at_index(checkpointloadersimple_4, 2),
167
+ )
168
+
169
+ saveimage_9 = saveimage.save_images(
170
+ filename_prefix="ComfyUI", images=get_value_at_index(vaedecode_8, 0)
171
+ )
172
+
173
+ saved_path = f"output/{saveimage_9['ui']['images'][0]['filename']}"
174
+ return saved_path
175
+
176
+
177
+ if __name__ == "__main__":
178
+ # Comment out the main() call in the exported Python code
179
+
180
+ # Start your Gradio app
181
+ with gr.Blocks() as app:
182
+ # Add a title
183
+ gr.Markdown("# SD prompt")
184
+
185
+ with gr.Row():
186
+ with gr.Column():
187
+ # Add an input
188
+ prompt_input = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...")
189
+
190
+ # The generate button
191
+ generate_btn = gr.Button("Generate")
192
+
193
+ with gr.Column():
194
+ # The output image
195
+ output_image = gr.Image(label="Generated Image")
196
+
197
+ # When clicking the button, it will trigger the `generate_image` function, with the respective inputs
198
+ # and the output an image
199
+ generate_btn.click(
200
+ fn=generate_image,
201
+ inputs=[prompt_input],
202
+ outputs=[output_image]
203
+ )
204
+ app.launch(share=True)
requirements.txt ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ comfyui-frontend-package==1.12.14
2
+ torch
3
+ torchsde
4
+ torchvision
5
+ torchaudio
6
+ numpy>=1.25.0
7
+ einops
8
+ transformers>=4.28.1
9
+ tokenizers>=0.13.3
10
+ sentencepiece
11
+ safetensors>=0.4.2
12
+ aiohttp>=3.11.8
13
+ yarl>=1.18.0
14
+ pyyaml
15
+ Pillow
16
+ scipy
17
+ tqdm
18
+ psutil
19
+
20
+ #non essential dependencies:
21
+ kornia>=0.7.1
22
+ spandrel
23
+ soundfile
24
+ av
25
+