bewizz commited on
Commit
994053d
·
verified ·
1 Parent(s): 5d45289

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. SD3-Batch-Creation/.gitattributes +35 -0
  2. SD3-Batch-Creation/README.md +13 -0
  3. app.py +39 -85
  4. sd3.json +273 -184
SD3-Batch-Creation/.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
SD3-Batch-Creation/README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: SD3 Batch Creation
3
+ emoji: 🌍
4
+ colorFrom: gray
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: 4.36.1
8
+ app_file: app.py
9
+ pinned: false
10
+ license: gpl
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -10,110 +10,77 @@ import zipfile
10
  from typing import List
11
 
12
  # Define constants
13
- WORKFLOW_FILENAME = 'sd3.json'
14
- ROOT_DIR = os.getcwd() # Root directory of the project
15
- OUTPUT_DIR = os.path.join(ROOT_DIR, 'output')
16
- USER_OUTPUTS_DIR = os.path.join(OUTPUT_DIR, 'user_outputs')
17
- URL = "https://3653-47-216-153-41.ngrok-free.app/prompt" # Replace with your ngrok URL
18
-
19
- # Create output directories if they don't exist
20
- os.makedirs(USER_OUTPUTS_DIR, exist_ok=True)
21
 
22
  # Configure logging
23
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
24
 
25
  # Shared state for cancellation
26
  cancel_processing = False
27
- log_messages = ""
28
-
29
- def log_message(message):
30
- global log_messages
31
- log_messages += message + "\n"
32
- logging.info(message)
33
-
34
- def find_workflow_in_root(root_dir, filename):
35
- log_message(f"Searching for {filename} in root directory {root_dir}")
36
- for root, _, files in os.walk(root_dir):
37
- if filename in files:
38
- file_path = os.path.join(root, filename)
39
- log_message(f"Found workflow file at {file_path}")
40
- return file_path
41
- log_message(f"Workflow file {filename} not found in root directory {root_dir}")
42
- return None
43
 
44
  def read_workflow(file_path):
45
- log_message(f"Reading workflow from {file_path}")
46
- try:
47
- with open(file_path, 'r') as file:
48
- workflow = json.load(file)
49
- return workflow
50
- except Exception as e:
51
- log_message(f"Error reading workflow: {e}")
52
- return None
53
 
54
  def update_workflow(workflow, prompt, negative_prompt):
55
- log_message(f"Updating workflow with new prompts: {prompt}, negative: {negative_prompt}")
56
  workflow["6"]["inputs"]["text"] = prompt
57
  workflow["71"]["inputs"]["text"] = negative_prompt
58
  return workflow
59
 
60
  def write_workflow(workflow, file_path):
61
- log_message(f"Writing updated workflow to {file_path}")
62
- try:
63
- with open(file_path, 'w') as file:
64
- json.dump(workflow, file, indent=4)
65
- except Exception as e:
66
- log_message(f"Error writing workflow: {e}")
67
 
68
  def send_workflow_to_comfyui(workflow, url):
69
  headers = {"Content-Type": "application/json"}
70
  try:
71
  response = requests.post(url, headers=headers, json={"prompt": workflow})
72
  response.raise_for_status()
73
- log_message(f"Workflow sent successfully: {response.status_code}")
74
- log_message(f"Response content: {response.content}")
75
  except requests.exceptions.RequestException as e:
76
- log_message(f"Error sending workflow to ComfyUI: {e}")
77
  raise
78
 
79
  def monitor_output_images(output_dir, previous_images, timeout=60):
80
  start_time = time.time()
81
- log_message(f"Monitoring {output_dir} for new images...")
82
  while time.time() - start_time < timeout:
83
  current_images = os.listdir(output_dir)
84
  new_images = [img for img in current_images if img not in previous_images]
85
  if new_images:
86
  latest_image = new_images[-1]
87
- log_message(f"New image found: {latest_image}")
88
  return latest_image
89
  time.sleep(1)
90
- log_message(f"Timeout while waiting for new images in {output_dir}")
91
  return None
92
 
93
  def copy_file_with_retry(src, dst_dir, file_index, retries=5, delay=1):
94
  dst = os.path.join(dst_dir, f"SD3_{file_index:05d}.png")
95
- log_message(f"Attempting to copy file from {src} to {dst}")
96
  for _ in range(retries):
97
  try:
98
  shutil.copy(src, dst)
99
- log_message(f"File copied successfully to {dst}")
100
  return dst
101
  except PermissionError:
102
  time.sleep(delay)
103
- log_message(f"PermissionError encountered. Retrying...")
104
- log_message(f"Failed to copy {src} to {dst} after {retries} retries")
105
  raise PermissionError(f"Failed to copy {src} to {dst} after {retries} retries")
106
 
107
  def zip_files(output_images: List[str], zip_interval: int, zip_folder: str):
108
  zip_files = []
109
  for i in range(0, len(output_images), zip_interval):
110
  zip_filename = os.path.join(zip_folder, f"images_{i//zip_interval + 1}_{time.time_ns()}.zip")
111
- log_message(f"Creating zip file {zip_filename}")
112
  with zipfile.ZipFile(zip_filename, 'w') as zipf:
113
  for img in output_images[i:i+zip_interval]:
114
  zipf.write(img, os.path.basename(img))
115
  zip_files.append(zip_filename)
116
- log_message(f"Zip files created: {zip_files}")
117
  return zip_files
118
 
119
  def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interval):
@@ -124,15 +91,7 @@ def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interva
124
  zip_files_list = []
125
  file_index = 1
126
 
127
- workflow_path = find_workflow_in_root(ROOT_DIR, WORKFLOW_FILENAME)
128
- if workflow_path is None:
129
- log_message("Workflow file not found. Exiting process_prompts.")
130
- return [], []
131
-
132
- workflow = read_workflow(workflow_path)
133
- if workflow is None:
134
- log_message("Workflow is None, exiting process_prompts.")
135
- return [], []
136
 
137
  total_prompts = len(prompts)
138
  previous_images = os.listdir(OUTPUT_DIR)
@@ -142,7 +101,7 @@ def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interva
142
  try:
143
  for i, prompt in enumerate(prompts):
144
  if cancel_processing:
145
- log_message("Processing cancelled by user.")
146
  break
147
  if not prompt.strip():
148
  continue
@@ -150,12 +109,12 @@ def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interva
150
  negative_prompt = negative_prompts[i] if i < len(negative_prompts) else ""
151
 
152
  updated_workflow = update_workflow(workflow, prompt, negative_prompt)
153
- write_workflow(updated_workflow, workflow_path)
154
 
155
- log_message(f"Updated workflow: {json.dumps(updated_workflow, indent=4)}")
156
 
157
  send_workflow_to_comfyui(updated_workflow, URL)
158
- log_message(f"Sent workflow to ComfyUI for prompt {i + 1}/{total_prompts}")
159
 
160
  new_image = None
161
  retries = 0
@@ -163,22 +122,21 @@ def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interva
163
  new_image = monitor_output_images(OUTPUT_DIR, previous_images)
164
  if new_image is None:
165
  retries += 1
166
- log_message(f"Retrying ({retries}/5)...")
167
  time.sleep(5)
168
  else:
169
  time.sleep(2)
170
 
171
  if new_image is None:
172
- log_message("Error monitoring output images: Timed out waiting for new image.")
173
  continue
174
 
175
  new_image_path = os.path.join(OUTPUT_DIR, new_image)
176
- log_message(f"New image generated: {new_image_path}")
177
  try:
178
  copied_image_path = copy_file_with_retry(new_image_path, user_folder, file_index)
179
- log_message(f"New image generated and copied to user folder: {copied_image_path}")
180
  except PermissionError as e:
181
- log_message(f"Failed to copy file after retries: {e}")
182
  continue
183
 
184
  output_images.append(copied_image_path)
@@ -192,7 +150,7 @@ def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interva
192
  zip_files_list.extend(new_zip_files)
193
 
194
  logs += f"Processed {i + 1}/{total_prompts} - Done: {i + 1}, Left: {total_prompts - (i + 1)}\n"
195
- yield output_images, zip_files_list, logs + log_messages
196
 
197
  if cancel_processing or (len(output_images) % zip_interval != 0):
198
  zip_folder = os.path.join(user_folder, "zipped_images")
@@ -200,8 +158,8 @@ def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interva
200
  new_zip_files = zip_files(output_images, zip_interval, zip_folder)
201
  zip_files_list.extend(new_zip_files)
202
 
203
- except Exception as e:
204
- log_message(f"Exception during prompt processing: {e}")
205
 
206
  return output_images, zip_files_list
207
 
@@ -283,9 +241,9 @@ def main():
283
  logs_output = gr.Textbox(lines=10, interactive=False, label="Logs")
284
 
285
  def generate_user_folder():
286
- user_folder = os.path.normpath(os.path.join(USER_OUTPUTS_DIR, f'SD3{random.randint(1000, 9999)}'))
287
  os.makedirs(user_folder, exist_ok=True)
288
- log_message(f"Generated user folder: {user_folder}")
289
  return user_folder
290
 
291
  def on_click(prompts_text, negative_prompts_text, zip_interval):
@@ -293,16 +251,12 @@ def main():
293
  user_folder = generate_user_folder()
294
  output_images, zip_files_list = [], []
295
  logs = ""
296
- try:
297
- for images, zip_files, log_msg in process_prompts(prompts_text, negative_prompts_text, user_folder, zip_interval):
298
- output_images = images
299
- zip_files_list = zip_files
300
- logs = log_msg
301
- yield images, zip_files_list, logs + log_messages
302
- except Exception as e:
303
- log_message(f"Error during prompt processing: {e}")
304
- logs += f"Error: {e}\n"
305
- yield output_images, zip_files_list, logs + log_messages
306
 
307
  process_btn.click(
308
  fn=on_click,
@@ -316,7 +270,7 @@ def main():
316
  outputs=[]
317
  )
318
 
319
- demo.launch()
320
 
321
  if __name__ == "__main__":
322
  main()
 
10
  from typing import List
11
 
12
  # Define constants
13
+ COMFYUI_DIR = r"C:\Users\bewiz\OneDrive\Desktop\AI\ComfyUI_windows_portable\ComfyUI"
14
+ WORKFLOW_PATH = os.path.join(COMFYUI_DIR, 'sd3.json')
15
+ OUTPUT_DIR = os.path.join(COMFYUI_DIR, 'output')
16
+ URL = "http://127.0.0.1:8188/prompt"
 
 
 
 
17
 
18
  # Configure logging
19
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
20
 
21
  # Shared state for cancellation
22
  cancel_processing = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  def read_workflow(file_path):
25
+ logging.info(f"Reading workflow from {file_path}")
26
+ with open(file_path, 'r') as file:
27
+ workflow = json.load(file)
28
+ return workflow
 
 
 
 
29
 
30
  def update_workflow(workflow, prompt, negative_prompt):
31
+ logging.info(f"Updating workflow with new prompts: {prompt}, negative: {negative_prompt}")
32
  workflow["6"]["inputs"]["text"] = prompt
33
  workflow["71"]["inputs"]["text"] = negative_prompt
34
  return workflow
35
 
36
  def write_workflow(workflow, file_path):
37
+ logging.info(f"Writing updated workflow to {file_path}")
38
+ with open(file_path, 'w') as file:
39
+ json.dump(workflow, file, indent=4)
 
 
 
40
 
41
  def send_workflow_to_comfyui(workflow, url):
42
  headers = {"Content-Type": "application/json"}
43
  try:
44
  response = requests.post(url, headers=headers, json={"prompt": workflow})
45
  response.raise_for_status()
46
+ logging.info(f"Workflow sent successfully: {response.status_code}")
47
+ logging.debug(f"Response content: {response.content}")
48
  except requests.exceptions.RequestException as e:
49
+ logging.error(f"Error sending workflow to ComfyUI: {e}")
50
  raise
51
 
52
  def monitor_output_images(output_dir, previous_images, timeout=60):
53
  start_time = time.time()
54
+ logging.info(f"Monitoring {output_dir} for new images...")
55
  while time.time() - start_time < timeout:
56
  current_images = os.listdir(output_dir)
57
  new_images = [img for img in current_images if img not in previous_images]
58
  if new_images:
59
  latest_image = new_images[-1]
60
+ logging.info(f"New image found: {latest_image}")
61
  return latest_image
62
  time.sleep(1)
63
+ logging.info(f"Timeout while waiting for new images in {output_dir}")
64
  return None
65
 
66
  def copy_file_with_retry(src, dst_dir, file_index, retries=5, delay=1):
67
  dst = os.path.join(dst_dir, f"SD3_{file_index:05d}.png")
 
68
  for _ in range(retries):
69
  try:
70
  shutil.copy(src, dst)
 
71
  return dst
72
  except PermissionError:
73
  time.sleep(delay)
 
 
74
  raise PermissionError(f"Failed to copy {src} to {dst} after {retries} retries")
75
 
76
  def zip_files(output_images: List[str], zip_interval: int, zip_folder: str):
77
  zip_files = []
78
  for i in range(0, len(output_images), zip_interval):
79
  zip_filename = os.path.join(zip_folder, f"images_{i//zip_interval + 1}_{time.time_ns()}.zip")
 
80
  with zipfile.ZipFile(zip_filename, 'w') as zipf:
81
  for img in output_images[i:i+zip_interval]:
82
  zipf.write(img, os.path.basename(img))
83
  zip_files.append(zip_filename)
 
84
  return zip_files
85
 
86
  def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interval):
 
91
  zip_files_list = []
92
  file_index = 1
93
 
94
+ workflow = read_workflow(WORKFLOW_PATH)
 
 
 
 
 
 
 
 
95
 
96
  total_prompts = len(prompts)
97
  previous_images = os.listdir(OUTPUT_DIR)
 
101
  try:
102
  for i, prompt in enumerate(prompts):
103
  if cancel_processing:
104
+ logging.info("Processing cancelled by user.")
105
  break
106
  if not prompt.strip():
107
  continue
 
109
  negative_prompt = negative_prompts[i] if i < len(negative_prompts) else ""
110
 
111
  updated_workflow = update_workflow(workflow, prompt, negative_prompt)
112
+ write_workflow(updated_workflow, WORKFLOW_PATH)
113
 
114
+ logging.debug(f"Updated workflow: {json.dumps(updated_workflow, indent=4)}")
115
 
116
  send_workflow_to_comfyui(updated_workflow, URL)
117
+ logging.info(f"Sent workflow to ComfyUI for prompt {i + 1}/{total_prompts}")
118
 
119
  new_image = None
120
  retries = 0
 
122
  new_image = monitor_output_images(OUTPUT_DIR, previous_images)
123
  if new_image is None:
124
  retries += 1
125
+ logging.warning(f"Retrying ({retries}/5)...")
126
  time.sleep(5)
127
  else:
128
  time.sleep(2)
129
 
130
  if new_image is None:
131
+ logging.error("Error monitoring output images: Timed out waiting for new image.")
132
  continue
133
 
134
  new_image_path = os.path.join(OUTPUT_DIR, new_image)
 
135
  try:
136
  copied_image_path = copy_file_with_retry(new_image_path, user_folder, file_index)
137
+ logging.info(f"New image generated and copied to user folder: {copied_image_path}")
138
  except PermissionError as e:
139
+ logging.error(f"Failed to copy file after retries: {e}")
140
  continue
141
 
142
  output_images.append(copied_image_path)
 
150
  zip_files_list.extend(new_zip_files)
151
 
152
  logs += f"Processed {i + 1}/{total_prompts} - Done: {i + 1}, Left: {total_prompts - (i + 1)}\n"
153
+ yield output_images, zip_files_list, logs
154
 
155
  if cancel_processing or (len(output_images) % zip_interval != 0):
156
  zip_folder = os.path.join(user_folder, "zipped_images")
 
158
  new_zip_files = zip_files(output_images, zip_interval, zip_folder)
159
  zip_files_list.extend(new_zip_files)
160
 
161
+ except KeyboardInterrupt:
162
+ logging.info("Script interrupted by user.")
163
 
164
  return output_images, zip_files_list
165
 
 
241
  logs_output = gr.Textbox(lines=10, interactive=False, label="Logs")
242
 
243
  def generate_user_folder():
244
+ user_folder = os.path.normpath(os.path.join(OUTPUT_DIR, f'SD3{random.randint(1000, 9999)}'))
245
  os.makedirs(user_folder, exist_ok=True)
246
+ logging.info(f"Generated user folder: {user_folder}")
247
  return user_folder
248
 
249
  def on_click(prompts_text, negative_prompts_text, zip_interval):
 
251
  user_folder = generate_user_folder()
252
  output_images, zip_files_list = [], []
253
  logs = ""
254
+ for images, zip_files, log_msg in process_prompts(prompts_text, negative_prompts_text, user_folder, zip_interval):
255
+ output_images = images
256
+ zip_files_list = zip_files
257
+ logs = log_msg
258
+ yield images, zip_files_list, logs
259
+ return output_images, zip_files_list, logs
 
 
 
 
260
 
261
  process_btn.click(
262
  fn=on_click,
 
270
  outputs=[]
271
  )
272
 
273
+ demo.launch(share=True)
274
 
275
  if __name__ == "__main__":
276
  main()
sd3.json CHANGED
@@ -1,187 +1,276 @@
1
- {
2
- "6": {
3
- "inputs": {
4
- "text": "\"A graffiti art comparison featuring the word 'Creativity' across three different styles. First, SD1.5: a simple graffiti-style text on a plain urban wall, with basic lettering and minimal background details. BAD QUALITY.. labeled in words \"SD 1.5\" \n\nSecond, SDXL: detailed graffiti art on a vibrant wall, with bold colors, stylish fonts, and some 3D elements that add depth and creativity. GOOD QUALITY - LABELED in words \"SDXL\"\n\nThird, SD3: ultra-realistic graffiti with dynamic and intricate textures, shadows, and depth. The word 'Creativity' appears to pop out from the wall, with advanced 3D effects and lifelike details, creating a stunning visual impact.\" AMAZING QUALITY TEXT \"SD3\"\n\n",
5
- "clip": [
6
- "11",
7
- 0
8
- ]
9
- },
10
- "class_type": "CLIPTextEncode",
11
- "_meta": {
12
- "title": "CLIP Text Encode (Prompt)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
- },
15
- "11": {
16
- "inputs": {
17
- "clip_name1": "clip_g.safetensors",
18
- "clip_name2": "clip_l.safetensors",
19
- "clip_name3": "t5xxl_fp16.safetensors"
20
- },
21
- "class_type": "TripleCLIPLoader",
22
- "_meta": {
23
- "title": "TripleCLIPLoader"
 
 
24
  }
25
- },
26
- "13": {
27
- "inputs": {
28
- "shift": 3,
29
- "model": [
30
- "252",
31
- 0
32
- ]
33
- },
34
- "class_type": "ModelSamplingSD3",
35
- "_meta": {
36
- "title": "ModelSamplingSD3"
37
  }
38
- },
39
- "67": {
40
- "inputs": {
41
- "conditioning": [
42
- "71",
43
- 0
44
- ]
45
- },
46
- "class_type": "ConditioningZeroOut",
47
- "_meta": {
48
- "title": "ConditioningZeroOut"
49
- }
50
- },
51
- "68": {
52
- "inputs": {
53
- "start": 0.1,
54
- "end": 1,
55
- "conditioning": [
56
- "67",
57
- 0
58
- ]
59
- },
60
- "class_type": "ConditioningSetTimestepRange",
61
- "_meta": {
62
- "title": "ConditioningSetTimestepRange"
63
- }
64
- },
65
- "69": {
66
- "inputs": {
67
- "conditioning_1": [
68
- "68",
69
- 0
70
- ],
71
- "conditioning_2": [
72
- "70",
73
- 0
74
- ]
75
- },
76
- "class_type": "ConditioningCombine",
77
- "_meta": {
78
- "title": "Conditioning (Combine)"
79
- }
80
- },
81
- "70": {
82
- "inputs": {
83
- "start": 0,
84
- "end": 0.4533332519531249,
85
- "conditioning": [
86
- "71",
87
- 0
88
- ]
89
- },
90
- "class_type": "ConditioningSetTimestepRange",
91
- "_meta": {
92
- "title": "ConditioningSetTimestepRange"
93
- }
94
- },
95
- "71": {
96
- "inputs": {
97
- "text": "bad quality, poor quality, doll, disfigured, jpg, toy, bad anatomy, missing limbs, missing fingers, 3d, cgi",
98
- "clip": [
99
- "11",
100
- 0
101
- ]
102
- },
103
- "class_type": "CLIPTextEncode",
104
- "_meta": {
105
- "title": "CLIP Text Encode (Negative Prompt)"
106
- }
107
- },
108
- "135": {
109
- "inputs": {
110
- "width": 1024,
111
- "height": 1024,
112
- "batch_size": 1
113
- },
114
- "class_type": "EmptySD3LatentImage",
115
- "_meta": {
116
- "title": "EmptySD3LatentImage"
117
- }
118
- },
119
- "231": {
120
- "inputs": {
121
- "samples": [
122
- "271",
123
- 0
124
- ],
125
- "vae": [
126
- "252",
127
- 2
128
- ]
129
- },
130
- "class_type": "VAEDecode",
131
- "_meta": {
132
- "title": "VAE Decode"
133
- }
134
- },
135
- "252": {
136
- "inputs": {
137
- "ckpt_name": "3\\sd3_medium_incl_clips_t5xxlfp8.safetensors"
138
- },
139
- "class_type": "CheckpointLoaderSimple",
140
- "_meta": {
141
- "title": "Load Checkpoint"
142
- }
143
- },
144
- "271": {
145
- "inputs": {
146
- "seed": 945512652412924,
147
- "steps": 28,
148
- "cfg": 4.5,
149
- "sampler_name": "dpmpp_2m",
150
- "scheduler": "sgm_uniform",
151
- "denoise": 1,
152
- "model": [
153
- "13",
154
- 0
155
- ],
156
- "positive": [
157
- "6",
158
- 0
159
- ],
160
- "negative": [
161
- "69",
162
- 0
163
- ],
164
- "latent_image": [
165
- "135",
166
- 0
167
- ]
168
- },
169
- "class_type": "KSampler",
170
- "_meta": {
171
- "title": "KSampler"
172
- }
173
- },
174
- "273": {
175
- "inputs": {
176
- "filename_prefix": "SD3",
177
- "images": [
178
- "231",
179
- 0
180
- ]
181
- },
182
- "class_type": "SaveImage",
183
- "_meta": {
184
- "title": "Save Image"
185
- }
186
- }
187
- }
 
1
+ import os
2
+ import json
3
+ import requests
4
+ import gradio as gr
5
+ import random
6
+ import time
7
+ import logging
8
+ import shutil
9
+ import zipfile
10
+ from typing import List
11
+
12
+ # Define constants
13
+ COMFYUI_DIR = r"C:\Users\bewiz\OneDrive\Desktop\AI\ComfyUI_windows_portable\ComfyUI"
14
+ WORKFLOW_PATH = os.path.join(COMFYUI_DIR, 'sd3.json')
15
+ OUTPUT_DIR = os.path.join(COMFYUI_DIR, 'output')
16
+ URL = "http://127.0.0.1:8188/prompt"
17
+
18
+ # Configure logging
19
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
20
+
21
+ # Shared state for cancellation
22
+ cancel_processing = False
23
+
24
+ def read_workflow(file_path):
25
+ logging.info(f"Reading workflow from {file_path}")
26
+ with open(file_path, 'r') as file:
27
+ workflow = json.load(file)
28
+ return workflow
29
+
30
+ def update_workflow(workflow, prompt, negative_prompt):
31
+ logging.info(f"Updating workflow with new prompts: {prompt}, negative: {negative_prompt}")
32
+ workflow["6"]["inputs"]["text"] = prompt
33
+ workflow["71"]["inputs"]["text"] = negative_prompt
34
+ return workflow
35
+
36
+ def write_workflow(workflow, file_path):
37
+ logging.info(f"Writing updated workflow to {file_path}")
38
+ with open(file_path, 'w') as file:
39
+ json.dump(workflow, file, indent=4)
40
+
41
+ def send_workflow_to_comfyui(workflow, url):
42
+ headers = {"Content-Type": "application/json"}
43
+ try:
44
+ response = requests.post(url, headers=headers, json={"prompt": workflow})
45
+ response.raise_for_status()
46
+ logging.info(f"Workflow sent successfully: {response.status_code}")
47
+ logging.debug(f"Response content: {response.content}")
48
+ except requests.exceptions.RequestException as e:
49
+ logging.error(f"Error sending workflow to ComfyUI: {e}")
50
+ raise
51
+
52
+ def monitor_output_images(output_dir, previous_images, timeout=60):
53
+ start_time = time.time()
54
+ logging.info(f"Monitoring {output_dir} for new images...")
55
+ while time.time() - start_time < timeout:
56
+ current_images = os.listdir(output_dir)
57
+ new_images = [img for img in current_images if img not in previous_images]
58
+ if new_images:
59
+ latest_image = new_images[-1]
60
+ logging.info(f"New image found: {latest_image}")
61
+ return latest_image
62
+ time.sleep(1)
63
+ logging.info(f"Timeout while waiting for new images in {output_dir}")
64
+ return None
65
+
66
+ def copy_file_with_retry(src, dst_dir, file_index, retries=5, delay=1):
67
+ dst = os.path.join(dst_dir, f"SD3_{file_index:05d}.png")
68
+ for _ in range(retries):
69
+ try:
70
+ shutil.copy(src, dst)
71
+ return dst
72
+ except PermissionError:
73
+ time.sleep(delay)
74
+ raise PermissionError(f"Failed to copy {src} to {dst} after {retries} retries")
75
+
76
+ def zip_files(output_images: List[str], zip_interval: int, zip_folder: str):
77
+ zip_files = []
78
+ for i in range(0, len(output_images), zip_interval):
79
+ zip_filename = os.path.join(zip_folder, f"images_{i//zip_interval + 1}_{time.time_ns()}.zip")
80
+ with zipfile.ZipFile(zip_filename, 'w') as zipf:
81
+ for img in output_images[i:i+zip_interval]:
82
+ zipf.write(img, os.path.basename(img))
83
+ zip_files.append(zip_filename)
84
+ return zip_files
85
+
86
+ def process_prompts(prompts_text, negative_prompt_text, user_folder, zip_interval):
87
+ global cancel_processing
88
+ prompts = [line.strip() for line in prompts_text.split('\n\n') if line.strip()]
89
+ negative_prompts = [line.strip() for line in negative_prompt_text.split('\n') if line.strip()]
90
+ output_images = []
91
+ zip_files_list = []
92
+ file_index = 1
93
+
94
+ workflow = read_workflow(WORKFLOW_PATH)
95
+
96
+ total_prompts = len(prompts)
97
+ previous_images = os.listdir(OUTPUT_DIR)
98
+
99
+ logs = ""
100
+
101
+ try:
102
+ for i, prompt in enumerate(prompts):
103
+ if cancel_processing:
104
+ logging.info("Processing cancelled by user.")
105
+ break
106
+ if not prompt.strip():
107
+ continue
108
+
109
+ negative_prompt = negative_prompts[i] if i < len(negative_prompts) else ""
110
+
111
+ updated_workflow = update_workflow(workflow, prompt, negative_prompt)
112
+ write_workflow(updated_workflow, WORKFLOW_PATH)
113
+
114
+ logging.debug(f"Updated workflow: {json.dumps(updated_workflow, indent=4)}")
115
+
116
+ send_workflow_to_comfyui(updated_workflow, URL)
117
+ logging.info(f"Sent workflow to ComfyUI for prompt {i + 1}/{total_prompts}")
118
+
119
+ new_image = None
120
+ retries = 0
121
+ while new_image is None and retries < 5:
122
+ new_image = monitor_output_images(OUTPUT_DIR, previous_images)
123
+ if new_image is None:
124
+ retries += 1
125
+ logging.warning(f"Retrying ({retries}/5)...")
126
+ time.sleep(5)
127
+ else:
128
+ time.sleep(2)
129
+
130
+ if new_image is None:
131
+ logging.error("Error monitoring output images: Timed out waiting for new image.")
132
+ continue
133
+
134
+ new_image_path = os.path.join(OUTPUT_DIR, new_image)
135
+ try:
136
+ copied_image_path = copy_file_with_retry(new_image_path, user_folder, file_index)
137
+ logging.info(f"New image generated and copied to user folder: {copied_image_path}")
138
+ except PermissionError as e:
139
+ logging.error(f"Failed to copy file after retries: {e}")
140
+ continue
141
+
142
+ output_images.append(copied_image_path)
143
+ previous_images.append(new_image)
144
+ file_index += 1
145
+
146
+ if len(output_images) % zip_interval == 0 and not cancel_processing:
147
+ zip_folder = os.path.join(user_folder, "zipped_images")
148
+ os.makedirs(zip_folder, exist_ok=True)
149
+ new_zip_files = zip_files(output_images[-zip_interval:], zip_interval, zip_folder)
150
+ zip_files_list.extend(new_zip_files)
151
+
152
+ logs += f"Processed {i + 1}/{total_prompts} - Done: {i + 1}, Left: {total_prompts - (i + 1)}\n"
153
+ yield output_images, zip_files_list, logs
154
+
155
+ if cancel_processing or (len(output_images) % zip_interval != 0):
156
+ zip_folder = os.path.join(user_folder, "zipped_images")
157
+ os.makedirs(zip_folder, exist_ok=True)
158
+ new_zip_files = zip_files(output_images, zip_interval, zip_folder)
159
+ zip_files_list.extend(new_zip_files)
160
+
161
+ except KeyboardInterrupt:
162
+ logging.info("Script interrupted by user.")
163
+
164
+ return output_images, zip_files_list
165
+
166
+ def cancel_processing_fn():
167
+ global cancel_processing
168
+ cancel_processing = True
169
+
170
+ def reset_cancel_processing_fn():
171
+ global cancel_processing
172
+ cancel_processing = False
173
+
174
+ def main():
175
+ with gr.Blocks(css="""
176
+ .gradio-container {font-family: Arial, sans-serif;}
177
+ .psychedelic-text span {
178
+ animation: colorchange 10s infinite;
179
  }
180
+ @keyframes colorchange {
181
+ 0% { color: #ff69b4; }
182
+ 10% { color: #ba55d3; }
183
+ 20% { color: #7b68ee; }
184
+ 30% { color: #00bfff; }
185
+ 40% { color: #3cb371; }
186
+ 50% { color: #ffff54; }
187
+ 60% { color: #ffa500; }
188
+ 70% { color: #ff4500; }
189
+ 80% { color: #ff1493; }
190
+ 90% { color: #da70d6; }
191
+ 100% { color: #ff69b4; }
192
  }
193
+ .image-container img {
194
+ width: 250px;
195
+ height: 250px;
 
 
 
 
 
 
 
 
 
196
  }
197
+ """) as demo:
198
+ with gr.Row():
199
+ with gr.Column(scale=1):
200
+ gr.Markdown("### beWiZ's GroOvy SD3 Batch Imagine")
201
+ gr.HTML('<div class="image-container"><img src="https://raw.githubusercontent.com/downlifted/Groovy-StyleSuite/main/groovy.png" alt="GroOvy - SD3 Batch Imagine Logo"></div>')
202
+ with gr.Accordion("Developer Information", open=False):
203
+ gr.Markdown("### Made by BeWiZ")
204
+ gr.Markdown('<div class="image-container"><a href="https://twitter.com/AiAnarchist"><img src="https://raw.githubusercontent.com/downlifted/pictoprompt/master/aia.png" alt="BeWiZ Logo"></a></div>')
205
+ gr.Markdown("Contact: [downlifted@gmail.com](mailto:downlifted@gmail.com)")
206
+ gr.Markdown("Twitter: [@AiAnarchist](https://x.com/AiAnarchist)")
207
+ with gr.Accordion("About SD3 Batch Imagine", open=False):
208
+ gr.Markdown("""
209
+ ### SD3 Batch Imagine: Batch Image Generation
210
+ Produce large batches of images using the latest SD3 Medium model. This tool allows you to generate images quickly and efficiently.
211
+ - **ComfyUI**: For seamless integration and image processing.
212
+ - **Hugging Face**: For state-of-the-art language models.
213
+ - **Gradio**: For an intuitive user interface.
214
+ """)
215
+
216
+ with gr.Accordion("Instructions", open=True):
217
+ gr.Markdown("""
218
+ **SD3 Batch Imagine Instructions**
219
+ - Enter your prompts below, one per empty line.
220
+ - Enter your negative prompts below, one per line. (Optional)
221
+ - Set the zip interval to determine how many images will be included in each zip file.
222
+ - Click "Process Prompts" to start generating images.
223
+ - Click "Cancel Processing" to stop the current batch run.
224
+ - Watch the progress as images are generated in real-time.
225
+ - At the end of the process, zip files containing your images will be available for download.
226
+ """)
227
+
228
+ with gr.Column(scale=2):
229
+ gr.Markdown("### Enter Prompts")
230
+ prompts_text = gr.Textbox(lines=20, placeholder="Enter your prompts here, one per empty line.", label="Prompts")
231
+ negative_prompts_text = gr.Textbox(lines=5, placeholder="Enter your negative prompts here, one per line.", label="Negative Prompts")
232
+ zip_interval = gr.Number(value=10, label="Zip Interval", precision=0)
233
+ process_btn = gr.Button("Process Prompts")
234
+ cancel_btn = gr.Button("Cancel Processing")
235
+ progress_text = gr.Markdown("Progress")
236
+ gallery_output = gr.Gallery(label="Generated Images")
237
+ zip_files_output = gr.Files(label="Zip Files")
238
+
239
+ with gr.Column(scale=1):
240
+ gr.Markdown("### Detailed Logs")
241
+ logs_output = gr.Textbox(lines=10, interactive=False, label="Logs")
242
+
243
+ def generate_user_folder():
244
+ user_folder = os.path.normpath(os.path.join(OUTPUT_DIR, f'SD3{random.randint(1000, 9999)}'))
245
+ os.makedirs(user_folder, exist_ok=True)
246
+ logging.info(f"Generated user folder: {user_folder}")
247
+ return user_folder
248
+
249
+ def on_click(prompts_text, negative_prompts_text, zip_interval):
250
+ reset_cancel_processing_fn()
251
+ user_folder = generate_user_folder()
252
+ output_images, zip_files_list = [], []
253
+ logs = ""
254
+ for images, zip_files, log_msg in process_prompts(prompts_text, negative_prompts_text, user_folder, zip_interval):
255
+ output_images = images
256
+ zip_files_list = zip_files
257
+ logs = log_msg
258
+ yield images, zip_files_list, logs
259
+ return output_images, zip_files_list, logs
260
+
261
+ process_btn.click(
262
+ fn=on_click,
263
+ inputs=[prompts_text, negative_prompts_text, zip_interval],
264
+ outputs=[gallery_output, zip_files_output, logs_output]
265
+ )
266
+
267
+ cancel_btn.click(
268
+ fn=cancel_processing_fn,
269
+ inputs=[],
270
+ outputs=[]
271
+ )
272
+
273
+ demo.launch(share=True)
274
+
275
+ if __name__ == "__main__":
276
+ main()