yash184 commited on
Commit
60441ff
·
verified ·
1 Parent(s): 936b7e3

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +471 -30
Dockerfile CHANGED
@@ -1,30 +1,471 @@
1
- # Base image llama.cpp se hi le rahe hain
2
- FROM ghcr.io/ggml-org/llama.cpp:full
3
-
4
- WORKDIR /app
5
-
6
- # System dependencies install karna
7
- RUN apt update && apt install -y python3 python3-pip python3-venv
8
-
9
- # Virtual environment setup
10
- RUN python3 -m venv /opt/venv
11
- ENV PATH="/opt/venv/bin:$PATH"
12
-
13
- # Python tools install karna
14
- RUN pip install -U pip huggingface_hub
15
-
16
- # Model download karna (Qwen2.5-Coder-3B-Instruct)
17
- RUN python3 -c 'from huggingface_hub import hf_hub_download; \
18
- repo="bartowski/Qwen2.5-Coder-3B-Instruct-GGUF"; \
19
- hf_hub_download(repo_id=repo, filename="Qwen2.5-Coder-3B-Instruct-Q4_K_M.gguf", local_dir="/app")'
20
-
21
- # Server start karne ka command
22
- CMD ["--server", \
23
- "-m", "/app/Qwen2.5-Coder-3B-Instruct-Q4_K_M.gguf", \
24
- "--host", "0.0.0.0", \
25
- "--port", "7860", \
26
- "-t", "2", \
27
- "--cache-type-k", "q8_0", \
28
- "--cache-type-v", "iq4_nl", \
29
- "-c", "18192", \
30
- "-n", "4096"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ )