Update app.py
Browse files
app.py
CHANGED
@@ -1,12 +1,12 @@
|
|
1 |
# -*- coding: utf-8 -*-
|
2 |
"""
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
"""
|
7 |
|
8 |
import gradio as gr
|
9 |
-
import numpy as np
|
10 |
import random
|
11 |
import torch
|
12 |
from diffusers import StableDiffusionPipeline
|
@@ -45,6 +45,12 @@ DEFAULT_HUB_MODELS = [
|
|
45 |
# Add other diffusers-compatible SD1.5 models here
|
46 |
]
|
47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
# --- Determine available devices and set up options ---
|
49 |
# This logic is from the user's script and works well for Spaces
|
50 |
AVAILABLE_DEVICES = ["CPU"]
|
@@ -92,6 +98,7 @@ INITIAL_MODEL_ID = DEFAULT_HUB_MODELS[0] if DEFAULT_HUB_MODELS else None
|
|
92 |
if INITIAL_MODEL_ID:
|
93 |
print(f"\nLoading initial model '{INITIAL_MODEL_ID}' on startup...")
|
94 |
try:
|
|
|
95 |
current_pipeline = StableDiffusionPipeline.from_pretrained(
|
96 |
INITIAL_MODEL_ID,
|
97 |
torch_dtype=initial_dtype_to_use,
|
@@ -146,131 +153,106 @@ def infer(
|
|
146 |
progress=gr.Progress(track_tqdm=True), # Added progress argument from template
|
147 |
):
|
148 |
"""Generates an image using the selected model and parameters on the chosen device."""
|
149 |
-
global current_pipeline, current_model_id, current_device_loaded, SCHEDULER_MAP
|
150 |
-
|
151 |
-
# Check if initial load failed
|
152 |
-
if current_pipeline is None and model_identifier != INITIAL_MODEL_ID:
|
153 |
-
# Try loading the selected model if initial load failed or model is different
|
154 |
-
pass # Logic below handles loading
|
155 |
-
|
156 |
-
if not model_identifier or model_identifier == "No models found":
|
157 |
-
raise gr.Error(f"No model selected or available. Please select a model from the list.")
|
158 |
-
if not prompt:
|
159 |
-
raise gr.Error("Please enter a prompt.")
|
160 |
-
|
161 |
-
# Map selected device string to PyTorch device string
|
162 |
-
device_to_use = "cuda" if selected_device_str == "GPU" and "GPU" in AVAILABLE_DEVICES else "cpu"
|
163 |
-
# If GPU was selected but not available, raise an error specific to this condition
|
164 |
-
if selected_device_str == "GPU" and device_to_use == "cpu":
|
165 |
-
raise gr.Error("GPU selected but CUDA is not available to PyTorch on this Space. Please select CPU or ensure the Space is configured with a GPU and the CUDA version of PyTorch is installed.")
|
166 |
-
|
167 |
-
# Determine dtype based on the actual device being used
|
168 |
-
dtype_to_use = torch.float32 # Default
|
169 |
-
if device_to_use == "cuda":
|
170 |
-
if torch.cuda.is_available() and torch.cuda.get_device_capability(0)[0] >= 7:
|
171 |
-
dtype_to_use = torch.float16
|
172 |
-
else:
|
173 |
-
dtype_to_use = torch.float32
|
174 |
-
else:
|
175 |
-
dtype_to_use = torch.float32
|
176 |
-
|
177 |
-
|
178 |
-
print(f"Attempting generation on device: {device_to_use}, using dtype: {dtype_to_use}")
|
179 |
|
180 |
-
#
|
181 |
-
# Check if the requested model identifier OR the requested device has changed
|
182 |
-
# Use string comparison for current_device_loaded as it's a torch.device object
|
183 |
if current_pipeline is None or current_model_id != model_identifier or (current_device_loaded is not None and str(current_device_loaded) != device_to_use):
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
try:
|
191 |
-
|
192 |
-
print("
|
193 |
-
except Exception as
|
194 |
-
print(f"Warning:
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
|
|
|
|
|
|
|
|
|
|
245 |
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
current_device_loaded = None
|
251 |
-
print(f"Error loading model '{model_identifier}': {e}")
|
252 |
-
error_message_lower = str(e).lower()
|
253 |
-
# Provide more specific error messages based on common exceptions
|
254 |
-
if "cannot find requested files" in error_message_lower or "404 client error" in error_message_lower or "no such file or directory" in error_message_lower:
|
255 |
-
raise gr.Error(f"Model '{model_identifier}' not found on Hugging Face Hub or in repo files. Check ID/path or internet connection. Error: {e}")
|
256 |
-
elif "checkpointsnotfounderror" in error_message_lower or "valueerror: could not find a valid model structure" in error_message_lower:
|
257 |
-
raise gr.Error(f"No valid diffusers model at '{model_identifier}'. Ensure it's a diffusers format ID/path. Error: {e}")
|
258 |
-
elif "out of memory" in error_message_lower:
|
259 |
-
raise gr.Error(f"Out of Memory (OOM) loading model. This Space might not have enough RAM/VRAM for this model. Try a lighter model or select CPU (if available). Error: {e}")
|
260 |
-
elif "cusolver64" in error_message_lower or "cuda driver version" in error_message_lower or "cuda error" in error_message_lower:
|
261 |
-
raise gr.Error(f"CUDA/GPU Driver/Installation Error on Space: {e}. Check Space hardware or select CPU.")
|
262 |
-
elif "safetensors_rust.safetensorserror" in error_message_lower or "oserror: cannot load" in error_message_lower or "filenotfounderror" in error_message_lower:
|
263 |
-
raise gr.Error(f"Model file error for '{model_identifier}': {e}. Files might be corrupt or incomplete on the Hub/in repo.")
|
264 |
-
elif "could not import" in error_message_lower or "module not found" in error_message_lower:
|
265 |
-
raise gr.Error(f"Dependency error: {e}. Ensure required libraries are in requirements.txt.")
|
266 |
-
else:
|
267 |
-
raise gr.Error(f"Failed to load model '{model_identifier}': {e}")
|
268 |
|
269 |
# Check if pipeline is successfully loaded before proceeding
|
270 |
if current_pipeline is None:
|
271 |
raise gr.Error("Model failed to load. Cannot generate image.")
|
272 |
|
273 |
-
|
274 |
# 2. Configure Scheduler
|
275 |
selected_scheduler_class = SCHEDULER_MAP.get(scheduler_name)
|
276 |
if selected_scheduler_class is None:
|
@@ -322,26 +304,41 @@ def infer(
|
|
322 |
|
323 |
|
324 |
# 4. Set Seed Generator
|
325 |
-
generator = None
|
326 |
# The generator device needs to match the pipeline device
|
327 |
generator_device = current_pipeline.device # Must match the pipeline device
|
328 |
|
329 |
if randomize_seed: # Use the randomize_seed checkbox
|
330 |
-
seed = random.randint(0, MAX_SEED) # Re-randomize seed
|
331 |
print(f"Randomizing seed to: {seed}")
|
332 |
else:
|
333 |
# Use provided seed if not randomizing (-1 will still use it)
|
|
|
|
|
|
|
|
|
|
|
334 |
print(f"Using provided seed: {int(seed)}")
|
335 |
|
336 |
|
337 |
try:
|
|
|
|
|
338 |
# Explicitly move generator to the desired device
|
339 |
-
generator = torch.Generator(device=generator_device).manual_seed(
|
340 |
-
print(f"Generator set with seed {
|
341 |
except Exception as e:
|
342 |
-
|
343 |
-
|
|
|
344 |
generator = None # Let pipeline handle random seed if generator creation fails or device mismatch
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
345 |
|
346 |
# 5. Generate Image
|
347 |
# Ensure required parameters are integers/floats
|
@@ -354,7 +351,7 @@ def infer(
|
|
354 |
if width <= 0 or height <= 0:
|
355 |
raise ValueError("Image width and height must be positive.")
|
356 |
|
357 |
-
print(f"Generating: Prompt='{prompt[:80]}{'...' if len(prompt) > 80 else ''}', NegPrompt='{negative_prompt[:80]}{'...' if len(negative_prompt) > 80 else ''}', Steps={num_inference_steps_int}, CFG={guidance_scale_float}, Size={width}x{height}, Scheduler={scheduler_name}, Seed={
|
358 |
start_time = time.time()
|
359 |
|
360 |
try:
|
@@ -366,7 +363,7 @@ def infer(
|
|
366 |
guidance_scale=guidance_scale_float,
|
367 |
width=width,
|
368 |
height=height,
|
369 |
-
generator=generator,
|
370 |
# Pass progress object for tqdm tracking in Gradio
|
371 |
callback_steps=max(1, num_inference_steps_int // 20), # Update progress bar periodically
|
372 |
callback=lambda step, timestep, latents: progress((step / num_inference_steps_int, f"Step {step}/{num_inference_steps_int}")),
|
@@ -381,8 +378,11 @@ def infer(
|
|
381 |
print(f"Generation finished in {end_time - start_time:.2f} seconds.")
|
382 |
generated_image = output.images[0]
|
383 |
|
|
|
|
|
|
|
384 |
# Return both the image and the seed (potentially randomized)
|
385 |
-
return generated_image,
|
386 |
|
387 |
except gr.Error as e:
|
388 |
# Re-raise Gradio errors directly
|
@@ -423,8 +423,16 @@ else:
|
|
423 |
initial_model_choices = model_choices
|
424 |
# Set a reasonable default if available
|
425 |
initial_default_model = INITIAL_MODEL_ID if INITIAL_MODEL_ID else "No models found"
|
426 |
-
model_dropdown_interactive = True if
|
427 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
|
429 |
scheduler_choices = list(SCHEDULER_MAP.keys())
|
430 |
|
@@ -449,8 +457,10 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo: # Added Soft theme from
|
|
449 |
# Add a note about model loading time
|
450 |
if INITIAL_MODEL_ID:
|
451 |
gr.Markdown(f"*(Note: The initial model '{INITIAL_MODEL_ID}' is loading... First generation might take longer.)*")
|
|
|
|
|
452 |
else:
|
453 |
-
gr.Markdown(f"*(Note: No
|
454 |
|
455 |
|
456 |
with gr.Row():
|
@@ -487,8 +497,9 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo: # Added Soft theme from
|
|
487 |
)
|
488 |
# Combine seed input and randomize checkbox
|
489 |
with gr.Row():
|
490 |
-
|
491 |
-
|
|
|
492 |
|
493 |
|
494 |
generate_button = gr.Button("✨ Generate Image ✨", variant="primary", scale=1) # Added emojis
|
@@ -529,25 +540,14 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo: # Added Soft theme from
|
|
529 |
)
|
530 |
|
531 |
# Add examples from template
|
532 |
-
# Ensure examples
|
533 |
-
# Examples inputs: [prompt, neg_prompt, seed, randomize_seed, width, height, cfg_scale, steps]
|
534 |
-
# Note: Size and Scheduler are not easily handled in standard examples, they'll use defaults.
|
535 |
-
# Let's adjust the example inputs to match the infer function's first few parameters
|
536 |
-
example_prompts = [
|
537 |
-
["Astronaut in a jungle, cold color palette, muted colors, detailed, 8k", None, 0, True, "512x512", "Euler", 7.5, 30],
|
538 |
-
["An astronaut riding a green horse", None, 0, True, "512x512", "Euler", 7.5, 30],
|
539 |
-
["A delicious ceviche cheesecake slice", None, 0, True, "512x512", "Euler", 7.5, 30],
|
540 |
-
]
|
541 |
-
# Update example inputs to match the infer function parameters
|
542 |
-
# [model_identifier, selected_device_str, prompt, negative_prompt, steps, cfg_scale, scheduler_name, size, seed, randomize_seed]
|
543 |
-
# Need to add dummy values for model, device, steps, cfg, scheduler, size for examples
|
544 |
-
# Let's simplify examples to just prompt/neg_prompt for typical template usage
|
545 |
template_examples = [
|
546 |
"Astronaut in a jungle, cold color palette, muted colors, detailed, 8k",
|
547 |
"An astronaut riding a green horse",
|
548 |
"A delicious ceviche cheesecake slice",
|
549 |
]
|
550 |
-
#
|
|
|
551 |
gr.Examples(examples=template_examples, inputs=[prompt_input])
|
552 |
|
553 |
|
@@ -559,7 +559,7 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo: # Added Soft theme from
|
|
559 |
1. Select a model from the dropdown (Hugging Face Hub ID). Models are downloaded and cached on the Space.
|
560 |
2. Choose your processing device (GPU recommended if available).
|
561 |
3. Enter your positive and optional negative prompts.
|
562 |
-
4. Adjust advanced settings (Steps, CFG Scale, Scheduler, Size, Seed) if needed.
|
563 |
5. Click "Generate Image".
|
564 |
The first generation with a new model/device might take some time to load.
|
565 |
""" # Removed notes about local models and batch files
|
@@ -576,7 +576,7 @@ if __name__ == "__main__":
|
|
576 |
print(f"Available devices detected by PyTorch: {', '.join(AVAILABLE_DEVICES)}")
|
577 |
print(f"Default device selected by app: {DEFAULT_DEVICE}")
|
578 |
if current_pipeline:
|
579 |
-
print(f"Initial model '{current_model_id}' loaded successfully.")
|
580 |
else:
|
581 |
print("No initial model loaded. Check model list and network connectivity.")
|
582 |
|
|
|
1 |
# -*- coding: utf-8 -*-
|
2 |
"""
|
3 |
+
CipherCore SD1.5 Image Generator, FAST CPU INFERENCE
|
4 |
+
Raxephion @2025
|
5 |
+
|
6 |
"""
|
7 |
|
8 |
import gradio as gr
|
9 |
+
import numpy as np # <-- Needed for np.iinfo
|
10 |
import random
|
11 |
import torch
|
12 |
from diffusers import StableDiffusionPipeline
|
|
|
45 |
# Add other diffusers-compatible SD1.5 models here
|
46 |
]
|
47 |
|
48 |
+
# --- Constants for Gradio UI / Generation ---
|
49 |
+
MAX_SEED = np.iinfo(np.int32).max # <-- Added this line back! Defines the maximum seed value
|
50 |
+
# MAX_IMAGE_SIZE = 1024 # This was in the template but not strictly used in the logic outside the slider max, keeping it defined is harmless but maybe not needed
|
51 |
+
# However, let's add MAX_IMAGE_SIZE as it was related to the sliders in the template
|
52 |
+
MAX_IMAGE_SIZE_SLIDER = 1024 # Renamed to avoid confusion, used only for slider max
|
53 |
+
|
54 |
# --- Determine available devices and set up options ---
|
55 |
# This logic is from the user's script and works well for Spaces
|
56 |
AVAILABLE_DEVICES = ["CPU"]
|
|
|
98 |
if INITIAL_MODEL_ID:
|
99 |
print(f"\nLoading initial model '{INITIAL_MODEL_ID}' on startup...")
|
100 |
try:
|
101 |
+
# Load the pipeline onto the initial device and dtype
|
102 |
current_pipeline = StableDiffusionPipeline.from_pretrained(
|
103 |
INITIAL_MODEL_ID,
|
104 |
torch_dtype=initial_dtype_to_use,
|
|
|
153 |
progress=gr.Progress(track_tqdm=True), # Added progress argument from template
|
154 |
):
|
155 |
"""Generates an image using the selected model and parameters on the chosen device."""
|
156 |
+
global current_pipeline, current_model_id, current_device_loaded, SCHEDULER_MAP, MAX_SEED # <-- Make MAX_SEED global
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
|
158 |
+
# Check if initial load failed or model is different
|
|
|
|
|
159 |
if current_pipeline is None or current_model_id != model_identifier or (current_device_loaded is not None and str(current_device_loaded) != device_to_use):
|
160 |
+
# This check is done before parameter parsing so we can determine device/dtype for loading
|
161 |
+
# Need to redo some parameter parsing here to get device_to_use early
|
162 |
+
temp_device_to_use = "cuda" if selected_device_str == "GPU" and "GPU" in AVAILABLE_DEVICES else "cpu"
|
163 |
+
temp_dtype_to_use = torch.float32
|
164 |
+
if temp_device_to_use == "cuda":
|
165 |
+
if torch.cuda.is_available() and torch.cuda.get_device_capability(0)[0] >= 7:
|
166 |
+
temp_dtype_to_use = torch.float16
|
167 |
+
else:
|
168 |
+
temp_dtype_to_use = torch.float32
|
169 |
+
else:
|
170 |
+
temp_dtype_to_use = torch.float32
|
171 |
+
|
172 |
+
# Now proceed with actual model loading based on parsed device/dtype
|
173 |
+
print(f"Loading model: {model_identifier} onto {temp_device_to_use} with dtype {temp_dtype_to_use}...")
|
174 |
+
# Clear previous pipeline to potentially free memory *before* loading the new one
|
175 |
+
if current_pipeline is not None:
|
176 |
+
print(f"Unloading previous model '{current_model_id}' from {current_device_loaded}...")
|
177 |
+
if str(current_device_loaded) == "cuda":
|
178 |
+
try:
|
179 |
+
current_pipeline.to("cpu")
|
180 |
+
print("Moved previous pipeline to CPU.")
|
181 |
+
except Exception as move_e:
|
182 |
+
print(f"Warning: Failed to move previous pipeline to CPU: {move_e}")
|
183 |
+
del current_pipeline
|
184 |
+
current_pipeline = None # Set to None immediately
|
185 |
+
if str(current_device_loaded) == "cuda":
|
186 |
try:
|
187 |
+
torch.cuda.empty_cache()
|
188 |
+
print("Cleared CUDA cache.")
|
189 |
+
except Exception as cache_e:
|
190 |
+
print(f"Warning: Error clearing CUDA cache: {cache_e}")
|
191 |
+
|
192 |
+
# Ensure the device is actually available if not CPU (redundant with earlier check but safe)
|
193 |
+
if temp_device_to_use == "cuda":
|
194 |
+
if not torch.cuda.is_available():
|
195 |
+
raise gr.Error("CUDA selected but not available to PyTorch on this Space. Please select CPU or ensure the Space is configured with a GPU and the CUDA version of PyTorch is installed.")
|
196 |
+
|
197 |
+
try:
|
198 |
+
pipeline = StableDiffusionPipeline.from_pretrained(
|
199 |
+
model_identifier,
|
200 |
+
torch_dtype=temp_dtype_to_use, # Use the determined dtype for loading
|
201 |
+
safety_checker=None,
|
202 |
+
)
|
203 |
+
pipeline = pipeline.to(temp_device_to_use) # Use the determined device
|
204 |
+
|
205 |
+
current_pipeline = pipeline
|
206 |
+
current_model_id = model_identifier
|
207 |
+
current_device_loaded = torch.device(temp_device_to_use) # Store the actual device object
|
208 |
+
|
209 |
+
# Basic check for SD1.x architecture
|
210 |
+
unet_config = getattr(pipeline, 'unet', None)
|
211 |
+
if unet_config and hasattr(unet_config, 'config') and hasattr(unet_config.config, 'cross_attention_dim'):
|
212 |
+
cross_attn_dim = unet_config.config.cross_attention_dim
|
213 |
+
if cross_attn_dim != 768:
|
214 |
+
warning_msg = (f"Warning: Loaded model '{model_identifier}' might not be a standard SD 1.x model "
|
215 |
+
f"(expected UNet cross_attention_dim 768, found {cross_attn_dim}). "
|
216 |
+
"Results may be unexpected or generation might fail.")
|
217 |
+
print(warning_msg)
|
218 |
+
gr.Warning(warning_msg)
|
219 |
+
else:
|
220 |
+
print("UNet cross_attention_dim is 768, consistent with SD 1.x.")
|
221 |
+
else:
|
222 |
+
print("Could not check UNet cross_attention_dim.")
|
223 |
+
|
224 |
+
print(f"Model '{model_identifier}' loaded successfully on {current_device_loaded} with dtype {temp_dtype_to_use}.")
|
225 |
+
|
226 |
+
except Exception as e:
|
227 |
+
current_pipeline = None
|
228 |
+
current_model_id = None
|
229 |
+
current_device_loaded = None
|
230 |
+
print(f"Error loading model '{model_identifier}': {e}")
|
231 |
+
error_message_lower = str(e).lower()
|
232 |
+
if "cannot find requested files" in error_message_lower or "404 client error" in error_message_lower or "no such file or directory" in error_message_lower:
|
233 |
+
raise gr.Error(f"Model '{model_identifier}' not found on Hugging Face Hub or in repo files. Check ID/path or internet connection. Error: {e}")
|
234 |
+
elif "checkpointsnotfounderror" in error_message_lower or "valueerror: could not find a valid model structure" in error_message_lower:
|
235 |
+
raise gr.Error(f"No valid diffusers model at '{model_identifier}'. Ensure it's a diffusers format ID/path. Error: {e}")
|
236 |
+
elif "out of memory" in error_message_lower:
|
237 |
+
raise gr.Error(f"Out of Memory (OOM) loading model. This Space might not have enough RAM/VRAM for this model. Try a lighter model or select CPU (if available). Error: {e}")
|
238 |
+
elif "cusolver64" in error_message_lower or "cuda driver version" in error_message_lower or "cuda error" in error_message_lower:
|
239 |
+
raise gr.Error(f"CUDA/GPU Driver/Installation Error on Space: {e}. Check Space hardware or select CPU.")
|
240 |
+
elif "safetensors_rust.safetensorserror" in error_message_lower or "oserror: cannot load" in error_message_lower or "filenotfounderror" in error_message_lower:
|
241 |
+
raise gr.Error(f"Model file error for '{model_identifier}': {e}. Files might be corrupt or incomplete on the Hub/in repo.")
|
242 |
+
elif "could not import" in error_message_lower or "module not found" in error_message_lower:
|
243 |
+
raise gr.Error(f"Dependency error: {e}. Ensure required libraries are in requirements.txt.")
|
244 |
+
else:
|
245 |
+
raise gr.Error(f"Failed to load model '{model_identifier}': {e}")
|
246 |
|
247 |
+
# Re-determine device_to_use and dtype_to_use *after* ensuring pipeline is loaded
|
248 |
+
# They should match current_device_loaded and the pipeline's dtype
|
249 |
+
device_to_use = str(current_pipeline.device) if current_pipeline else ("cuda" if selected_device_str == "GPU" and "GPU" in AVAILABLE_DEVICES else "cpu")
|
250 |
+
dtype_to_use = current_pipeline.dtype if current_pipeline else torch.float32 # Fallback if somehow pipeline is still None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
|
252 |
# Check if pipeline is successfully loaded before proceeding
|
253 |
if current_pipeline is None:
|
254 |
raise gr.Error("Model failed to load. Cannot generate image.")
|
255 |
|
|
|
256 |
# 2. Configure Scheduler
|
257 |
selected_scheduler_class = SCHEDULER_MAP.get(scheduler_name)
|
258 |
if selected_scheduler_class is None:
|
|
|
304 |
|
305 |
|
306 |
# 4. Set Seed Generator
|
|
|
307 |
# The generator device needs to match the pipeline device
|
308 |
generator_device = current_pipeline.device # Must match the pipeline device
|
309 |
|
310 |
if randomize_seed: # Use the randomize_seed checkbox
|
311 |
+
seed = random.randint(0, MAX_SEED) # Re-randomize seed using MAX_SEED
|
312 |
print(f"Randomizing seed to: {seed}")
|
313 |
else:
|
314 |
# Use provided seed if not randomizing (-1 will still use it)
|
315 |
+
# If seed is -1 but randomize_seed is False, we should still use a random seed,
|
316 |
+
# but make it deterministic based on system time or similar if possible, or just MAX_SEED based random.
|
317 |
+
# Given the UI has a 'randomize_seed' checkbox, let's treat seed=-1 as a specific "use system random" signal IF randomize_seed is also False.
|
318 |
+
# Or, more simply, if randomize_seed is False, always use the value in the seed input.
|
319 |
+
# Let's stick to the simpler interpretation: if randomize_seed is True, override seed input. If False, use seed input value.
|
320 |
print(f"Using provided seed: {int(seed)}")
|
321 |
|
322 |
|
323 |
try:
|
324 |
+
# Ensure seed is an integer for the generator
|
325 |
+
seed_int = int(seed)
|
326 |
# Explicitly move generator to the desired device
|
327 |
+
generator = torch.Generator(device=generator_device).manual_seed(seed_int)
|
328 |
+
print(f"Generator set with seed {seed_int} on device: {generator_device}")
|
329 |
except Exception as e:
|
330 |
+
# Handle potential issues like non-integer seed input
|
331 |
+
print(f"Warning: Error setting seed generator with seed {seed} on device {generator_device}: {e}. Falling back to default generator (potentially on CPU) and using a potentially different seed.")
|
332 |
+
gr.Warning(f"Failed to set seed generator with seed {seed}. Using random seed. Error: {e}")
|
333 |
generator = None # Let pipeline handle random seed if generator creation fails or device mismatch
|
334 |
+
# If generator creation failed, the actual seed used might be different. How to report it?
|
335 |
+
# The simplest is to let the pipeline run and report the seed *we attempted to use*.
|
336 |
+
# Or, if we know pipeline will use a random seed on failure, report that.
|
337 |
+
# For simplicity, let's report the seed_int we derived UNLESS randomize_seed was True, then report the generated random seed.
|
338 |
+
# No, the most accurate is to let the pipeline generate, and some diffusers versions return the generator state/seed.
|
339 |
+
# However, the standard pipeline output doesn't return the seed.
|
340 |
+
# Let's just report the seed we *tried* to use. If randomize_seed was True, it's the random one. If False, it's the user input one.
|
341 |
+
pass # Keep the last calculated seed_int or seed value
|
342 |
|
343 |
# 5. Generate Image
|
344 |
# Ensure required parameters are integers/floats
|
|
|
351 |
if width <= 0 or height <= 0:
|
352 |
raise ValueError("Image width and height must be positive.")
|
353 |
|
354 |
+
print(f"Generating: Prompt='{prompt[:80]}{'...' if len(prompt) > 80 else ''}', NegPrompt='{negative_prompt[:80]}{'...' if len(negative_prompt) > 80 else ''}', Steps={num_inference_steps_int}, CFG={guidance_scale_float}, Size={width}x{height}, Scheduler={scheduler_name}, Seed={seed_int if generator else 'Random (Generator Failed)'}, Device={device_to_use}, Dtype={dtype_to_use}")
|
355 |
start_time = time.time()
|
356 |
|
357 |
try:
|
|
|
363 |
guidance_scale=guidance_scale_float,
|
364 |
width=width,
|
365 |
height=height,
|
366 |
+
generator=generator, # Pass the generator (which might be None)
|
367 |
# Pass progress object for tqdm tracking in Gradio
|
368 |
callback_steps=max(1, num_inference_steps_int // 20), # Update progress bar periodically
|
369 |
callback=lambda step, timestep, latents: progress((step / num_inference_steps_int, f"Step {step}/{num_inference_steps_int}")),
|
|
|
378 |
print(f"Generation finished in {end_time - start_time:.2f} seconds.")
|
379 |
generated_image = output.images[0]
|
380 |
|
381 |
+
# Determine the seed to return: the one we attempted to use
|
382 |
+
actual_seed_used = seed_int if generator else -1 # Return -1 or the input seed if generator failed
|
383 |
+
|
384 |
# Return both the image and the seed (potentially randomized)
|
385 |
+
return generated_image, actual_seed_used
|
386 |
|
387 |
except gr.Error as e:
|
388 |
# Re-raise Gradio errors directly
|
|
|
423 |
initial_model_choices = model_choices
|
424 |
# Set a reasonable default if available
|
425 |
initial_default_model = INITIAL_MODEL_ID if INITIAL_MODEL_ID else "No models found"
|
426 |
+
model_dropdown_interactive = True # Make it interactive if there's *any* model choice
|
427 |
|
428 |
+
# Ensure the initial default model is actually in the choices list if possible
|
429 |
+
if initial_default_model != "No models found" and initial_default_model not in initial_model_choices:
|
430 |
+
print(f"Warning: Initial default model '{initial_default_model}' is not in the model_choices list.")
|
431 |
+
if initial_model_choices and initial_model_choices[0] != "No models found":
|
432 |
+
initial_default_model = initial_model_choices[0]
|
433 |
+
print(f"Setting default model to first available choice: {initial_default_model}")
|
434 |
+
else:
|
435 |
+
initial_default_model = "No models found" # Fallback if no choices
|
436 |
|
437 |
scheduler_choices = list(SCHEDULER_MAP.keys())
|
438 |
|
|
|
457 |
# Add a note about model loading time
|
458 |
if INITIAL_MODEL_ID:
|
459 |
gr.Markdown(f"*(Note: The initial model '{INITIAL_MODEL_ID}' is loading... First generation might take longer.)*")
|
460 |
+
elif initial_default_model != "No models found":
|
461 |
+
gr.Markdown(f"*(Note: Loading model '{initial_default_model}' on first generation... This might take some time.)*")
|
462 |
else:
|
463 |
+
gr.Markdown(f"*(Note: No models available. Add Hub IDs to DEFAULT_HUB_MODELS in the script.)*")
|
464 |
|
465 |
|
466 |
with gr.Row():
|
|
|
497 |
)
|
498 |
# Combine seed input and randomize checkbox
|
499 |
with gr.Row():
|
500 |
+
# Use MAX_SEED for slider max
|
501 |
+
seed_input = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0, precision=0, interactive=True) # Use 0 as default, interactive initially
|
502 |
+
randomize_seed_checkbox = gr.Checkbox(label="Randomize seed", value=True) # Simplified label
|
503 |
|
504 |
|
505 |
generate_button = gr.Button("✨ Generate Image ✨", variant="primary", scale=1) # Added emojis
|
|
|
540 |
)
|
541 |
|
542 |
# Add examples from template
|
543 |
+
# Ensure examples map to the correct input component indices
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
544 |
template_examples = [
|
545 |
"Astronaut in a jungle, cold color palette, muted colors, detailed, 8k",
|
546 |
"An astronaut riding a green horse",
|
547 |
"A delicious ceviche cheesecake slice",
|
548 |
]
|
549 |
+
# Examples will only populate the first input they match.
|
550 |
+
# In this case, passing just a list of strings populates the first Textbox: prompt_input.
|
551 |
gr.Examples(examples=template_examples, inputs=[prompt_input])
|
552 |
|
553 |
|
|
|
559 |
1. Select a model from the dropdown (Hugging Face Hub ID). Models are downloaded and cached on the Space.
|
560 |
2. Choose your processing device (GPU recommended if available).
|
561 |
3. Enter your positive and optional negative prompts.
|
562 |
+
4. Adjust advanced settings (Steps, CFG Scale, Scheduler, Size, Seed) if needed. The "Randomize seed" checkbox will override the seed value in the input box.
|
563 |
5. Click "Generate Image".
|
564 |
The first generation with a new model/device might take some time to load.
|
565 |
""" # Removed notes about local models and batch files
|
|
|
576 |
print(f"Available devices detected by PyTorch: {', '.join(AVAILABLE_DEVICES)}")
|
577 |
print(f"Default device selected by app: {DEFAULT_DEVICE}")
|
578 |
if current_pipeline:
|
579 |
+
print(f"Initial model '{current_model_id}' loaded successfully on {current_device_loaded}.")
|
580 |
else:
|
581 |
print("No initial model loaded. Check model list and network connectivity.")
|
582 |
|