Equityone commited on
Commit
9bd137d
·
verified ·
1 Parent(s): 4754e9f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +232 -318
app.py CHANGED
@@ -12,364 +12,278 @@ import numpy as np
12
  import cv2
13
  from skimage import exposure
14
  import torch
15
- from dataclasses import dataclass
16
- from enum import Enum
17
- import textwrap
18
 
19
- # Configuration
20
  logging.basicConfig(level=logging.DEBUG)
21
  logger = logging.getLogger(__name__)
22
  load_dotenv()
23
 
24
- class StyleCategory(Enum):
25
- TRADITIONAL = "Styles Traditionnels"
26
- DIGITAL = "Rendus Numériques"
27
- PHOTO = "Photographique"
28
- ILLUSTRATION = "Illustration"
29
- CONCEPT = "Conceptuel"
30
- TYPOGRAPHY = "Typographie"
31
-
32
- @dataclass
33
- class StyleDefinition:
34
- name: str
35
- category: StyleCategory
36
- prompt_prefix: str
37
- negative_prompt: str
38
- params: Dict[str, Any]
39
- recommended_resolution: Tuple[int, int]
40
- processing_steps: List[str]
41
-
42
- ARTISTIC_STYLES = {
43
- # Styles Traditionnels
44
- "Renaissance": StyleDefinition(
45
- name="Renaissance",
46
- category=StyleCategory.TRADITIONAL,
47
- prompt_prefix="renaissance style, anatomically correct, detailed texture, chiaroscuro lighting",
48
- negative_prompt="modern, abstract, simplified",
49
- params={
50
- "guidance_scale": 9.0,
51
- "num_inference_steps": 50,
52
- "detail_level": 0.95,
53
- "lighting_complexity": "high"
54
  },
55
- recommended_resolution=(3840, 2160),
56
- processing_steps=["detail_enhancement", "lighting_optimization", "texture_refinement"]
57
- ),
58
-
59
- # Rendus Numériques
60
- "Cyberpunk": StyleDefinition(
61
- name="Cyberpunk",
62
- category=StyleCategory.DIGITAL,
63
- prompt_prefix="cyberpunk style, neon lights, high tech, volumetric fog",
64
- negative_prompt="natural, vintage, traditional",
65
- params={
66
- "saturation_boost": 1.9,
67
- "neon_glow": True,
68
- "volumetric_lighting": True
69
  },
70
- recommended_resolution=(2560, 1440),
71
- processing_steps=["neon_enhancement", "volumetric_shading", "color_grading"]
72
- ),
73
 
74
- # Styles supplémentaires similaires...
75
- }
76
-
77
- TEXT_EFFECTS = {
78
- "Réaliste": {
79
- "render_params": {
80
- "sharpness": 1.4,
81
- "antialiasing": True,
82
- "realistic_shadows": True
 
83
  },
84
- "font_requirements": ["high_resolution", "professional"],
85
- "processing_steps": ["shadow_mapping", "texture_overlay"]
86
- },
87
- "Néon": {
88
- "render_params": {
89
- "glow_intensity": 1.5,
90
- "bloom_radius": 10,
91
- "color_vibrance": 1.8
92
  },
93
- "effects": ["outer_glow", "inner_glow", "light_rays"],
94
- "processing_steps": ["glow_generation", "bloom_effect", "color_enhancement"]
95
- },
96
- # Autres effets textuels...
97
- }
98
-
99
- class QualityPreset(Enum):
100
- DRAFT = {
101
- "resolution_scale": 0.5,
102
- "inference_steps": 20,
103
- "guidance_scale": 7.0
104
- }
105
- STANDARD = {
106
- "resolution_scale": 1.0,
107
- "inference_steps": 50,
108
- "guidance_scale": 7.5
109
- }
110
- PREMIUM = {
111
- "resolution_scale": 2.0,
112
- "inference_steps": 100,
113
- "guidance_scale": 8.0
114
  }
 
115
 
116
- class ImageProcessor:
117
- """Processeur avancé pour le traitement d'images"""
118
-
119
  def __init__(self):
120
- self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
121
-
122
- def process_image(self, image: Image.Image, style: StyleDefinition, quality: QualityPreset) -> Image.Image:
123
- """Pipeline complet de traitement d'image"""
 
 
 
 
 
 
 
 
 
 
 
 
124
  try:
125
- # Application des étapes de traitement définies dans le style
126
- for step in style.processing_steps:
127
- processing_method = getattr(self, f"_apply_{step}")
128
- image = processing_method(image, style.params)
129
-
130
- # Optimisation finale selon le preset de qualité
131
- image = self._apply_quality_optimization(image, quality.value)
132
 
133
- return image
 
 
 
 
 
 
134
 
 
135
  except Exception as e:
136
- logger.error(f"Erreur lors du traitement de l'image: {str(e)}")
137
  return image
138
-
139
- def _apply_detail_enhancement(self, image: Image.Image, params: Dict) -> Image.Image:
140
- """Amélioration des détails avec contrôle précis"""
141
- np_image = np.array(image)
142
-
143
- # Application d'un filtre de netteté adaptatif
144
- kernel_size = int(params.get("detail_level", 0.8) * 5)
145
- kernel = np.ones((kernel_size, kernel_size), np.float32) / (kernel_size * kernel_size)
146
- filtered = cv2.filter2D(np_image, -1, kernel)
147
-
148
- return Image.fromarray(filtered)
149
-
150
- def _apply_neon_enhancement(self, image: Image.Image, params: Dict) -> Image.Image:
151
- """Effets néon et lumineux avancés"""
152
- # Conversion en HSV pour manipulation des couleurs
153
- np_image = np.array(image)
154
- hsv = cv2.cvtColor(np_image, cv2.COLOR_RGB2HSV)
155
-
156
- # Augmentation de la saturation
157
- hsv[..., 1] = hsv[..., 1] * params.get("saturation_boost", 1.5)
158
-
159
- # Effet de bloom
160
- if params.get("neon_glow"):
161
- bloom_intensity = params.get("bloom_intensity", 0.3)
162
- blur = cv2.GaussianBlur(hsv, (15, 15), 0)
163
- hsv = cv2.addWeighted(hsv, 1, blur, bloom_intensity, 0)
164
-
165
- # Reconversion en RGB
166
- enhanced = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
167
- return Image.fromarray(enhanced)
168
 
169
- class TextRenderer:
170
- """Gestionnaire avancé de rendu de texte"""
171
-
172
- def __init__(self):
173
- self.default_font = ImageFont.load_default()
174
- self.fonts = self._initialize_fonts()
175
-
176
- def _initialize_fonts(self) -> Dict[str, ImageFont.FreeTypeFont]:
177
- """Initialise les polices disponibles"""
178
- fonts = {
179
- "default": self.default_font,
180
- }
181
-
182
- # Tentative de chargement des polices système courantes
183
- common_fonts = {
184
- "arial": "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
185
- "times": "/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf",
186
- "courier": "/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf"
187
- }
188
-
189
- for name, path in common_fonts.items():
190
- try:
191
- fonts[name] = ImageFont.truetype(path, size=40)
192
- except OSError:
193
- logger.warning(f"Police {name} non trouvée, utilisation police par défaut")
194
- fonts[name] = self.default_font
195
-
196
- return fonts
197
-
198
- def render_text(self, image: Image.Image, text: str, effect: str, position: Tuple[int, int], font_name: str = "default") -> Image.Image:
199
- """Application d'effets de texte avancés"""
200
- effect_params = TEXT_EFFECTS[effect]
201
-
202
- # Création d'un calque pour le texte
203
- text_layer = Image.new('RGBA', image.size, (0, 0, 0, 0))
204
- draw = ImageDraw.Draw(text_layer)
205
-
206
- # Application des effets spécifiques
207
- for step in effect_params.get("processing_steps", []):
208
- text_layer = getattr(self, f"_apply_{step}")(text_layer, text, position, effect_params)
209
-
210
- # Fusion avec l'image principale
211
- return Image.alpha_composite(image.convert('RGBA'), text_layer)
212
-
213
- def _apply_glow_generation(self, layer: Image.Image, text: str, position: Tuple[int, int], params: Dict) -> Image.Image:
214
- """Génération d'effets de lumière pour le texte"""
215
- glow_intensity = params["render_params"].get("glow_intensity", 1.0)
216
-
217
- # Création de plusieurs couches de glow
218
- for radius in range(3, 15, 2):
219
- glow_layer = layer.filter(ImageFilter.GaussianBlur(radius))
220
- layer = Image.alpha_composite(layer, glow_layer)
221
-
222
- return layer
223
 
224
- class EquityArtEngine:
225
- """Moteur principal de génération artistique"""
226
- def __init__(self):
227
- self.image_processor = ImageProcessor()
228
- self.text_renderer = TextRenderer()
229
- self.model_url = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
230
- token = os.getenv('HUGGINGFACE_TOKEN')
231
- if not token:
232
- logger.error("HUGGINGFACE_TOKEN non trouvé!")
233
- self.headers = {"Authorization": f"Bearer {token}"}
234
-
 
 
 
 
 
 
 
 
235
  def __init__(self):
236
- self.image_processor = ImageProcessor()
237
- self.text_renderer = TextRenderer()
238
- self.model_url = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
239
  self.headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
240
-
241
- async def generate(self, prompt: str, style: str, quality: QualityPreset,
242
- text_params: Optional[Dict] = None) -> Tuple[Optional[Image.Image], str]:
243
- """Génération complète avec tous les effets"""
 
244
  try:
245
- # Récupération du style et validation
246
- style_def = ARTISTIC_STYLES.get(style)
247
- if not style_def:
248
- return None, "Style non reconnu"
249
-
250
- # Construction du prompt optimisé
251
- full_prompt = f"{style_def.prompt_prefix}, {prompt}"
252
 
 
 
 
253
  # Paramètres de génération
254
- params = {
255
- "prompt": full_prompt,
256
- "negative_prompt": style_def.negative_prompt,
257
- **quality.value
 
258
  }
259
-
260
- # Génération de l'image de base
261
- response = await self._generate_base_image(params)
262
- if not response:
263
- return None, "Échec de la génération"
264
-
265
- # Traitement selon le style
266
- processed_image = self.image_processor.process_image(response, style_def, quality)
267
-
268
- # Ajout de texte si nécessaire
269
- if text_params:
270
- processed_image = self.text_renderer.render_text(
271
- processed_image,
272
- text_params["text"],
273
- text_params["effect"],
274
- text_params["position"]
275
- )
276
-
277
- return processed_image, "Génération réussie"
278
-
279
- except Exception as e:
280
- logger.error(f"Erreur lors de la génération: {str(e)}")
281
- return None, f"Erreur: {str(e)}"
282
-
283
- async def _generate_base_image(self, params: Dict) -> Optional[Image.Image]:
284
- """Génération de l'image base via API"""
285
- try:
286
  response = requests.post(
287
- self.model_url,
288
  headers=self.headers,
289
- json={"inputs": params["prompt"], "parameters": params},
290
  timeout=30
291
  )
292
-
293
  if response.status_code != 200:
294
- return None
295
-
296
- return Image.open(io.BytesIO(response.content))
297
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  except Exception as e:
299
- logger.error(f"Erreur API: {str(e)}")
300
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
 
302
  def create_interface():
303
- """Interface utilisateur Gradio"""
304
- engine = EquityArtEngine()
305
-
306
- with gr.Blocks(css="style.css") as app:
307
- gr.HTML("""
308
- <div class="header">
309
- <h1>🎨 Equity Art Engine Pro</h1>
310
- <p>Système de Génération Artistique Avancé</p>
311
- </div>
312
- """)
313
-
314
- with gr.Tab("Création"):
315
- with gr.Row():
316
- with gr.Column():
317
- prompt = gr.Textbox(
318
- label="Description",
319
- placeholder="Décrivez votre vision..."
320
- )
321
-
322
- style = gr.Dropdown(
323
- choices=[s.name for s in ARTISTIC_STYLES.values()],
324
- label="Style Artistique"
325
- )
326
-
327
- quality = gr.Radio(
328
- choices=[q.name for q in QualityPreset],
329
- value="STANDARD",
330
- label="Qualité"
331
- )
332
-
333
- with gr.Column():
334
- text_input = gr.Textbox(
335
- label="Texte à ajouter",
336
- placeholder="Optionnel"
337
- )
338
-
339
- text_effect = gr.Dropdown(
340
- choices=list(TEXT_EFFECTS.keys()),
341
- label="Effet de Texte"
342
  )
343
-
344
- generate_btn = gr.Button("Générer", variant="primary")
345
- image_output = gr.Image(label="Résultat")
346
- status = gr.Textbox(label="Status")
347
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  # Logique de génération
349
- def generate_artwork(prompt, style, quality, text, effect):
350
- text_params = {
351
- "text": text,
352
- "effect": effect,
353
- "position": (50, 50) # Position par défaut
354
- } if text else None
355
-
356
- result, status_msg = engine.generate(
357
  prompt=prompt,
358
- style=style,
359
- quality=QualityPreset[quality],
360
- text_params=text_params
 
361
  )
362
 
363
- return result, status_msg
364
-
365
  generate_btn.click(
366
- generate_artwork,
367
- inputs=[prompt, style, quality, text_input, text_effect],
368
- outputs=[image_output, status]
369
  )
370
-
371
- return app
372
 
373
  if __name__ == "__main__":
374
- app = create_interface()
375
- app.launch()
 
12
  import cv2
13
  from skimage import exposure
14
  import torch
 
 
 
15
 
 
16
  logging.basicConfig(level=logging.DEBUG)
17
  logger = logging.getLogger(__name__)
18
  load_dotenv()
19
 
20
+ # Constantes pour les styles disponibles
21
+ STYLE_CATEGORIES = {
22
+ "TRADITIONAL": {
23
+ "Renaissance": {
24
+ "prompt": "renaissance style masterpiece, anatomical precision, detailed texture, chiaroscuro lighting, oil painting technique, museum quality",
25
+ "negative_prompt": "modern, abstract, simple, flat, digital art",
26
+ "params": {
27
+ "guidance_scale": 9.0,
28
+ "num_inference_steps": 50,
29
+ "resolution": (4096, 4096),
30
+ "detail_threshold": 0.95,
31
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  },
33
+ "Impressionnisme": {
34
+ "prompt": "impressionist style, loose brushstrokes, natural light, vivid colors, en plein air painting",
35
+ "negative_prompt": "sharp details, digital art, modern",
36
+ "params": {
37
+ "guidance_scale": 7.5,
38
+ "num_inference_steps": 40,
39
+ "resolution": (2048, 2048),
40
+ "brush_simulation": True,
41
+ }
 
 
 
 
 
42
  },
43
+ # ... autres styles traditionnels
44
+ },
 
45
 
46
+ "DIGITAL": {
47
+ "Cyberpunk": {
48
+ "prompt": "cyberpunk style, neon lights, volumetric fog, tech noir, high contrast, futuristic city",
49
+ "negative_prompt": "natural, vintage, traditional art",
50
+ "params": {
51
+ "guidance_scale": 8.0,
52
+ "neon_intensity": 1.5,
53
+ "volumetric_lighting": True,
54
+ "resolution": (3840, 2160),
55
+ }
56
  },
57
+ "Holographique": {
58
+ "prompt": "holographic effect, iridescent colors, light refraction, transparent layers, futuristic",
59
+ "negative_prompt": "flat, matte, solid colors",
60
+ "params": {
61
+ "iridescence": 1.0,
62
+ "transparency": 0.7,
63
+ "resolution": (2560, 1440),
64
+ }
65
  },
66
+ # ... autres styles numériques
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
+ }
69
 
70
+ class TextEffectProcessor:
 
 
71
  def __init__(self):
72
+ self.effects = {
73
+ "Réaliste": self._realistic_text,
74
+ "Néon": self._neon_text,
75
+ "Holographique": self._holographic_text,
76
+ "3D": self._3d_text,
77
+ "Vintage": self._vintage_text,
78
+ "Graffiti": self._graffiti_text,
79
+ "Matrix": self._matrix_text
80
+ }
81
+
82
+ def apply_effect(self, image: Image.Image, text: str, effect: str, position: Tuple[int, int]) -> Image.Image:
83
+ if effect in self.effects:
84
+ return self.effects[effect](image, text, position)
85
+ return self._default_text(image, text, position)
86
+
87
+ def _realistic_text(self, image: Image.Image, text: str, position: Tuple[int, int]) -> Image.Image:
88
  try:
89
+ draw = ImageDraw.Draw(image)
90
+ # Chargement d'une police par défaut
91
+ font = ImageFont.load_default()
 
 
 
 
92
 
93
+ # Effet d'ombre réaliste
94
+ shadow_offset = 2
95
+ # Dessiner l'ombre
96
+ draw.text((position[0] + shadow_offset, position[1] + shadow_offset),
97
+ text, font=font, fill=(0, 0, 0, 128))
98
+ # Dessiner le texte principal
99
+ draw.text(position, text, font=font, fill=(255, 255, 255))
100
 
101
+ return image
102
  except Exception as e:
103
+ logger.error(f"Erreur lors du rendu réaliste: {str(e)}")
104
  return image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
+ def _neon_text(self, image: Image.Image, text: str, position: Tuple[int, int]) -> Image.Image:
107
+ try:
108
+ # Création d'un calque pour le texte néon
109
+ text_layer = Image.new('RGBA', image.size, (0, 0, 0, 0))
110
+ draw = ImageDraw.Draw(text_layer)
111
+ font = ImageFont.load_default()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ # Effet de glow
114
+ glow_colors = [(255, 182, 193), (255, 192, 203), (255, 202, 213)]
115
+ for i, color in enumerate(glow_colors):
116
+ offset = (3 - i) * 2
117
+ draw.text((position[0] - offset, position[1] - offset),
118
+ text, font=font, fill=color + (150,))
119
+
120
+ # Texte principal
121
+ draw.text(position, text, font=font, fill=(255, 255, 255, 255))
122
+
123
+ # Fusion des calques
124
+ return Image.alpha_composite(image.convert('RGBA'), text_layer)
125
+ except Exception as e:
126
+ logger.error(f"Erreur lors du rendu néon: {str(e)}")
127
+ return image
128
+
129
+ # ... autres méthodes d'effets de texte
130
+
131
+ class ImageGenerator:
132
  def __init__(self):
133
+ self.api_url = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
 
 
134
  self.headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
135
+ self.text_processor = TextEffectProcessor()
136
+
137
+ async def generate_image(self, prompt: str, style_category: str, style_name: str,
138
+ text: Optional[str] = None, text_effect: Optional[str] = None,
139
+ position: Optional[Tuple[int, int]] = None) -> Tuple[Optional[Image.Image], str]:
140
  try:
141
+ # Récupération des paramètres du style
142
+ style_info = STYLE_CATEGORIES[style_category][style_name]
 
 
 
 
 
143
 
144
+ # Construction du prompt final
145
+ final_prompt = f"{style_info['prompt']}, {prompt}"
146
+
147
  # Paramètres de génération
148
+ generation_params = {
149
+ "inputs": final_prompt,
150
+ "negative_prompt": style_info["negative_prompt"],
151
+ "num_inference_steps": style_info["params"]["num_inference_steps"],
152
+ "guidance_scale": style_info["params"]["guidance_scale"],
153
  }
154
+
155
+ # Appel à l'API
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  response = requests.post(
157
+ self.api_url,
158
  headers=self.headers,
159
+ json=generation_params,
160
  timeout=30
161
  )
162
+
163
  if response.status_code != 200:
164
+ return None, f"Erreur API: {response.status_code}"
165
+
166
+ # Traitement de l'image générée
167
+ image = Image.open(io.BytesIO(response.content))
168
+
169
+ # Application des effets de style spécifiques
170
+ image = self._apply_style_effects(image, style_info["params"])
171
+
172
+ # Ajout de texte si demandé
173
+ if text and text_effect:
174
+ image = self.text_processor.apply_effect(
175
+ image, text, text_effect,
176
+ position or (image.width//2, image.height//2)
177
+ )
178
+
179
+ return image, "Génération réussie!"
180
+
181
+ except Exception as e:
182
+ logger.error(f"Erreur lors de la génération: {str(e)}")
183
+ return None, f"Erreur: {str(e)}"
184
+
185
+ def _apply_style_effects(self, image: Image.Image, style_params: Dict) -> Image.Image:
186
+ """Application des effets spécifiques au style"""
187
+ try:
188
+ # Conversion pour traitement
189
+ img_array = np.array(image)
190
+
191
+ # Application des effets selon les paramètres
192
+ if style_params.get("neon_intensity"):
193
+ img_array = self._apply_neon_effect(img_array, style_params["neon_intensity"])
194
+
195
+ if style_params.get("volumetric_lighting"):
196
+ img_array = self._apply_volumetric_lighting(img_array)
197
+
198
+ # Reconversion en image PIL
199
+ return Image.fromarray(img_array)
200
+
201
  except Exception as e:
202
+ logger.error(f"Erreur lors de l'application des effets: {str(e)}")
203
+ return image
204
+
205
+ def _apply_neon_effect(self, img_array: np.ndarray, intensity: float) -> np.ndarray:
206
+ """Applique un effet néon à l'image"""
207
+ # Conversion en HSV pour manipulation des couleurs
208
+ hsv = cv2.cvtColor(img_array, cv2.COLOR_RGB2HSV)
209
+ # Augmentation de la saturation
210
+ hsv[..., 1] = np.clip(hsv[..., 1] * intensity, 0, 255)
211
+ return cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
212
+
213
+ def _apply_volumetric_lighting(self, img_array: np.ndarray) -> np.ndarray:
214
+ """Ajoute un effet de lumière volumétrique"""
215
+ # Création d'un masque de luminosité
216
+ gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
217
+ blur = cv2.GaussianBlur(gray, (0, 0), 15)
218
+ return cv2.addWeighted(img_array, 1, cv2.cvtColor(blur, cv2.COLOR_GRAY2RGB), 0.2, 0)
219
 
220
  def create_interface():
221
+ generator = ImageGenerator()
222
+
223
+ with gr.Blocks() as demo:
224
+ gr.HTML("""<h1 style='text-align: center'>🎨 Equity Art Engine</h1>""")
225
+
226
+ with gr.Row():
227
+ with gr.Column(scale=1):
228
+ # Contrôles de génération
229
+ prompt = gr.Textbox(label="Description de l'image")
230
+ style_category = gr.Dropdown(
231
+ choices=list(STYLE_CATEGORIES.keys()),
232
+ label="Catégorie de Style"
233
+ )
234
+ style_name = gr.Dropdown(
235
+ label="Style Spécifique"
236
+ )
237
+
238
+ # Mise à jour dynamique des styles disponibles
239
+ def update_styles(category):
240
+ return gr.Dropdown.update(
241
+ choices=list(STYLE_CATEGORIES[category].keys())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  )
243
+ style_category.change(
244
+ update_styles,
245
+ inputs=[style_category],
246
+ outputs=[style_name]
247
+ )
248
+
249
+ # Contrôles de texte
250
+ text_input = gr.Textbox(label="Texte à ajouter (optionnel)")
251
+ text_effect = gr.Dropdown(
252
+ choices=["Réaliste", "Néon", "Holographique", "3D", "Vintage", "Graffiti", "Matrix"],
253
+ label="Effet de texte"
254
+ )
255
+
256
+ with gr.Column(scale=2):
257
+ # Zone de résultat
258
+ image_output = gr.Image(label="Image générée")
259
+ status_output = gr.Textbox(label="Status")
260
+
261
+ # Bouton de génération
262
+ generate_btn = gr.Button("Générer")
263
+
264
  # Logique de génération
265
+ def generate(prompt, category, style, text, effect):
266
+ if not prompt or not category or not style:
267
+ return None, "Veuillez remplir tous les champs requis"
268
+
269
+ image, status = generator.generate_image(
 
 
 
270
  prompt=prompt,
271
+ style_category=category,
272
+ style_name=style,
273
+ text=text if text else None,
274
+ text_effect=effect if text else None
275
  )
276
 
277
+ return image, status
278
+
279
  generate_btn.click(
280
+ generate,
281
+ inputs=[prompt, style_category, style_name, text_input, text_effect],
282
+ outputs=[image_output, status_output]
283
  )
284
+
285
+ return demo
286
 
287
  if __name__ == "__main__":
288
+ demo = create_interface()
289
+ demo.launch()