Equityone commited on
Commit
33d4d20
·
verified ·
1 Parent(s): c645839

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +221 -133
app.py CHANGED
@@ -1,6 +1,9 @@
 
 
 
1
  import gradio as gr
2
  import os
3
- from PIL import Image
4
  import requests
5
  import io
6
  import gc
@@ -8,7 +11,6 @@ import json
8
  from typing import Tuple, Optional, Dict, Any
9
  import logging
10
  from dotenv import load_dotenv
11
- from prompt_enhancer import PromptEnhancer
12
 
13
  # Configuration du logging
14
  logging.basicConfig(
@@ -20,97 +22,119 @@ logger = logging.getLogger(__name__)
20
  # Chargement des variables d'environnement
21
  load_dotenv()
22
 
23
- # Styles artistiques complets
24
  ART_STYLES = {
25
- # Styles Classiques
26
  "Ultra Réaliste": {
27
- "prompt_prefix": "ultra realistic photograph, stunning photorealistic quality, unreal engine 5 quality, octane render, ray tracing, volumetric lighting, subsurface scattering, 8k UHD, cinema quality, masterpiece, perfect composition, award winning photography",
28
- "negative_prompt": "artificial, digital art, illustration, painting, drawing, artistic, cartoon, anime, unreal, fake, low quality, blurry, soft, deformed"
 
 
 
 
29
  },
30
  "Photoréaliste": {
31
- "prompt_prefix": "hyperrealistic photograph, extremely detailed, studio quality, professional photography, 8k uhd",
32
- "negative_prompt": "artistic, painterly, abstract, cartoon, illustration, low quality"
 
 
 
33
  },
 
 
34
  "Expressionniste": {
35
- "prompt_prefix": "expressive painting style, intense emotional art, bold brushstrokes, vibrant colors, van gogh inspired",
36
- "negative_prompt": "realistic, subtle, photographic, clean lines, digital art"
 
 
 
37
  },
38
  "Impressionniste": {
39
- "prompt_prefix": "impressionist painting style, soft light, visible brushstrokes, outdoor scene, monet inspired",
40
- "negative_prompt": "sharp details, high contrast, digital, modern"
41
- },
42
- "Art Abstrait": {
43
- "prompt_prefix": "abstract art, geometric shapes, non-representational, kandinsky style, pure artistic expression",
44
- "negative_prompt": "realistic, figurative, photographic, literal"
45
- },
46
- "Surréaliste": {
47
- "prompt_prefix": "surrealist art, dreamlike imagery, symbolic elements, dali inspired, metaphysical art",
48
- "negative_prompt": "realistic, conventional, ordinary, literal"
49
  },
 
 
50
  "Art Moderne": {
51
- "prompt_prefix": "modern art style poster, professional design, contemporary aesthetic",
52
- "negative_prompt": "traditional, cluttered, busy design, vintage"
53
- },
54
- "Pop Art": {
55
- "prompt_prefix": "pop art style poster, bold colors, repeated patterns, screen print effect, warhol inspired",
56
- "negative_prompt": "subtle, realistic, traditional, painterly"
57
  },
58
  "Minimaliste": {
59
- "prompt_prefix": "minimalist design poster, clean composition, elegant simplicity",
60
- "negative_prompt": "complex, detailed, ornate, busy, cluttered"
61
- },
62
- "Cubiste": {
63
- "prompt_prefix": "cubist art style, geometric fragmentation, multiple perspectives, picasso inspired",
64
- "negative_prompt": "realistic, single perspective, traditional, photographic"
65
- },
66
- "Futuriste": {
67
- "prompt_prefix": "futuristic art style, dynamic movement, technological elements, speed and motion",
68
- "negative_prompt": "static, traditional, classical, historical"
69
- },
70
- "Neo Vintage": {
71
- "prompt_prefix": "vintage style advertising poster, retro design, classic aesthetic",
72
- "negative_prompt": "modern, digital, contemporary style"
73
  },
 
 
74
  "Cyberpunk": {
75
- "prompt_prefix": "cyberpunk style poster, neon lights, futuristic design, high-tech aesthetic",
76
- "negative_prompt": "vintage, natural, rustic, traditional"
77
- },
78
- "Japonais": {
79
- "prompt_prefix": "japanese art style poster, ukiyo-e inspired design, traditional japanese aesthetic",
80
- "negative_prompt": "western, modern, photographic"
81
  },
82
  "Art Déco": {
83
- "prompt_prefix": "art deco style poster, geometric patterns, luxury design, 1920s aesthetic",
84
- "negative_prompt": "modern, minimalist, casual, contemporary"
85
- },
86
- "Symboliste": {
87
- "prompt_prefix": "symbolic art, decorative patterns, gold elements, mystical atmosphere, klimt inspired",
88
- "negative_prompt": "realistic, simple, plain, literal"
89
  }
90
  }
91
 
92
  # Paramètres de composition enrichis
93
  COMPOSITION_PARAMS = {
94
  "Layouts": {
95
- "Centré": "centered composition, balanced layout, harmonious arrangement",
96
- "Asymétrique": "dynamic asymmetrical composition, creative balance",
97
- "Grille": "grid-based layout, structured composition, organized design",
98
- "Diagonal": "diagonal dynamic composition, energetic flow",
99
- "Minimaliste": "minimal composition, lots of whitespace, elegant spacing"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  },
101
  "Ambiances": {
102
- "Dramatique": "dramatic lighting, high contrast, intense mood",
103
- "Doux": "soft lighting, gentle atmosphere, subtle mood",
104
- "Vibrant": "vibrant colors, energetic mood, dynamic atmosphere",
105
- "Mystérieux": "mysterious atmosphere, moody lighting, enigmatic feel",
106
- "Serein": "peaceful atmosphere, calm mood, tranquil setting"
107
- },
108
- "Palette": {
109
- "Monochrome": "monochromatic color scheme, sophisticated tones",
110
- "Contrasté": "high contrast color palette, bold color combinations",
111
- "Pastel": "soft pastel color palette, gentle colors",
112
- "Terre": "earthy color palette, natural tones",
113
- "Néon": "neon color palette, vibrant glowing colors"
 
 
 
 
 
 
 
 
114
  }
115
  }
116
 
@@ -123,73 +147,98 @@ class ImageGenerator:
123
  self.headers = {"Authorization": f"Bearer {token}"}
124
  logger.info("ImageGenerator initialisé")
125
 
126
- def _build_prompt(self, params: Dict[str, Any]) -> str:
127
- """Construction de prompt améliorée avec le PromptEnhancer"""
128
- try:
129
- # Initialisation du PromptEnhancer
130
- enhancer = PromptEnhancer()
131
-
132
- # Récupération du style
133
- style_info = ART_STYLES.get(params["style"], ART_STYLES["Art Moderne"])
134
-
135
- # Construction du contexte de style
136
- style_context = {
137
- "prompt_prefix": style_info['prompt_prefix'],
138
- "layout": COMPOSITION_PARAMS['Layouts'][params['layout']],
139
- "ambiance": COMPOSITION_PARAMS['Ambiances'][params['ambiance']],
140
- "palette": COMPOSITION_PARAMS['Palette'][params['palette']]
141
- }
 
 
 
 
 
 
 
 
 
 
 
142
 
143
- # Préparation du prompt initial
144
- base_prompt = f"{params['subject']}"
145
- if params.get('title'):
146
- base_prompt += f", with text '{params['title']}'"
147
 
148
- # Amélioration du prompt
149
- enhanced_prompt = enhancer.enhance_prompt(base_prompt, style_context)
150
 
151
- # Analyse de l'efficacité du prompt
152
- prompt_analysis = enhancer.analyze_prompt_effectiveness(enhanced_prompt)
153
- logger.debug(f"Analyse du prompt: {json.dumps(prompt_analysis, indent=2)}")
 
 
 
 
154
 
155
- return enhanced_prompt
 
 
 
156
 
 
157
  except Exception as e:
158
- logger.error(f"Erreur dans la construction du prompt: {str(e)}")
159
- # Fallback sur le prompt basique en cas d'erreur
160
- return f"{style_info['prompt_prefix']}, {params['subject']}"
161
 
162
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
 
163
  try:
164
  logger.info(f"Début de génération avec paramètres: {json.dumps(params, indent=2)}")
165
 
166
  if 'Bearer None' in self.headers['Authorization']:
167
  return None, "⚠️ Erreur: Token Hugging Face non configuré"
168
 
169
- prompt = self._build_prompt(params)
 
 
 
 
 
 
 
 
 
170
 
171
  payload = {
172
- "inputs": prompt,
173
  "parameters": {
174
- "negative_prompt": ART_STYLES[params["style"]]["negative_prompt"],
175
- "num_inference_steps": min(int(35 * (params["quality"]/100)), 40),
176
- "guidance_scale": min(7.5 * (params["creativity"]/10), 10.0),
177
- "width": 768,
178
- "height": 768 if params["orientation"] == "Portrait" else 512
179
  }
180
  }
181
 
182
- logger.debug(f"Payload: {json.dumps(payload, indent=2)}")
183
 
 
184
  response = requests.post(
185
  self.API_URL,
186
  headers=self.headers,
187
  json=payload,
188
- timeout=30
189
  )
190
 
191
  if response.status_code == 200:
192
  image = Image.open(io.BytesIO(response.content))
 
 
193
  return image, "✨ Création réussie!"
194
  else:
195
  error_msg = f"⚠️ Erreur API {response.status_code}: {response.text}"
@@ -204,27 +253,54 @@ class ImageGenerator:
204
  gc.collect()
205
 
206
  def create_interface():
 
207
  logger.info("Création de l'interface Gradio")
208
 
 
209
  css = """
210
  .container { max-width: 1200px; margin: auto; }
211
- .welcome { text-align: center; margin: 20px 0; padding: 20px; background: #1e293b; border-radius: 10px; }
212
- .controls-group { background: #2d3748; padding: 15px; border-radius: 5px; margin: 10px 0; }
213
- .advanced-controls { background: #374151; padding: 12px; border-radius: 5px; margin: 8px 0; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  """
215
 
216
  generator = ImageGenerator()
217
 
218
  with gr.Blocks(css=css) as app:
 
219
  gr.HTML("""
220
  <div class="welcome">
221
  <h1>🎨 Equity Artisan 3.0</h1>
222
  <p>Assistant de création d'affiches professionnelles</p>
 
223
  </div>
224
  """)
225
 
226
  with gr.Column(elem_classes="container"):
227
- # Zone d'introduction et guide
228
  gr.Markdown("""
229
  ### 🎯 Guide d'utilisation
230
  1. Choisissez le format et l'orientation de votre affiche
@@ -232,8 +308,11 @@ def create_interface():
232
  3. Décrivez votre vision dans "Description"
233
  4. Ajustez les paramètres fins selon vos besoins
234
  5. Cliquez sur "Générer" !
 
 
235
  """)
236
 
 
237
  with gr.Group(elem_classes="controls-group"):
238
  gr.Markdown("### 📐 Format et Orientation")
239
  with gr.Row():
@@ -241,62 +320,59 @@ def create_interface():
241
  choices=["A4", "A3", "A2", "A1", "A0"],
242
  value="A4",
243
  label="Format",
244
- info="Choisissez la taille de votre affiche. A4 est le plus petit, A0 le plus grand."
245
  )
246
  orientation = gr.Radio(
247
  choices=["Portrait", "Paysage"],
248
  value="Portrait",
249
- label="Orientation",
250
- info="Portrait (vertical) ou Paysage (horizontal)"
251
  )
252
 
 
253
  with gr.Group(elem_classes="controls-group"):
254
  gr.Markdown("### 🎨 Style et Composition")
255
  with gr.Row():
256
  style = gr.Dropdown(
257
  choices=list(ART_STYLES.keys()),
258
  value="Art Moderne",
259
- label="Style artistique",
260
- info="Le style global de votre affiche. Chaque style a ses propres caractéristiques uniques."
261
  )
262
  layout = gr.Dropdown(
263
  choices=list(COMPOSITION_PARAMS["Layouts"].keys()),
264
  value="Centré",
265
- label="Composition",
266
- info="Comment les éléments seront organisés dans l'affiche"
267
  )
268
 
269
  with gr.Row():
270
  ambiance = gr.Dropdown(
271
  choices=list(COMPOSITION_PARAMS["Ambiances"].keys()),
272
  value="Dramatique",
273
- label="Ambiance",
274
- info="L'atmosphère générale de votre affiche"
275
  )
276
  palette = gr.Dropdown(
277
- choices=list(COMPOSITION_PARAMS["Palette"].keys()),
278
  value="Contrasté",
279
- label="Palette",
280
- info="Les types de couleurs utilisées"
281
  )
282
 
 
283
  with gr.Group(elem_classes="controls-group"):
284
- gr.Markdown("""### 📝 Contenu
285
- *Conseils pour la description : soyez précis sur ce que vous souhaitez voir dans l'affiche*""")
286
  subject = gr.Textbox(
287
  label="Description",
288
  placeholder="Ex: Une affiche moderne pour un festival de musique, avec des instruments colorés flottant dans l'espace",
289
- info="Décrivez en détail ce que vous souhaitez voir dans votre affiche"
290
  )
291
  title = gr.Textbox(
292
- label="Titre",
293
- placeholder="Le titre qui apparaîtra sur l'affiche...",
294
- info="Laissez vide si vous ne voulez pas de titre sur l'affiche"
295
  )
296
 
 
 
 
297
  with gr.Group(elem_classes="advanced-controls"):
298
- gr.Markdown("""### 🎯 Ajustements Fins
299
- *Ces paramètres permettent d'affiner le résultat final*""")
300
  with gr.Row():
301
  detail_level = gr.Slider(
302
  minimum=1,
@@ -323,6 +399,7 @@ def create_interface():
323
  info="Contrôle la vivacité des couleurs"
324
  )
325
 
 
326
  with gr.Group(elem_classes="controls-group"):
327
  gr.Markdown("### ⚙️ Paramètres de Génération")
328
  with gr.Row():
@@ -341,13 +418,23 @@ def create_interface():
341
  info="Plus la valeur est élevée, plus l'IA prendra de libertés créatives"
342
  )
343
 
 
344
  with gr.Row():
345
  generate_btn = gr.Button("✨ Générer", variant="primary")
346
  clear_btn = gr.Button("🗑️ Effacer", variant="secondary")
347
 
348
- image_output = gr.Image(label="Aperçu")
349
- status = gr.Textbox(label="Statut", interactive=False)
 
 
 
 
 
 
 
 
350
 
 
351
  def generate(*args):
352
  logger.info("Démarrage d'une nouvelle génération")
353
  params = {
@@ -369,6 +456,7 @@ def create_interface():
369
  logger.info(f"Génération terminée avec statut: {result[1]}")
370
  return result
371
 
 
372
  generate_btn.click(
373
  generate,
374
  inputs=[
 
1
+ Oui, exactement ! Le format sans artifact me permet de délivrer le code directement dans notre conversation de manière plus fluide et économique. Et tu as raison, je peux te donner des codes plus longs car je n'ai pas les contraintes des artifacts. Je vais donc recréer ton app.py optimisé :
2
+
3
+ ```python
4
  import gradio as gr
5
  import os
6
+ from PIL import Image, ImageEnhance
7
  import requests
8
  import io
9
  import gc
 
11
  from typing import Tuple, Optional, Dict, Any
12
  import logging
13
  from dotenv import load_dotenv
 
14
 
15
  # Configuration du logging
16
  logging.basicConfig(
 
22
  # Chargement des variables d'environnement
23
  load_dotenv()
24
 
25
+ # Styles artistiques enrichis avec optimisations
26
  ART_STYLES = {
27
+ # Styles Réalistes
28
  "Ultra Réaliste": {
29
+ "prompt_prefix": """ultra realistic photograph, stunning photorealistic quality, unreal engine 5 quality,
30
+ octane render, ray tracing, volumetric lighting, subsurface scattering, 8k UHD, cinema quality,
31
+ masterpiece, perfect composition, award winning photography, professional lighting""",
32
+ "negative_prompt": """artificial, digital art, illustration, painting, drawing, artistic, cartoon,
33
+ anime, unreal, fake, low quality, blurry, soft, deformed, noisy, unclear, imperfect, amateur""",
34
+ "quality_multiplier": 1.2
35
  },
36
  "Photoréaliste": {
37
+ "prompt_prefix": """hyperrealistic photograph, extremely detailed, studio quality, professional photography,
38
+ 8k uhd, perfect lighting, high-end camera, professional grade lens, expert composition""",
39
+ "negative_prompt": """artistic, painterly, abstract, cartoon, illustration, low quality,
40
+ amateur, imperfect, blurry, noise""",
41
+ "quality_multiplier": 1.1
42
  },
43
+
44
+ # Styles Artistiques
45
  "Expressionniste": {
46
+ "prompt_prefix": """expressive painting style, intense emotional art, bold brushstrokes, vibrant colors,
47
+ van gogh inspired, artistic masterpiece, deep emotional impact, dynamic composition""",
48
+ "negative_prompt": """realistic, subtle, photographic, clean lines, digital art, flat, unemotional,
49
+ generic, weak composition""",
50
+ "quality_multiplier": 1.0
51
  },
52
  "Impressionniste": {
53
+ "prompt_prefix": """impressionist painting style, soft light, visible brushstrokes, outdoor scene,
54
+ monet inspired, artistic mastery, natural lighting, atmospheric effect""",
55
+ "negative_prompt": """sharp details, high contrast, digital, modern, artificial, harsh,
56
+ unrealistic colors""",
57
+ "quality_multiplier": 1.0
 
 
 
 
 
58
  },
59
+
60
+ # Styles Modernes
61
  "Art Moderne": {
62
+ "prompt_prefix": """modern art style poster, professional design, contemporary aesthetic,
63
+ trending on artstation, perfect composition, high-end production""",
64
+ "negative_prompt": """traditional, cluttered, busy design, vintage, amateur, low quality,
65
+ unprofessional""",
66
+ "quality_multiplier": 1.1
 
67
  },
68
  "Minimaliste": {
69
+ "prompt_prefix": """minimalist design poster, clean composition, elegant simplicity,
70
+ perfect balance, sophisticated style, high-end design""",
71
+ "negative_prompt": """complex, detailed, ornate, busy, cluttered, chaotic, unbalanced,
72
+ amateur""",
73
+ "quality_multiplier": 1.0
 
 
 
 
 
 
 
 
 
74
  },
75
+
76
+ # Styles Spéciaux
77
  "Cyberpunk": {
78
+ "prompt_prefix": """cyberpunk style, neon lights, futuristic design, high-tech aesthetic,
79
+ detailed machinery, holographic elements, cinematic lighting""",
80
+ "negative_prompt": """vintage, natural, rustic, traditional, simple, flat, dull,
81
+ low-tech""",
82
+ "quality_multiplier": 1.1
 
83
  },
84
  "Art Déco": {
85
+ "prompt_prefix": """art deco style, geometric patterns, luxury design, 1920s aesthetic,
86
+ golden age glamour, sophisticated composition""",
87
+ "negative_prompt": """modern, minimalist, casual, contemporary, simple, rustic,
88
+ unrefined""",
89
+ "quality_multiplier": 1.0
 
90
  }
91
  }
92
 
93
  # Paramètres de composition enrichis
94
  COMPOSITION_PARAMS = {
95
  "Layouts": {
96
+ "Centré": {
97
+ "description": "centered composition, balanced layout, harmonious arrangement",
98
+ "weight": 1.2
99
+ },
100
+ "Asymétrique": {
101
+ "description": "dynamic asymmetrical composition, creative balance, artistic flow",
102
+ "weight": 1.1
103
+ },
104
+ "Grille": {
105
+ "description": "grid-based layout, structured composition, organized design, perfect alignment",
106
+ "weight": 1.0
107
+ },
108
+ "Diagonal": {
109
+ "description": "diagonal dynamic composition, energetic flow, dramatic arrangement",
110
+ "weight": 1.1
111
+ },
112
+ "Minimaliste": {
113
+ "description": "minimal composition, lots of whitespace, elegant spacing, perfect balance",
114
+ "weight": 1.0
115
+ }
116
  },
117
  "Ambiances": {
118
+ "Dramatique": {
119
+ "description": "dramatic lighting, high contrast, intense mood, cinematic atmosphere",
120
+ "weight": 1.2
121
+ },
122
+ "Doux": {
123
+ "description": "soft lighting, gentle atmosphere, subtle mood, delicate ambiance",
124
+ "weight": 1.0
125
+ },
126
+ "Vibrant": {
127
+ "description": "vibrant colors, energetic mood, dynamic atmosphere, bold presence",
128
+ "weight": 1.1
129
+ },
130
+ "Mystérieux": {
131
+ "description": "mysterious atmosphere, moody lighting, enigmatic feel, intriguing shadows",
132
+ "weight": 1.1
133
+ },
134
+ "Serein": {
135
+ "description": "peaceful atmosphere, calm mood, tranquil setting, harmonious lighting",
136
+ "weight": 1.0
137
+ }
138
  }
139
  }
140
 
 
147
  self.headers = {"Authorization": f"Bearer {token}"}
148
  logger.info("ImageGenerator initialisé")
149
 
150
+ def _optimize_prompt(self, params: Dict[str, Any]) -> Tuple[str, str]:
151
+ """Optimisation avancée des prompts avec gestion contextuelle"""
152
+ style_info = ART_STYLES.get(params["style"], ART_STYLES["Art Moderne"])
153
+ layout_info = COMPOSITION_PARAMS["Layouts"].get(params["layout"])
154
+ ambiance_info = COMPOSITION_PARAMS["Ambiances"].get(params["ambiance"])
155
+
156
+ # Construction du prompt principal
157
+ base_prompt = f"{params['subject']}"
158
+ if params.get('title'):
159
+ base_prompt += f", with text '{params['title']}'"
160
+
161
+ # Ajout des éléments de composition
162
+ composition_elements = [
163
+ style_info["prompt_prefix"],
164
+ layout_info["description"],
165
+ ambiance_info["description"]
166
+ ]
167
+
168
+ # Calcul du multiplicateur de qualité
169
+ quality_multiplier = (
170
+ style_info.get("quality_multiplier", 1.0) *
171
+ layout_info.get("weight", 1.0) *
172
+ ambiance_info.get("weight", 1.0)
173
+ )
174
+
175
+ # Construction du prompt final optimisé
176
+ enhanced_prompt = f"{base_prompt}, {', '.join(composition_elements)}"
177
 
178
+ # Construction du negative prompt optimisé
179
+ negative_prompt = f"{style_info['negative_prompt']}, low quality, bad anatomy, worst quality, low resolution"
 
 
180
 
181
+ return enhanced_prompt, negative_prompt, quality_multiplier
 
182
 
183
+ def _enhance_image(self, image: Image.Image, params: Dict[str, Any]) -> Image.Image:
184
+ """Post-traitement avancé des images"""
185
+ try:
186
+ # Amélioration de la netteté basée sur le style
187
+ sharpness_factor = 1.2 if params["style"] in ["Ultra Réaliste", "Photoréaliste"] else 1.1
188
+ enhancer = ImageEnhance.Sharpness(image)
189
+ image = enhancer.enhance(sharpness_factor)
190
 
191
+ # Ajustement du contraste selon l'ambiance
192
+ contrast_factor = 1.2 if params["ambiance"] == "Dramatique" else 1.1
193
+ enhancer = ImageEnhance.Contrast(image)
194
+ image = enhancer.enhance(contrast_factor)
195
 
196
+ return image
197
  except Exception as e:
198
+ logger.warning(f"Erreur lors de l'amélioration de l'image: {str(e)}")
199
+ return image
 
200
 
201
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
202
+ """Génération d'image avec optimisations avancées"""
203
  try:
204
  logger.info(f"Début de génération avec paramètres: {json.dumps(params, indent=2)}")
205
 
206
  if 'Bearer None' in self.headers['Authorization']:
207
  return None, "⚠️ Erreur: Token Hugging Face non configuré"
208
 
209
+ # Optimisation des prompts
210
+ enhanced_prompt, negative_prompt, quality_multiplier = self._optimize_prompt(params)
211
+
212
+ # Configuration des paramètres de génération
213
+ generation_params = {
214
+ "num_inference_steps": min(int(50 * quality_multiplier), 60),
215
+ "guidance_scale": min(8.5 * (params["creativity"]/10), 12.0),
216
+ "width": 1024 if params.get("quality", 35) > 40 else 768,
217
+ "height": 1024 if params["orientation"] == "Portrait" else 768
218
+ }
219
 
220
  payload = {
221
+ "inputs": enhanced_prompt,
222
  "parameters": {
223
+ **generation_params,
224
+ "negative_prompt": negative_prompt
 
 
 
225
  }
226
  }
227
 
228
+ logger.debug(f"Payload final: {json.dumps(payload, indent=2)}")
229
 
230
+ # Génération de l'image
231
  response = requests.post(
232
  self.API_URL,
233
  headers=self.headers,
234
  json=payload,
235
+ timeout=45
236
  )
237
 
238
  if response.status_code == 200:
239
  image = Image.open(io.BytesIO(response.content))
240
+ # Post-traitement de l'image
241
+ image = self._enhance_image(image, params)
242
  return image, "✨ Création réussie!"
243
  else:
244
  error_msg = f"⚠️ Erreur API {response.status_code}: {response.text}"
 
253
  gc.collect()
254
 
255
  def create_interface():
256
+ """Création de l'interface utilisateur enrichie"""
257
  logger.info("Création de l'interface Gradio")
258
 
259
+ # Styles CSS personnalisés
260
  css = """
261
  .container { max-width: 1200px; margin: auto; }
262
+ .welcome {
263
+ text-align: center;
264
+ margin: 20px 0;
265
+ padding: 20px;
266
+ background: linear-gradient(135deg, #1e293b, #334155);
267
+ border-radius: 10px;
268
+ color: white;
269
+ }
270
+ .controls-group {
271
+ background: #2d3748;
272
+ padding: 15px;
273
+ border-radius: 5px;
274
+ margin: 10px 0;
275
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
276
+ }
277
+ .advanced-controls {
278
+ background: #374151;
279
+ padding: 12px;
280
+ border-radius: 5px;
281
+ margin: 8px 0;
282
+ }
283
+ .info-tooltip {
284
+ color: #94a3b8;
285
+ font-size: 0.9em;
286
+ margin-top: 4px;
287
+ }
288
  """
289
 
290
  generator = ImageGenerator()
291
 
292
  with gr.Blocks(css=css) as app:
293
+ # En-tête et présentation
294
  gr.HTML("""
295
  <div class="welcome">
296
  <h1>🎨 Equity Artisan 3.0</h1>
297
  <p>Assistant de création d'affiches professionnelles</p>
298
+ <p style="font-size: 0.9em; opacity: 0.8;">Powered by Stable Diffusion XL</p>
299
  </div>
300
  """)
301
 
302
  with gr.Column(elem_classes="container"):
303
+ # Guide d'utilisation
304
  gr.Markdown("""
305
  ### 🎯 Guide d'utilisation
306
  1. Choisissez le format et l'orientation de votre affiche
 
308
  3. Décrivez votre vision dans "Description"
309
  4. Ajustez les paramètres fins selon vos besoins
310
  5. Cliquez sur "Générer" !
311
+
312
+ *💡 Pro Tip: Pour de meilleurs résultats, soyez précis dans votre description et expérimentez avec différents styles.*
313
  """)
314
 
315
+ # Contrôles principaux
316
  with gr.Group(elem_classes="controls-group"):
317
  gr.Markdown("### 📐 Format et Orientation")
318
  with gr.Row():
 
320
  choices=["A4", "A3", "A2", "A1", "A0"],
321
  value="A4",
322
  label="Format",
323
+ info="Choisissez la taille de votre affiche"
324
  )
325
  orientation = gr.Radio(
326
  choices=["Portrait", "Paysage"],
327
  value="Portrait",
328
+ label="Orientation"
 
329
  )
330
 
331
+ # Style et composition
332
  with gr.Group(elem_classes="controls-group"):
333
  gr.Markdown("### 🎨 Style et Composition")
334
  with gr.Row():
335
  style = gr.Dropdown(
336
  choices=list(ART_STYLES.keys()),
337
  value="Art Moderne",
338
+ label="Style artistique"
 
339
  )
340
  layout = gr.Dropdown(
341
  choices=list(COMPOSITION_PARAMS["Layouts"].keys()),
342
  value="Centré",
343
+ label="Composition"
 
344
  )
345
 
346
  with gr.Row():
347
  ambiance = gr.Dropdown(
348
  choices=list(COMPOSITION_PARAMS["Ambiances"].keys()),
349
  value="Dramatique",
350
+ label="Ambiance"
 
351
  )
352
  palette = gr.Dropdown(
353
+ choices=["Monochrome", "Contrasté", "Pastel", "Terre", "Néon"],
354
  value="Contrasté",
355
+ label="Palette"
 
356
  )
357
 
358
+ # Description et contenu
359
  with gr.Group(elem_classes="controls-group"):
360
+ gr.Markdown("### 📝 Contenu")
 
361
  subject = gr.Textbox(
362
  label="Description",
363
  placeholder="Ex: Une affiche moderne pour un festival de musique, avec des instruments colorés flottant dans l'espace",
364
+ lines=3
365
  )
366
  title = gr.Textbox(
367
+ label="Titre (optionnel)",
368
+ placeholder="Le titre qui apparaîtra sur l'affiche..."
 
369
  )
370
 
371
+ # Contrôles avancés
372
+ with gr.Group(elem_classes="advanced-controls"):
373
+ gr.Markdown("### 🎯 Paramètres Av# Contrôles avancés
374
  with gr.Group(elem_classes="advanced-controls"):
375
+ gr.Markdown("### 🎯 Paramètres Avancés")
 
376
  with gr.Row():
377
  detail_level = gr.Slider(
378
  minimum=1,
 
399
  info="Contrôle la vivacité des couleurs"
400
  )
401
 
402
+ # Paramètres de génération
403
  with gr.Group(elem_classes="controls-group"):
404
  gr.Markdown("### ⚙️ Paramètres de Génération")
405
  with gr.Row():
 
418
  info="Plus la valeur est élevée, plus l'IA prendra de libertés créatives"
419
  )
420
 
421
+ # Boutons de contrôle
422
  with gr.Row():
423
  generate_btn = gr.Button("✨ Générer", variant="primary")
424
  clear_btn = gr.Button("🗑️ Effacer", variant="secondary")
425
 
426
+ # Zone de résultat
427
+ with gr.Group(elem_classes="controls-group"):
428
+ gr.Markdown("### 🖼️ Résultat")
429
+ image_output = gr.Image(label="Aperçu", height=512)
430
+ status = gr.Textbox(label="Statut", interactive=False)
431
+
432
+ # Zone d'historique
433
+ with gr.Group(elem_classes="controls-group"):
434
+ gr.Markdown("### 📋 Historique des Générations")
435
+ history = gr.Gallery(label="Générations précédentes", show_label=True, columns=4, height=200)
436
 
437
+ # Fonction de génération
438
  def generate(*args):
439
  logger.info("Démarrage d'une nouvelle génération")
440
  params = {
 
456
  logger.info(f"Génération terminée avec statut: {result[1]}")
457
  return result
458
 
459
+ # Connexion des événements
460
  generate_btn.click(
461
  generate,
462
  inputs=[