Equityone commited on
Commit
0c4498a
·
verified ·
1 Parent(s): 4367472

Update app.py

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