yukee1992 commited on
Commit
4697537
Β·
verified Β·
1 Parent(s): 26de2ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -60
app.py CHANGED
@@ -98,94 +98,80 @@ class JobStatus(str, Enum):
98
  FAILED = "failed"
99
 
100
  # =============================================
101
- # Style and Size Configuration
102
  # =============================================
103
 
104
- # Available image styles with their prompts
105
  STYLE_CONFIGS = {
106
  "childrens_book": {
107
  "name": "Children's Book Style",
108
  "description": "Soft, whimsical watercolor illustration style",
109
  "prompt_prefix": "children's book illustration, watercolor style, soft colors, whimsical, magical, storybook art, professional illustration, cute",
110
- "negative": "photorealistic, dark, scary, adult content, violent",
111
- "default_width": 768,
112
- "default_height": 1024
113
  },
114
  "realistic": {
115
  "name": "Realistic Style",
116
  "description": "Photorealistic, lifelike images",
117
  "prompt_prefix": "photorealistic, ultra realistic, detailed, natural lighting, professional photography, 8k, sharp focus",
118
- "negative": "cartoon, anime, painting, illustration, blurry, low quality",
119
- "default_width": 768,
120
- "default_height": 1024
121
  },
122
  "anime": {
123
  "name": "Anime Style",
124
  "description": "Japanese animation style",
125
  "prompt_prefix": "anime style, Japanese animation, vibrant colors, detailed artwork, high quality, studio ghibli inspired",
126
- "negative": "photorealistic, 3d render, realistic, ugly, blurry",
127
- "default_width": 768,
128
- "default_height": 1024
129
  },
130
  "fantasy": {
131
  "name": "Fantasy Style",
132
  "description": "Magical, ethereal fantasy art",
133
  "prompt_prefix": "fantasy art, magical, ethereal, digital painting, concept art, epic, mystical, dreamlike",
134
- "negative": "realistic, modern, mundane, blurry, low quality",
135
- "default_width": 768,
136
- "default_height": 1024
137
  },
138
  "pixel_art": {
139
  "name": "Pixel Art Style",
140
  "description": "Retro video game pixel art",
141
  "prompt_prefix": "pixel art, retro video game style, 16-bit, detailed pixels, vibrant colors, game sprite",
142
- "negative": "realistic, smooth, 3d, blurry, high resolution",
143
- "default_width": 512,
144
- "default_height": 512
145
  },
146
  "oil_painting": {
147
  "name": "Oil Painting Style",
148
  "description": "Classic oil painting aesthetic",
149
  "prompt_prefix": "oil painting, classic art, renaissance style, detailed brushstrokes, masterpiece, canvas texture",
150
- "negative": "digital art, cartoon, anime, photograph, modern",
151
- "default_width": 768,
152
- "default_height": 1024
153
  },
154
  "sketch": {
155
  "name": "Sketch Style",
156
  "description": "Hand-drawn pencil sketch",
157
  "prompt_prefix": "pencil sketch, hand drawn, detailed drawing, artistic sketch, charcoal drawing, monochrome",
158
- "negative": "color, painting, digital, photograph, realistic colors",
159
- "default_width": 768,
160
- "default_height": 1024
161
  },
162
  "cyberpunk": {
163
  "name": "Cyberpunk Style",
164
  "description": "Futuristic cyberpunk aesthetic",
165
  "prompt_prefix": "cyberpunk style, neon lights, futuristic, sci-fi, dark atmosphere, vibrant neon colors, blade runner aesthetic",
166
- "negative": "vintage, pastel, bright daylight, natural, realistic",
167
- "default_width": 768,
168
- "default_height": 1024
169
  },
170
  "minimalist": {
171
  "name": "Minimalist Style",
172
  "description": "Clean, simple minimalist design",
173
  "prompt_prefix": "minimalist style, simple, clean design, flat illustration, geometric, pastel colors, modern art",
174
- "negative": "detailed, complex, photorealistic, cluttered, busy",
175
- "default_width": 768,
176
- "default_height": 1024
177
  },
178
  "watercolor": {
179
  "name": "Watercolor Style",
180
  "description": "Soft watercolor painting",
181
  "prompt_prefix": "watercolor painting, soft colors, artistic, flowing, delicate, wet on wet technique, traditional art",
182
- "negative": "digital, sharp lines, photorealistic, heavy texture",
183
- "default_width": 768,
184
- "default_height": 1024
 
 
 
 
185
  }
186
  }
187
 
188
- # Size presets with valid dimensions (divisible by 8)
189
  SIZE_PRESETS = {
190
  "square": {"width": 768, "height": 768, "description": "1:1 Square"},
191
  "portrait": {"width": 768, "height": 1024, "description": "3:4 Portrait"},
@@ -229,7 +215,7 @@ class InfographicItem(BaseModel):
229
  class InfographicRequest(BaseModel):
230
  title: str
231
  items: List[InfographicItem]
232
- style: str = "food_photography"
233
  image_size: str = "story"
234
  custom_width: Optional[int] = None
235
  custom_height: Optional[int] = None
@@ -275,44 +261,64 @@ current_pipe = None
275
  model_lock = threading.Lock()
276
 
277
  # =============================================
278
- # HELPER FUNCTIONS WITH DIMENSION VALIDATION
279
  # =============================================
280
 
281
  def validate_dimensions(width, height):
282
  """Ensure dimensions are compatible with Stable Diffusion (divisible by 8)"""
283
- # SD models require dimensions divisible by 8
284
  width = (width // 8) * 8
285
  height = (height // 8) * 8
286
 
287
  # Minimum and maximum constraints
288
- width = max(256, min(1024, width))
289
- height = max(256, min(1024, height))
290
 
291
  return width, height
292
 
293
  def get_image_dimensions(size_preset, custom_width=None, custom_height=None):
294
- """Get image dimensions based on preset or custom values with validation"""
295
- if size_preset == "custom" and custom_width and custom_height:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  width, height = custom_width, custom_height
297
- elif size_preset in SIZE_PRESETS:
298
- preset = SIZE_PRESETS[size_preset]
299
- width, height = preset["width"], preset["height"]
300
  else:
301
  # Default to portrait
302
  width, height = 768, 1024
303
 
304
  # Validate dimensions
305
  width, height = validate_dimensions(width, height)
 
 
306
  return width, height
307
 
308
  def get_style_config(style_name):
309
- """Get style configuration or return default"""
310
  if style_name in STYLE_CONFIGS:
311
  return STYLE_CONFIGS[style_name]
312
  return STYLE_CONFIGS["childrens_book"]
313
 
314
  def enhance_prompt_with_style(scene_visual, style="childrens_book", custom_style_prompt=None):
315
- """Enhanced prompt with style configuration"""
316
  if custom_style_prompt:
317
  style_prefix = custom_style_prompt
318
  else:
@@ -349,6 +355,8 @@ def generate_image_with_settings(prompt, model_choice, style, scene_number, cons
349
  generator = torch.Generator(device="cpu")
350
  generator.manual_seed(scene_seed)
351
 
 
 
352
  image = pipe(
353
  prompt=enhanced_prompt,
354
  negative_prompt=negative_prompt,
@@ -622,6 +630,7 @@ def generate_storybook_background(job_id: str):
622
 
623
  project_id = story_request.project_id or story_request.story_title.replace(' ', '_').lower()
624
 
 
625
  width, height = get_image_dimensions(
626
  story_request.image_size,
627
  story_request.custom_width,
@@ -682,7 +691,7 @@ def generate_storybook_background(job_id: str):
682
  }
683
 
684
  if project_id and image_urls:
685
- report_to_tracker(project_id, "image", "completed", image_urls)
686
 
687
  update_job_status(job_id, JobStatus.COMPLETED, 100, "Storybook completed!", result)
688
 
@@ -755,11 +764,8 @@ class InfographicLayoutGenerator:
755
  except Exception as e:
756
  return image
757
 
758
- def create_responsive_layout(self, num_items):
759
  """Calculate responsive layout"""
760
- width = 900
761
- height = 1600
762
-
763
  if num_items <= 3:
764
  icon_size = 180
765
  columns = 1
@@ -808,7 +814,7 @@ class InfographicLayoutGenerator:
808
 
809
  draw = ImageDraw.Draw(canvas)
810
  num_items = len(items_with_prompts)
811
- positions, icon_size, columns = self.create_responsive_layout(num_items)
812
 
813
  # Draw title
814
  title_font = self.get_font(48, bold=True)
@@ -895,6 +901,7 @@ def generate_infographic_background(job_id: str):
895
  request = InfographicRequest(**job_data["request"])
896
  project_id = request.project_id or f"infographic_{int(time.time())}"
897
 
 
898
  width, height = get_image_dimensions(
899
  request.image_size,
900
  request.custom_width,
@@ -920,18 +927,24 @@ def generate_infographic_background(job_id: str):
920
  image_urls = []
921
  items_data = []
922
 
 
 
 
 
923
  for i, item in enumerate(items):
924
  progress = 10 + int(((i + 1) / len(items)) * 70)
925
  update_job_status(job_id, JobStatus.PROCESSING, progress, f"Generating {item.name}")
926
 
927
  try:
 
928
  image = generate_image_with_settings(
929
  item.prompt,
930
  "dreamshaper-8",
931
- "realistic",
932
  i + 1,
933
  None,
934
- 768, 1024
 
935
  )
936
  generated_images.append(image)
937
 
@@ -950,6 +963,7 @@ def generate_infographic_background(job_id: str):
950
  })
951
 
952
  except Exception as e:
 
953
  placeholder = Image.new('RGB', (512, 512), (240, 240, 240))
954
  generated_images.append(placeholder)
955
 
@@ -957,6 +971,7 @@ def generate_infographic_background(job_id: str):
957
 
958
  update_job_status(job_id, JobStatus.PROCESSING, 85, "Creating layout...")
959
 
 
960
  layout_generator = InfographicLayoutGenerator()
961
  items_with_prompts = [(item.name, item.prompt) for item in items]
962
  infographic = layout_generator.create_food_infographic(
@@ -997,7 +1012,7 @@ def generate_infographic_background(job_id: str):
997
  async def generate_storybook(request: dict, background_tasks: BackgroundTasks):
998
  """Main endpoint with style and size options"""
999
  try:
1000
- print(f"πŸ“₯ Received storybook request - Style: {request.get('style', 'childrens_book')}")
1001
 
1002
  if 'consistency_seed' not in request:
1003
  request['consistency_seed'] = random.randint(1000, 9999)
@@ -1012,6 +1027,7 @@ async def generate_storybook(request: dict, background_tasks: BackgroundTasks):
1012
  job_id = create_job(story_request)
1013
  background_tasks.add_task(generate_storybook_background, job_id)
1014
 
 
1015
  width, height = get_image_dimensions(
1016
  request.get('image_size', 'portrait'),
1017
  request.get('custom_width'),
@@ -1034,17 +1050,20 @@ async def generate_storybook(request: dict, background_tasks: BackgroundTasks):
1034
  async def generate_infographic(request: dict, background_tasks: BackgroundTasks):
1035
  """Generate infographic with style and size options"""
1036
  try:
1037
- print(f"πŸ“₯ Received infographic request - Style: {request.get('style', 'food_photography')}")
1038
 
1039
  if 'project_id' not in request:
1040
  request['project_id'] = f"infographic_{int(time.time())}"
1041
  if 'image_size' not in request:
1042
  request['image_size'] = 'story'
 
 
1043
 
1044
  infographic_request = InfographicRequest(**request)
1045
  job_id = create_job(infographic_request)
1046
  background_tasks.add_task(generate_infographic_background, job_id)
1047
 
 
1048
  width, height = get_image_dimensions(
1049
  request.get('image_size', 'story'),
1050
  request.get('custom_width'),
@@ -1068,8 +1087,7 @@ async def get_available_styles():
1068
  """Get all available image styles"""
1069
  styles = {key: {
1070
  "name": config["name"],
1071
- "description": config["description"],
1072
- "default_size": f"{config['default_width']}x{config['default_height']}"
1073
  } for key, config in STYLE_CONFIGS.items()}
1074
  return {"styles": styles}
1075
 
@@ -1175,8 +1193,7 @@ def create_gradio_interface():
1175
  styles_md = ""
1176
  for key, config in STYLE_CONFIGS.items():
1177
  styles_md += f"### **{config['name']}** (`{key}`)\n"
1178
- styles_md += f"{config['description']}\n"
1179
- styles_md += f"*Default size: {config['default_width']}x{config['default_height']}*\n\n"
1180
  gr.Markdown(styles_md)
1181
 
1182
  gr.Markdown("## Available Size Presets")
@@ -1194,7 +1211,7 @@ demo = create_gradio_interface()
1194
  async def root():
1195
  return {
1196
  "message": "Enhanced Image Generator API",
1197
- "version": "2.0",
1198
  "available_styles": list(STYLE_CONFIGS.keys()),
1199
  "available_sizes": list(SIZE_PRESETS.keys()),
1200
  "endpoints": {
 
98
  FAILED = "failed"
99
 
100
  # =============================================
101
+ # Style Configuration (NO SIZE DEFAULTS)
102
  # =============================================
103
 
104
+ # Available image styles with their prompts (size removed)
105
  STYLE_CONFIGS = {
106
  "childrens_book": {
107
  "name": "Children's Book Style",
108
  "description": "Soft, whimsical watercolor illustration style",
109
  "prompt_prefix": "children's book illustration, watercolor style, soft colors, whimsical, magical, storybook art, professional illustration, cute",
110
+ "negative": "photorealistic, dark, scary, adult content, violent"
 
 
111
  },
112
  "realistic": {
113
  "name": "Realistic Style",
114
  "description": "Photorealistic, lifelike images",
115
  "prompt_prefix": "photorealistic, ultra realistic, detailed, natural lighting, professional photography, 8k, sharp focus",
116
+ "negative": "cartoon, anime, painting, illustration, blurry, low quality"
 
 
117
  },
118
  "anime": {
119
  "name": "Anime Style",
120
  "description": "Japanese animation style",
121
  "prompt_prefix": "anime style, Japanese animation, vibrant colors, detailed artwork, high quality, studio ghibli inspired",
122
+ "negative": "photorealistic, 3d render, realistic, ugly, blurry"
 
 
123
  },
124
  "fantasy": {
125
  "name": "Fantasy Style",
126
  "description": "Magical, ethereal fantasy art",
127
  "prompt_prefix": "fantasy art, magical, ethereal, digital painting, concept art, epic, mystical, dreamlike",
128
+ "negative": "realistic, modern, mundane, blurry, low quality"
 
 
129
  },
130
  "pixel_art": {
131
  "name": "Pixel Art Style",
132
  "description": "Retro video game pixel art",
133
  "prompt_prefix": "pixel art, retro video game style, 16-bit, detailed pixels, vibrant colors, game sprite",
134
+ "negative": "realistic, smooth, 3d, blurry, high resolution"
 
 
135
  },
136
  "oil_painting": {
137
  "name": "Oil Painting Style",
138
  "description": "Classic oil painting aesthetic",
139
  "prompt_prefix": "oil painting, classic art, renaissance style, detailed brushstrokes, masterpiece, canvas texture",
140
+ "negative": "digital art, cartoon, anime, photograph, modern"
 
 
141
  },
142
  "sketch": {
143
  "name": "Sketch Style",
144
  "description": "Hand-drawn pencil sketch",
145
  "prompt_prefix": "pencil sketch, hand drawn, detailed drawing, artistic sketch, charcoal drawing, monochrome",
146
+ "negative": "color, painting, digital, photograph, realistic colors"
 
 
147
  },
148
  "cyberpunk": {
149
  "name": "Cyberpunk Style",
150
  "description": "Futuristic cyberpunk aesthetic",
151
  "prompt_prefix": "cyberpunk style, neon lights, futuristic, sci-fi, dark atmosphere, vibrant neon colors, blade runner aesthetic",
152
+ "negative": "vintage, pastel, bright daylight, natural, realistic"
 
 
153
  },
154
  "minimalist": {
155
  "name": "Minimalist Style",
156
  "description": "Clean, simple minimalist design",
157
  "prompt_prefix": "minimalist style, simple, clean design, flat illustration, geometric, pastel colors, modern art",
158
+ "negative": "detailed, complex, photorealistic, cluttered, busy"
 
 
159
  },
160
  "watercolor": {
161
  "name": "Watercolor Style",
162
  "description": "Soft watercolor painting",
163
  "prompt_prefix": "watercolor painting, soft colors, artistic, flowing, delicate, wet on wet technique, traditional art",
164
+ "negative": "digital, sharp lines, photorealistic, heavy texture"
165
+ },
166
+ "news": {
167
+ "name": "News Style",
168
+ "description": "Realistic news photography style",
169
+ "prompt_prefix": "professional news photography, photojournalism style, documentary photography, realistic, detailed, natural lighting, high resolution",
170
+ "negative": "cartoon, anime, painting, illustration, blurry, low quality, staged"
171
  }
172
  }
173
 
174
+ # Size presets (independent from style)
175
  SIZE_PRESETS = {
176
  "square": {"width": 768, "height": 768, "description": "1:1 Square"},
177
  "portrait": {"width": 768, "height": 1024, "description": "3:4 Portrait"},
 
215
  class InfographicRequest(BaseModel):
216
  title: str
217
  items: List[InfographicItem]
218
+ style: str = "realistic"
219
  image_size: str = "story"
220
  custom_width: Optional[int] = None
221
  custom_height: Optional[int] = None
 
261
  model_lock = threading.Lock()
262
 
263
  # =============================================
264
+ # HELPER FUNCTIONS WITH SEPARATE SIZE CONTROL
265
  # =============================================
266
 
267
  def validate_dimensions(width, height):
268
  """Ensure dimensions are compatible with Stable Diffusion (divisible by 8)"""
 
269
  width = (width // 8) * 8
270
  height = (height // 8) * 8
271
 
272
  # Minimum and maximum constraints
273
+ width = max(256, min(1920, width))
274
+ height = max(256, min(2048, height))
275
 
276
  return width, height
277
 
278
  def get_image_dimensions(size_preset, custom_width=None, custom_height=None):
279
+ """Get image dimensions based on preset - COMPLETELY INDEPENDENT OF STYLE"""
280
+
281
+ print(f"πŸ“ Getting dimensions for preset: {size_preset}")
282
+
283
+ # Handle size presets
284
+ if size_preset == "story":
285
+ width, height = 1080, 1920
286
+ elif size_preset == "square":
287
+ width, height = 768, 768
288
+ elif size_preset == "portrait":
289
+ width, height = 768, 1024
290
+ elif size_preset == "landscape":
291
+ width, height = 1024, 768
292
+ elif size_preset == "wide":
293
+ width, height = 1280, 720
294
+ elif size_preset == "ultrawide":
295
+ width, height = 1920, 768
296
+ elif size_preset == "instagram":
297
+ width, height = 1080, 1080
298
+ elif size_preset == "facebook":
299
+ width, height = 1200, 632
300
+ elif size_preset == "twitter":
301
+ width, height = 1600, 896
302
+ elif size_preset == "custom" and custom_width and custom_height:
303
  width, height = custom_width, custom_height
 
 
 
304
  else:
305
  # Default to portrait
306
  width, height = 768, 1024
307
 
308
  # Validate dimensions
309
  width, height = validate_dimensions(width, height)
310
+
311
+ print(f"πŸ“ Final dimensions: {width}x{height}")
312
  return width, height
313
 
314
  def get_style_config(style_name):
315
+ """Get style configuration (NO SIZE INFO)"""
316
  if style_name in STYLE_CONFIGS:
317
  return STYLE_CONFIGS[style_name]
318
  return STYLE_CONFIGS["childrens_book"]
319
 
320
  def enhance_prompt_with_style(scene_visual, style="childrens_book", custom_style_prompt=None):
321
+ """Enhanced prompt with style configuration - NO SIZE"""
322
  if custom_style_prompt:
323
  style_prefix = custom_style_prompt
324
  else:
 
355
  generator = torch.Generator(device="cpu")
356
  generator.manual_seed(scene_seed)
357
 
358
+ print(f"🎨 Generating: {style} style, {width}x{height}")
359
+
360
  image = pipe(
361
  prompt=enhanced_prompt,
362
  negative_prompt=negative_prompt,
 
630
 
631
  project_id = story_request.project_id or story_request.story_title.replace(' ', '_').lower()
632
 
633
+ # Get dimensions based on size preset (independent of style)
634
  width, height = get_image_dimensions(
635
  story_request.image_size,
636
  story_request.custom_width,
 
691
  }
692
 
693
  if project_id and image_urls:
694
+ report_to_tracker(project_id, "storybook", "completed", image_urls)
695
 
696
  update_job_status(job_id, JobStatus.COMPLETED, 100, "Storybook completed!", result)
697
 
 
764
  except Exception as e:
765
  return image
766
 
767
+ def create_responsive_layout(self, num_items, width=900, height=1600):
768
  """Calculate responsive layout"""
 
 
 
769
  if num_items <= 3:
770
  icon_size = 180
771
  columns = 1
 
814
 
815
  draw = ImageDraw.Draw(canvas)
816
  num_items = len(items_with_prompts)
817
+ positions, icon_size, columns = self.create_responsive_layout(num_items, width, height)
818
 
819
  # Draw title
820
  title_font = self.get_font(48, bold=True)
 
901
  request = InfographicRequest(**job_data["request"])
902
  project_id = request.project_id or f"infographic_{int(time.time())}"
903
 
904
+ # Get dimensions based on size preset (independent of style)
905
  width, height = get_image_dimensions(
906
  request.image_size,
907
  request.custom_width,
 
927
  image_urls = []
928
  items_data = []
929
 
930
+ # Use a standard size for individual item images (not the infographic size)
931
+ item_width = 768
932
+ item_height = 768
933
+
934
  for i, item in enumerate(items):
935
  progress = 10 + int(((i + 1) / len(items)) * 70)
936
  update_job_status(job_id, JobStatus.PROCESSING, progress, f"Generating {item.name}")
937
 
938
  try:
939
+ # Generate individual item images at standard size
940
  image = generate_image_with_settings(
941
  item.prompt,
942
  "dreamshaper-8",
943
+ request.style,
944
  i + 1,
945
  None,
946
+ item_width,
947
+ item_height
948
  )
949
  generated_images.append(image)
950
 
 
963
  })
964
 
965
  except Exception as e:
966
+ print(f"❌ Failed for {item.name}: {e}")
967
  placeholder = Image.new('RGB', (512, 512), (240, 240, 240))
968
  generated_images.append(placeholder)
969
 
 
971
 
972
  update_job_status(job_id, JobStatus.PROCESSING, 85, "Creating layout...")
973
 
974
+ # Create infographic with the specified dimensions
975
  layout_generator = InfographicLayoutGenerator()
976
  items_with_prompts = [(item.name, item.prompt) for item in items]
977
  infographic = layout_generator.create_food_infographic(
 
1012
  async def generate_storybook(request: dict, background_tasks: BackgroundTasks):
1013
  """Main endpoint with style and size options"""
1014
  try:
1015
+ print(f"πŸ“₯ Received storybook request")
1016
 
1017
  if 'consistency_seed' not in request:
1018
  request['consistency_seed'] = random.randint(1000, 9999)
 
1027
  job_id = create_job(story_request)
1028
  background_tasks.add_task(generate_storybook_background, job_id)
1029
 
1030
+ # Get dimensions for response
1031
  width, height = get_image_dimensions(
1032
  request.get('image_size', 'portrait'),
1033
  request.get('custom_width'),
 
1050
  async def generate_infographic(request: dict, background_tasks: BackgroundTasks):
1051
  """Generate infographic with style and size options"""
1052
  try:
1053
+ print(f"πŸ“₯ Received infographic request")
1054
 
1055
  if 'project_id' not in request:
1056
  request['project_id'] = f"infographic_{int(time.time())}"
1057
  if 'image_size' not in request:
1058
  request['image_size'] = 'story'
1059
+ if 'style' not in request:
1060
+ request['style'] = 'realistic'
1061
 
1062
  infographic_request = InfographicRequest(**request)
1063
  job_id = create_job(infographic_request)
1064
  background_tasks.add_task(generate_infographic_background, job_id)
1065
 
1066
+ # Get dimensions for response
1067
  width, height = get_image_dimensions(
1068
  request.get('image_size', 'story'),
1069
  request.get('custom_width'),
 
1087
  """Get all available image styles"""
1088
  styles = {key: {
1089
  "name": config["name"],
1090
+ "description": config["description"]
 
1091
  } for key, config in STYLE_CONFIGS.items()}
1092
  return {"styles": styles}
1093
 
 
1193
  styles_md = ""
1194
  for key, config in STYLE_CONFIGS.items():
1195
  styles_md += f"### **{config['name']}** (`{key}`)\n"
1196
+ styles_md += f"{config['description']}\n\n"
 
1197
  gr.Markdown(styles_md)
1198
 
1199
  gr.Markdown("## Available Size Presets")
 
1211
  async def root():
1212
  return {
1213
  "message": "Enhanced Image Generator API",
1214
+ "version": "3.0",
1215
  "available_styles": list(STYLE_CONFIGS.keys()),
1216
  "available_sizes": list(SIZE_PRESETS.keys()),
1217
  "endpoints": {