Equityone commited on
Commit
52c6cb7
·
verified ·
1 Parent(s): 68b569a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -84
app.py CHANGED
@@ -8,21 +8,17 @@ import json
8
  from typing import Tuple, Optional, Dict, Any
9
  import logging
10
  from dotenv import load_dotenv
11
- import time
12
 
13
  # Configuration du logging
14
- logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
 
 
 
15
  logger = logging.getLogger(__name__)
16
 
17
  # Chargement des variables d'environnement
18
  load_dotenv()
19
 
20
- # Constantes
21
- MAX_RETRIES = 3
22
- TIMEOUT = 60
23
- DEFAULT_WIDTH = 768
24
- DEFAULT_HEIGHT = 768
25
-
26
  # Styles artistiques étendus
27
  ART_STYLES = {
28
  "Art Moderne": {
@@ -56,10 +52,6 @@ ART_STYLES = {
56
  "Japonais": {
57
  "prompt_prefix": "japanese art style poster, ukiyo-e inspired design",
58
  "negative_prompt": "western, modern, photographic"
59
- },
60
- "Ultra Réaliste": {
61
- "prompt_prefix": "hyper-realistic poster, photographic quality, extremely detailed",
62
- "negative_prompt": "cartoon, illustration, stylized, abstract"
63
  }
64
  }
65
 
@@ -98,77 +90,85 @@ class ImageGenerator:
98
  logger.info("ImageGenerator initialisé")
99
 
100
  def _build_prompt(self, params: Dict[str, Any]) -> str:
 
101
  style_info = ART_STYLES.get(params["style"], ART_STYLES["Neo Vintage"])
102
  prompt = f"{style_info['prompt_prefix']}, {params['subject']}"
103
-
104
- for param_type in ['layout', 'ambiance', 'palette']:
105
- if params.get(param_type):
106
- prompt += f", {COMPOSITION_PARAMS[param_type.capitalize()][params[param_type]]}"
107
-
108
- for param, description in [
109
- ("detail_level", "highly detailed" if params.get("detail_level", 0) > 7 else "moderately detailed"),
110
- ("contrast", "high contrast" if params.get("contrast", 0) > 7 else "balanced contrast"),
111
- ("saturation", "vibrant colors" if params.get("saturation", 0) > 7 else "subtle colors")
112
- ]:
113
- if params.get(param):
114
- prompt += f", {description}"
115
-
 
 
 
 
 
 
 
116
  if params.get("title"):
117
  prompt += f", with text saying '{params['title']}'"
118
-
119
  logger.debug(f"Prompt final: {prompt}")
120
  return prompt
121
 
122
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
123
- for attempt in range(MAX_RETRIES):
124
- try:
125
- logger.info(f"Tentative de génération {attempt + 1}/{MAX_RETRIES}")
126
- if 'Bearer None' in self.headers['Authorization']:
127
- return None, "⚠️ Erreur: Token Hugging Face non configuré"
128
-
129
- prompt = self._build_prompt(params)
130
- payload = {
131
- "inputs": prompt,
132
- "parameters": {
133
- "negative_prompt": ART_STYLES[params["style"]]["negative_prompt"],
134
- "num_inference_steps": min(int(35 * (params["quality"]/100)), 50),
135
- "guidance_scale": min(7.5 * (params["creativity"]/10), 15.0),
136
- "width": DEFAULT_WIDTH,
137
- "height": DEFAULT_HEIGHT if params["orientation"] == "Portrait" else DEFAULT_WIDTH
138
- }
139
  }
 
140
 
141
- logger.debug(f"Payload: {json.dumps(payload, indent=2)}")
142
- response = requests.post(self.API_URL, headers=self.headers, json=payload, timeout=TIMEOUT)
143
- response.raise_for_status()
 
 
 
 
144
 
 
145
  image = Image.open(io.BytesIO(response.content))
146
  return image, "✨ Création réussie!"
 
 
 
 
147
 
148
- except requests.exceptions.RequestException as e:
149
- logger.warning(f"Erreur de requête à la tentative {attempt + 1}: {str(e)}")
150
- if attempt < MAX_RETRIES - 1:
151
- time.sleep(2 ** attempt) # Attente exponentielle
152
- else:
153
- return None, f"⚠️ Erreur de connexion après {MAX_RETRIES} tentatives: {str(e)}"
154
-
155
- except Exception as e:
156
- logger.exception("Erreur inattendue pendant la génération:")
157
- return None, f"⚠️ Erreur inattendue: {str(e)}"
158
-
159
- finally:
160
- gc.collect()
161
 
162
  def create_interface():
163
  logger.info("Création de l'interface Gradio")
164
  css = """
165
  .container { max-width: 1200px; margin: auto; }
166
- .welcome { text-align: center; margin: 20px 0; padding: 20px; background: #1e293b; border-radius: 10px; color: white; }
167
- .controls-group { background: #2d3748; padding: 15px; border-radius: 5px; margin: 10px 0; color: white; }
168
  .advanced-controls { background: #374151; padding: 12px; border-radius: 5px; margin: 8px 0; }
169
- .gradio-slider input[type="range"] { accent-color: #4a5568; }
170
- .gradio-button { transition: all 0.3s ease; }
171
- .gradio-button:hover { transform: translateY(-2px); box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); }
172
  """
173
 
174
  generator = ImageGenerator()
@@ -176,58 +176,118 @@ def create_interface():
176
  with gr.Blocks(css=css) as app:
177
  gr.HTML("""
178
  <div class="welcome">
179
- <h1>🎨 Equity Artisan 4.0</h1>
180
- <p>Assistant de création d'affiches professionnelles avancé</p>
181
  </div>
182
  """)
183
 
184
  with gr.Column(elem_classes="container"):
 
185
  with gr.Group(elem_classes="controls-group"):
186
  gr.Markdown("### 📐 Format et Orientation")
187
  with gr.Row():
188
- format_size = gr.Dropdown(choices=["A4", "A3", "A2", "A1", "A0"], value="A4", label="Format")
189
- orientation = gr.Radio(choices=["Portrait", "Paysage"], value="Portrait", label="Orientation")
 
 
 
 
 
 
 
 
190
 
 
191
  with gr.Group(elem_classes="controls-group"):
192
  gr.Markdown("### 🎨 Style et Composition")
193
  with gr.Row():
194
- style = gr.Dropdown(choices=list(ART_STYLES.keys()), value="Neo Vintage", label="Style artistique")
195
- layout = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Layouts"].keys()), value="Centré", label="Composition")
 
 
 
 
 
 
 
 
196
  with gr.Row():
197
- ambiance = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Ambiances"].keys()), value="Dramatique", label="Ambiance")
198
- palette = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Palette"].keys()), value="Contrasté", label="Palette")
 
 
 
 
 
 
 
 
199
 
 
200
  with gr.Group(elem_classes="controls-group"):
201
  gr.Markdown("### 📝 Contenu")
202
- subject = gr.Textbox(label="Description", placeholder="Décrivez votre vision...")
203
- title = gr.Textbox(label="Titre", placeholder="Titre de l'affiche...")
 
 
 
 
 
 
204
 
 
205
  with gr.Group(elem_classes="advanced-controls"):
206
  gr.Markdown("### 🎯 Ajustements Fins")
207
  with gr.Row():
208
- detail_level = gr.Slider(minimum=1, maximum=10, value=7, step=1, label="Niveau de Détail")
209
- contrast = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Contraste")
210
- saturation = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Saturation")
 
 
 
 
 
 
 
 
 
211
 
 
212
  with gr.Group(elem_classes="controls-group"):
213
  with gr.Row():
214
- quality = gr.Slider(minimum=30, maximum=50, value=35, label="Qualité")
215
- creativity = gr.Slider(minimum=5, maximum=15, value=7.5, label="Créativité")
 
 
 
 
 
 
216
 
 
217
  with gr.Row():
218
  generate_btn = gr.Button("✨ Générer", variant="primary")
219
  clear_btn = gr.Button("🗑️ Effacer", variant="secondary")
220
 
 
221
  image_output = gr.Image(label="Aperçu")
222
  status = gr.Textbox(label="Statut", interactive=False)
223
 
224
  def generate(*args):
225
  logger.info("Démarrage d'une nouvelle génération")
226
  params = {
227
- "format_size": args[0], "orientation": args[1], "style": args[2],
228
- "layout": args[3], "ambiance": args[4], "palette": args[5],
229
- "subject": args[6], "title": args[7], "detail_level": args[8],
230
- "contrast": args[9], "saturation": args[10], "quality": args[11],
 
 
 
 
 
 
 
 
231
  "creativity": args[12]
232
  }
233
  result = generator.generate(params)
@@ -236,11 +296,17 @@ def create_interface():
236
 
237
  generate_btn.click(
238
  generate,
239
- inputs=[format_size, orientation, style, layout, ambiance, palette, subject, title, detail_level, contrast, saturation, quality, creativity],
 
 
 
240
  outputs=[image_output, status]
241
  )
242
 
243
- clear_btn.click(lambda: (None, "🗑️ Image effacée"), outputs=[image_output, status])
 
 
 
244
 
245
  logger.info("Interface créée avec succès")
246
  return app
 
8
  from typing import Tuple, Optional, Dict, Any
9
  import logging
10
  from dotenv import load_dotenv
 
11
 
12
  # Configuration du logging
13
+ logging.basicConfig(
14
+ level=logging.DEBUG,
15
+ format='%(asctime)s - %(levelname)s - %(message)s'
16
+ )
17
  logger = logging.getLogger(__name__)
18
 
19
  # Chargement des variables d'environnement
20
  load_dotenv()
21
 
 
 
 
 
 
 
22
  # Styles artistiques étendus
23
  ART_STYLES = {
24
  "Art Moderne": {
 
52
  "Japonais": {
53
  "prompt_prefix": "japanese art style poster, ukiyo-e inspired design",
54
  "negative_prompt": "western, modern, photographic"
 
 
 
 
55
  }
56
  }
57
 
 
90
  logger.info("ImageGenerator initialisé")
91
 
92
  def _build_prompt(self, params: Dict[str, Any]) -> str:
93
+ """Construction de prompt améliorée"""
94
  style_info = ART_STYLES.get(params["style"], ART_STYLES["Neo Vintage"])
95
  prompt = f"{style_info['prompt_prefix']}, {params['subject']}"
96
+
97
+ # Ajout des paramètres de composition
98
+ if params.get("layout"):
99
+ prompt += f", {COMPOSITION_PARAMS['Layouts'][params['layout']]}"
100
+ if params.get("ambiance"):
101
+ prompt += f", {COMPOSITION_PARAMS['Ambiances'][params['ambiance']]}"
102
+ if params.get("palette"):
103
+ prompt += f", {COMPOSITION_PARAMS['Palette'][params['palette']]}"
104
+
105
+ # Ajout des ajustements fins
106
+ if params.get("detail_level"):
107
+ detail_strength = params["detail_level"]
108
+ prompt += f", {'highly detailed' if detail_strength > 7 else 'moderately detailed'}"
109
+ if params.get("contrast"):
110
+ contrast_strength = params["contrast"]
111
+ prompt += f", {'high contrast' if contrast_strength > 7 else 'balanced contrast'}"
112
+ if params.get("saturation"):
113
+ saturation_strength = params["saturation"]
114
+ prompt += f", {'vibrant colors' if saturation_strength > 7 else 'subtle colors'}"
115
+
116
  if params.get("title"):
117
  prompt += f", with text saying '{params['title']}'"
118
+
119
  logger.debug(f"Prompt final: {prompt}")
120
  return prompt
121
 
122
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
123
+ try:
124
+ logger.info(f"Début de génération avec paramètres: {json.dumps(params, indent=2)}")
125
+ if 'Bearer None' in self.headers['Authorization']:
126
+ return None, "⚠️ Erreur: Token Hugging Face non configuré"
127
+
128
+ prompt = self._build_prompt(params)
129
+
130
+ # Configuration de base
131
+ payload = {
132
+ "inputs": prompt,
133
+ "parameters": {
134
+ "negative_prompt": ART_STYLES[params["style"]]["negative_prompt"],
135
+ "num_inference_steps": min(int(35 * (params["quality"]/100)), 40),
136
+ "guidance_scale": min(7.5 * (params["creativity"]/10), 10.0),
137
+ "width": 768,
138
+ "height": 768 if params["orientation"] == "Portrait" else 512
139
  }
140
+ }
141
 
142
+ logger.debug(f"Payload: {json.dumps(payload, indent=2)}")
143
+ response = requests.post(
144
+ self.API_URL,
145
+ headers=self.headers,
146
+ json=payload,
147
+ timeout=30
148
+ )
149
 
150
+ if response.status_code == 200:
151
  image = Image.open(io.BytesIO(response.content))
152
  return image, "✨ Création réussie!"
153
+ else:
154
+ error_msg = f"⚠️ Erreur API {response.status_code}: {response.text}"
155
+ logger.error(error_msg)
156
+ return None, error_msg
157
 
158
+ except Exception as e:
159
+ error_msg = f"⚠️ Erreur: {str(e)}"
160
+ logger.exception("Erreur pendant la génération:")
161
+ return None, error_msg
162
+ finally:
163
+ gc.collect()
 
 
 
 
 
 
 
164
 
165
  def create_interface():
166
  logger.info("Création de l'interface Gradio")
167
  css = """
168
  .container { max-width: 1200px; margin: auto; }
169
+ .welcome { text-align: center; margin: 20px 0; padding: 20px; background: #1e293b; border-radius: 10px; }
170
+ .controls-group { background: #2d3748; padding: 15px; border-radius: 5px; margin: 10px 0; }
171
  .advanced-controls { background: #374151; padding: 12px; border-radius: 5px; margin: 8px 0; }
 
 
 
172
  """
173
 
174
  generator = ImageGenerator()
 
176
  with gr.Blocks(css=css) as app:
177
  gr.HTML("""
178
  <div class="welcome">
179
+ <h1>🎨 Equity Artisan 3.0</h1>
180
+ <p>Assistant de création d'affiches professionnelles</p>
181
  </div>
182
  """)
183
 
184
  with gr.Column(elem_classes="container"):
185
+ # Format et Orientation
186
  with gr.Group(elem_classes="controls-group"):
187
  gr.Markdown("### 📐 Format et Orientation")
188
  with gr.Row():
189
+ format_size = gr.Dropdown(
190
+ choices=["A4", "A3", "A2", "A1", "A0"],
191
+ value="A4",
192
+ label="Format"
193
+ )
194
+ orientation = gr.Radio(
195
+ choices=["Portrait", "Paysage"],
196
+ value="Portrait",
197
+ label="Orientation"
198
+ )
199
 
200
+ # Style et Composition
201
  with gr.Group(elem_classes="controls-group"):
202
  gr.Markdown("### 🎨 Style et Composition")
203
  with gr.Row():
204
+ style = gr.Dropdown(
205
+ choices=list(ART_STYLES.keys()),
206
+ value="Neo Vintage",
207
+ label="Style artistique"
208
+ )
209
+ layout = gr.Dropdown(
210
+ choices=list(COMPOSITION_PARAMS["Layouts"].keys()),
211
+ value="Centré",
212
+ label="Composition"
213
+ )
214
  with gr.Row():
215
+ ambiance = gr.Dropdown(
216
+ choices=list(COMPOSITION_PARAMS["Ambiances"].keys()),
217
+ value="Dramatique",
218
+ label="Ambiance"
219
+ )
220
+ palette = gr.Dropdown(
221
+ choices=list(COMPOSITION_PARAMS["Palette"].keys()),
222
+ value="Contrasté",
223
+ label="Palette"
224
+ )
225
 
226
+ # Contenu
227
  with gr.Group(elem_classes="controls-group"):
228
  gr.Markdown("### 📝 Contenu")
229
+ subject = gr.Textbox(
230
+ label="Description",
231
+ placeholder="Décrivez votre vision..."
232
+ )
233
+ title = gr.Textbox(
234
+ label="Titre",
235
+ placeholder="Titre de l'affiche..."
236
+ )
237
 
238
+ # Ajustements fins
239
  with gr.Group(elem_classes="advanced-controls"):
240
  gr.Markdown("### 🎯 Ajustements Fins")
241
  with gr.Row():
242
+ detail_level = gr.Slider(
243
+ minimum=1, maximum=10, value=7, step=1,
244
+ label="Niveau de Détail"
245
+ )
246
+ contrast = gr.Slider(
247
+ minimum=1, maximum=10, value=5, step=1,
248
+ label="Contraste"
249
+ )
250
+ saturation = gr.Slider(
251
+ minimum=1, maximum=10, value=5, step=1,
252
+ label="Saturation"
253
+ )
254
 
255
+ # Paramètres de génération
256
  with gr.Group(elem_classes="controls-group"):
257
  with gr.Row():
258
+ quality = gr.Slider(
259
+ minimum=30, maximum=50, value=35,
260
+ label="Qualité"
261
+ )
262
+ creativity = gr.Slider(
263
+ minimum=5, maximum=15, value=7.5,
264
+ label="Créativité"
265
+ )
266
 
267
+ # Boutons
268
  with gr.Row():
269
  generate_btn = gr.Button("✨ Générer", variant="primary")
270
  clear_btn = gr.Button("🗑️ Effacer", variant="secondary")
271
 
272
+ # Sortie
273
  image_output = gr.Image(label="Aperçu")
274
  status = gr.Textbox(label="Statut", interactive=False)
275
 
276
  def generate(*args):
277
  logger.info("Démarrage d'une nouvelle génération")
278
  params = {
279
+ "format_size": args[0],
280
+ "orientation": args[1],
281
+ "style": args[2],
282
+ "layout": args[3],
283
+ "ambiance": args[4],
284
+ "palette": args[5],
285
+ "subject": args[6],
286
+ "title": args[7],
287
+ "detail_level": args[8],
288
+ "contrast": args[9],
289
+ "saturation": args[10],
290
+ "quality": args[11],
291
  "creativity": args[12]
292
  }
293
  result = generator.generate(params)
 
296
 
297
  generate_btn.click(
298
  generate,
299
+ inputs=[
300
+ format_size, orientation, style, layout, ambiance, palette,
301
+ subject, title, detail_level, contrast, saturation, quality, creativity
302
+ ],
303
  outputs=[image_output, status]
304
  )
305
 
306
+ clear_btn.click(
307
+ lambda: (None, "🗑️ Image effacée"),
308
+ outputs=[image_output, status]
309
+ )
310
 
311
  logger.info("Interface créée avec succès")
312
  return app