Equityone commited on
Commit
2e9811d
·
verified ·
1 Parent(s): 5759851

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -258
app.py CHANGED
@@ -1,303 +1,175 @@
1
  import gradio as gr
2
  import os
3
- from PIL import Image, ImageDraw, ImageFont, ImageEnhance
4
  import requests
5
  import io
6
- import json
7
 
8
- # Styles artistiques professionnels inspirés des meilleurs designers
9
- PRO_STYLES = {
10
- "Neo Vintage": {
11
- "prompt_prefix": "professional high-end vintage poster, screen printing style, halftone textures, limited color palette",
12
- "guidance": 13.5,
13
- "steps": 75,
14
- "negative": "photorealistic, 3d, oversaturated, amateur",
15
- "reference": "modern vintage illustration masters"
16
- },
17
- "Art Contemporain": {
18
- "prompt_prefix": "contemporary art poster, bold artistic composition, professional design, gallery quality",
19
- "guidance": 12.5,
20
- "steps": 70,
21
- "negative": "basic, simple, childish",
22
- "reference": "modern art gallery style"
23
- },
24
- "Illustration Éditoriale": {
25
- "prompt_prefix": "professional editorial illustration, sophisticated art style, magazine quality",
26
- "guidance": 14.0,
27
- "steps": 80,
28
- "negative": "basic drawing, sketchy, unrefined",
29
- "reference": "high-end magazine art"
30
- },
31
- "Design Minimaliste Plus": {
32
- "prompt_prefix": "premium minimalist design, refined composition, luxury poster style",
33
- "guidance": 11.5,
34
- "steps": 65,
35
- "negative": "cluttered, busy, complex",
36
- "reference": "scandinavian design principles"
37
- }
38
- }
39
 
40
- # Collections artistiques spécialisées
41
- ARTISTIC_COLLECTIONS = {
42
- "Portraits Animaliers Pro": {
43
- "base_prompts": [
44
- "majestic animal portrait",
45
- "artistic wildlife illustration",
46
- "powerful animal character"
47
- ],
48
- "style_elements": [
49
- "dramatic lighting",
50
- "expressive eyes",
51
- "detailed textures",
52
- "strong personality"
53
- ],
54
- "negative": "cute, cartoon, realistic photo",
55
- "compositions": [
56
- "centered portrait",
57
- "dramatic angle",
58
- "close-up detail"
59
- ]
60
- },
61
- "Nature Graphique": {
62
- "base_prompts": [
63
- "graphic botanical art",
64
- "stylized nature elements",
65
- "organic patterns"
66
- ],
67
- "style_elements": [
68
- "decorative details",
69
- "flowing lines",
70
- "dynamic composition"
71
- ],
72
- "negative": "photographic, plain, realistic",
73
- "compositions": [
74
- "geometric arrangement",
75
- "pattern layout",
76
- "abstract interpretation"
77
- ]
78
- },
79
- "Urban Art Plus": {
80
- "base_prompts": [
81
- "sophisticated urban art",
82
- "street art fusion",
83
- "modern city aesthetic"
84
- ],
85
- "style_elements": [
86
- "street art textures",
87
- "urban patterns",
88
- "graffiti elements"
89
- ],
90
- "negative": "amateur graffiti, messy, unrefined",
91
- "compositions": [
92
- "dynamic urban composition",
93
- "street art layout",
94
- "modern city vibes"
95
- ]
96
- }
97
- }
98
-
99
- # Formats professionnels optimisés
100
- PRO_DIMENSIONS = {
101
- "A4+": (1152, 1634), # Optimisé pour qualité pro
102
- "A3+": (1634, 2314),
103
- "A2+": (2314, 3271),
104
- "A1+": (3271, 4628),
105
- "A0+": (4628, 6544)
106
- }
107
-
108
- class EquityArtisanPro:
109
- def __init__(self):
110
- self.model_url = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
111
- self.headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
112
-
113
- def generate_artwork(self, format_size, orientation, style, collection, prompt, quality, creativity):
114
  try:
115
- # Configuration des dimensions
116
- width, height = PRO_DIMENSIONS[format_size]
117
- if orientation == "Paysage":
118
- width, height = height, width
119
-
120
- # Construction du prompt artistique
121
- style_config = PRO_STYLES[style]
122
- collection_config = ARTISTIC_COLLECTIONS.get(collection)
123
-
124
- # Prompt engineering avancé
125
- enhanced_prompt = self._build_enhanced_prompt(
126
- base_prompt=prompt,
127
- style_config=style_config,
128
- collection_config=collection_config
129
- )
130
-
131
- # Configuration avancée
132
  payload = {
133
  "inputs": enhanced_prompt,
134
  "parameters": {
135
- "negative_prompt": self._build_negative_prompt(style_config, collection_config),
136
- "num_inference_steps": self._calculate_steps(style_config, quality),
137
- "guidance_scale": self._calculate_guidance(style_config, creativity),
138
- "width": width,
139
- "height": height,
140
- "seed": int(creativity * 1000) # Contrôle créatif
141
  }
142
  }
143
-
144
- print(f"Generating with enhanced prompt: {enhanced_prompt[:100]}...")
145
 
146
- response = requests.post(
147
- self.model_url,
148
- headers=self.headers,
149
- json=payload,
150
- timeout=60
151
- )
152
-
153
  if response.status_code == 200:
154
  image = Image.open(io.BytesIO(response.content))
155
- image = self._post_process_image(image, quality)
156
- return image, "✨ Chef d'œuvre créé avec succès!"
157
  else:
158
- return None, f"⚠️ Erreur {response.status_code}: {response.text}"
159
-
 
160
  except Exception as e:
161
- print(f"Error: {str(e)}")
162
  return None, f"⚠️ Erreur: {str(e)}"
163
 
164
- def _build_enhanced_prompt(self, base_prompt, style_config, collection_config=None):
165
- prompt_parts = [
166
- style_config["prompt_prefix"],
167
- base_prompt
168
- ]
169
-
170
- if collection_config:
171
- prompt_parts.extend([
172
- f"in style of {', '.join(collection_config['style_elements'])}",
173
- f"with {', '.join(collection_config['base_prompts'])}",
174
- f"featuring {', '.join(collection_config['compositions'])}"
175
- ])
176
-
177
- return ", ".join(prompt_parts) + ", professional poster design, masterpiece quality"
178
-
179
- def _build_negative_prompt(self, style_config, collection_config=None):
180
- negative_parts = [
181
- style_config["negative"],
182
- "poor quality, amateur design, basic composition"
183
- ]
184
-
185
- if collection_config:
186
- negative_parts.append(collection_config["negative"])
187
-
188
- return ", ".join(negative_parts)
189
-
190
- def _calculate_steps(self, style_config, quality):
191
- base_steps = style_config["steps"]
192
- return int(base_steps * (quality/85)) # Scaled by quality
193
-
194
- def _calculate_guidance(self, style_config, creativity):
195
- base_guidance = style_config["guidance"]
196
- return base_guidance * (creativity/10) # Scaled by creativity
197
-
198
- def _post_process_image(self, image, quality):
199
- if quality > 85:
200
- enhancer = ImageEnhance.Contrast(image)
201
- image = enhancer.enhance(1.2)
202
- enhancer = ImageEnhance.Sharpness(image)
203
- image = enhancer.enhance(1.3)
204
- return image
205
-
206
- def create_interface():
207
- artisan = EquityArtisanPro()
208
-
209
- with gr.Blocks(theme=gr.themes.Soft(
210
- primary_hue="indigo",
211
- secondary_hue="purple",
212
- )) as app:
213
  gr.HTML("""
214
- <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #4F46E5 0%, #7C3AED 100%); border-radius: 16px; margin-bottom: 24px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
215
- <h1 style="color: white; font-size: 2.5em; margin-bottom: 10px;">🎨 Equity Artisan 3.0</h1>
216
- <p style="color: #E5E7EB; font-size: 1.2em;">Créez des œuvres d'art uniques avec notre IA spécialisée</p>
217
  </div>
218
  """)
219
-
220
- with gr.Row():
221
- # Panneau de contrôle
222
- with gr.Column(scale=1):
223
- with gr.Group():
224
- gr.Markdown("### 📐 Format & Style")
225
  format_choice = gr.Dropdown(
226
- choices=list(PRO_DIMENSIONS.keys()),
227
- value="A4+",
228
- label="Format",
229
- info="Formats optimisés pour qualité professionnelle"
230
  )
231
  orientation = gr.Radio(
232
  choices=["Portrait", "Paysage"],
233
  value="Portrait",
234
  label="Orientation"
235
  )
236
- style = gr.Dropdown(
237
- choices=list(PRO_STYLES.keys()),
238
- value="Neo Vintage",
239
- label="Style Artistique",
240
- info="Styles inspirés des grands maîtres"
241
- )
242
 
243
- with gr.Group():
244
- gr.Markdown("### 🎨 Vision Artistique")
245
- collection = gr.Dropdown(
246
- choices=list(ARTISTIC_COLLECTIONS.keys()),
247
- label="Collection",
248
- info="Thèmes artistiques spécialisés"
249
- )
250
- prompt = gr.Textbox(
251
- lines=3,
252
- label="Description",
253
- placeholder="Décrivez votre vision artistique...",
254
- info="Soyez précis et créatif"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  )
256
-
257
- with gr.Group():
258
- gr.Markdown("### ✨ Paramètres Créatifs")
259
- quality = gr.Slider(
260
- minimum=70,
261
- maximum=100,
262
- value=85,
263
- label="Qualité Artistique",
264
- info="Influence la finesse des détails"
265
- )
266
- creativity = gr.Slider(
267
- minimum=7,
268
- maximum=15,
269
- value=10,
270
- label="Expression Créative",
271
- info="Balance entre fidélité et originalité"
272
- )
273
-
274
- generate_btn = gr.Button("✨ Créer", variant="primary", scale=1)
275
-
276
- # Zone de prévisualisation
277
- with gr.Column(scale=2):
278
- image_output = gr.Image(
279
- label="Votre Création",
280
- type="pil"
281
- )
282
- status = gr.Textbox(
283
- label="Statut",
284
- interactive=False
285
- )
286
 
287
  # Événements
288
  generate_btn.click(
289
- artisan.generate_artwork,
290
  inputs=[
291
  format_choice,
292
  orientation,
293
- style,
294
- collection,
295
  prompt,
 
296
  quality,
297
- creativity
 
298
  ],
299
  outputs=[image_output, status]
300
  )
 
 
 
 
 
301
 
302
  return app
303
 
 
1
  import gradio as gr
2
  import os
3
+ from PIL import Image, ImageDraw, ImageFont
4
  import requests
5
  import io
 
6
 
7
+ CUSTOM_CSS = """
8
+ .container { max-width: 1200px; margin: auto; }
9
+ .welcome { text-align: center; margin: 20px 0; padding: 20px; background: #1e293b; border-radius: 10px; }
10
+ .quality-controls { margin: 10px 0; padding: 10px; background: #2d3748; border-radius: 5px; }
11
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ def create_interface():
14
+ def generate_image(format_size, orientation, prompt, style, quality, creativity, negative_prompt=""):
15
+ API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
16
+ headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
17
+
18
+ # Dimensions de base optimisées
19
+ base_width = 1024
20
+ base_height = 1024
21
+
22
+ if orientation == "Portrait":
23
+ if format_size in ["A4", "A3"]:
24
+ base_width = 768
25
+ base_height = 1024
26
+ else:
27
+ if format_size in ["A4", "A3"]:
28
+ base_width = 1024
29
+ base_height = 768
30
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  try:
32
+ # Styles prédéfinis
33
+ style_prompts = {
34
+ "Moderne": "modern clean poster design, professional layout",
35
+ "Artistique": "artistic poster composition, creative design",
36
+ "Corporate": "professional business poster, corporate style",
37
+ "Impact": "bold impactful poster design, attention-grabbing"
38
+ }
39
+
40
+ enhanced_prompt = f"{style_prompts[style]}, {prompt}, high quality, detailed"
41
+ default_negative = "blurry, low quality, distorted, ugly, bad proportions, weird colors"
42
+ final_negative = negative_prompt if negative_prompt.strip() else default_negative
43
+
 
 
 
 
 
44
  payload = {
45
  "inputs": enhanced_prompt,
46
  "parameters": {
47
+ "negative_prompt": final_negative,
48
+ "num_inference_steps": min(max(30, int(quality)), 50),
49
+ "guidance_scale": min(max(5, creativity), 15),
50
+ "width": base_width,
51
+ "height": base_height
 
52
  }
53
  }
 
 
54
 
55
+ print(f"Envoi de la requête avec les paramètres: {payload}")
56
+
57
+ response = requests.post(API_URL, headers=headers, json=payload, timeout=30)
58
+
 
 
 
59
  if response.status_code == 200:
60
  image = Image.open(io.BytesIO(response.content))
61
+ return image, "✨ Image générée avec succès!"
 
62
  else:
63
+ print(f"Erreur API: {response.text}")
64
+ return None, f"⚠️ Erreur {response.status_code}: Essayez de modifier vos paramètres"
65
+
66
  except Exception as e:
67
+ print(f"Exception: {str(e)}")
68
  return None, f"⚠️ Erreur: {str(e)}"
69
 
70
+ with gr.Blocks(css=CUSTOM_CSS) as app:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  gr.HTML("""
72
+ <div class="welcome">
73
+ <h1>🤖 Equity Artisan 3.0</h1>
74
+ <p>Créez des affiches professionnelles étape par étape avec notre assistant créatif augmenté.</p>
75
  </div>
76
  """)
77
+
78
+ with gr.Column(elem_classes="container"):
79
+ # Étape 1: Format
80
+ with gr.Group():
81
+ gr.Markdown("### 📏 Étape 1: Format et Orientation")
82
+ with gr.Row():
83
  format_choice = gr.Dropdown(
84
+ choices=["A4", "A3", "A2", "A1", "A0"],
85
+ value="A4",
86
+ label="Format"
 
87
  )
88
  orientation = gr.Radio(
89
  choices=["Portrait", "Paysage"],
90
  value="Portrait",
91
  label="Orientation"
92
  )
 
 
 
 
 
 
93
 
94
+ # Étape 2: Création
95
+ with gr.Group():
96
+ gr.Markdown("### 🎨 Étape 2: Création Visuelle")
97
+
98
+ with gr.Row():
99
+ with gr.Column():
100
+ style = gr.Dropdown(
101
+ choices=["Moderne", "Artistique", "Corporate", "Impact"],
102
+ value="Moderne",
103
+ label="Style visuel"
104
+ )
105
+
106
+ prompt = gr.Textbox(
107
+ lines=3,
108
+ label="Description",
109
+ placeholder="Décrivez l'affiche que vous souhaitez...",
110
+ value="professional poster design with clean layout"
111
+ )
112
+
113
+ # Ajout du champ negative_prompt
114
+ negative_prompt = gr.Textbox(
115
+ label="Éléments à éviter (optionnel)",
116
+ placeholder="Ex: flou, texte illisible, distorsions...",
117
+ lines=2
118
+ )
119
+
120
+ with gr.Group(elem_classes="quality-controls"):
121
+ quality = gr.Slider(
122
+ minimum=30,
123
+ maximum=50,
124
+ value=35,
125
+ step=5,
126
+ label="Qualité",
127
+ info="Influence le niveau de détail"
128
+ )
129
+
130
+ creativity = gr.Slider(
131
+ minimum=5,
132
+ maximum=15,
133
+ value=7.5,
134
+ step=0.5,
135
+ label="Créativité",
136
+ info="Balance entre fidélité et créativité"
137
+ )
138
+
139
+ generate_btn = gr.Button("✨ Générer", variant="primary")
140
+ clear_btn = gr.Button("🗑️ Effacer", variant="secondary")
141
+
142
+ image_output = gr.Image(
143
+ label="Aperçu",
144
+ type="pil"
145
  )
146
+
147
+ # Statut
148
+ status = gr.Textbox(
149
+ label="Status",
150
+ interactive=False,
151
+ value="Prêt à générer"
152
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
  # Événements
155
  generate_btn.click(
156
+ generate_image,
157
  inputs=[
158
  format_choice,
159
  orientation,
 
 
160
  prompt,
161
+ style,
162
  quality,
163
+ creativity,
164
+ negative_prompt # Ajout du negative_prompt aux inputs
165
  ],
166
  outputs=[image_output, status]
167
  )
168
+
169
+ clear_btn.click(
170
+ lambda: (None, "Image effacée"),
171
+ outputs=[image_output, status]
172
+ )
173
 
174
  return app
175