Equityone commited on
Commit
5647bfd
·
verified ·
1 Parent(s): 55c5eb8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +288 -58
app.py CHANGED
@@ -10,13 +10,16 @@ import logging
10
  from dotenv import load_dotenv
11
 
12
  # Configuration du logging
13
- logging.basicConfig(level=logging.INFO)
 
 
 
14
  logger = logging.getLogger(__name__)
15
 
16
  # Chargement des variables d'environnement
17
  load_dotenv()
18
 
19
- # Styles artistiques
20
  ART_STYLES = {
21
  "Art Moderne": {
22
  "prompt_prefix": "modern art style poster, professional design",
@@ -33,85 +36,312 @@ ART_STYLES = {
33
  "Minimaliste": {
34
  "prompt_prefix": "minimalist design poster, clean composition",
35
  "negative_prompt": "complex, detailed, ornate, busy"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
37
  }
38
 
39
- # Configuration de l'API
40
- API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- def generate_image(params: Dict[str, Any]) -> Tuple[Optional[Image.Image], str]:
43
- """Génère une image via l'API Hugging Face"""
44
- try:
45
- headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
46
-
47
- style = ART_STYLES[params["style"]]
48
- prompt = f"{style['prompt_prefix']}, {params['subject']}"
49
-
50
- # Configuration de la requête
51
- payload = {
52
- "inputs": prompt,
53
- "parameters": {
54
- "negative_prompt": style["negative_prompt"],
55
- "num_inference_steps": 30,
56
- "guidance_scale": 7.5,
57
- "width": 768,
58
- "height": 768
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
- }
61
-
62
- response = requests.post(API_URL, headers=headers, json=payload)
63
-
64
- if response.status_code == 200:
65
- image = Image.open(io.BytesIO(response.content))
66
- return image, "✨ Création réussie!"
67
- else:
68
- return None, f"⚠️ Erreur {response.status_code}: {response.text}"
69
 
70
- except Exception as e:
71
- logger.error(f"Erreur: {str(e)}")
72
- return None, f"⚠️ Erreur: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  def create_interface():
75
- """Crée l'interface Gradio"""
76
- with gr.Blocks() as app:
 
 
 
 
 
 
 
 
 
 
77
  gr.HTML("""
78
- <h1 style='text-align: center'>🎨 Generart</h1>
79
- <p style='text-align: center'>Créez des affiches artistiques avec l'IA</p>
 
 
80
  """)
81
 
82
- with gr.Row():
83
- with gr.Column():
84
- style = gr.Dropdown(
85
- choices=list(ART_STYLES.keys()),
86
- value="Neo Vintage",
87
- label="Style artistique"
88
- )
89
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  subject = gr.Textbox(
91
  label="Description",
92
  placeholder="Décrivez votre vision..."
93
  )
94
-
95
- generate_btn = gr.Button("✨ Générer")
96
-
97
- with gr.Column():
98
- image_output = gr.Image(label="Résultat")
99
- status = gr.Textbox(label="Statut")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- def on_generate(style_val, subject_val):
102
- return generate_image({
103
- "style": style_val,
104
- "subject": subject_val
105
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  generate_btn.click(
108
- fn=on_generate,
109
- inputs=[style, subject],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  outputs=[image_output, status]
111
  )
112
 
 
113
  return app
114
 
115
  if __name__ == "__main__":
116
  app = create_interface()
 
117
  app.launch()
 
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": {
25
  "prompt_prefix": "modern art style poster, professional design",
 
36
  "Minimaliste": {
37
  "prompt_prefix": "minimalist design poster, clean composition",
38
  "negative_prompt": "complex, detailed, ornate, busy"
39
+ },
40
+ "Cyberpunk": {
41
+ "prompt_prefix": "cyberpunk style poster, neon lights, futuristic design",
42
+ "negative_prompt": "vintage, natural, rustic, traditional"
43
+ },
44
+ "Aquarelle": {
45
+ "prompt_prefix": "watercolor art style poster, fluid artistic design",
46
+ "negative_prompt": "digital, sharp, photorealistic"
47
+ },
48
+ "Art Déco": {
49
+ "prompt_prefix": "art deco style poster, geometric patterns, luxury design",
50
+ "negative_prompt": "modern, minimalist, casual"
51
+ },
52
+ "Japonais": {
53
+ "prompt_prefix": "japanese art style poster, ukiyo-e inspired design",
54
+ "negative_prompt": "western, modern, photographic"
55
  }
56
  }
57
 
58
+ # Paramètres de composition
59
+ COMPOSITION_PARAMS = {
60
+ "Layouts": {
61
+ "Centré": "centered composition, balanced layout",
62
+ "Asymétrique": "dynamic asymmetrical composition",
63
+ "Grille": "grid-based layout, structured composition",
64
+ "Diagonal": "diagonal dynamic composition",
65
+ "Minimaliste": "minimal composition, lots of whitespace"
66
+ },
67
+ "Ambiances": {
68
+ "Dramatique": "dramatic lighting, high contrast",
69
+ "Doux": "soft lighting, gentle atmosphere",
70
+ "Vibrant": "vibrant colors, energetic mood",
71
+ "Mystérieux": "mysterious atmosphere, moody lighting",
72
+ "Serein": "peaceful atmosphere, calm mood"
73
+ },
74
+ "Palette": {
75
+ "Monochrome": "monochromatic color scheme",
76
+ "Contrasté": "high contrast color palette",
77
+ "Pastel": "soft pastel color palette",
78
+ "Terre": "earthy color palette",
79
+ "Néon": "neon color palette"
80
+ }
81
+ }
82
 
83
+ class ImageGenerator:
84
+ def __init__(self):
85
+ self.API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
86
+ token = os.getenv('HUGGINGFACE_TOKEN')
87
+ if not token:
88
+ logger.error("HUGGINGFACE_TOKEN non trouvé!")
89
+ self.headers = {"Authorization": f"Bearer {token}"}
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))
156
+ return image, "✨ Création réussie!"
157
+ else:
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:")
165
+ return None, error_msg
166
+ finally:
167
+ gc.collect()
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
 
344
  if __name__ == "__main__":
345
  app = create_interface()
346
+ logger.info("Démarrage de l'application")
347
  app.launch()