aexyb commited on
Commit
a6573ee
·
verified ·
1 Parent(s): 342daa1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -324
app.py CHANGED
@@ -1,49 +1,119 @@
1
- def download_prebuilt_binary():
2
- """Try to download pre-built sd-cli (faster than compiling)"""
3
- print("\n🔄 Trying pre-built binary...")
4
-
5
- # GitHub releases often have pre-built binaries
6
- url = "https://github.com/leejet/stable-diffusion/releases/latest/download/sd-cli-linux-x64"
7
-
8
- try:
9
- Path("stable-diffusion.cpp/bin").mkdir(parents=True, exist_ok=True)
10
- dest = "stable-diffusion.cpp/bin/sd-cli"
11
- urllib.request.urlretrieve(url, dest)
12
-
13
- # Make executable
14
- os.chmod(dest, 0o755)
15
-
16
- print("✅ Pre-built binary downloaded!")
17
- return dest
18
- except:
19
- print("⚠️ Pre-built not available, will compile from source")
20
- return None
21
-
22
  """
23
  Flux Text-to-Image Generator (CPU Only)
24
- Auto-setup included - downloads models on first run
25
  """
26
 
27
  # ============================================================
28
- # PART 1: AUTO SETUP - Download models if missing
29
  # ============================================================
30
  import os
31
  import sys
 
32
  import urllib.request
33
  from pathlib import Path
34
 
35
- def auto_setup():
36
- """Ensure all required files exist"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  print("\n" + "="*60)
38
- print("🔧 RUNNING AUTO-SETUP...")
39
  print("="*60 + "\n")
40
 
41
- # Create directories
42
- Path("models").mkdir(exist_ok=True)
43
- Path("outputs").mkdir(exist_ok=True)
44
- print("✅ Created directories: models/, outputs/")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
- # Define models
47
  models = {
48
  "bonsai-flux2-klein-ternary-q2_k.gguf":
49
  "https://huggingface.co/bonsai-models/flux.1-klein-gguf/resolve/main/bonsai-flux2-klein-ternary-q2_k.gguf",
@@ -53,39 +123,61 @@ def auto_setup():
53
  "https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF/resolve/main/qwen2.5-1.5b-instruct-q2_k.gguf",
54
  }
55
 
56
- # Download missing models
57
  for filename, url in models.items():
58
- filepath = Path("models") / filename
59
 
60
  if filepath.exists():
61
  size_mb = filepath.stat().st_size / (1024*1024)
62
- print(f"✅ Found: {filename} ({size_mb:.1f} MB)")
63
  else:
64
- print(f"📥 Downloading: {filename}")
65
  try:
66
  urllib.request.urlretrieve(url, filepath)
67
  size_mb = filepath.stat().st_size / (1024*1024)
68
  print(f" ✅ Saved ({size_mb:.1f} MB)")
69
  except Exception as e:
70
- print(f" ❌ Error: {e}")
71
- print(f" ⚠️ Manual download needed from:")
72
- print(f" {url}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  print("\n" + "="*60)
75
  print("✅ SETUP COMPLETE")
 
 
 
76
  print("="*60 + "\n")
77
 
78
  # Run setup
79
- auto_setup()
 
80
 
81
  # ============================================================
82
  # PART 2: IMPORTS & CONFIGURATION
83
  # ============================================================
84
  import gradio as gr
85
- import subprocess
86
  from datetime import datetime
87
 
88
- # Paths
89
  MODELS_DIR = "./models"
90
  OUTPUTS_DIR = "./outputs"
91
 
@@ -93,7 +185,8 @@ DIFFUSION_MODEL = os.path.join(MODELS_DIR, "bonsai-flux2-klein-ternary-q2_k.gguf
93
  VAE_MODEL = os.path.join(MODELS_DIR, "flux2-vae.safetensors")
94
  LLM_MODEL = os.path.join(MODELS_DIR, "qwen_3_4b.gguf")
95
 
96
- SD_CLI = "./stable-diffusion.cpp/bin/sd-cli" # Adjust if needed
 
97
 
98
 
99
  # ============================================================
@@ -111,288 +204,17 @@ def generate_image(
111
  ):
112
  """Generate image using stable diffusion.cpp"""
113
 
114
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
115
- output_filename = f"generated_{timestamp}.png"
116
- output_path = os.path.join(OUTPUTS_DIR, output_filename)
117
-
118
- cmd = [
119
- SD_CLI,
120
- "--diffusion-model", DIFFUSION_MODEL,
121
- "--vae", VAE_MODEL,
122
- "--llm", LLM_MODEL,
123
- "-p", prompt,
124
- "--cfg-scale", str(cfg_scale),
125
- "--steps", str(steps),
126
- "-W", str(width),
127
- "-H", str(height),
128
- "-o", output_path,
129
- "--offload-to-cpu",
130
- "--diffusion-fa",
131
- "--vae-tiling",
132
- ]
133
-
134
- if seed > 0:
135
- cmd.extend(["--seed", str(seed)])
136
- if negative_prompt:
137
- cmd.extend(["-n", negative_prompt])
138
-
139
- progress(0.1, desc="Starting generation...")
140
-
141
- try:
142
- result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
143
- progress(0.9, desc="Processing output...")
144
-
145
- if result.returncode != 0:
146
- return None, f"Error: {result.stderr}"
147
-
148
- if os.path.exists(output_path):
149
- progress(1.0, desc="Complete!")
150
- return output_path, "✅ Image generated successfully!"
151
- else:
152
- return None, "Output file not found"
153
-
154
- except subprocess.TimeoutExpired:
155
- return None, "⏰ Generation timed out (5 min limit)"
156
- except Exception as e:
157
- return None, f"❌ Error: {str(e)}"
158
 
 
159
 
160
- # ============================================================
161
- # PART 4: GRADIO INTERFACE
162
- # ============================================================
163
- with gr.Blocks(title="Flux Text-to-Image (CPU)", theme=gr.themes.Soft()) as demo:
164
-
165
- gr.Markdown("""
166
- # 🎨 Flux Text-to-Image Generator
167
- ### CPU-Powered | stable diffusion.cpp | No GPU Required ⚡
168
- """)
169
-
170
- with gr.Row():
171
- with gr.Column(scale=2):
172
- prompt_input = gr.Textbox(
173
- label="✍️ Prompt",
174
- placeholder="A red fox in snow, detailed, 8k...",
175
- lines=3,
176
- value="a red fox in snow, detailed, 8k"
177
- )
178
-
179
- neg_prompt = gr.Textbox(
180
- label="🚫 Negative Prompt (optional)",
181
- placeholder="blurry, low quality...",
182
- lines=2
183
- )
184
-
185
- with gr.Column(scale=1):
186
- cfg_slider = gr.Slider(1.0, 7.0, value=1.0, step=0.5, label="⚙️ CFG Scale")
187
- steps_slider = gr.Slider(1, 20, value=4, step=1, label="🔄 Steps")
188
- seed_input = gr.Number(label="🎲 Seed (-1=random)", value=-1, precision=0)
189
-
190
- with gr.Row():
191
- gen_btn = gr.Button("🚀 Generate Image", variant="primary", size="lg")
192
- clear_btn = gr.Button("🗑️ Clear", size="lg")
193
-
194
- with gr.Row():
195
- output_image = gr.Image(label="🖼️ Generated Image", type="filepath", height=400)
196
- status_output = gr.Textbox(label="📊 Status", interactive=False)
197
-
198
- gen_btn.click(
199
- fn=generate_image,
200
- inputs=[prompt_input, neg_prompt, cfg_slider, steps_slider, seed_input],
201
- outputs=[output_image, status_output]
202
- )
203
-
204
- clear_btn.click(
205
- fn=lambda: (None, "", "", 1.0, 4, -1, None, ""),
206
- outputs=[prompt_input, neg_prompt, cfg_slider, steps_slider, seed_input,
207
- output_image, status_output]
208
- )
209
-
210
-
211
- # ============================================================
212
- # PART 5: LAUNCH
213
- # ============================================================
214
- if __name__ == "__main__":
215
- demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
216
- import gradio as gr
217
- import os
218
- import subprocess
219
- import tempfile
220
- from pathlib import Path
221
- from datetime import datetime
222
-
223
- # Configuration
224
- MODELS_DIR = os.path.getenv("MODELS_DIR", "./models")
225
- OUTPUTS_DIR = os.path.getenv("OUTPUTS_DIR", "./outputs")
226
-
227
- DIFFUSION_MODEL = os.path.join(MODELS_DIR, "bonsai-flux2-klein-ternary-q2_k.gguf")
228
- VAE_MODEL = os.path.join(MODELS_DIR, "flux2-vae.safetensors")
229
- LLM_MODEL = os.path.join(MODELS_DIR, "qwen_3_4b.gguf")
230
-
231
- SD_CPP_PATH = os.path.getenv("SD_CPP_PATH", "./stable-diffusion.cpp")
232
- SD_CLI = os.path.join(SD_CPP_PATH, "bin"/"sd-cli") # or ./build/bin/sd-cli
233
-
234
- def generate_image(
235
- prompt: str,
236
- negative_prompt: str = "",
237
- cfg_scale: float = 1.0,
238
- steps: int = 4,
239
- width: int = 1024,
240
- height: int = 1024,
241
- seed: int = -1,
242
- progress=gr.Progress()
243
- ):
244
- """
245
- Generate image using stable diffusion.cpp CLI
246
- """
247
-
248
- # Create output filename
249
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
250
- output_filename = f"generated_{timestamp}.png"
251
- output_path = os.path.join(OUTPUTS_DIR, output_filename)
252
-
253
- # Ensure directories exist
254
- Path(OUTPUTS_DIR).mkdir(parents=True, exist_ok=True)
255
-
256
- # Build command
257
- cmd = [
258
- SD_CLI,
259
- "--diffusion-model", DIFFUSION_MODEL,
260
- "--vae", VAE_MODEL,
261
- "--llm", LLM_MODEL,
262
- "-p", prompt,
263
- "--cfg-scale", str(cfg_scale),
264
- "--steps", str(steps),
265
- "-W", str(width),
266
- "-H", str(height),
267
- "-o", output_path,
268
- "--offload-to-cpu",
269
- "--diffusion-fa",
270
- "--vae-tiling",
271
- ]
272
-
273
- if seed > 0:
274
- cmd.extend(["--seed", str(seed)])
275
-
276
- if negative_prompt:
277
- cmd.extend(["-n", negative_prompt])
278
-
279
- progress(0.1, desc="Starting generation...")
280
-
281
- try:
282
- # Run stable diffusion.cpp
283
- result = subprocess.run(
284
- cmd,
285
- capture_output=True,
286
- text=True,
287
- timeout=300 # 5 minute timeout
288
- )
289
-
290
- progress(0.9, desc="Processing output...")
291
-
292
- if result.returncode != 0:
293
- return None, f"Error: {result.stderr}"
294
-
295
- if os.path.path.exists(output_path):
296
- progress(1.0, desc="Complete!")
297
- return output_path, "✅ Image generated successfully!"
298
- else:
299
- return None, "Output file not found"
300
-
301
- except subprocess.TimeoutExpired:
302
- return None, "⏰ Generation timed out (5 min limit)"
303
- except Exception as e:
304
- return None, f"❌ Error: {str(e)}"
305
-
306
-
307
- # Create Gradio Interface
308
- with gr.Blocks(
309
- title="Flux Text-to-Image (CPU)",
310
- theme=gr.themes.Soft(),
311
- css="""
312
- .gradio-container {max-width: 900px !important;}
313
- """
314
- ) as demo:
315
-
316
- gr.Markdown("""
317
- # 🎨 Flux Text-to-Image Generator
318
- ### CPU-Powered | stable diffusion.cpp | No GPU Required ⚡
319
- """)
320
-
321
- with gr.Row():
322
- with gr.Column(scale=2):
323
- prompt_input = gr.Textbox(
324
- label="✍️ Prompt",
325
- placeholder="A red fox in snow, detailed, 8k...",
326
- lines=3,
327
- value="a red fox in snow, detailed, 8k"
328
- )
329
-
330
- neg_prompt = gr.Textbox(
331
- label="🚫 Negative Prompt (optional)",
332
- placeholder="blurry, low quality...",
333
- lines=2
334
- )
335
-
336
- with gr.Column(scale=1):
337
- cfg_slider = gr.Slider(
338
- minimum=1.0,
339
- maximum=7.0,
340
- value=1.0,
341
- step=0.5,
342
- label="⚙️ CFG Scale",
343
- info="Lower=faster, Higher=prompt adherence"
344
- )
345
-
346
- steps_slider = gr.Slider(
347
- minimum=1,
348
- maximum=20,
349
- value=4,
350
- step=1,
351
- label="🔄 Inference Steps",
352
- info="4 recommended for speed"
353
- )
354
-
355
- seed_input = gr.Number(
356
- label="🎲 Seed (-1=random)",
357
- value=-1,
358
- precision=0
359
- )
360
-
361
- with gr.Row():
362
- gen_btn = gr.Button("🚀 Generate Image", variant="primary", size="lg")
363
- clear_btn = gr.Button("🗑️ Clear", size="lg")
364
-
365
- with gr.Row():
366
- with gr.Column():
367
- output_image = gr.Image(
368
- label="🖼️ Generated Image",
369
- type="filepath",
370
- height=400
371
- )
372
-
373
- with gr.Column():
374
- status_output = gr.Textbox(
375
- label="📊 Status",
376
- interactive=False
377
- )
378
-
379
- # Event handlers
380
- gen_btn.click(
381
- fn=generate_image,
382
- inputs=[prompt_input, neg_prompt, cfg_slider, steps_slider, seed_input],
383
- outputs=[output_image, status_output]
384
- )
385
-
386
- clear_btn.click(
387
- fn=lambda: (None, "", "", 1.0, 4, -1, None, ""),
388
- outputs=[prompt_input, neg_prompt, cfg_slider, steps_slider, seed_input,
389
- output_image, status_output]
390
- )
391
 
392
- # Launch
393
- if __name__ == "__main__":
394
- demo.launch(
395
- server_name="0.0.0.0",
396
- server_port=7860,
397
- share=False
398
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """
2
  Flux Text-to-Image Generator (CPU Only)
3
+ Auto-builds stable-diffusion.cpp on first run
4
  """
5
 
6
  # ============================================================
7
+ # PART 1: AUTO SETUP - Build & Download Everything
8
  # ============================================================
9
  import os
10
  import sys
11
+ import subprocess
12
  import urllib.request
13
  from pathlib import Path
14
 
15
+ def run_cmd(cmd, description=""):
16
+ """Run shell command and show output"""
17
+ print(f"\n🔧 {description}")
18
+ print(f" Command: {' '.join(cmd) if isinstance(cmd, list) else cmd}")
19
+
20
+ try:
21
+ result = subprocess.run(
22
+ cmd if isinstance(cmd, list) else cmd.split(),
23
+ capture_output=True,
24
+ text=True,
25
+ shell=not isinstance(cmd, list)
26
+ )
27
+
28
+ if result.returncode != 0:
29
+ print(f" ❌ Error:\n{result.stderr}")
30
+ return False
31
+
32
+ print(f" ✅ Success")
33
+ return True
34
+ except Exception as e:
35
+ print(f" ❌ Exception: {e}")
36
+ return False
37
+
38
+ def build_sd_cpp():
39
+ """Build stable-diffusion.cpp from source"""
40
  print("\n" + "="*60)
41
+ print("🏗️ BUILDING STABLE DIFFUSION.CPP")
42
  print("="*60 + "\n")
43
 
44
+ # Check if already built
45
+ sd_cli = Path("./stable-diffusion.cpp/build/bin/sd-cli")
46
+ if sd_cli.exists():
47
+ print("✅ stable-diffusion.cpp already built!")
48
+ return str(sd_cli.absolute())
49
+
50
+ # Clone repository
51
+ if not Path("stable-diffusion.cpp").exists():
52
+ print("📥 Cloning stable-diffusion.cpp repository...")
53
+
54
+ # Try git clone, fallback to download
55
+ if not run_cmd([
56
+ "git", "clone",
57
+ "--depth", "1", # Shallow clone for speed
58
+ "https://github.com/leejet/stable-diffusion.git",
59
+ "stable-diffusion.cpp"
60
+ ], "Clone repo"):
61
+
62
+ print("⚠️ Git failed, trying alternative...")
63
+ return None
64
+
65
+ os.chdir("stable-diffusion.cpp")
66
+
67
+ # Install cmake if needed (for HF Spaces)
68
+ print("\n📦 Ensuring build dependencies...")
69
+ subprocess.run(["apt-get", "update"], capture_output=True)
70
+ subprocess.run(["apt-get", "install", "-y", "cmake", "build-essential"],
71
+ capture_output=True)
72
+
73
+ # Create build directory
74
+ Path("build").mkdir(exist_ok=True)
75
+ os.chdir("build")
76
+
77
+ # Configure with CMake (CPU only!)
78
+ print("\n⚙️ Configuring build (CPU mode)...")
79
+ if not run_cmd([
80
+ "cmake", "..",
81
+ "-DSD_CPU=ON", # CPU backend only
82
+ "-DSD_CUDA=OFF", # Disable CUDA
83
+ "-DCMAKE_BUILD_TYPE=Release"
84
+ ], "CMake configure"):
85
+ os.chdir("../..")
86
+ return None
87
+
88
+ # Build
89
+ print("\n🔨 Compiling... (this may take 5-10 minutes)")
90
+ if not run_cmd([
91
+ "cmake", "--build", ".",
92
+ "--config", "Release",
93
+ f"-j{os.cpu_count() or 2}"
94
+ ], "Build"):
95
+ os.chdir("../..")
96
+ return None
97
+
98
+ os.chdir("../..")
99
+
100
+ # Verify
101
+ if sd_cli.exists():
102
+ print(f"\n✅ Build complete! Binary at: {sd_cli}")
103
+ return str(sd_cli.absolute())
104
+ else:
105
+ print("\n❌ Build failed - binary not found")
106
+ return None
107
+
108
+ def download_models():
109
+ """Download required model files"""
110
+ print("\n" + "="*60)
111
+ print("📥 DOWNLOADING MODELS")
112
+ print("="*60 + "\n")
113
+
114
+ models_dir = Path("models")
115
+ models_dir.mkdir(exist_ok=True)
116
 
 
117
  models = {
118
  "bonsai-flux2-klein-ternary-q2_k.gguf":
119
  "https://huggingface.co/bonsai-models/flux.1-klein-gguf/resolve/main/bonsai-flux2-klein-ternary-q2_k.gguf",
 
123
  "https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF/resolve/main/qwen2.5-1.5b-instruct-q2_k.gguf",
124
  }
125
 
 
126
  for filename, url in models.items():
127
+ filepath = models_dir / filename
128
 
129
  if filepath.exists():
130
  size_mb = filepath.stat().st_size / (1024*1024)
131
+ print(f"✅ {filename} ({size_mb:.1f} MB) - already exists")
132
  else:
133
+ print(f"📥 Downloading {filename}...")
134
  try:
135
  urllib.request.urlretrieve(url, filepath)
136
  size_mb = filepath.stat().st_size / (1024*1024)
137
  print(f" ✅ Saved ({size_mb:.1f} MB)")
138
  except Exception as e:
139
+ print(f" ❌ Failed: {e}")
140
+
141
+ def main_setup():
142
+ """Run all setup steps"""
143
+ print("\n" + "#"*60)
144
+ print("#"*60)
145
+ print("# 🎨 FLUX TEXT-TO-IMAGE SETUP")
146
+ print("#"*60)
147
+ print("#"*60)
148
+
149
+ # Step 1: Build stable-diffusion.cpp
150
+ global SD_CLI_PATH
151
+ SD_CLI_PATH = build_sd_cpp()
152
+
153
+ if not SD_CLI_PATH:
154
+ print("\n⚠️ WARNING: Could not build stable-diffusion.cpp")
155
+ print(" You may need to install it manually.")
156
+ SD_CLI_PATH = "./stable-diffusion.cpp/build/bin/sd-cli"
157
+
158
+ # Step 2: Download models
159
+ download_models()
160
+
161
+ # Step 3: Create outputs dir
162
+ Path("outputs").mkdir(exist_ok=True)
163
 
164
  print("\n" + "="*60)
165
  print("✅ SETUP COMPLETE")
166
+ print("="*60)
167
+ print(f"\nSD CLI Path: {SD_CLI_PATH}")
168
+ print("Models: ./models/")
169
  print("="*60 + "\n")
170
 
171
  # Run setup
172
+ SD_CLI_PATH = None
173
+ main_setup()
174
 
175
  # ============================================================
176
  # PART 2: IMPORTS & CONFIGURATION
177
  # ============================================================
178
  import gradio as gr
 
179
  from datetime import datetime
180
 
 
181
  MODELS_DIR = "./models"
182
  OUTPUTS_DIR = "./outputs"
183
 
 
185
  VAE_MODEL = os.path.join(MODELS_DIR, "flux2-vae.safetensors")
186
  LLM_MODEL = os.path.join(MODELS_DIR, "qwen_3_4b.gguf")
187
 
188
+ # Use the built path or fallback
189
+ SD_CLI = SD_CLI_PATH or "./stable-diffusion.cpp/build/bin/sd-cli"
190
 
191
 
192
  # ============================================================
 
204
  ):
205
  """Generate image using stable diffusion.cpp"""
206
 
207
+ # Verify CLI exists
208
+ if not os.path.exists(SD_CLI):
209
+ return None, f"""❌ Error: sd-cli not found at: {SD_CLI}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
+ Please ensure stable-diffusion.cpp is installed:
212
 
213
+ Option A: Let this app auto-build it (restart the Space)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
+ Option B: Manual installation:
216
+ ```bash
217
+ git clone --depth 1 https://github.com/leejet/stable-diffusion.git
218
+ cd stable-diffusion
219
+ cmake -B build -DSD_CPU=ON
220
+ cmake --build build --config Release -j$(nproc)