Update app.py
Browse files
app.py
CHANGED
|
@@ -181,72 +181,284 @@ current_pipe = None
|
|
| 181 |
model_lock = threading.Lock()
|
| 182 |
|
| 183 |
# =============================================
|
| 184 |
-
#
|
| 185 |
# =============================================
|
| 186 |
class InfographicLayoutGenerator:
|
| 187 |
def __init__(self):
|
| 188 |
-
|
| 189 |
-
self.
|
| 190 |
-
self.text_color = (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
|
|
|
|
|
|
| 192 |
def create_food_infographic(self, title, items_with_prompts, generated_images):
|
| 193 |
"""
|
| 194 |
-
Create
|
| 195 |
"""
|
| 196 |
-
#
|
| 197 |
-
|
| 198 |
-
|
| 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
|
| 206 |
-
canvas =
|
| 207 |
draw = ImageDraw.Draw(canvas)
|
| 208 |
|
| 209 |
-
#
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
|
| 221 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 =
|
| 226 |
draw.text((title_x, title_y), title, font=title_font, fill=self.title_color)
|
| 227 |
|
| 228 |
-
# Draw
|
| 229 |
-
|
| 230 |
-
draw.line([
|
| 231 |
-
|
| 232 |
-
#
|
| 233 |
-
|
| 234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
for i, ((food_name, _), img) in enumerate(zip(items_with_prompts, generated_images)):
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
|
| 241 |
-
#
|
| 242 |
-
|
| 243 |
-
img_resized = img.resize((img_size, img_size))
|
| 244 |
-
canvas.paste(img_resized, (img_x, img_y))
|
| 245 |
|
| 246 |
-
# Draw food name with
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 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 |
-
#
|
| 1158 |
# =============================================
|
| 1159 |
def test_infographic(title, items_text):
|
| 1160 |
-
"""
|
| 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 |
-
|
|
|
|
|
|
|
| 1173 |
generated_images = []
|
| 1174 |
for i, item in enumerate(items):
|
| 1175 |
-
|
| 1176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1177 |
generated_images.append(img)
|
| 1178 |
|
| 1179 |
-
|
|
|
|
|
|
|
| 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"✅
|
| 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=
|
| 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(
|