yash184 commited on
Commit
c61154b
·
verified ·
1 Parent(s): 4606d64

Update Dockerfile

Browse files

FROM python:3.11-slim

WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

EXPOSE 7860

CMD ["python", "app.py"]

Files changed (1) hide show
  1. Dockerfile +0 -471
Dockerfile CHANGED
@@ -1,471 +0,0 @@
1
- import gradio as gr
2
- import numpy as np
3
- import torch
4
- from PIL import Image
5
- import os
6
- from pathlib import Path
7
- import logging
8
- from typing import Optional, Tuple
9
- import time
10
- from diffusers import StableDiffusionXLImg2ImgPipeline, StableDiffusionXLPipeline
11
- import gguf
12
- import ctypes
13
-
14
- # Configure logging
15
- logging.basicConfig(level=logging.INFO)
16
- logger = logging.getLogger(__name__)
17
-
18
- # ===================== DEVICE & CONFIG =====================
19
- DEVICE = "cpu" # CPU-only for HuggingFace Spaces
20
- DTYPE = torch.float32 # CPU ke liye float32 use karna zaroori hai
21
-
22
- # FLUX.1 Model Config
23
- MODEL_CONFIG = {
24
- "model_id": "unsloth/FLUX.1-Kontext-dev-GGUF",
25
- "gguf_file": "flux1-dev-Q4_K_M.gguf", # Quantized version
26
- "use_safetensors": False,
27
- }
28
-
29
- # Fallback to Stability if GGUF load nahi hota
30
- FALLBACK_MODEL = "stabilityai/stable-diffusion-xl-base-1.0"
31
-
32
- # ===================== GLOBAL STATE =====================
33
- class PipelineManager:
34
- def __init__(self):
35
- self.txt2img_pipe = None
36
- self.img2img_pipe = None
37
- self.model_loaded = False
38
- self.current_model = None
39
- self.load_lock = False
40
-
41
- def load_flux_gguf(self):
42
- """Load FLUX.1 GGUF model from HF"""
43
- try:
44
- logger.info("📥 Loading FLUX.1 GGUF model...")
45
-
46
- # Try loading from HF hub with GGUF support
47
- from huggingface_hub import hf_hub_download
48
-
49
- model_path = hf_hub_download(
50
- repo_id=MODEL_CONFIG["model_id"],
51
- filename=MODEL_CONFIG["gguf_file"],
52
- cache_dir="./models"
53
- )
54
-
55
- logger.info(f"✅ GGUF downloaded: {model_path}")
56
-
57
- # Load using llama-cpp for GGUF
58
- from llama_cpp import Llama
59
- llm = Llama.from_pretrained(
60
- MODEL_CONFIG["model_id"],
61
- filename=MODEL_CONFIG["gguf_file"],
62
- n_gpu_layers=-1, # CPU-only, to GPU layers = -1
63
- n_threads=os.cpu_count(),
64
- verbose=False
65
- )
66
-
67
- logger.info("✅ FLUX.1 GGUF loaded successfully!")
68
- self.current_model = "flux1-gguf"
69
- return True
70
-
71
- except Exception as e:
72
- logger.warning(f"⚠️ GGUF loading failed: {e}")
73
- return False
74
-
75
- def load_flux_diffusers(self):
76
- """Load FLUX.1 using diffusers (as fallback)"""
77
- try:
78
- logger.info("📥 Loading FLUX.1 via diffusers...")
79
-
80
- # Lighter quantized version for CPU
81
- self.txt2img_pipe = StableDiffusionXLPipeline.from_pretrained(
82
- "stabilityai/stable-diffusion-xl-base-1.0",
83
- torch_dtype=DTYPE,
84
- use_safetensors=True,
85
- variant="fp32"
86
- )
87
-
88
- self.txt2img_pipe = self.txt2img_pipe.to(DEVICE)
89
- self.txt2img_pipe.enable_attention_slicing() # CPU ke liye memory optimize
90
-
91
- self.img2img_pipe = StableDiffusionXLImg2ImgPipeline.from_pretrained(
92
- "stabilityai/stable-diffusion-xl-refiner-1.0",
93
- torch_dtype=DTYPE,
94
- use_safetensors=True,
95
- variant="fp32"
96
- )
97
-
98
- self.img2img_pipe = self.img2img_pipe.to(DEVICE)
99
- self.img2img_pipe.enable_attention_slicing()
100
-
101
- logger.info("✅ FLUX.1 diffusers pipeline loaded!")
102
- self.current_model = "flux1-diffusers"
103
- self.model_loaded = True
104
- return True
105
-
106
- except Exception as e:
107
- logger.error(f"❌ Diffusers loading failed: {e}")
108
- return False
109
-
110
- def initialize(self):
111
- """Initialize pipelines"""
112
- if self.load_lock:
113
- return
114
-
115
- self.load_lock = True
116
-
117
- # Try GGUF first
118
- if not self.load_flux_gguf():
119
- # Fallback to diffusers
120
- self.load_flux_diffusers()
121
-
122
- self.load_lock = False
123
-
124
- def generate_txt2img(
125
- self,
126
- prompt: str,
127
- negative_prompt: str = "",
128
- num_inference_steps: int = 20,
129
- guidance_scale: float = 7.5,
130
- height: int = 768,
131
- width: int = 768,
132
- seed: int = -1
133
- ) -> Image.Image:
134
- """Text-to-Image generation"""
135
-
136
- if not self.model_loaded:
137
- raise RuntimeError("Model not initialized")
138
-
139
- if seed == -1:
140
- seed = int(time.time())
141
-
142
- generator = torch.Generator(device=DEVICE).manual_seed(seed)
143
-
144
- logger.info(f"🎨 Generating txt2img: {prompt[:50]}...")
145
-
146
- with torch.no_grad(): # CPU memory optimization
147
- image = self.txt2img_pipe(
148
- prompt=prompt,
149
- negative_prompt=negative_prompt,
150
- num_inference_steps=num_inference_steps,
151
- guidance_scale=guidance_scale,
152
- height=height,
153
- width=width,
154
- generator=generator
155
- ).images[0]
156
-
157
- logger.info("✅ Generation complete!")
158
- return image
159
-
160
- def generate_img2img(
161
- self,
162
- prompt: str,
163
- image: Image.Image,
164
- negative_prompt: str = "",
165
- num_inference_steps: int = 20,
166
- guidance_scale: float = 7.5,
167
- strength: float = 0.8,
168
- seed: int = -1
169
- ) -> Image.Image:
170
- """Image-to-Image generation"""
171
-
172
- if not self.model_loaded:
173
- raise RuntimeError("Model not initialized")
174
-
175
- if seed == -1:
176
- seed = int(time.time())
177
-
178
- generator = torch.Generator(device=DEVICE).manual_seed(seed)
179
-
180
- # Resize image to 768x768
181
- image = image.resize((768, 768), Image.Resampling.LANCZOS)
182
-
183
- logger.info(f"🖼️ Generating img2img: {prompt[:50]}...")
184
-
185
- with torch.no_grad():
186
- image = self.img2img_pipe(
187
- prompt=prompt,
188
- image=image,
189
- negative_prompt=negative_prompt,
190
- num_inference_steps=num_inference_steps,
191
- guidance_scale=guidance_scale,
192
- strength=strength,
193
- generator=generator
194
- ).images[0]
195
-
196
- logger.info("✅ Generation complete!")
197
- return image
198
-
199
- # Initialize global pipeline manager
200
- pipeline_manager = PipelineManager()
201
-
202
- # ===================== GRADIO INTERFACE =====================
203
-
204
- def generate_txt2img_ui(
205
- prompt: str,
206
- negative_prompt: str,
207
- num_steps: int,
208
- guidance: float,
209
- height: int,
210
- width: int,
211
- seed: int
212
- ):
213
- """Gradio wrapper for txt2img"""
214
- try:
215
- if not pipeline_manager.model_loaded:
216
- return None, "❌ Model not loaded yet. Please wait..."
217
-
218
- image = pipeline_manager.generate_txt2img(
219
- prompt=prompt,
220
- negative_prompt=negative_prompt,
221
- num_inference_steps=num_steps,
222
- guidance_scale=guidance,
223
- height=height,
224
- width=width,
225
- seed=seed
226
- )
227
-
228
- return image, "✅ Generation successful!"
229
-
230
- except Exception as e:
231
- logger.error(f"Error in txt2img: {e}")
232
- return None, f"❌ Error: {str(e)}"
233
-
234
- def generate_img2img_ui(
235
- prompt: str,
236
- image: Image.Image,
237
- negative_prompt: str,
238
- num_steps: int,
239
- guidance: float,
240
- strength: float,
241
- seed: int
242
- ):
243
- """Gradio wrapper for img2img"""
244
- try:
245
- if image is None:
246
- return None, "❌ Please upload an image first"
247
-
248
- if not pipeline_manager.model_loaded:
249
- return None, "❌ Model not loaded yet. Please wait..."
250
-
251
- result = pipeline_manager.generate_img2img(
252
- prompt=prompt,
253
- image=image,
254
- negative_prompt=negative_prompt,
255
- num_inference_steps=num_steps,
256
- guidance_scale=guidance,
257
- strength=strength,
258
- seed=seed
259
- )
260
-
261
- return result, "✅ Generation successful!"
262
-
263
- except Exception as e:
264
- logger.error(f"Error in img2img: {e}")
265
- return None, f"❌ Error: {str(e)}"
266
-
267
- # ===================== GRADIO BLOCKS UI =====================
268
-
269
- with gr.Blocks(title="FLUX.1 GGUF - Text/Image Generator", theme=gr.themes.Soft()) as demo:
270
-
271
- gr.Markdown("# 🎨 FLUX.1 GGUF Generator")
272
- gr.Markdown("CPU-optimized Text-to-Image & Image-to-Image generation")
273
-
274
- # Status indicator
275
- status = gr.Textbox(value="⏳ Loading model...", interactive=False, label="Status")
276
-
277
- with gr.Tabs():
278
-
279
- # ===== TAB 1: TEXT-TO-IMAGE =====
280
- with gr.Tab("📝 Text-to-Image"):
281
- with gr.Row():
282
- with gr.Column(scale=1):
283
- txt2img_prompt = gr.Textbox(
284
- label="Prompt",
285
- placeholder="A beautiful sunset over mountains...",
286
- lines=3
287
- )
288
- txt2img_negative = gr.Textbox(
289
- label="Negative Prompt",
290
- placeholder="blurry, low quality, distorted...",
291
- lines=2
292
- )
293
-
294
- with gr.Row():
295
- txt2img_height = gr.Slider(
296
- minimum=256,
297
- maximum=1024,
298
- value=768,
299
- step=64,
300
- label="Height"
301
- )
302
- txt2img_width = gr.Slider(
303
- minimum=256,
304
- maximum=1024,
305
- value=768,
306
- step=64,
307
- label="Width"
308
- )
309
-
310
- with gr.Row():
311
- txt2img_steps = gr.Slider(
312
- minimum=1,
313
- maximum=50,
314
- value=20,
315
- step=1,
316
- label="Inference Steps"
317
- )
318
- txt2img_guidance = gr.Slider(
319
- minimum=1,
320
- maximum=15,
321
- value=7.5,
322
- step=0.5,
323
- label="Guidance Scale"
324
- )
325
-
326
- txt2img_seed = gr.Number(
327
- value=-1,
328
- label="Seed (-1 = random)",
329
- precision=0
330
- )
331
-
332
- txt2img_generate = gr.Button(
333
- "🎨 Generate Image",
334
- variant="primary",
335
- size="lg"
336
- )
337
-
338
- with gr.Column(scale=1):
339
- txt2img_output = gr.Image(label="Generated Image", type="pil")
340
- txt2img_status = gr.Textbox(interactive=False, label="Result")
341
-
342
- txt2img_generate.click(
343
- generate_txt2img_ui,
344
- inputs=[
345
- txt2img_prompt,
346
- txt2img_negative,
347
- txt2img_steps,
348
- txt2img_guidance,
349
- txt2img_height,
350
- txt2img_width,
351
- txt2img_seed
352
- ],
353
- outputs=[txt2img_output, txt2img_status]
354
- )
355
-
356
- # ===== TAB 2: IMAGE-TO-IMAGE =====
357
- with gr.Tab("🖼️ Image-to-Image"):
358
- with gr.Row():
359
- with gr.Column(scale=1):
360
- img2img_input = gr.Image(
361
- label="Input Image",
362
- type="pil"
363
- )
364
-
365
- img2img_prompt = gr.Textbox(
366
- label="Prompt",
367
- placeholder="Transform the image to...",
368
- lines=3
369
- )
370
- img2img_negative = gr.Textbox(
371
- label="Negative Prompt",
372
- placeholder="blurry, low quality...",
373
- lines=2
374
- )
375
-
376
- with gr.Row():
377
- img2img_steps = gr.Slider(
378
- minimum=1,
379
- maximum=50,
380
- value=20,
381
- step=1,
382
- label="Inference Steps"
383
- )
384
- img2img_guidance = gr.Slider(
385
- minimum=1,
386
- maximum=15,
387
- value=7.5,
388
- step=0.5,
389
- label="Guidance Scale"
390
- )
391
-
392
- img2img_strength = gr.Slider(
393
- minimum=0,
394
- maximum=1,
395
- value=0.8,
396
- step=0.05,
397
- label="Strength (0=no change, 1=full change)"
398
- )
399
-
400
- img2img_seed = gr.Number(
401
- value=-1,
402
- label="Seed (-1 = random)",
403
- precision=0
404
- )
405
-
406
- img2img_generate = gr.Button(
407
- "🖼️ Generate Image",
408
- variant="primary",
409
- size="lg"
410
- )
411
-
412
- with gr.Column(scale=1):
413
- img2img_output = gr.Image(label="Generated Image", type="pil")
414
- img2img_status = gr.Textbox(interactive=False, label="Result")
415
-
416
- img2img_generate.click(
417
- generate_img2img_ui,
418
- inputs=[
419
- img2img_prompt,
420
- img2img_input,
421
- img2img_negative,
422
- img2img_steps,
423
- img2img_guidance,
424
- img2img_strength,
425
- img2img_seed
426
- ],
427
- outputs=[img2img_output, img2img_status]
428
- )
429
-
430
- # ===== TAB 3: INFO =====
431
- with gr.Tab("ℹ️ Info"):
432
- gr.Markdown(f"""
433
- ## Model Information
434
- - **Model**: {MODEL_CONFIG['model_id']}
435
- - **Device**: CPU (HuggingFace Spaces)
436
- - **Data Type**: {DTYPE}
437
- - **Features**: Text-to-Image, Image-to-Image
438
-
439
- ## Tips
440
- - ⏱️ CPU inference slower than GPU, expect 2-5 min per image
441
- - 🎯 Higher steps = better quality but slower
442
- - 📐 Larger dimensions = slower generation
443
- - 💡 Detailed prompts = better results
444
- - 🔄 Strength 0.8-0.9 recommended for img2img
445
- """)
446
-
447
- # ===================== STARTUP =====================
448
-
449
- def on_load():
450
- """Initialize model on startup"""
451
- logger.info("🚀 Starting FLUX.1 App...")
452
- pipeline_manager.initialize()
453
-
454
- if pipeline_manager.model_loaded:
455
- return "✅ Model loaded! Ready to generate."
456
- else:
457
- return "⚠️ Model initialization in progress or fallback mode active."
458
-
459
- # Load model on app start
460
- gr.on_load(on_load)
461
-
462
- # ===================== LAUNCH =====================
463
-
464
- if __name__ == "__main__":
465
- demo.launch(
466
- server_name="0.0.0.0",
467
- server_port=7860,
468
- share=True,
469
- show_error=True,
470
- debug=False
471
- )