Lizug commited on
Commit
6d84e1c
Β·
verified Β·
1 Parent(s): e597021

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +185 -0
  2. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gc
3
+ import random
4
+ import numpy as np
5
+ import torch
6
+ import gradio as gr
7
+ import spaces
8
+ from PIL import Image
9
+ from diffusers.models import QwenImageTransformer2DModel
10
+ from diffusers import QwenImageEditPlusPipeline
11
+ from diffusers.utils import load_image
12
+
13
+ # ── Device setup ──────────────────────────────────────────────────────────────
14
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
+ print("Using device:", device)
16
+
17
+ # ── Model loading ─────────────────────────────────────────────────────────────
18
+ MODEL_ID = "prithivMLmods/FireRed-Image-Edit-1.0-8bit" # 8-bit = lebih hemat VRAM
19
+ dtype = torch.bfloat16
20
+
21
+ transformer = QwenImageTransformer2DModel.from_pretrained(
22
+ MODEL_ID,
23
+ subfolder="transformer",
24
+ torch_dtype=dtype,
25
+ )
26
+
27
+ pipe = QwenImageEditPlusPipeline.from_pretrained(
28
+ MODEL_ID,
29
+ transformer=transformer,
30
+ torch_dtype=dtype,
31
+ ).to(device)
32
+
33
+ MAX_SEED = np.iinfo(np.int32).max
34
+
35
+ # ── Helpers ───────────────────────────────────────────────────────────────────
36
+ def update_dimensions_on_upload(image):
37
+ """Auto-detect best output size from uploaded image."""
38
+ if image is None:
39
+ return 1024, 1024
40
+ pil = Image.fromarray(image) if not isinstance(image, Image.Image) else image
41
+ w, h = pil.size
42
+ # snap to nearest multiple of 64, cap at 1024
43
+ w = min(round(w / 64) * 64, 1024)
44
+ h = min(round(h / 64) * 64, 1024)
45
+ return w, h
46
+
47
+
48
+ # ── Inference ─────────────────────────────────────────────────────────────────
49
+ @spaces.GPU(duration=90)
50
+ def generate(
51
+ images,
52
+ prompt,
53
+ seed,
54
+ randomize_seed,
55
+ width,
56
+ height,
57
+ guidance_scale,
58
+ num_inference_steps,
59
+ ):
60
+ if not images:
61
+ raise gr.Error("⚠️ Upload minimal 1 gambar dulu ya!")
62
+ if not prompt.strip():
63
+ raise gr.Error("⚠️ Tulis prompt dulu – apa yang mau diubah?")
64
+
65
+ if randomize_seed:
66
+ seed = random.randint(0, MAX_SEED)
67
+
68
+ generator = torch.Generator(device=device).manual_seed(seed)
69
+
70
+ pil_images = []
71
+ for img in images:
72
+ if img is None:
73
+ continue
74
+ pil = Image.fromarray(img).convert("RGB") if not isinstance(img, Image.Image) else img.convert("RGB")
75
+ pil_images.append(pil)
76
+
77
+ result = pipe(
78
+ image=pil_images,
79
+ prompt=prompt,
80
+ width=width,
81
+ height=height,
82
+ guidance_scale=guidance_scale,
83
+ num_inference_steps=num_inference_steps,
84
+ generator=generator,
85
+ )
86
+
87
+ gc.collect()
88
+ torch.cuda.empty_cache()
89
+
90
+ return result.images[0], seed
91
+
92
+
93
+ # ── UI ────────────────────────────────────────────────────────────────────────
94
+ TITLE = """
95
+ <div style="text-align:center; padding: 12px 0 4px">
96
+ <h1 style="font-size:2rem; font-weight:700; margin:0">πŸ”₯ FireRed Image Edit</h1>
97
+ <p style="color:#666; margin:6px 0 0">
98
+ Upload foto β†’ tulis instruksi β†’ dapatkan hasil edit berkualitas tinggi
99
+ </p>
100
+ </div>
101
+ """
102
+
103
+ EXAMPLES = [
104
+ [None, "Ganti background dengan pantai tropis saat sunset", 42, False, 1024, 1024, 3.5, 4],
105
+ [None, "Ubah baju jadi warna merah dengan motif batik", 7, False, 1024, 1024, 3.5, 4],
106
+ [None, "Tambahkan efek snow/salju di seluruh gambar", 0, False, 1024, 1024, 3.5, 4],
107
+ ]
108
+
109
+ css = """
110
+ #col-left { min-width: 360px; }
111
+ #col-right { min-width: 360px; }
112
+ .gr-button-primary { background: #e63946 !important; border-color: #e63946 !important; }
113
+ footer { display: none !important; }
114
+ """
115
+
116
+ with gr.Blocks(css=css, title="FireRed Image Edit") as demo:
117
+ gr.HTML(TITLE)
118
+
119
+ with gr.Row():
120
+ # ── Left column ───────────────────────────────────────────────────────
121
+ with gr.Column(elem_id="col-left"):
122
+ input_images = gr.Gallery(
123
+ label="πŸ“Έ Upload Gambar (1–3 foto)",
124
+ columns=3,
125
+ rows=1,
126
+ height=280,
127
+ type="numpy",
128
+ interactive=True,
129
+ )
130
+
131
+ prompt = gr.Textbox(
132
+ label="✏️ Instruksi Edit",
133
+ placeholder="Contoh: ganti warna baju jadi biru tua, tambahkan kacamata hitam...",
134
+ lines=3,
135
+ )
136
+
137
+ with gr.Row():
138
+ run_btn = gr.Button("πŸ”₯ Generate", variant="primary", scale=3)
139
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", scale=1)
140
+
141
+ with gr.Accordion("βš™οΈ Advanced Settings", open=False):
142
+ seed = gr.Slider(0, MAX_SEED, value=42, step=1, label="Seed")
143
+ randomize_seed = gr.Checkbox(value=True, label="Randomize seed")
144
+
145
+ with gr.Row():
146
+ width = gr.Slider(512, 1024, value=1024, step=64, label="Width")
147
+ height = gr.Slider(512, 1024, value=1024, step=64, label="Height")
148
+
149
+ guidance_scale = gr.Slider(1.0, 7.0, value=3.5, step=0.1, label="Guidance Scale")
150
+ num_inference_steps = gr.Slider(1, 8, value=4, step=1, label="Steps (4 = fast)")
151
+
152
+ # ── Right column ──────────────────────────────────────────────────────
153
+ with gr.Column(elem_id="col-right"):
154
+ output_image = gr.Image(label="✨ Hasil Edit", type="pil", height=480)
155
+ used_seed = gr.Number(label="Seed yang dipakai", interactive=False)
156
+
157
+ # ── Event wiring ──────────────────────────────────────────────────────────
158
+ input_images.upload(
159
+ fn=lambda imgs: update_dimensions_on_upload(imgs[0] if imgs else None),
160
+ inputs=input_images,
161
+ outputs=[width, height],
162
+ )
163
+
164
+ run_btn.click(
165
+ fn=generate,
166
+ inputs=[input_images, prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps],
167
+ outputs=[output_image, used_seed],
168
+ )
169
+
170
+ clear_btn.click(
171
+ fn=lambda: (None, "", 42, True, 1024, 1024, 3.5, 4, None, 0),
172
+ outputs=[input_images, prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps, output_image, used_seed],
173
+ )
174
+
175
+ gr.Markdown("""
176
+ ---
177
+ **Tips:**
178
+ - πŸ–ΌοΈ Upload 1–3 gambar sekaligus untuk multi-image editing (misal: virtual try-on)
179
+ - ⚑ Steps = 4 sudah cukup cepat dan hasilnya bagus
180
+ - 🌱 Seed tetap = hasil konsisten; centang *Randomize* untuk variasi
181
+ - πŸ”₯ Model: [prithivMLmods/FireRed-Image-Edit-1.0-8bit](https://huggingface.co/prithivMLmods/FireRed-Image-Edit-1.0-8bit)
182
+ """)
183
+
184
+ if __name__ == "__main__":
185
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ transformers
4
+ diffusers>=0.37.0
5
+ accelerate
6
+ bitsandbytes
7
+ gradio
8
+ spaces
9
+ Pillow
10
+ numpy