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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +373 -155
app.py CHANGED
@@ -1,185 +1,403 @@
1
  import gradio as gr
2
- from typing import Dict, Any, Tuple, Optional
3
  from PIL import Image
4
- import torch
5
- from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler
 
 
 
6
  import logging
7
- from dataclasses import dataclass
8
  from prompt_enhancer import PromptEnhancer
9
 
10
- @dataclass
11
- class GenerationConfig:
12
- width: int = 1024
13
- height: int = 1024
14
- num_inference_steps: int = 50
15
- guidance_scale: float = 7.5
16
- high_noise_frac: float = 0.8
17
- negative_prompt: str = ""
18
 
19
- class EnhancedImageGenerator:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  def __init__(self):
21
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
22
- self.pipeline = self._initialize_pipeline()
23
- self.prompt_enhancer = PromptEnhancer()
24
-
25
- def _initialize_pipeline(self) -> StableDiffusionXLPipeline:
26
- pipeline = StableDiffusionXLPipeline.from_pretrained(
27
- "stabilityai/stable-diffusion-xl-base-1.0",
28
- torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
29
- use_safetensors=True,
30
- variant="fp16" if self.device == "cuda" else None
31
- )
32
-
33
- # Optimisations cruciales pour la qualité
34
- pipeline.scheduler = DPMSolverMultistepScheduler.from_config(
35
- pipeline.scheduler.config,
36
- algorithm_type="dpmsolver++",
37
- use_karras_sigmas=True
38
- )
39
-
40
- if self.device == "cuda":
41
- pipeline.enable_xformers_memory_efficient_attention()
42
- pipeline.enable_model_cpu_offload()
43
-
44
- return pipeline
45
-
46
- def _enhance_prompt(self, base_prompt: str, style_params: Dict[str, Any]) -> str:
47
- """Amélioration avancée des prompts avec analyse contextuelle"""
48
- enhanced = self.prompt_enhancer.enhance(
49
- base_prompt,
50
- style=style_params["style"],
51
- composition=style_params["composition"],
52
- mood=style_params["mood"]
53
- )
54
-
55
- # Ajout d'optimisations de qualité spécifiques
56
- quality_terms = [
57
- "masterpiece",
58
- "highly detailed",
59
- "professional",
60
- "award winning",
61
- "stunning",
62
- f"resolution {style_params.get('resolution', '8k')}",
63
- "perfect composition"
64
- ]
65
-
66
- return f"{enhanced}, {', '.join(quality_terms)}"
67
-
68
- def generate(
69
- self,
70
- params: Dict[str, Any],
71
- config: GenerationConfig
72
- ) -> Tuple[Optional[Image.Image], str]:
73
  try:
74
- # Optimisation du prompt
75
- enhanced_prompt = self._enhance_prompt(params["prompt"], params)
76
-
77
- # Configuration avancée de la génération
78
- with torch.inference_mode():
79
- image = self.pipeline(
80
- prompt=enhanced_prompt,
81
- negative_prompt=config.negative_prompt,
82
- width=config.width,
83
- height=config.height,
84
- num_inference_steps=config.num_inference_steps,
85
- guidance_scale=config.guidance_scale,
86
- high_noise_frac=config.high_noise_frac,
87
- ).images[0]
88
-
89
- return image, "Génération réussie!"
 
 
 
 
 
 
 
 
 
 
 
 
90
  except Exception as e:
91
- logging.error(f"Erreur lors de la génération: {str(e)}")
92
- return None, f"Erreur: {str(e)}"
93
-
94
- def create_enhanced_interface():
95
- # Styles enrichis avec paramètres optimisés
96
- ENHANCED_STYLES = {
97
- "Ultra Réaliste": {
98
- "prompt_enhancement": "ultra photorealistic, 8k UHD, hyperdetailed",
99
- "quality_boost": 1.2,
100
- "steps_multiplier": 1.3
101
- },
102
- "Artistique Pro": {
103
- "prompt_enhancement": "professional artistic composition, perfect lighting",
104
- "quality_boost": 1.1,
105
- "steps_multiplier": 1.2
106
- }
107
- # ... autres styles
108
- }
109
 
110
- with gr.Blocks(theme=gr.themes.Soft()) as interface:
111
- with gr.Row():
112
- with gr.Column(scale=2):
113
- # Interface utilisateur améliorée
114
- prompt_input = gr.Textbox(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  label="Description",
116
- placeholder="Décrivez votre vision en détail...",
117
- lines=3
118
  )
119
-
 
 
 
 
 
 
 
 
120
  with gr.Row():
121
- style_selector = gr.Dropdown(
122
- choices=list(ENHANCED_STYLES.keys()),
123
- label="Style",
124
- value="Ultra Réaliste"
 
 
 
125
  )
126
- quality_slider = gr.Slider(
127
  minimum=1,
128
- maximum=5,
129
- value=4,
130
- label="Niveau de Qualité",
131
- info="Impact la finesse des détails"
 
 
 
 
 
 
 
 
 
132
  )
133
 
 
 
134
  with gr.Row():
135
- resolution_selector = gr.Radio(
136
- choices=["4K", "8K"],
137
- value="8K",
138
- label="Résolution"
 
 
139
  )
140
-
141
- aspect_ratio = gr.Radio(
142
- choices=["1:1", "16:9", "9:16"],
143
- value="1:1",
144
- label="Format"
 
145
  )
146
 
147
- with gr.Column(scale=3):
148
- output_image = gr.Image(label="Résultat")
149
- status = gr.Textbox(label="Status")
150
-
151
- generate_btn = gr.Button("Générer", variant="primary")
152
-
153
- # Logique de génération optimisée
154
- def generate_optimized(prompt, style, quality, resolution, aspect):
155
- generator = EnhancedImageGenerator()
156
-
157
- # Configuration adaptative
158
- config = GenerationConfig(
159
- num_inference_steps=int(50 * ENHANCED_STYLES[style]["steps_multiplier"]),
160
- guidance_scale=7.5 * ENHANCED_STYLES[style]["quality_boost"],
161
- width=3840 if resolution == "4K" else 7680,
162
- height=2160 if resolution == "4K" else 4320
163
- )
164
-
165
  params = {
166
- "prompt": prompt,
167
- "style": style,
168
- "resolution": resolution,
169
- "quality_level": quality
 
 
 
 
 
 
 
 
 
170
  }
171
-
172
- return generator.generate(params, config)
 
173
 
174
  generate_btn.click(
175
- generate_optimized,
176
- inputs=[prompt_input, style_selector, quality_slider,
177
- resolution_selector, aspect_ratio],
178
- outputs=[output_image, status]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  )
180
 
181
- return interface
 
182
 
183
  if __name__ == "__main__":
184
- app = create_enhanced_interface()
 
185
  app.launch()
 
1
  import gradio as gr
2
+ import os
3
  from PIL import Image
4
+ import requests
5
+ import io
6
+ import gc
7
+ 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(
15
+ level=logging.DEBUG,
16
+ format='%(asctime)s - %(levelname)s - %(message)s'
17
+ )
18
+ logger = logging.getLogger(__name__)
 
 
19
 
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
+
117
+ class ImageGenerator:
118
  def __init__(self):
119
+ self.API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
120
+ token = os.getenv('HUGGINGFACE_TOKEN')
121
+ if not token:
122
+ logger.error("HUGGINGFACE_TOKEN non trouvé!")
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}"
196
+ logger.error(error_msg)
197
+ return None, error_msg
198
+
199
+ except Exception as e:
200
+ error_msg = f"⚠️ Erreur: {str(e)}"
201
+ logger.exception("Erreur pendant la génération:")
202
+ return None, error_msg
203
+ finally:
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
231
+ 2. Sélectionnez un style artistique et une composition
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():
240
+ format_size = gr.Dropdown(
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,
303
+ maximum=10,
304
+ value=7,
305
+ step=1,
306
+ label="Niveau de Détail",
307
+ info="Plus la valeur est élevée, plus l'image sera détaillée"
308
  )
309
+ contrast = gr.Slider(
310
  minimum=1,
311
+ maximum=10,
312
+ value=5,
313
+ step=1,
314
+ label="Contraste",
315
+ info="Influence l'intensité des couleurs et la différence entre les zones claires et sombres"
316
+ )
317
+ saturation = gr.Slider(
318
+ minimum=1,
319
+ maximum=10,
320
+ value=5,
321
+ step=1,
322
+ label="Saturation",
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():
329
+ quality = gr.Slider(
330
+ minimum=30,
331
+ maximum=50,
332
+ value=35,
333
+ label="Qualité",
334
+ info="Influence la qualité finale de l'image. Une valeur plus élevée prend plus de temps"
335
  )
336
+ creativity = gr.Slider(
337
+ minimum=5,
338
+ maximum=15,
339
+ value=7.5,
340
+ label="Créativité",
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 = {
354
+ "format_size": args[0],
355
+ "orientation": args[1],
356
+ "style": args[2],
357
+ "layout": args[3],
358
+ "ambiance": args[4],
359
+ "palette": args[5],
360
+ "subject": args[6],
361
+ "title": args[7],
362
+ "detail_level": args[8],
363
+ "contrast": args[9],
364
+ "saturation": args[10],
365
+ "quality": args[11],
366
+ "creativity": args[12]
367
  }
368
+ result = generator.generate(params)
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=[
375
+ format_size,
376
+ orientation,
377
+ style,
378
+ layout,
379
+ ambiance,
380
+ palette,
381
+ subject,
382
+ title,
383
+ detail_level,
384
+ contrast,
385
+ saturation,
386
+ quality,
387
+ creativity
388
+ ],
389
+ outputs=[image_output, status]
390
+ )
391
+
392
+ clear_btn.click(
393
+ lambda: (None, "🗑️ Image effacée"),
394
+ outputs=[image_output, status]
395
  )
396
 
397
+ logger.info("Interface créée avec succès")
398
+ return app
399
 
400
  if __name__ == "__main__":
401
+ app = create_interface()
402
+ logger.info("Démarrage de l'application")
403
  app.launch()