K1Z3M1112 commited on
Commit
2f6eac7
·
verified ·
1 Parent(s): 8ef50c8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +248 -88
app.py CHANGED
@@ -1,138 +1,242 @@
1
- import spaces
2
  import gradio as gr
3
  import torch
4
  from PIL import Image
5
- from transformers import AutoProcessor
6
- from longcat_image.models import LongCatImageTransformer2DModel
7
- from longcat_image.pipelines import LongCatImageEditPipeline
8
  import numpy as np
9
  import random
 
10
 
11
- # --- Model Loading ---
12
- device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
 
13
 
14
- # Image Edit Model
15
- edit_model_id = 'meituan-longcat/LongCat-Image-Edit'
16
- print(f"🔄 Loading Image Edit model from {edit_model_id}...")
17
- edit_text_processor = AutoProcessor.from_pretrained(
18
- edit_model_id,
19
- subfolder='tokenizer'
20
- )
21
 
22
- edit_transformer = LongCatImageTransformer2DModel.from_pretrained(
23
- edit_model_id,
24
- subfolder='transformer',
25
- torch_dtype=torch.bfloat16,
26
- use_safetensors=True
27
- ).to(device)
 
 
 
 
 
 
 
 
 
 
28
 
29
- edit_pipe = LongCatImageEditPipeline.from_pretrained(
30
- edit_model_id,
31
- transformer=edit_transformer,
32
- text_processor=edit_text_processor,
33
- )
34
- edit_pipe.to(device, torch.bfloat16)
35
 
36
- print(f"✅ Image Edit model loaded successfully on {device}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- MAX_SEED = np.iinfo(np.int32).max
 
 
 
 
 
 
 
 
39
 
40
- @spaces.GPU(duration=120)
41
  def edit_image(
42
  input_image: Image.Image,
43
  prompt: str,
44
  seed: int,
45
  randomize_seed: bool,
46
- guidance_scale: float = 4.5,
47
- num_inference_steps: int = 50,
48
  progress=gr.Progress()
49
  ):
50
- """Edit image based on text prompt"""
51
  if input_image is None:
52
- raise gr.Error("Please upload an image first")
53
  if not prompt or prompt.strip() == "":
54
- raise gr.Error("Please enter an edit instruction")
55
 
56
  if randomize_seed:
57
  seed = random.randint(0, MAX_SEED)
58
 
59
  try:
60
- progress(0.1, desc="Preparing image...")
 
 
 
 
 
61
  if input_image.mode != 'RGB':
62
  input_image = input_image.convert('RGB')
63
 
64
- progress(0.2, desc="Generating edited image...")
 
 
 
 
 
 
 
 
 
65
  generator = torch.Generator(device).manual_seed(seed)
66
 
 
 
 
67
  with torch.inference_mode():
68
- output = edit_pipe(
69
  input_image,
70
  prompt,
71
  negative_prompt="",
72
  guidance_scale=guidance_scale,
73
  num_inference_steps=num_inference_steps,
74
  num_images_per_prompt=1,
75
- generator=generator
 
76
  )
77
 
78
- progress(1.0, desc="Done!")
79
- return output.images[0], seed
 
 
 
 
 
 
80
 
81
  except Exception as e:
82
- raise gr.Error(f"Error during image editing: {str(e)}")
83
-
84
- # Image editing examples
85
- edit_examples = [
86
- ["assets/example_cat.jpg", "make the cat wear a red hat"],
87
- ["assets/example_landscape.jpg", "add a rainbow in the sky"],
88
- ["assets/example_portrait.jpg", "change the hairstyle to curly"],
89
- ]
90
 
91
  css = """
92
  #col-container {
93
- margin: 0 auto;
94
- max-width: 960px;
95
  }
96
  .generate-btn {
97
- background: linear-gradient(90deg, #4B79A1 0%, #283E51 100%) !important;
98
- border: none !important;
99
- color: white !important;
 
100
  }
101
  .generate-btn:hover {
102
- transform: translateY(-2px);
103
- box-shadow: 0 5px 15px rgba(0,0,0,0.2);
104
  }
105
- .image-upload {
106
- min-height: 300px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
  """
109
 
110
  with gr.Blocks(css=css, theme=gr.themes.Soft()) as app:
111
  gr.HTML("""
112
  <center>
113
- <h1>LongCat-Image 6B - Image Editor</h1>
114
- <p>Upload an image and describe how you want to edit it</p>
 
 
 
 
115
  </center>
116
  """)
117
 
118
  with gr.Column(elem_id="col-container"):
 
 
 
 
 
 
 
 
 
 
119
  with gr.Row():
120
  with gr.Column(scale=1):
121
  # Input Image
122
  input_image = gr.Image(
123
- label="Input Image",
124
  type="pil",
125
- elem_classes=["image-upload"]
 
126
  )
127
 
128
  # Edit Prompt
129
  prompt = gr.Textbox(
130
- label="Edit Instruction",
131
- placeholder="Describe how you want to edit the image...",
132
- lines=3
133
  )
134
 
135
- with gr.Accordion("Advanced Settings", open=False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  with gr.Row():
137
  seed = gr.Slider(
138
  label="Seed",
@@ -142,29 +246,31 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as app:
142
  step=1
143
  )
144
  randomize_seed = gr.Checkbox(
145
- label="Randomize seed",
146
  value=True
147
  )
148
 
149
  with gr.Row():
150
  steps = gr.Slider(
151
- label="Inference Steps",
152
- value=50,
153
  minimum=10,
154
- maximum=100,
155
- step=1
 
156
  )
157
  guidance_scale = gr.Slider(
158
  label="Guidance Scale",
159
- value=4.5,
160
  minimum=1.0,
161
- maximum=20.0,
162
- step=0.5
 
163
  )
164
 
165
  # Generate Button
166
  generate_btn = gr.Button(
167
- "🎨 Edit Image",
168
  variant='primary',
169
  elem_classes=["generate-btn"],
170
  scale=1
@@ -173,25 +279,62 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as app:
173
  with gr.Column(scale=1):
174
  # Output Image
175
  output_image = gr.Image(
176
- label="Edited Image",
177
  type="pil",
178
- elem_classes=["image-upload"]
 
179
  )
180
 
181
- # Seed output
182
- seed_output = gr.Number(
183
- label="Used Seed",
184
- visible=True
185
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
- # Examples
188
  gr.Examples(
189
- examples=edit_examples,
 
 
 
 
190
  inputs=[input_image, prompt],
191
- outputs=[output_image, seed_output],
192
- fn=edit_image,
193
- cache_examples=False,
194
- label="Try these examples:"
195
  )
196
 
197
  # Connect the button
@@ -205,7 +348,7 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as app:
205
  guidance_scale,
206
  steps
207
  ],
208
- outputs=[output_image, seed_output]
209
  )
210
 
211
  # Also allow prompt submission with Enter
@@ -219,7 +362,24 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as app:
219
  guidance_scale,
220
  steps
221
  ],
222
- outputs=[output_image, seed_output]
223
  )
224
 
225
- app.launch(share=True, mcp_server=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import torch
3
  from PIL import Image
 
 
 
4
  import numpy as np
5
  import random
6
+ import time
7
 
8
+ # บังคับใช้ CPU
9
+ device = torch.device('cpu')
10
+ print(f"Using device: {device}")
11
 
12
+ MAX_SEED = np.iinfo(np.int32).max
 
 
 
 
 
 
13
 
14
+ def load_edit_model():
15
+ """โหลดโมเดลสำหรับ CPU"""
16
+ try:
17
+ from transformers import AutoProcessor
18
+ from longcat_image.models import LongCatImageTransformer2DModel
19
+ from longcat_image.pipelines import LongCatImageEditPipeline
20
+
21
+ edit_model_id = 'meituan-longcat/LongCat-Image-Edit'
22
+ print(f"🔄 Loading Image Edit model from {edit_model_id}...")
23
+ print("⚠️ Using CPU mode - this will be slower but no GPU memory issues")
24
+
25
+ # โหลดโมเดลแบบ float32 สำหรับ CPU
26
+ edit_text_processor = AutoProcessor.from_pretrained(
27
+ edit_model_id,
28
+ subfolder='tokenizer'
29
+ )
30
 
31
+ edit_transformer = LongCatImageTransformer2DModel.from_pretrained(
32
+ edit_model_id,
33
+ subfolder='transformer',
34
+ torch_dtype=torch.float32, # ใช้ float32 สำหรับ CPU
35
+ use_safetensors=True
36
+ ).to(device)
37
 
38
+ edit_pipe = LongCatImageEditPipeline.from_pretrained(
39
+ edit_model_id,
40
+ transformer=edit_transformer,
41
+ text_processor=edit_text_processor,
42
+ torch_dtype=torch.float32
43
+ )
44
+ edit_pipe.to(device)
45
+
46
+ # ปิด offload เพื่อป้องกันปัญหา
47
+ edit_pipe.unet = edit_pipe.unet.to(device)
48
+ if hasattr(edit_pipe, 'vae'):
49
+ edit_pipe.vae = edit_pipe.vae.to(device)
50
+
51
+ print(f"✅ Image Edit model loaded successfully on {device}")
52
+ return edit_pipe
53
+ except Exception as e:
54
+ print(f"Error loading model: {e}")
55
+ return None
56
 
57
+ # ตัวแปร global สำหรับโมเดล
58
+ edit_pipe = None
59
+
60
+ def get_edit_pipe():
61
+ """โหลดโมเดลเมื่อต้องการใช้จริง"""
62
+ global edit_pipe
63
+ if edit_pipe is None:
64
+ edit_pipe = load_edit_model()
65
+ return edit_pipe
66
 
 
67
  def edit_image(
68
  input_image: Image.Image,
69
  prompt: str,
70
  seed: int,
71
  randomize_seed: bool,
72
+ guidance_scale: float = 4.0,
73
+ num_inference_steps: int = 20, # ลด steps สำหรับ CPU
74
  progress=gr.Progress()
75
  ):
76
+ """Edit image based on text prompt - CPU version"""
77
  if input_image is None:
78
+ raise gr.Error("กรุณาอัพโหลดภาพก่อน")
79
  if not prompt or prompt.strip() == "":
80
+ raise gr.Error("กรุณาระบุคำสั่งการแก้ไขภาพ")
81
 
82
  if randomize_seed:
83
  seed = random.randint(0, MAX_SEED)
84
 
85
  try:
86
+ progress(0.1, desc="กำลังโหลดโมเดล...")
87
+ pipe = get_edit_pipe()
88
+ if pipe is None:
89
+ raise gr.Error("ไม่สามารถโหลดโมเดลได้ กรุณาตรวจสอบการติดตั้ง")
90
+
91
+ progress(0.3, desc="กำลังเตรียมภาพ...")
92
  if input_image.mode != 'RGB':
93
  input_image = input_image.convert('RGB')
94
 
95
+ # Resize image เพื่อเพิ่มความเร็ว (CPU ต้องการภาพขนาดเล็ก)
96
+ max_size = 512 # ขนาดเล็กสำหรับ CPU
97
+ if max(input_image.size) > max_size:
98
+ ratio = max_size / max(input_image.size)
99
+ new_width = int(input_image.width * ratio)
100
+ new_height = int(input_image.height * ratio)
101
+ input_image = input_image.resize((new_width, new_height), Image.LANCZOS)
102
+ print(f"ปรับขนาดภาพเป็น {new_width}x{new_height} สำหรับ CPU")
103
+
104
+ progress(0.5, desc="กำลังสร้างภาพ... (โปรดรอ 2-5 นาที)")
105
  generator = torch.Generator(device).manual_seed(seed)
106
 
107
+ # เริ่มจับเวลา
108
+ start_time = time.time()
109
+
110
  with torch.inference_mode():
111
+ output = pipe(
112
  input_image,
113
  prompt,
114
  negative_prompt="",
115
  guidance_scale=guidance_scale,
116
  num_inference_steps=num_inference_steps,
117
  num_images_per_prompt=1,
118
+ generator=generator,
119
+ output_type="pil"
120
  )
121
 
122
+ # คำนวณเวลา
123
+ elapsed_time = time.time() - start_time
124
+ minutes = int(elapsed_time // 60)
125
+ seconds = int(elapsed_time % 60)
126
+
127
+ progress(1.0, desc=f"เสร็จสิ้น! ใช้เวลา {minutes} นาที {seconds} วินาที")
128
+
129
+ return output.images[0], seed, f"ใช้เวลา: {minutes} นาที {seconds} วินาที"
130
 
131
  except Exception as e:
132
+ print(f"Error: {str(e)}")
133
+ raise gr.Error(f"เกิดข้อผิดพลาด: {str(e)}")
 
 
 
 
 
 
134
 
135
  css = """
136
  #col-container {
137
+ margin: 0 auto;
138
+ max-width: 900px;
139
  }
140
  .generate-btn {
141
+ background: linear-gradient(90deg, #4CAF50 0%, #2E7D32 100%) !important;
142
+ border: none !important;
143
+ color: white !important;
144
+ font-weight: bold !important;
145
  }
146
  .generate-btn:hover {
147
+ transform: translateY(-2px);
148
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2) !important;
149
  }
150
+ .cpu-warning {
151
+ background-color: #e3f2fd;
152
+ border: 2px solid #2196F3;
153
+ border-radius: 10px;
154
+ padding: 15px;
155
+ margin: 15px 0;
156
+ color: #1565c0;
157
+ }
158
+ .time-info {
159
+ background-color: #e8f5e9;
160
+ border: 1px solid #4CAF50;
161
+ border-radius: 8px;
162
+ padding: 10px;
163
+ margin: 10px 0;
164
+ color: #2E7D32;
165
+ }
166
+ .image-box {
167
+ border: 2px dashed #ddd;
168
+ border-radius: 10px;
169
+ padding: 10px;
170
+ background: #fafafa;
171
  }
172
  """
173
 
174
  with gr.Blocks(css=css, theme=gr.themes.Soft()) as app:
175
  gr.HTML("""
176
  <center>
177
+ <h1 style="background: linear-gradient(90deg, #4CAF50, #2E7D32); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px;">
178
+ 🖼️ LongCat-Image Editor (CPU Version)
179
+ </h1>
180
+ <p style="color: #666; margin-bottom: 20px;">
181
+ แก้ไขภาพด้วยปัญญาประดิษฐ์ - รุ่นประหยัดหน่วยความจำ (ใช้ CPU เท่านั้น)
182
+ </p>
183
  </center>
184
  """)
185
 
186
  with gr.Column(elem_id="col-container"):
187
+ # Warning about CPU mode
188
+ gr.HTML("""
189
+ <div class="cpu-warning">
190
+ ⚠️ <strong>โหมด CPU:</strong> กำลังใช้ CPU เท่านั้นในการประมวลผล<br>
191
+ ⏱️ <strong>เวลาในการประมวลผล:</strong> ประมาณ 2-5 นาทีต่อภาพ<br>
192
+ 📏 <strong>ขนาดภาพแนะนำ:</strong> ไม่เกิน 512x512 พิกเซล<br>
193
+ 💡 <strong>ข้อดี:</strong> ไม่ต้องใช้การ์ดจอ ไม่มีปัญหาเรื่องหน่วยความจำ
194
+ </div>
195
+ """)
196
+
197
  with gr.Row():
198
  with gr.Column(scale=1):
199
  # Input Image
200
  input_image = gr.Image(
201
+ label="📤 ภาพต้นฉบับ",
202
  type="pil",
203
+ elem_classes=["image-box"],
204
+ height=300
205
  )
206
 
207
  # Edit Prompt
208
  prompt = gr.Textbox(
209
+ label="✏️ คำสั่งแก้ไขภาพ",
210
+ placeholder="ตัวอย่าง: 'ทำให้แมวใส่หมวก', 'เปลี่ยนพื้นหลังเป็นทะเล', 'เพิ่มแว่นตาดำ'...",
211
+ lines=2
212
  )
213
 
214
+ # Quick edit suggestions (Thai version)
215
+ with gr.Row():
216
+ quick_edits = [
217
+ ("เพิ่มแว่นตา", "เพิ่มแว่นตากันแดดให้บุคคล"),
218
+ ("เปลี่ยนฤดู", "เปลี่ยนเป็นหน้าหนาวที่มีหิมะ"),
219
+ ("กลางคืน", "ทำให้เป็นเวลากลางคืนมีดาว"),
220
+ ("เพิ่มสัตว์", "เพิ่มสุนัขน่ารักในภาพ"),
221
+ ]
222
+
223
+ for btn_text, edit_text in quick_edits:
224
+ btn = gr.Button(
225
+ btn_text,
226
+ size="sm",
227
+ variant="secondary",
228
+ scale=0
229
+ )
230
+
231
+ def make_click_fn(text):
232
+ return lambda: text
233
+
234
+ btn.click(
235
+ fn=make_click_fn(edit_text),
236
+ outputs=prompt
237
+ )
238
+
239
+ with gr.Accordion("⚙️ การตั้งค่าขั้นสูง", open=False):
240
  with gr.Row():
241
  seed = gr.Slider(
242
  label="Seed",
 
246
  step=1
247
  )
248
  randomize_seed = gr.Checkbox(
249
+ label="สุ่ม Seed",
250
  value=True
251
  )
252
 
253
  with gr.Row():
254
  steps = gr.Slider(
255
+ label="จำนวนขั้นตอน",
256
+ value=20,
257
  minimum=10,
258
+ maximum=30,
259
+ step=1,
260
+ info="น้อย = เร็ว, มาก = คุณภาพดีขึ้น"
261
  )
262
  guidance_scale = gr.Slider(
263
  label="Guidance Scale",
264
+ value=4.0,
265
  minimum=1.0,
266
+ maximum=7.0,
267
+ step=0.5,
268
+ info="ความเข้มงวดในการทำตามคำสั่ง"
269
  )
270
 
271
  # Generate Button
272
  generate_btn = gr.Button(
273
+ "🎨 แก้ไขภาพ",
274
  variant='primary',
275
  elem_classes=["generate-btn"],
276
  scale=1
 
279
  with gr.Column(scale=1):
280
  # Output Image
281
  output_image = gr.Image(
282
+ label="🖼️ ภาพที่แก้ไขแล้ว",
283
  type="pil",
284
+ elem_classes=["image-box"],
285
+ height=300
286
  )
287
 
288
+ # Time and seed info
289
+ time_info = gr.Markdown(
290
+ "",
291
+ elem_classes=["time-info"]
292
  )
293
+
294
+ # Seed output
295
+ with gr.Row():
296
+ seed_output = gr.Number(
297
+ label="Seed ที่ใช้",
298
+ visible=True
299
+ )
300
+ copy_seed_btn = gr.Button(
301
+ "📋 คัดลอก Seed",
302
+ size="sm",
303
+ variant="secondary"
304
+ )
305
+
306
+ def copy_seed(seed_val):
307
+ return seed_val
308
+
309
+ copy_seed_btn.click(
310
+ fn=copy_seed,
311
+ inputs=seed_output,
312
+ outputs=seed
313
+ )
314
+
315
+ # Tips section (Thai)
316
+ gr.HTML("""
317
+ <div style="margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px;">
318
+ <h4 style="margin-top: 0;">💡 คำแนะนำสำหรับผลลัพธ์ที่ดีที่สุด:</h4>
319
+ <ul style="margin-bottom: 0;">
320
+ <li>ใช้คำสั่งที่ชัดเจนและเป็นรูปธรรม</li>
321
+ <li>เริ่มจาก 20 ขั้นตอน (steps) และปรับเพิ่มถ้าจำเป็น</li>
322
+ <li>ใช้ Guidance Scale ระหว่าง 3.5-5.0</li>
323
+ <li>อัพโหลดภาพไม่เกิน 512x512 พิกเซลสำหรับความเร็วสูงสุด</li>
324
+ <li>ถ้าต้องการภาพใหญ่ ให้ใช้การปรับขนาดภายหลัง</li>
325
+ </ul>
326
+ </div>
327
+ """)
328
 
329
+ # Example images
330
  gr.Examples(
331
+ examples=[
332
+ ["ตัวอย่างภาพแมว", "ทำให้แมวใส่หมวกใบใหญ่สีแดง"],
333
+ ["ตัวอย่างภาพทิวทัศน์", "เพิ่มรุ้งกินน้ำบนฟ้า"],
334
+ ["ตัวอย่างภาพบุคคล", "เปลี่ยนทรงผมให้เป็นลอน"],
335
+ ],
336
  inputs=[input_image, prompt],
337
+ label="ตัวอย่างคำสั่ง"
 
 
 
338
  )
339
 
340
  # Connect the button
 
348
  guidance_scale,
349
  steps
350
  ],
351
+ outputs=[output_image, seed_output, time_info]
352
  )
353
 
354
  # Also allow prompt submission with Enter
 
362
  guidance_scale,
363
  steps
364
  ],
365
+ outputs=[output_image, seed_output, time_info]
366
  )
367
 
368
+ # ล้างหน่วยความจำ
369
+ import gc
370
+ gc.collect()
371
+
372
+ if __name__ == "__main__":
373
+ # โหลดโมเดลล่วงหน้า
374
+ print("กำลังโหลดโมเดลล่วงหน้า...")
375
+ _ = get_edit_pipe()
376
+
377
+ app.launch(
378
+ share=False,
379
+ server_name="0.0.0.0",
380
+ server_port=7860,
381
+ show_error=True,
382
+ debug=False,
383
+ enable_queue=True,
384
+ max_threads=1
385
+ )