Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
from flask import Flask, request, jsonify
|
2 |
from flask_cors import CORS
|
3 |
-
from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline,
|
4 |
import torch
|
5 |
import os
|
6 |
from PIL import Image
|
@@ -8,6 +8,7 @@ import base64
|
|
8 |
import time
|
9 |
import logging
|
10 |
from huggingface_hub import list_repo_files
|
|
|
11 |
|
12 |
# Disable GPU detection (remove these lines if GPU is available)
|
13 |
os.environ["CUDA_VISIBLE_DEVICES"] = ""
|
@@ -22,21 +23,22 @@ CORS(app)
|
|
22 |
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
23 |
logger = logging.getLogger(__name__)
|
24 |
|
25 |
-
# Log device
|
26 |
logger.info(f"Device in use: {torch.device('cpu')}")
|
|
|
27 |
|
28 |
# Model cache
|
29 |
model_cache = {}
|
30 |
model_paths = {
|
31 |
-
"ssd-1b": "segmind/SSD-1B", #
|
32 |
"sd-v1-5": "remiai3/stable-diffusion-v1-5"
|
33 |
}
|
34 |
|
35 |
-
# Image ratio to dimensions (optimized for CPU)
|
36 |
ratio_to_dims = {
|
37 |
-
"1:1": (
|
38 |
-
"3:4": (
|
39 |
-
"16:9": (
|
40 |
}
|
41 |
|
42 |
def load_model(model_id):
|
@@ -57,7 +59,9 @@ def load_model(model_id):
|
|
57 |
use_safetensors=True,
|
58 |
low_cpu_mem_usage=True
|
59 |
)
|
60 |
-
|
|
|
|
|
61 |
pipe.enable_attention_slicing()
|
62 |
pipe.to(torch.device("cpu")) # Change to "cuda" if GPU is available
|
63 |
model_cache[model_id] = pipe
|
@@ -83,11 +87,15 @@ def generate():
|
|
83 |
prompt = data.get('prompt', '')
|
84 |
ratio = data.get('ratio', '1:1')
|
85 |
num_images = min(int(data.get('num_images', 1)), 4)
|
86 |
-
guidance_scale = float(data.get('guidance_scale', 7.5))
|
|
|
|
|
|
|
87 |
|
88 |
if not prompt:
|
89 |
return jsonify({"error": "Prompt is required"}), 400
|
90 |
-
|
|
|
91 |
if model_id == 'ssd-1b' and num_images > 1:
|
92 |
return jsonify({"error": "SSD-1B allows only 1 image per generation"}), 400
|
93 |
if model_id == 'ssd-1b' and ratio != '1:1':
|
@@ -95,21 +103,34 @@ def generate():
|
|
95 |
if model_id == 'sd-v1-5' and len(prompt.split()) > 77:
|
96 |
return jsonify({"error": "Prompt exceeds 77 tokens for Stable Diffusion v1.5"}), 400
|
97 |
|
98 |
-
width, height = ratio_to_dims.get(ratio, (
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
pipe = load_model(model_id)
|
100 |
pipe.to(torch.device("cpu")) # Change to "cuda" if GPU is available
|
101 |
|
102 |
images = []
|
103 |
-
num_inference_steps =
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
|
114 |
output_dir = "outputs"
|
115 |
os.makedirs(output_dir, exist_ok=True)
|
@@ -122,6 +143,7 @@ def generate():
|
|
122 |
image_urls.append(f"data:image/png;base64,{img_data}")
|
123 |
os.remove(img_path)
|
124 |
|
|
|
125 |
return jsonify({"images": image_urls})
|
126 |
|
127 |
except Exception as e:
|
|
|
1 |
from flask import Flask, request, jsonify
|
2 |
from flask_cors import CORS
|
3 |
+
from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline, UniPCMultistepScheduler
|
4 |
import torch
|
5 |
import os
|
6 |
from PIL import Image
|
|
|
8 |
import time
|
9 |
import logging
|
10 |
from huggingface_hub import list_repo_files
|
11 |
+
import psutil
|
12 |
|
13 |
# Disable GPU detection (remove these lines if GPU is available)
|
14 |
os.environ["CUDA_VISIBLE_DEVICES"] = ""
|
|
|
23 |
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
24 |
logger = logging.getLogger(__name__)
|
25 |
|
26 |
+
# Log device and memory info
|
27 |
logger.info(f"Device in use: {torch.device('cpu')}")
|
28 |
+
logger.info(f"Available memory: {psutil.virtual_memory().available / (1024 ** 3):.2f} GB")
|
29 |
|
30 |
# Model cache
|
31 |
model_cache = {}
|
32 |
model_paths = {
|
33 |
+
"ssd-1b": "segmind/SSD-1B", # Using segmind/SSD-1B for testing
|
34 |
"sd-v1-5": "remiai3/stable-diffusion-v1-5"
|
35 |
}
|
36 |
|
37 |
+
# Image ratio to dimensions (optimized for CPU, multiple of 8)
|
38 |
ratio_to_dims = {
|
39 |
+
"1:1": (512, 512), # Default for SSD-1B
|
40 |
+
"3:4": (384, 512),
|
41 |
+
"16:9": (512, 288)
|
42 |
}
|
43 |
|
44 |
def load_model(model_id):
|
|
|
59 |
use_safetensors=True,
|
60 |
low_cpu_mem_usage=True
|
61 |
)
|
62 |
+
# Use UniPCMultistepScheduler for SSD-1B, DPMSolver for SD-v1-5
|
63 |
+
scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) if model_id == "ssd-1b" else DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
|
64 |
+
pipe.scheduler = scheduler
|
65 |
pipe.enable_attention_slicing()
|
66 |
pipe.to(torch.device("cpu")) # Change to "cuda" if GPU is available
|
67 |
model_cache[model_id] = pipe
|
|
|
87 |
prompt = data.get('prompt', '')
|
88 |
ratio = data.get('ratio', '1:1')
|
89 |
num_images = min(int(data.get('num_images', 1)), 4)
|
90 |
+
guidance_scale = float(min(max(data.get('guidance_scale', 7.5), 1.0), 20.0)) # Clamp guidance scale
|
91 |
+
|
92 |
+
# Log input parameters
|
93 |
+
logger.info(f"Generating with model: {model_id}, prompt: {prompt}, ratio: {ratio}, num_images: {num_images}, guidance_scale: {guidance_scale}")
|
94 |
|
95 |
if not prompt:
|
96 |
return jsonify({"error": "Prompt is required"}), 400
|
97 |
+
if len(prompt) > 512:
|
98 |
+
return jsonify({"error": "Prompt is too long (max 512 characters)"}), 400
|
99 |
if model_id == 'ssd-1b' and num_images > 1:
|
100 |
return jsonify({"error": "SSD-1B allows only 1 image per generation"}), 400
|
101 |
if model_id == 'ssd-1b' and ratio != '1:1':
|
|
|
103 |
if model_id == 'sd-v1-5' and len(prompt.split()) > 77:
|
104 |
return jsonify({"error": "Prompt exceeds 77 tokens for Stable Diffusion v1.5"}), 400
|
105 |
|
106 |
+
width, height = ratio_to_dims.get(ratio, (512, 512))
|
107 |
+
if width % 8 != 0 or height % 8 != 0:
|
108 |
+
return jsonify({"error": "Width and height must be multiples of 8"}), 400
|
109 |
+
|
110 |
+
# Log memory before generation
|
111 |
+
logger.info(f"Memory before generation: {psutil.virtual_memory().available / (1024 ** 3):.2f} GB")
|
112 |
+
|
113 |
pipe = load_model(model_id)
|
114 |
pipe.to(torch.device("cpu")) # Change to "cuda" if GPU is available
|
115 |
|
116 |
images = []
|
117 |
+
num_inference_steps = 30 if model_id == 'ssd-1b' else 40 # Unified steps for stability
|
118 |
+
try:
|
119 |
+
for _ in range(num_images):
|
120 |
+
image = pipe(
|
121 |
+
prompt=prompt,
|
122 |
+
height=height,
|
123 |
+
width=width,
|
124 |
+
num_inference_steps=num_inference_steps,
|
125 |
+
guidance_scale=guidance_scale
|
126 |
+
).images[0]
|
127 |
+
images.append(image)
|
128 |
+
except IndexError as e:
|
129 |
+
logger.error(f"IndexError during generation: {str(e)}")
|
130 |
+
return jsonify({"error": f"Generation failed due to invalid index access: {str(e)}"}), 500
|
131 |
+
except Exception as e:
|
132 |
+
logger.error(f"Unexpected error during generation: {str(e)}")
|
133 |
+
return jsonify({"error": f"Generation failed: {str(e)}"}), 500
|
134 |
|
135 |
output_dir = "outputs"
|
136 |
os.makedirs(output_dir, exist_ok=True)
|
|
|
143 |
image_urls.append(f"data:image/png;base64,{img_data}")
|
144 |
os.remove(img_path)
|
145 |
|
146 |
+
logger.info(f"Generation successful, returning {len(image_urls)} images")
|
147 |
return jsonify({"images": image_urls})
|
148 |
|
149 |
except Exception as e:
|