Equityone commited on
Commit
1191660
·
verified ·
1 Parent(s): 87dd51f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -114
app.py CHANGED
@@ -57,7 +57,12 @@ ART_STYLES = {
57
  "Bande Dessinée": {
58
  "prompt_prefix": "comic book style poster, vibrant colors, bold outlines",
59
  "negative_prompt": "realistic, photographic, subtle, muted colors"
60
- }
 
 
 
 
 
61
  }
62
 
63
  # Paramètres de composition étendus
@@ -74,49 +79,48 @@ COMPOSITION_PARAMS = {
74
  "Symétrie": "symmetrical composition, mirror-like balance",
75
  "Cadre dans le cadre": "frame within a frame composition"
76
  },
77
- "Ambiances": {
78
- "Dramatique": "dramatic lighting, high contrast",
79
- "Doux": "soft lighting, gentle atmosphere",
80
- "Vibrant": "vibrant colors, energetic mood",
81
- "Mystérieux": "mysterious atmosphere, moody lighting",
82
- "Serein": "peaceful atmosphere, calm mood",
83
- "Rétro": "retro atmosphere, nostalgic mood",
84
- "Futuriste": "futuristic atmosphere, high-tech mood",
85
- "Onirique": "dreamy atmosphere, surreal mood",
86
- "Industriel": "industrial atmosphere, raw and urban mood",
87
- "Naturel": "natural atmosphere, organic and earthy mood"
88
- },
89
- "Palette": {
90
- "Monochrome": "monochromatic color scheme",
91
- "Contrasté": "high contrast color palette",
92
- "Pastel": "soft pastel color palette",
93
- "Terre": "earthy color palette",
94
- "Néon": "neon color palette",
95
- "Complémentaire": "complementary color scheme",
96
- "Analogique": "analogous color scheme",
97
- "Triadique": "triadic color scheme",
98
- "Tétradique": "tetradic color scheme",
99
- "Tons rompus": "muted tones color palette"
100
- }
101
  }
102
 
103
  class ImageGenerator:
104
  def __init__(self):
105
- self.API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
 
106
  token = os.getenv('HUGGINGFACE_TOKEN')
 
107
  if not token:
108
  logger.error("HUGGINGFACE_TOKEN non trouvé!")
 
109
  self.headers = {"Authorization": f"Bearer {token}"}
 
110
  logger.info("ImageGenerator initialisé")
111
 
112
  def _build_prompt(self, params: Dict[str, Any]) -> str:
113
  style_info = ART_STYLES.get(params["style"], ART_STYLES["Neo Vintage"])
 
114
  prompt = f"{style_info['prompt_prefix']}, {params['subject']}"
115
 
116
  if params.get("layout"):
117
  prompt += f", {COMPOSITION_PARAMS['Layouts'][params['layout']]}"
 
118
  if params.get("ambiance"):
119
  prompt += f", {COMPOSITION_PARAMS['Ambiances'][params['ambiance']]}"
 
120
  if params.get("palette"):
121
  prompt += f", {COMPOSITION_PARAMS['Palette'][params['palette']]}"
122
 
@@ -124,7 +128,7 @@ class ImageGenerator:
124
  ("detail_level", "highly detailed" if params.get("detail_level", 0) > 7 else "moderately detailed"),
125
  ("contrast", "high contrast" if params.get("contrast", 0) > 7 else "balanced contrast"),
126
  ("saturation", "vibrant colors" if params.get("saturation", 0) > 7 else "subtle colors")
127
- ]:
128
  if params.get(param):
129
  prompt += f", {description}"
130
 
@@ -132,46 +136,55 @@ class ImageGenerator:
132
  prompt += f", with text saying '{params['title']}'"
133
 
134
  logger.debug(f"Prompt final: {prompt}")
 
135
  return prompt
136
 
137
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
138
  try:
139
- logger.info(f"Début de génération avec paramètres: {json.dumps(params, indent=2)}")
 
140
  if 'Bearer None' in self.headers['Authorization']:
141
- return None, "⚠️ Erreur: Token Hugging Face non configuré"
142
-
143
  prompt = self._build_prompt(params)
 
144
  payload = {
145
- "inputs": prompt,
146
- "parameters": {
147
- "negative_prompt": ART_STYLES[params["style"]]["negative_prompt"],
148
- "num_inference_steps": min(int(35 * (params["quality"]/100)), 40),
149
- "guidance_scale": min(7.5 * (params["creativity"]/10), 10.0),
150
- "width": 768,
151
- "height": 768 if params["orientation"] == "Portrait" else 512
152
  }
153
  }
154
-
155
- logger.debug(f"Payload: {json.dumps(payload, indent=2)}")
156
- response = requests.post(self.API_URL, headers=self.headers, json=payload, timeout=30)
157
-
 
 
 
 
158
  if response.status_code == 200:
159
  image = Image.open(io.BytesIO(response.content))
160
- return image, "✨ Création réussie!"
161
  else:
162
- error_msg = f"⚠️ Erreur API {response.status_code}: {response.text}"
163
  logger.error(error_msg)
164
- return None, error_msg
165
-
166
  except Exception as e:
167
- error_msg = f"⚠️ Erreur: {str(e)}"
168
  logger.exception("Erreur pendant la génération:")
169
- return None, error_msg
 
170
  finally:
171
  gc.collect()
172
 
173
  def create_interface():
174
  logger.info("Création de l'interface Gradio")
 
175
  css = """
176
  .container { max-width: 1200px; margin: auto; }
177
  .welcome { text-align: center; margin: 20px 0; padding: 20px; background: #3498db; border-radius: 10px; color: white; }
@@ -179,84 +192,107 @@ def create_interface():
179
  .advanced-controls { background: #bdc3c7; padding: 12px; border-radius: 5px; margin: 8px 0; }
180
  .gradio-slider input[type="range"] { accent-color: #3498db; }
181
  .gradio-button { transition: all 0.3s ease; }
182
- .gradio-button:hover { transform: translateY(-2px); box-shadow: 0 4px 6px rgba(52, 152, 219, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); }
183
  """
184
-
185
  generator = ImageGenerator()
186
-
187
  with gr.Blocks(css=css) as app:
188
- gr.HTML("""
189
- <div class="welcome">
190
- <h1>🎨 Equity Artisan 4.0</h1>
191
- <p>Assistant de création d'affiches professionnelles avancé</p>
192
- </div>
193
- """)
194
-
195
- with gr.Column(elem_classes="container"):
196
- with gr.Group(elem_classes="controls-group"):
197
- gr.Markdown("### 📐 Format et Orientation")
198
- with gr.Row():
199
- format_size = gr.Dropdown(choices=["A4", "A3", "A2", "A1", "A0"], value="A4", label="Format")
200
- orientation = gr.Radio(choices=["Portrait", "Paysage"], value="Portrait", label="Orientation")
201
-
202
- with gr.Group(elem_classes="controls-group"):
203
- gr.Markdown("### 🎨 Style et Composition")
204
- with gr.Row():
205
- style = gr.Dropdown(choices=list(ART_STYLES.keys()), value="Neo Vintage", label="Style artistique")
206
- layout = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Layouts"].keys()), value="Centré", label="Composition")
207
- with gr.Row():
208
- ambiance = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Ambiances"].keys()), value="Dramatique", label="Ambiance")
209
- palette = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Palette"].keys()), value="Contrasté", label="Palette")
 
 
210
 
211
- with gr.Group(elem_classes="controls-group"):
212
- gr.Markdown("### 📝 Contenu")
213
- subject = gr.Textbox(label="Description", placeholder="Décrivez votre vision...")
214
- title = gr.Textbox(label="Titre", placeholder="Titre de l'affiche...")
215
 
216
- with gr.Group(elem_classes="advanced-controls"):
217
- gr.Markdown("### 🎯 Ajustements Fins")
218
- with gr.Row():
219
- detail_level = gr.Slider(minimum=1, maximum=10, value=7, step=1, label="Niveau de Détail")
220
- contrast = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Contraste")
221
- saturation = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Saturation")
222
 
223
- with gr.Group(elem_classes="controls-group"):
224
- with gr.Row():
225
- quality = gr.Slider(minimum=30, maximum=50, value=35, label="Qualité")
226
- creativity = gr.Slider(minimum=5, maximum=15, value=7.5, label="Créativité")
227
 
228
- with gr.Row():
229
- generate_btn = gr.Button("✨ Générer", variant="primary")
230
- clear_btn = gr.Button("🗑️ Effacer", variant="secondary")
231
 
232
- image_output = gr.Image(label="Aperçu")
233
- status = gr.Textbox(label="Statut", interactive=False)
234
 
235
- def generate(*args):
236
- logger.info("Démarrage d'une nouvelle génération")
237
- params = {
238
- "format_size": args[0], "orientation": args[1], "style": args[2],
239
- "layout": args[3], "ambiance": args[4], "palette": args[5],
240
- "subject": args[6], "title": args[7], "detail_level": args[8],
241
- "contrast": args[9], "saturation": args[10], "quality": args[11],
242
- "creativity": args[12]
243
- }
244
- result = generator.generate(params)
245
- logger.info(f"Génération terminée avec statut: {result[1]}")
246
- return result
 
 
 
 
 
 
 
 
 
 
 
247
 
248
- generate_btn.click(
249
- generate,
250
- inputs=[format_size, orientation, style, layout, ambiance, palette, subject, title, detail_level, contrast, saturation, quality, creativity],
251
- outputs=[image_output, status]
252
- )
 
 
 
 
 
 
 
 
 
 
253
 
254
- clear_btn.click(lambda: (None, "🗑️ Image effacée"), outputs=[image_output, status])
255
 
256
- logger.info("Interface créée avec succès")
257
- return app
258
 
259
  if __name__ == "__main__":
260
- app = create_interface()
261
- logger.info("Démarrage de l'application")
262
- app.launch()
 
57
  "Bande Dessinée": {
58
  "prompt_prefix": "comic book style poster, vibrant colors, bold outlines",
59
  "negative_prompt": "realistic, photographic, subtle, muted colors"
60
+ },
61
+ # New styles added here
62
+ **"Noir et Blanc": {**
63
+ **"prompt_prefix": "black and white style poster, monochromatic design",**
64
+ **"negative_prompt": "colorful, vibrant designs"**
65
+ **},**
66
  }
67
 
68
  # Paramètres de composition étendus
 
79
  "Symétrie": "symmetrical composition, mirror-like balance",
80
  "Cadre dans le cadre": "frame within a frame composition"
81
  },
82
+ # New ambiance added here
83
+ **"Ambiances": {**
84
+ **"Dramatique": "dramatic lighting, high contrast",**
85
+ **"Doux": "soft lighting, gentle atmosphere",**
86
+ **"Vibrant": "vibrant colors, energetic mood",**
87
+ **"Mystérieux": "mysterious atmosphere, moody lighting",**
88
+ **"Serein": "peaceful atmosphere, calm mood",**
89
+ **"Rétro": "retro atmosphere, nostalgic mood",**
90
+ **"Futuriste": "futuristic atmosphere, high-tech mood",**
91
+ **"Onirique": "dreamy atmosphere, surreal mood",**
92
+ **"Industriel": "industrial atmosphere, raw and urban mood",**
93
+ **"Naturel": "natural atmosphere, organic and earthy mood",**
94
+ **"Nocturne": "nocturnal atmosphere, dark and moody lighting"**
95
+ **},**
96
+ # Palette remains unchanged
97
+ ...
 
 
 
 
 
 
 
 
98
  }
99
 
100
  class ImageGenerator:
101
  def __init__(self):
102
+ self.API_URL = 'https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0'
103
+
104
  token = os.getenv('HUGGINGFACE_TOKEN')
105
+
106
  if not token:
107
  logger.error("HUGGINGFACE_TOKEN non trouvé!")
108
+
109
  self.headers = {"Authorization": f"Bearer {token}"}
110
+
111
  logger.info("ImageGenerator initialisé")
112
 
113
  def _build_prompt(self, params: Dict[str, Any]) -> str:
114
  style_info = ART_STYLES.get(params["style"], ART_STYLES["Neo Vintage"])
115
+
116
  prompt = f"{style_info['prompt_prefix']}, {params['subject']}"
117
 
118
  if params.get("layout"):
119
  prompt += f", {COMPOSITION_PARAMS['Layouts'][params['layout']]}"
120
+
121
  if params.get("ambiance"):
122
  prompt += f", {COMPOSITION_PARAMS['Ambiances'][params['ambiance']]}"
123
+
124
  if params.get("palette"):
125
  prompt += f", {COMPOSITION_PARAMS['Palette'][params['palette']]}"
126
 
 
128
  ("detail_level", "highly detailed" if params.get("detail_level", 0) > 7 else "moderately detailed"),
129
  ("contrast", "high contrast" if params.get("contrast", 0) > 7 else "balanced contrast"),
130
  ("saturation", "vibrant colors" if params.get("saturation", 0) > 7 else "subtle colors")
131
+ ]:
132
  if params.get(param):
133
  prompt += f", {description}"
134
 
 
136
  prompt += f", with text saying '{params['title']}'"
137
 
138
  logger.debug(f"Prompt final: {prompt}")
139
+
140
  return prompt
141
 
142
  def generate(self, params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
143
  try:
144
+ logger.info(f"Démarrage de génération avec paramètres: {json.dumps(params)}")
145
+
146
  if 'Bearer None' in self.headers['Authorization']:
147
+ return None,"⚠️ Erreur: Token Hugging Face non configuré"
148
+
149
  prompt = self._build_prompt(params)
150
+
151
  payload = {
152
+ 'inputs': prompt,
153
+ 'parameters': {
154
+ 'negative_prompt': ART_STYLES[params["style"]]["negative_prompt"],
155
+ 'num_inference_steps': min(int(35 * (params["quality"] / 100)), 40),
156
+ 'guidance_scale': min(7.5 * (params["creativity"] / 10), 10.0),
157
+ 'width': 768,
158
+ 'height': 768 if params["orientation"] == 'Portrait' else 512,
159
  }
160
  }
161
+
162
+ logger.debug(f'Payload: {json.dumps(payload)}')
163
+
164
+ response = requests.post(self.API_URL,
165
+ headers=self.headers,
166
+ json=payload,
167
+ timeout=30)
168
+
169
  if response.status_code == 200:
170
  image = Image.open(io.BytesIO(response.content))
171
+ return image,"✨ Création réussie!"
172
  else:
173
+ error_msg = f'⚠️ Erreur API {response.status_code}: {response.text}'
174
  logger.error(error_msg)
175
+ return None,error_msg
176
+
177
  except Exception as e:
178
+ error_msg = f'⚠️ Erreur: {str(e)}'
179
  logger.exception("Erreur pendant la génération:")
180
+ return None,error_msg
181
+
182
  finally:
183
  gc.collect()
184
 
185
  def create_interface():
186
  logger.info("Création de l'interface Gradio")
187
+
188
  css = """
189
  .container { max-width: 1200px; margin: auto; }
190
  .welcome { text-align: center; margin: 20px 0; padding: 20px; background: #3498db; border-radius: 10px; color: white; }
 
192
  .advanced-controls { background: #bdc3c7; padding: 12px; border-radius: 5px; margin: 8px 0; }
193
  .gradio-slider input[type="range"] { accent-color: #3498db; }
194
  .gradio-button { transition: all 0.3s ease; }
195
+ .gradio-button:hover { transform: translateY(-2px); box-shadow: 0 4px 6px rgba(52 ,152 ,219 ,0.11),0 1px 3px rgba(0 ,0 ,0 ,0.08); }
196
  """
197
+
198
  generator = ImageGenerator()
199
+
200
  with gr.Blocks(css=css) as app:
201
+
202
+ gr.HTML("""
203
+ <div class="welcome">
204
+ <h1>🎨 Equity Artisan 4.0</h1>
205
+ <p>Assistant de création d'affiches professionnelles avancé</p>
206
+ </div>
207
+ """)
208
+
209
+ with gr.Column(elem_classes="container"):
210
+ with gr.Group(elem_classes="controls-group"):
211
+ gr.Markdown("### 📐 Format et Orientation")
212
+ with gr.Row():
213
+ format_size = gr.Dropdown(choices=["A4","A3","A2","A1","A0"], value="A4", label="Format")
214
+ orientation = gr.Radio(choices=["Portrait","Paysage"], value="Portrait", label="Orientation")
215
+
216
+ with gr.Group(elem_classes="controls-group"):
217
+ gr.Markdown("### 🎨 Style et Composition")
218
+ with gr.Row():
219
+ style = gr.Dropdown(choices=list(ART_STYLES.keys()), value="Neo Vintage", label="Style artistique")
220
+ layout = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Layouts"].keys()), value="Centré", label="Composition")
221
+
222
+ with gr.Row():
223
+ ambiance = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Ambiances"].keys()), value="Dramatique", label="Ambiance")
224
+ palette = gr.Dropdown(choices=list(COMPOSITION_PARAMS["Palette"].keys()), value="Contrasté", label="Palette")
225
 
226
+ with gr.Group(elem_classes="controls-group"):
227
+ gr.Markdown("### 📝 Contenu")
228
+ subject = gr.Textbox(label="Description", placeholder="Décrivez votre vision...")
229
+ title = gr.Textbox(label="Titre", placeholder="Titre de l'affiche...")
230
 
231
+ with gr.Group(elem_classes="advanced-controls"):
232
+ gr.Markdown("### 🎯 Ajustements Fins")
233
+ with gr.Row():
234
+ detail_level = gr.Slider(minimum=1 ,maximum=10 ,value=7 ,step=1 ,label="Niveau de Détail")
235
+ contrast = gr.Slider(minimum=1 ,maximum=10 ,value=5 ,step=1 ,label="Contraste")
236
+ saturation = gr.Slider(minimum=1 ,maximum=10 ,value=5 ,step=1 ,label="Saturation")
237
 
238
+ with gr.Group(elem_classes="controls-group"):
239
+ with gr.Row():
240
+ quality = gr.Slider(minimum=30,maximum=50,value=35,label="Qualité")
241
+ creativity = gr.Slider(minimum=5,maximum=15,value=7.5,label="Créativité")
242
 
243
+ with gr.Row():
244
+ generate_btn = gr.Button("✨ Générer", variant="primary")
245
+ clear_btn = gr.Button("🗑️ Effacer", variant="secondary")
246
 
247
+ image_output = gr.Image(label="Aperçu")
248
+ status = gr.Textbox(label="Statut", interactive=False)
249
 
250
+ def generate(*args):
251
+ logger.info("Démarrage d'une nouvelle génération")
252
+
253
+ params = {
254
+ 'format_size': args[0],
255
+ 'orientation': args[1],
256
+ 'style': args[2],
257
+ 'layout': args[3],
258
+ 'ambiance': args[4],
259
+ 'palette': args[5],
260
+ 'subject': args[6],
261
+ 'title': args[7],
262
+ 'detail_level': args[8],
263
+ 'contrast': args[9],
264
+ 'saturation': args[10],
265
+ 'quality': args[11],
266
+ 'creativity': args[12]
267
+ }
268
+
269
+ result = generator.generate(params)
270
+ logger.info(f"Génération terminée avec statut: {result[1]}")
271
+
272
+ return result
273
 
274
+ generate_btn.click(generate,
275
+ inputs=[format_size,
276
+ orientation,
277
+ style,
278
+ layout,
279
+ ambiance,
280
+ palette,
281
+ subject,
282
+ title,
283
+ detail_level,
284
+ contrast,
285
+ saturation,
286
+ quality,
287
+ creativity],
288
+ outputs=[image_output,status])
289
 
290
+ clear_btn.click(lambda: (None,"🗑️ Image effacée"), outputs=[image_output,status])
291
 
292
+ logger.info("Interface créée avec succès")
293
+ return app
294
 
295
  if __name__ == "__main__":
296
+ app = create_interface()
297
+ logger.info("Démarrage de l'application")
298
+ app.launch()