yukee1992 commited on
Commit
caf9716
·
verified ·
1 Parent(s): 6e1a44d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +295 -57
app.py CHANGED
@@ -181,72 +181,284 @@ current_pipe = None
181
  model_lock = threading.Lock()
182
 
183
  # =============================================
184
- # ADDED: Infographic Layout Generator Class
185
  # =============================================
186
  class InfographicLayoutGenerator:
187
  def __init__(self):
188
- self.title_color = (41, 128, 185) # Blue
189
- self.background_color = (255, 255, 255) # White
190
- self.text_color = (44, 62, 80) # Dark gray
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
 
 
192
  def create_food_infographic(self, title, items_with_prompts, generated_images):
193
  """
194
- Create an infographic with title and multiple food items
195
  """
196
- # Calculate dimensions
197
- num_items = len(items_with_prompts)
198
- item_height = 300
199
- title_height = 120
200
- margin = 50
201
-
202
- width = 1200
203
- height = title_height + (num_items * item_height) + (num_items * margin)
204
 
205
- # Create base canvas
206
- canvas = Image.new('RGB', (width, height), self.background_color)
207
  draw = ImageDraw.Draw(canvas)
208
 
209
- # Try to load fonts, use default if not available
210
- try:
211
- title_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 60)
212
- item_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 40)
213
- except:
214
- try:
215
- title_font = ImageFont.truetype("arial.ttf", 60)
216
- item_font = ImageFont.truetype("arial.ttf", 40)
217
- except:
218
- title_font = ImageFont.load_default()
219
- item_font = ImageFont.load_default()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
- # Draw title
 
 
 
 
 
 
 
 
 
222
  title_bbox = draw.textbbox((0, 0), title, font=title_font)
223
  title_width = title_bbox[2] - title_bbox[0]
224
  title_x = (width - title_width) // 2
225
- title_y = 40
226
  draw.text((title_x, title_y), title, font=title_font, fill=self.title_color)
227
 
228
- # Draw separator line
229
- line_y = title_y + 80
230
- draw.line([(100, line_y), (width-100, line_y)], fill=(200, 200, 200), width=3)
231
-
232
- # Place images for each point
233
- y_offset = line_y + 40
234
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  for i, ((food_name, _), img) in enumerate(zip(items_with_prompts, generated_images)):
236
- # Image position
237
- img_x = 100
238
- img_y = y_offset + (i * (item_height + margin))
239
- img_size = 200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
- # Resize and paste image
242
- if img:
243
- img_resized = img.resize((img_size, img_size))
244
- canvas.paste(img_resized, (img_x, img_y))
245
 
246
- # Draw food name with bullet point
247
- text_x = img_x + img_size + 40
248
- text_y = img_y + (img_size // 2) - 20
249
- draw.text((text_x, text_y), f"• {food_name}", font=item_font, fill=self.text_color)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
 
251
  return canvas
252
 
@@ -891,9 +1103,15 @@ def generate_infographic_background(job_id: str):
891
  try:
892
  print(f"🖼️ Generating image for: {item.name}")
893
 
 
 
 
 
 
 
894
  # Generate image using your existing function
895
  image = generate_image_simple(
896
- item.prompt,
897
  "dreamshaper-8", # Use default model
898
  "food_photography", # Use food photography style
899
  i + 1,
@@ -1154,10 +1372,10 @@ async def get_local_images():
1154
  return get_local_storage_info()
1155
 
1156
  # =============================================
1157
- # ADDED: Test Functions for Gradio
1158
  # =============================================
1159
  def test_infographic(title, items_text):
1160
- """Test function for infographic generation in Gradio"""
1161
  try:
1162
  # Parse items (format: "name:prompt;name2:prompt2")
1163
  items = []
@@ -1169,21 +1387,41 @@ def test_infographic(title, items_text):
1169
  if not items:
1170
  return None, "❌ Please enter at least one item"
1171
 
1172
- # Generate images
 
 
1173
  generated_images = []
1174
  for i, item in enumerate(items):
1175
- enhanced_prompt = f"{item['prompt']}, high quality, appetizing"
1176
- img = generate_image_simple(enhanced_prompt, "dreamshaper-8", "food_photography", i+1, None)
 
 
 
 
 
 
 
 
 
 
 
 
 
1177
  generated_images.append(img)
1178
 
1179
- # Create infographic
 
 
1180
  layout_gen = InfographicLayoutGenerator()
1181
  items_with_prompts = [(item['name'], item['prompt']) for item in items]
1182
  infographic = layout_gen.create_food_infographic(title, items_with_prompts, generated_images)
1183
 
1184
- return infographic, f"✅ Generated infographic with {len(items)} items"
1185
 
1186
  except Exception as e:
 
 
 
1187
  return None, f"❌ Error: {str(e)}"
1188
 
1189
  # GRADIO INTERFACE
@@ -1225,7 +1463,7 @@ def create_gradio_interface():
1225
  infographic_title = gr.Textbox(
1226
  label="Title",
1227
  value="肠道友好的 7种食物",
1228
- placeholder="Enter infographic title..."
1229
  )
1230
  infographic_items = gr.Textbox(
1231
  label="Items (name:prompt;name2:prompt2)",
@@ -1236,7 +1474,7 @@ def create_gradio_interface():
1236
  infographic_btn = gr.Button("Generate Infographic", variant="primary")
1237
 
1238
  with gr.Column():
1239
- infographic_output = gr.Image(label="Generated Infographic", height=600)
1240
  infographic_status = gr.Textbox(label="Status")
1241
 
1242
  infographic_btn.click(
 
181
  model_lock = threading.Lock()
182
 
183
  # =============================================
184
+ # ENHANCED: Infographic Layout Generator Class
185
  # =============================================
186
  class InfographicLayoutGenerator:
187
  def __init__(self):
188
+ # Warm, earthy color palette
189
+ self.title_color = (139, 69, 19) # Saddle brown
190
+ self.text_color = (101, 67, 33) # Dark brown
191
+ self.accent_color = (205, 133, 63) # Peru brown
192
+ self.border_color = (160, 82, 45) # Sienna
193
+
194
+ def create_paper_texture(self, width, height):
195
+ """Create old paper background texture"""
196
+ # Base color - cream/old paper
197
+ base_color = (245, 235, 210)
198
+ paper = Image.new('RGB', (width, height), base_color)
199
+ draw = ImageDraw.Draw(paper)
200
+
201
+ # Add noise for texture
202
+ for _ in range(width * height // 100):
203
+ x = random.randint(0, width-1)
204
+ y = random.randint(0, height-1)
205
+ # Random dark/light spots
206
+ noise = random.randint(-15, 15)
207
+ r = max(0, min(255, base_color[0] + noise))
208
+ g = max(0, min(255, base_color[1] + noise))
209
+ b = max(0, min(255, base_color[2] + noise))
210
+ paper.putpixel((x, y), (r, g, b))
211
+
212
+ # Add subtle brown stains
213
+ for _ in range(30):
214
+ x = random.randint(0, width-1)
215
+ y = random.randint(0, height-1)
216
+ radius = random.randint(30, 80)
217
+ for dx in range(-radius, radius):
218
+ for dy in range(-radius, radius):
219
+ if dx*dx + dy*dy <= radius*radius:
220
+ nx, ny = x + dx, y + dy
221
+ if 0 <= nx < width and 0 <= ny < height:
222
+ r, g, b = paper.getpixel((nx, ny))
223
+ # Add subtle brown tint
224
+ r = max(0, min(255, r - 8))
225
+ g = max(0, min(255, g - 5))
226
+ b = max(0, min(255, b - 3))
227
+ paper.putpixel((nx, ny), (r, g, b))
228
+
229
+ return paper
230
+
231
+ def remove_background(self, image):
232
+ """Simple background removal - makes white/light backgrounds transparent"""
233
+ # Convert to RGBA if not already
234
+ if image.mode != 'RGBA':
235
+ image = image.convert('RGBA')
236
+
237
+ data = image.getdata()
238
+ new_data = []
239
+
240
+ # Threshold for white/light background
241
+ threshold = 240
242
+
243
+ for item in data:
244
+ # If pixel is very light (likely background), make transparent
245
+ if item[0] > threshold and item[1] > threshold and item[2] > threshold:
246
+ new_data.append((255, 255, 255, 0)) # Transparent
247
+ else:
248
+ new_data.append(item)
249
+
250
+ image.putdata(new_data)
251
+ return image
252
+
253
+ def get_font(self, size, bold=False):
254
+ """Get font with Chinese/English support"""
255
+ font_paths = [
256
+ # Windows Chinese fonts
257
+ "C:/Windows/Fonts/msyh.ttc", # Microsoft YaHei
258
+ "C:/Windows/Fonts/simhei.ttf", # SimHei
259
+ "C:/Windows/Fonts/simsun.ttc", # SimSun
260
+ # Linux Chinese fonts
261
+ "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
262
+ "/usr/share/fonts/truetype/arphic/uming.ttc",
263
+ # Mac Chinese fonts
264
+ "/System/Library/Fonts/PingFang.ttc",
265
+ # Android fonts
266
+ "/system/fonts/NotoSansCJK-Regular.ttc",
267
+ # Linux fallback
268
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
269
+ # Windows fallback
270
+ "arial.ttf",
271
+ ]
272
+
273
+ if bold:
274
+ bold_paths = [
275
+ "C:/Windows/Fonts/msyhbd.ttc", # Microsoft YaHei Bold
276
+ "C:/Windows/Fonts/simhei.ttf",
277
+ "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
278
+ "/System/Library/Fonts/PingFang.ttc",
279
+ ]
280
+ font_paths = bold_paths + font_paths
281
+
282
+ for font_path in font_paths:
283
+ try:
284
+ return ImageFont.truetype(font_path, size)
285
+ except:
286
+ continue
287
+
288
+ return ImageFont.load_default()
289
+
290
+ def create_icon_from_image(self, image, size, bg_removal=True):
291
+ """Convert image to icon with optional background removal"""
292
+ if bg_removal:
293
+ image = self.remove_background(image)
294
+ else:
295
+ if image.mode != 'RGBA':
296
+ image = image.convert('RGBA')
297
+
298
+ # Resize maintaining aspect ratio
299
+ image.thumbnail((size, size), Image.Resampling.LANCZOS)
300
+
301
+ # Create square canvas with transparency
302
+ icon = Image.new('RGBA', (size, size), (0, 0, 0, 0))
303
+
304
+ # Center the image
305
+ x = (size - image.width) // 2
306
+ y = (size - image.height) // 2
307
+ icon.paste(image, (x, y), image)
308
 
309
+ return icon
310
+
311
  def create_food_infographic(self, title, items_with_prompts, generated_images):
312
  """
313
+ Create a beautiful 9:16 portrait infographic with old paper texture and icons
314
  """
315
+ # 9:16 portrait dimensions
316
+ width = 1080
317
+ height = 1920
 
 
 
 
 
318
 
319
+ # Create old paper background
320
+ canvas = self.create_paper_texture(width, height)
321
  draw = ImageDraw.Draw(canvas)
322
 
323
+ # Layout constants
324
+ top_margin = 140
325
+ bottom_margin = 100
326
+ side_margin = 60
327
+ title_height = 200
328
+ icon_size = 140
329
+ row_height = 180
330
+ columns = 2 # Two columns layout
331
+
332
+ # Calculate number of rows needed
333
+ num_items = len(items_with_prompts)
334
+ rows_per_column = (num_items + columns - 1) // columns
335
+
336
+ # Draw decorative border
337
+ border_padding = 20
338
+ # Outer border
339
+ draw.rectangle(
340
+ [border_padding, border_padding, width-border_padding, height-border_padding],
341
+ outline=self.border_color,
342
+ width=3
343
+ )
344
+ # Inner border
345
+ draw.rectangle(
346
+ [border_padding+10, border_padding+10, width-border_padding-10, height-border_padding-10],
347
+ outline=self.accent_color,
348
+ width=1
349
+ )
350
+
351
+ # Draw title area with decorative elements
352
+ title_font = self.get_font(70, bold=True)
353
 
354
+ # Title background
355
+ title_bg_y = top_margin - 30
356
+ draw.rectangle(
357
+ [side_margin, title_bg_y, width-side_margin, title_bg_y+150],
358
+ fill=(255, 255, 255, 220),
359
+ outline=self.border_color,
360
+ width=2
361
+ )
362
+
363
+ # Title text (supports Chinese)
364
  title_bbox = draw.textbbox((0, 0), title, font=title_font)
365
  title_width = title_bbox[2] - title_bbox[0]
366
  title_x = (width - title_width) // 2
367
+ title_y = top_margin
368
  draw.text((title_x, title_y), title, font=title_font, fill=self.title_color)
369
 
370
+ # Draw decorative elements around title
371
+ # Left decoration
372
+ draw.line([side_margin+20, title_y+40, side_margin+100, title_y+40],
373
+ fill=self.accent_color, width=3)
374
+ # Right decoration
375
+ draw.line([width-side_margin-100, title_y+40, width-side_margin-20, title_y+40],
376
+ fill=self.accent_color, width=3)
377
+
378
+ # Draw subtitle (English/Chinese)
379
+ subtitle_font = self.get_font(30)
380
+ subtitle = "Healthy Foods · 健康食品"
381
+ subtitle_bbox = draw.textbbox((0, 0), subtitle, font=subtitle_font)
382
+ subtitle_width = subtitle_bbox[2] - subtitle_bbox[0]
383
+ subtitle_x = (width - subtitle_width) // 2
384
+ subtitle_y = title_y + 80
385
+ draw.text((subtitle_x, subtitle_y), subtitle, font=subtitle_font, fill=self.text_color)
386
+
387
+ # Starting Y position for first row
388
+ start_y = top_margin + title_height + 40
389
+
390
+ # Place items in two columns
391
  for i, ((food_name, _), img) in enumerate(zip(items_with_prompts, generated_images)):
392
+ column = i // rows_per_column
393
+ row = i % rows_per_column
394
+
395
+ # Calculate position
396
+ if column == 0:
397
+ x_offset = side_margin + 30
398
+ else:
399
+ x_offset = width // 2 + 30
400
+
401
+ y_offset = start_y + (row * (row_height + 40))
402
+
403
+ # Create icon from image
404
+ icon = self.create_icon_from_image(img, icon_size, bg_removal=True)
405
+
406
+ # Draw decorative background for icon
407
+ icon_bg_size = icon_size + 20
408
+ icon_bg_x = x_offset - 10
409
+ icon_bg_y = y_offset - 10
410
+
411
+ # Draw circular background with subtle shadow
412
+ draw.ellipse(
413
+ [icon_bg_x+5, icon_bg_y+5, icon_bg_x+icon_bg_size+5, icon_bg_y+icon_bg_size+5],
414
+ fill=(0, 0, 0, 40)
415
+ )
416
+ draw.ellipse(
417
+ [icon_bg_x, icon_bg_y, icon_bg_x+icon_bg_size, icon_bg_y+icon_bg_size],
418
+ fill=(255, 255, 255, 240),
419
+ outline=self.accent_color,
420
+ width=2
421
+ )
422
 
423
+ # Paste icon (with transparency)
424
+ canvas.paste(icon, (x_offset, y_offset), icon)
 
 
425
 
426
+ # Draw food name with Chinese/English support
427
+ name_font = self.get_font(38, bold=True)
428
+ name_x = x_offset + icon_size + 25
429
+ name_y = y_offset + (icon_size // 2) - 35
430
+
431
+ # Food name
432
+ draw.text((name_x, name_y), food_name, font=name_font, fill=self.text_color)
433
+
434
+ # Draw number indicator
435
+ number_font = self.get_font(22)
436
+ number_text = f"#{i+1:02d}"
437
+ draw.text((name_x, name_y + 45), number_text, font=number_font, fill=self.accent_color)
438
+
439
+ # Draw small decorative line
440
+ line_y = name_y + 75
441
+ draw.line([name_x, line_y, name_x+70, line_y], fill=self.accent_color, width=2)
442
+
443
+ # Draw footer
444
+ footer_font = self.get_font(28)
445
+ footer_text = "· Fresh & Healthy · Made with Love ·"
446
+ footer_bbox = draw.textbbox((0, 0), footer_text, font=footer_font)
447
+ footer_width = footer_bbox[2] - footer_bbox[0]
448
+ footer_x = (width - footer_width) // 2
449
+ footer_y = height - bottom_margin + 10
450
+ draw.text((footer_x, footer_y), footer_text, font=footer_font, fill=self.border_color)
451
+
452
+ # Add corner decorations
453
+ decoration_positions = [
454
+ (border_padding+15, border_padding+15), # Top-left
455
+ (width-border_padding-45, border_padding+15), # Top-right
456
+ (border_padding+15, height-border_padding-45), # Bottom-left
457
+ (width-border_padding-45, height-border_padding-45) # Bottom-right
458
+ ]
459
+
460
+ for x, y in decoration_positions:
461
+ draw.arc([x, y, x+30, y+30], 0, 90, fill=self.accent_color, width=2)
462
 
463
  return canvas
464
 
 
1103
  try:
1104
  print(f"🖼️ Generating image for: {item.name}")
1105
 
1106
+ # Enhanced prompt for object on white background (easier to remove)
1107
+ enhanced_prompt = f"professional food photography, {item.prompt}, " \
1108
+ f"isolated on white background, studio lighting, " \
1109
+ f"cut out, transparent background style, " \
1110
+ f"high resolution, food magazine quality"
1111
+
1112
  # Generate image using your existing function
1113
  image = generate_image_simple(
1114
+ enhanced_prompt,
1115
  "dreamshaper-8", # Use default model
1116
  "food_photography", # Use food photography style
1117
  i + 1,
 
1372
  return get_local_storage_info()
1373
 
1374
  # =============================================
1375
+ # ENHANCED: Test Functions for Gradio
1376
  # =============================================
1377
  def test_infographic(title, items_text):
1378
+ """Enhanced test function for infographic generation with icon-style images"""
1379
  try:
1380
  # Parse items (format: "name:prompt;name2:prompt2")
1381
  items = []
 
1387
  if not items:
1388
  return None, "❌ Please enter at least one item"
1389
 
1390
+ print(f"🎨 Generating infographic with {len(items)} items...")
1391
+
1392
+ # Generate images with prompts optimized for transparent objects
1393
  generated_images = []
1394
  for i, item in enumerate(items):
1395
+ print(f" 🖼️ Generating image {i+1}/{len(items)}: {item['name']}")
1396
+
1397
+ # Enhanced prompt for object on white background (easier to remove)
1398
+ enhanced_prompt = f"professional food photography, {item['prompt']}, " \
1399
+ f"isolated on white background, studio lighting, " \
1400
+ f"cut out, transparent background style, " \
1401
+ f"high resolution, food magazine quality"
1402
+
1403
+ img = generate_image_simple(
1404
+ enhanced_prompt,
1405
+ "dreamshaper-8",
1406
+ "food_photography",
1407
+ i+1,
1408
+ None
1409
+ )
1410
  generated_images.append(img)
1411
 
1412
+ print(" 📐 Creating beautiful layout with old paper texture...")
1413
+
1414
+ # Create enhanced infographic
1415
  layout_gen = InfographicLayoutGenerator()
1416
  items_with_prompts = [(item['name'], item['prompt']) for item in items]
1417
  infographic = layout_gen.create_food_infographic(title, items_with_prompts, generated_images)
1418
 
1419
+ return infographic, f"✅ Created beautiful infographic with {len(items)} icon-style images on old paper"
1420
 
1421
  except Exception as e:
1422
+ print(f"❌ Error: {str(e)}")
1423
+ import traceback
1424
+ traceback.print_exc()
1425
  return None, f"❌ Error: {str(e)}"
1426
 
1427
  # GRADIO INTERFACE
 
1463
  infographic_title = gr.Textbox(
1464
  label="Title",
1465
  value="肠道友好的 7种食物",
1466
+ placeholder="Enter infographic title (supports Chinese)..."
1467
  )
1468
  infographic_items = gr.Textbox(
1469
  label="Items (name:prompt;name2:prompt2)",
 
1474
  infographic_btn = gr.Button("Generate Infographic", variant="primary")
1475
 
1476
  with gr.Column():
1477
+ infographic_output = gr.Image(label="Generated Infographic", height=700)
1478
  infographic_status = gr.Textbox(label="Status")
1479
 
1480
  infographic_btn.click(