Equityone commited on
Commit
343349d
·
verified ·
1 Parent(s): 14caaf8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +190 -248
app.py CHANGED
@@ -1,207 +1,150 @@
1
  import gradio as gr
2
  import os
3
- from PIL import Image, ImageEnhance, ImageFilter
4
  import requests
5
  import io
6
  import gc
7
  import json
 
8
  import logging
9
  from dotenv import load_dotenv
10
- from typing import Tuple, Optional, Dict, Any, List
11
  import numpy as np
12
- from dataclasses import dataclass
13
 
14
- # Configuration avancée du logging
15
  logging.basicConfig(
16
  level=logging.DEBUG,
17
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
 
 
 
 
18
  )
19
- logger = logging.getLogger("EquityArtisan")
20
-
21
- # Chargement des variables d'environnement
22
  load_dotenv()
23
 
24
- @dataclass
25
- class RenderingParams:
26
- """Paramètres de rendu avancés pour le contrôle fin de la génération"""
27
- steps: int # Nombre d'étapes d'inférence
28
- cfg_scale: float # Échelle de guidance
29
- width: int # Largeur
30
- height: int # Hauteur
31
- sampler: str # Méthode d'échantillonnage
32
- seed: Optional[int] # Seed pour la reproductibilité
33
-
34
- @dataclass
35
- class StyleConfig:
36
- """Configuration complète d'un style artistique"""
37
- prompt_prefix: str
38
- negative_prompt: str
39
- quality_modifiers: List[str]
40
- detail_modifiers: List[str]
41
- composition_rules: List[str]
42
-
43
- # Styles artistiques enrichis
44
  ART_STYLES = {
45
- "Ultra Photoréaliste": StyleConfig(
46
- prompt_prefix="masterpiece, ultra realistic photograph, octane render, unreal engine 5 rendering, ray tracing, global illumination, subsurface scattering, volumetric lighting, 8k uhd, photorealistic",
47
- negative_prompt="cartoon, illustration, painting, drawing, sketch, anime, low quality, blurry, noise, grain, deformed, ugly, disfigured",
48
- quality_modifiers=["hyperdetailed", "photographic", "award winning photography"],
49
- detail_modifiers=["intricate details", "sharp focus", "professional lighting"],
50
- composition_rules=["rule of thirds", "golden ratio", "perfect composition"]
51
- ),
52
- "Cinématique": StyleConfig(
53
- prompt_prefix="cinematic scene, anamorphic lens, movie still, dramatic lighting, high production value, professional cinematography, ARRI camera",
54
- negative_prompt="amateur, low budget, poor lighting, webcam, phone camera",
55
- quality_modifiers=["film grain", "color grading", "bokeh effect"],
56
- detail_modifiers=["depth of field", "motion blur", "lens flare"],
57
- composition_rules=["wide aspect ratio", "leading lines", "frame within frame"]
58
- ),
59
- # ... [Autres styles similaires] ...
60
- }
61
-
62
- # Paramètres de qualité avancés
63
- QUALITY_PRESETS = {
64
- "Standard": RenderingParams(
65
- steps=30,
66
- cfg_scale=7.5,
67
- width=768,
68
- height=768,
69
- sampler="Euler a",
70
- seed=None
71
- ),
72
- "Haute Qualité": RenderingParams(
73
- steps=40,
74
- cfg_scale=8.5,
75
- width=1024,
76
- height=1024,
77
- sampler="DPM++ 2M Karras",
78
- seed=None
79
- ),
80
- "Ultra Qualité": RenderingParams(
81
- steps=50,
82
- cfg_scale=9.0,
83
- width=1536,
84
- height=1536,
85
- sampler="DPM++ SDE Karras",
86
- seed=None
87
- )
88
- }
89
-
90
- # Enrichissement des paramètres de composition
91
- COMPOSITION_PARAMS = {
92
- "Layouts": {
93
- "Dynamique": {
94
- "description": "Composition dynamique avec lignes de force",
95
- "modifiers": ["dynamic composition", "leading lines", "visual flow"],
96
- "weights": {"foreground": 1.2, "background": 0.8}
97
- },
98
- "Équilibré": {
99
- "description": "Composition harmonieuse et équilibrée",
100
- "modifiers": ["balanced composition", "symmetrical layout", "visual harmony"],
101
- "weights": {"foreground": 1.0, "background": 1.0}
102
  }
103
- # ... [Autres layouts] ...
104
  },
105
- "Éclairages": {
106
- "Studio": {
107
- "description": "Éclairage professionnel type studio",
108
- "modifiers": ["professional studio lighting", "three-point lighting", "soft boxes"],
109
- "technical_params": {"contrast": 1.2, "highlights": 1.1}
110
- },
111
- "Naturel": {
112
- "description": "Éclairage naturel avec lumière ambiante",
113
- "modifiers": ["natural lighting", "golden hour", "ambient occlusion"],
114
- "technical_params": {"contrast": 0.9, "shadows": 0.8}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
- # ... [Autres éclairages] ...
117
  }
118
  }
119
 
120
- class AdvancedImageGenerator:
 
121
  def __init__(self):
122
- self.API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
123
- self.token = os.getenv('HUGGINGFACE_TOKEN')
124
- if not self.token:
125
- raise EnvironmentError("HUGGINGFACE_TOKEN non configuré")
126
- self.headers = {"Authorization": f"Bearer {self.token}"}
127
-
128
- # Initialisation du cache pour les paramètres optimaux
129
- self.optimization_cache = {}
130
- logger.info("AdvancedImageGenerator initialisé avec paramètres enrichis")
131
-
132
- def _optimize_prompt(self, base_prompt: str, style_config: StyleConfig, params: Dict[str, Any]) -> str:
133
- """Optimisation avancée du prompt avec analyse sémantique"""
134
- components = [
135
- style_config.prompt_prefix,
136
- base_prompt
137
- ]
138
 
139
- # Ajout des modificateurs de qualité selon le niveau demandé
140
- quality_level = params.get("quality", 50)
141
- if quality_level > 40:
142
- components.extend(style_config.quality_modifiers)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
- # Ajout des règles de composition
145
- components.extend(style_config.composition_rules)
146
-
147
- # Optimisation contextuelle basée sur le sujet
148
- if "portrait" in base_prompt.lower():
149
- components.extend([
150
- "perfect facial features",
151
- "detailed skin texture",
152
- "professional portrait lighting"
153
- ])
154
- elif "paysage" in base_prompt.lower():
155
- components.extend([
156
- "atmospheric perspective",
157
- "perfect weather conditions",
158
- "golden hour lighting"
159
- ])
160
-
161
- return ", ".join(components)
162
 
163
- def _apply_advanced_processing(self, image: Image.Image, params: Dict[str, Any]) -> Image.Image:
164
- """Application de traitements avancés post-génération"""
165
- try:
166
- # Amélioration des détails
167
- if params.get("detail_enhancement", True):
168
- image = image.filter(ImageFilter.DETAIL)
169
-
170
- # Optimisation du contraste local
171
- if params.get("local_contrast", True):
172
- enhancer = ImageEnhance.Contrast(image)
173
- image = enhancer.enhance(1.2)
174
-
175
- # Ajustement des couleurs
176
- if params.get("color_optimization", True):
177
- enhancer = ImageEnhance.Color(image)
178
- image = enhancer.enhance(1.1)
179
-
180
- return image
181
- except Exception as e:
182
- logger.error(f"Erreur lors du post-traitement: {e}")
183
- return image
184
 
185
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
186
- """Génération d'image avec paramètres avancés"""
187
  try:
188
- logger.info(f"Démarrage génération avec paramètres: {json.dumps(params, indent=2)}")
189
-
190
- style_config = ART_STYLES[params["style"]]
191
- prompt = self._optimize_prompt(params["subject"], style_config, params)
192
-
193
- # Sélection des paramètres de rendu
194
- quality_preset = QUALITY_PRESETS["Ultra Qualité" if params["quality"] > 45 else "Haute Qualité"]
195
-
 
196
  payload = {
197
  "inputs": prompt,
198
  "parameters": {
199
- "negative_prompt": style_config.negative_prompt,
200
- "num_inference_steps": quality_preset.steps,
201
- "guidance_scale": quality_preset.cfg_scale,
202
- "width": quality_preset.width,
203
- "height": quality_preset.height,
204
- "sampler": quality_preset.sampler
205
  }
206
  }
207
 
@@ -209,138 +152,138 @@ class AdvancedImageGenerator:
209
  self.API_URL,
210
  headers=self.headers,
211
  json=payload,
212
- timeout=60
213
  )
214
 
215
- if response.status_code != 200:
216
- raise Exception(f"Erreur API: {response.status_code}")
217
-
218
- # Traitement et optimisation de l'image générée
219
- image = Image.open(io.BytesIO(response.content))
220
- image = self._apply_advanced_processing(image, params)
221
-
222
- return image, "✨ Génération réussie avec paramètres optimaux!"
 
 
 
223
 
224
  except Exception as e:
225
- logger.exception("Erreur pendant la génération:")
226
- return None, f"⚠️ Erreur: {str(e)}"
 
 
 
227
 
 
228
  def create_interface():
229
- """Création de l'interface utilisateur enrichie"""
230
- logger.info("Initialisation de l'interface avancée")
231
 
 
232
  css = """
233
- .container { max-width: 1400px; margin: auto; padding: 20px; }
234
  .welcome {
235
  text-align: center;
236
  margin: 20px 0;
237
- padding: 30px;
238
  background: linear-gradient(135deg, #1e293b, #334155);
239
- border-radius: 15px;
240
  color: white;
241
  }
242
  .controls-group {
243
  background: #2d3748;
244
- padding: 20px;
245
- border-radius: 10px;
246
- margin: 15px 0;
247
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
248
  }
249
  """
250
 
251
- generator = AdvancedImageGenerator()
252
-
253
  with gr.Blocks(css=css) as app:
254
  gr.HTML("""
255
  <div class="welcome">
256
- <h1>🎨 Equity Artisan 4.0 Pro</h1>
257
- <p>Studio de Création Visuelle Avancé</p>
258
  </div>
259
  """)
260
 
261
  with gr.Column(elem_classes="container"):
262
- # Configuration principale
263
  with gr.Group(elem_classes="controls-group"):
264
- gr.Markdown("### 🎭 Style et Composition")
265
  with gr.Row():
 
 
 
 
 
 
 
 
 
 
266
  style = gr.Dropdown(
267
  choices=list(ART_STYLES.keys()),
268
- value="Ultra Photoréaliste",
269
  label="Style Artistique"
270
  )
271
- quality_preset = gr.Dropdown(
272
- choices=list(QUALITY_PRESETS.keys()),
273
- value="Haute Qualité",
274
- label="Preset de Qualité"
275
- )
276
 
277
- # Paramètres créatifs
278
  with gr.Group(elem_classes="controls-group"):
279
- gr.Markdown("### 🎨 Paramètres Créatifs")
280
- with gr.Row():
281
- subject = gr.Textbox(
282
- label="Description",
283
- placeholder="Décrivez votre vision en détail...",
284
- lines=3
285
- )
286
- composition = gr.Dropdown(
287
- choices=list(COMPOSITION_PARAMS["Layouts"].keys()),
288
- value="Dynamique",
289
- label="Type de Composition"
290
- )
291
-
292
- # Contrôles techniques
293
  with gr.Group(elem_classes="controls-group"):
294
- gr.Markdown("### ⚙️ Paramètres Techniques")
295
  with gr.Row():
296
  quality = gr.Slider(
297
  minimum=30,
298
- maximum=100,
299
- value=75,
300
- label="Niveau de Qualité"
301
  )
302
  detail_level = gr.Slider(
303
  minimum=1,
304
  maximum=10,
305
  value=8,
 
306
  label="Niveau de Détail"
307
  )
308
 
309
- # Génération
310
  with gr.Row():
311
- generate_btn = gr.Button("✨ Générer", variant="primary", size="lg")
312
- clear_btn = gr.Button("🗑️ Réinitialiser", variant="secondary")
313
 
314
- # Résultats
315
- image_output = gr.Image(
316
- label="Aperçu",
317
- elem_classes="result-image"
318
- )
319
- status = gr.Textbox(
320
- label="Statut",
321
- interactive=False
322
- )
323
 
324
- # Logique de génération
325
- def generate_image(*args):
326
  params = {
327
- "style": args[0],
328
- "quality_preset": args[1],
329
- "subject": args[2],
330
- "composition": args[3],
331
- "quality": args[4],
332
- "detail_level": args[5]
 
333
  }
334
  return generator.generate(params)
335
 
336
- # Événements
337
  generate_btn.click(
338
- generate_image,
339
  inputs=[
 
 
340
  style,
341
- quality_preset,
342
  subject,
343
- composition,
344
  quality,
345
  detail_level
346
  ],
@@ -348,11 +291,10 @@ def create_interface():
348
  )
349
 
350
  clear_btn.click(
351
- lambda: (None, "🔄 Interface réinitialisée"),
352
  outputs=[image_output, status]
353
  )
354
 
355
- logger.info("Interface créée avec succès")
356
  return app
357
 
358
  if __name__ == "__main__":
 
1
  import gradio as gr
2
  import os
3
+ from PIL import Image, ImageEnhance
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
  import numpy as np
12
+ import cv2
13
 
14
+ # Configuration du logging
15
  logging.basicConfig(
16
  level=logging.DEBUG,
17
+ format='%(asctime)s - %(levelname)s - %(message)s',
18
+ handlers=[
19
+ logging.FileHandler('equity_space.log'),
20
+ logging.StreamHandler()
21
+ ]
22
  )
23
+ logger = logging.getLogger(__name__)
 
 
24
  load_dotenv()
25
 
26
+ # 1. STYLES EQUITY (basés sur les 8 documents)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ART_STYLES = {
28
+ "Renaissance Technologique": {
29
+ "prompt_prefix": """ultra-detailed technical drawing, da vinci style engineering precision,
30
+ anatomical accuracy, golden ratio proportions, scientific illustration quality,
31
+ masterful light and shadow, highest level of detail, museum quality artwork""",
32
+ "negative_prompt": "simple sketch, imprecise, cartoon, abstract, low detail",
33
+ "quality_boost": 1.5,
34
+ "style_params": {
35
+ "detail_level": "maximum",
36
+ "technical_precision": True,
37
+ "historical_accuracy": True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
 
39
  },
40
+ "Innovation Moderne": {
41
+ "prompt_prefix": """cutting-edge technological design, futuristic engineering visual,
42
+ advanced mechanical detail, precise technical schematic, innovative concept art,
43
+ professional industrial visualization, high-tech aesthetic""",
44
+ "negative_prompt": "vintage, retro, simplified, abstract",
45
+ "quality_boost": 1.4,
46
+ "style_params": {
47
+ "tech_detail": "ultra",
48
+ "innovation_focus": True
49
+ }
50
+ },
51
+ "Photographie Analytique": {
52
+ "prompt_prefix": """professional analytical photography, ansel adams zone system,
53
+ ultra sharp detail, perfect exposure, museum grade quality, technical perfection,
54
+ masterful composition, extreme clarity""",
55
+ "negative_prompt": "blurry, artistic, painterly, low quality",
56
+ "quality_boost": 1.5,
57
+ "style_params": {
58
+ "photographic_precision": True,
59
+ "detail_preservation": "maximum"
60
+ }
61
+ },
62
+ "Vision Futuriste": {
63
+ "prompt_prefix": """advanced technological concept, future engineering visualization,
64
+ innovative architectural design, sci-fi technical precision, ultra modern aesthetic,
65
+ professional technical illustration""",
66
+ "negative_prompt": "historical, vintage, traditional, hand-drawn",
67
+ "quality_boost": 1.4,
68
+ "style_params": {
69
+ "future_tech": True,
70
+ "concept_clarity": "high"
71
  }
 
72
  }
73
  }
74
 
75
+ # 2. OPTIMISATION DE LA QUALITÉ
76
+ class ImageEnhancer:
77
  def __init__(self):
78
+ self.enhancement_pipeline = {
79
+ "technical_detail": self._enhance_technical_detail,
80
+ "color_refinement": self._refine_colors,
81
+ "sharpness_boost": self._boost_sharpness,
82
+ "contrast_optimization": self._optimize_contrast
83
+ }
 
 
 
 
 
 
 
 
 
 
84
 
85
+ def _enhance_technical_detail(self, image: np.ndarray) -> np.ndarray:
86
+ kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
87
+ return cv2.filter2D(image, -1, kernel)
88
+
89
+ def _refine_colors(self, image: np.ndarray) -> np.ndarray:
90
+ lab = cv2.cvtColor(image, cv2.COLOR_BGR2Lab)
91
+ l, a, b = cv2.split(lab)
92
+ clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
93
+ l = clahe.apply(l)
94
+ lab = cv2.merge((l,a,b))
95
+ return cv2.cvtColor(lab, cv2.COLOR_Lab2BGR)
96
+
97
+ def _boost_sharpness(self, image: np.ndarray) -> np.ndarray:
98
+ blurred = cv2.GaussianBlur(image, (0, 0), 3)
99
+ return cv2.addWeighted(image, 1.5, blurred, -0.5, 0)
100
+
101
+ def _optimize_contrast(self, image: np.ndarray) -> np.ndarray:
102
+ lab = cv2.cvtColor(image, cv2.COLOR_BGR2Lab)
103
+ l, a, b = cv2.split(lab)
104
+ clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
105
+ l = clahe.apply(l)
106
+ lab = cv2.merge((l,a,b))
107
+ return cv2.cvtColor(lab, cv2.COLOR_Lab2BGR)
108
+
109
+ def enhance_image(self, image: Image.Image, style_params: Dict) -> Image.Image:
110
+ cv_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
111
 
112
+ for enhancement, should_apply in style_params.items():
113
+ if should_apply and enhancement in self.enhancement_pipeline:
114
+ cv_image = self.enhancement_pipeline[enhancement](cv_image)
115
+
116
+ return Image.fromarray(cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB))
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
+ # 3. GÉNÉRATEUR D'IMAGES PRINCIPAL
119
+ class ImageGenerator:
120
+ def __init__(self):
121
+ self.API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
122
+ self.enhancer = ImageEnhancer()
123
+ token = os.getenv('HUGGINGFACE_TOKEN')
124
+ if not token:
125
+ logger.error("HUGGINGFACE_TOKEN non trouvé!")
126
+ self.headers = {"Authorization": f"Bearer {token}"}
127
+ logger.info("ImageGenerator initialisé")
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
 
130
  try:
131
+ style_info = ART_STYLES.get(params["style"])
132
+ if not style_info:
133
+ return None, "⚠️ Style non trouvé"
134
+
135
+ # Construction du prompt optimisé
136
+ prompt = f"{params['subject']}, {style_info['prompt_prefix']}"
137
+ if params.get('title'):
138
+ prompt += f", with text: {params['title']}"
139
+
140
  payload = {
141
  "inputs": prompt,
142
  "parameters": {
143
+ "negative_prompt": style_info["negative_prompt"],
144
+ "num_inference_steps": int(50 * style_info["quality_boost"]),
145
+ "guidance_scale": min(9.0 * style_info["quality_boost"], 12.0),
146
+ "width": 1024 if params.get("quality", 35) > 40 else 768,
147
+ "height": 1024 if params["orientation"] == "Portrait" else 768
 
148
  }
149
  }
150
 
 
152
  self.API_URL,
153
  headers=self.headers,
154
  json=payload,
155
+ timeout=45
156
  )
157
 
158
+ if response.status_code == 200:
159
+ image = Image.open(io.BytesIO(response.content))
160
+ enhanced_image = self.enhancer.enhance_image(
161
+ image,
162
+ style_info["style_params"]
163
+ )
164
+ return enhanced_image, "✨ Création réussie!"
165
+ else:
166
+ error_msg = f"⚠️ Erreur API {response.status_code}: {response.text}"
167
+ logger.error(error_msg)
168
+ return None, error_msg
169
 
170
  except Exception as e:
171
+ error_msg = f"⚠️ Erreur: {str(e)}"
172
+ logger.exception("Erreur génération:")
173
+ return None, error_msg
174
+ finally:
175
+ gc.collect()
176
 
177
+ # 4. INTERFACE UTILISATEUR
178
  def create_interface():
179
+ generator = ImageGenerator()
 
180
 
181
+ # Style CSS personnalisé
182
  css = """
183
+ .container { max-width: 1200px; margin: auto; }
184
  .welcome {
185
  text-align: center;
186
  margin: 20px 0;
187
+ padding: 20px;
188
  background: linear-gradient(135deg, #1e293b, #334155);
189
+ border-radius: 10px;
190
  color: white;
191
  }
192
  .controls-group {
193
  background: #2d3748;
194
+ padding: 15px;
195
+ border-radius: 5px;
196
+ margin: 10px 0;
197
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
198
  }
199
  """
200
 
 
 
201
  with gr.Blocks(css=css) as app:
202
  gr.HTML("""
203
  <div class="welcome">
204
+ <h1>🎨 Equity Artisan 3.0</h1>
205
+ <p>Assistant de Création d'Images Professionnelles</p>
206
  </div>
207
  """)
208
 
209
  with gr.Column(elem_classes="container"):
210
+ # Format et Style
211
  with gr.Group(elem_classes="controls-group"):
 
212
  with gr.Row():
213
+ format_size = gr.Dropdown(
214
+ choices=["A4", "A3", "A2", "A1"],
215
+ value="A4",
216
+ label="Format"
217
+ )
218
+ orientation = gr.Radio(
219
+ choices=["Portrait", "Paysage"],
220
+ value="Portrait",
221
+ label="Orientation"
222
+ )
223
  style = gr.Dropdown(
224
  choices=list(ART_STYLES.keys()),
225
+ value="Renaissance Technologique",
226
  label="Style Artistique"
227
  )
 
 
 
 
 
228
 
229
+ # Description
230
  with gr.Group(elem_classes="controls-group"):
231
+ subject = gr.Textbox(
232
+ label="Description",
233
+ placeholder="Décrivez votre vision technique ou artistique...",
234
+ lines=3
235
+ )
236
+ title = gr.Textbox(
237
+ label="Titre (optionnel)",
238
+ placeholder="Titre à inclure dans l'image..."
239
+ )
240
+
241
+ # Paramètres avancés
 
 
 
242
  with gr.Group(elem_classes="controls-group"):
 
243
  with gr.Row():
244
  quality = gr.Slider(
245
  minimum=30,
246
+ maximum=50,
247
+ value=40,
248
+ label="Qualité"
249
  )
250
  detail_level = gr.Slider(
251
  minimum=1,
252
  maximum=10,
253
  value=8,
254
+ step=1,
255
  label="Niveau de Détail"
256
  )
257
 
258
+ # Boutons
259
  with gr.Row():
260
+ generate_btn = gr.Button("✨ Générer", variant="primary")
261
+ clear_btn = gr.Button("🗑️ Effacer")
262
 
263
+ # Résultat
264
+ image_output = gr.Image(label="Résultat")
265
+ status = gr.Textbox(label="Status", interactive=False)
 
 
 
 
 
 
266
 
267
+ def generate(*args):
 
268
  params = {
269
+ "format_size": args[0],
270
+ "orientation": args[1],
271
+ "style": args[2],
272
+ "subject": args[3],
273
+ "title": args[4],
274
+ "quality": args[5],
275
+ "detail_level": args[6]
276
  }
277
  return generator.generate(params)
278
 
 
279
  generate_btn.click(
280
+ generate,
281
  inputs=[
282
+ format_size,
283
+ orientation,
284
  style,
 
285
  subject,
286
+ title,
287
  quality,
288
  detail_level
289
  ],
 
291
  )
292
 
293
  clear_btn.click(
294
+ lambda: (None, "🗑️ Image effacée"),
295
  outputs=[image_output, status]
296
  )
297
 
 
298
  return app
299
 
300
  if __name__ == "__main__":