Update app.py
Browse files
app.py
CHANGED
@@ -4,112 +4,87 @@ from PIL import Image, ImageDraw, ImageFont
|
|
4 |
import requests
|
5 |
import io
|
6 |
|
7 |
-
#
|
8 |
-
SUBJECT_PROMPTS = {
|
9 |
-
"insectes": {
|
10 |
-
"libellule": "hyper realistic dragonfly in flight with translucent wings, iridescent body, macro photography, detailed insect illustration, natural lighting, entomological precision",
|
11 |
-
"papillon": "detailed butterfly with intricate wing patterns, highly detailed macro photography, precise lepidoptera illustration",
|
12 |
-
"scarabée": "detailed beetle with shiny carapace, precise entomological macro photography"
|
13 |
-
},
|
14 |
-
"animaux": {
|
15 |
-
"loup": "majestic wolf portrait, detailed fur texture, highly detailed wild canine features, expressive eyes, professional wildlife photography",
|
16 |
-
"lion": "majestic lion portrait, detailed mane, powerful feline features, dramatic lighting, professional wildlife photography",
|
17 |
-
"renard": "elegant fox portrait, detailed fur texture, cunning vulpine features, professional wildlife photography"
|
18 |
-
}
|
19 |
-
}
|
20 |
-
|
21 |
-
# Styles artistiques améliorés
|
22 |
ART_STYLES = {
|
23 |
-
"Illustration Pro": {
|
24 |
-
"prompt_prefix": "professional high-end illustration, perfect composition, editorial quality artwork",
|
25 |
-
"style_modifiers": "sharp clean lines, elegant design, magazine quality finish",
|
26 |
-
"guidance": 13.5,
|
27 |
-
"steps": 70,
|
28 |
-
"negative_prompt": "amateur, sketchy, rough, unfinished, low quality"
|
29 |
-
},
|
30 |
"Neo Vintage": {
|
31 |
-
"prompt_prefix": "vintage
|
32 |
-
"
|
33 |
"guidance": 12.5,
|
34 |
-
"steps":
|
35 |
-
"negative_prompt": "
|
36 |
-
},
|
37 |
-
"Art Moderne": {
|
38 |
-
"prompt_prefix": "modern art style, contemporary design, abstract artistic interpretation",
|
39 |
-
"style_modifiers": "geometric shapes, bold colors, minimalist composition",
|
40 |
-
"guidance": 11.0,
|
41 |
-
"steps": 60,
|
42 |
-
"negative_prompt": "classical, photorealistic, traditional"
|
43 |
},
|
44 |
-
"
|
45 |
-
"prompt_prefix": "
|
46 |
-
"
|
47 |
-
"guidance":
|
48 |
"steps": 75,
|
49 |
-
"negative_prompt": "
|
50 |
},
|
51 |
-
"
|
52 |
-
"prompt_prefix": "
|
53 |
-
"
|
54 |
"guidance": 11.5,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
"steps": 60,
|
56 |
-
"negative_prompt": "
|
57 |
}
|
58 |
}
|
59 |
|
|
|
60 |
CUSTOM_CSS = """
|
61 |
.container { max-width: 1200px; margin: auto; }
|
62 |
.welcome { text-align: center; margin: 20px 0; padding: 20px; background: #1e293b; border-radius: 10px; }
|
63 |
.quality-controls { margin: 10px 0; padding: 10px; background: #2d3748; border-radius: 5px; }
|
64 |
-
.
|
65 |
"""
|
66 |
|
67 |
-
def
|
68 |
-
"""
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
-
if not base_prompt:
|
77 |
-
base_prompt = f"highly detailed {subject}"
|
78 |
-
|
79 |
-
# Ajout des détails spécifiques
|
80 |
if additional_details:
|
81 |
-
base_prompt
|
82 |
-
|
83 |
-
# Application du style
|
84 |
-
style_config = ART_STYLES[style]
|
85 |
-
final_prompt = f"{style_config['prompt_prefix']}, {base_prompt}, {style_config['style_modifiers']}"
|
86 |
|
87 |
-
return
|
88 |
|
89 |
-
def generate_image(format_size, orientation, subject, style, quality, creativity, additional_details=""):
|
90 |
API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
|
91 |
headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
|
92 |
|
93 |
try:
|
94 |
-
# Dimensions
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
-
|
99 |
-
|
100 |
-
base_width = 768
|
101 |
-
base_height = 1024
|
102 |
-
else:
|
103 |
-
if format_size in ["A4", "A3"]:
|
104 |
-
base_width = 1024
|
105 |
-
base_height = 768
|
106 |
-
|
107 |
-
# Construction du prompt optimisé
|
108 |
-
enhanced_prompt, negative_prompt = enhance_prompt(subject, style, additional_details)
|
109 |
|
110 |
-
print(f"Prompt final: {enhanced_prompt}") # Debug
|
111 |
-
print(f"Prompt négatif: {negative_prompt}") # Debug
|
112 |
-
|
113 |
# Configuration de la requête
|
114 |
payload = {
|
115 |
"inputs": enhanced_prompt,
|
@@ -117,18 +92,16 @@ def generate_image(format_size, orientation, subject, style, quality, creativity
|
|
117 |
"negative_prompt": negative_prompt,
|
118 |
"num_inference_steps": int(ART_STYLES[style]['steps'] * (quality/100)),
|
119 |
"guidance_scale": ART_STYLES[style]['guidance'] * (creativity/10),
|
120 |
-
"width":
|
121 |
-
"height":
|
122 |
}
|
123 |
}
|
124 |
|
125 |
-
print(f"Paramètres de génération: {payload}") # Debug
|
126 |
-
|
127 |
response = requests.post(API_URL, headers=headers, json=payload, timeout=60)
|
128 |
|
129 |
if response.status_code == 200:
|
130 |
image = Image.open(io.BytesIO(response.content))
|
131 |
-
return image, f"✨ Création {style} réussie
|
132 |
else:
|
133 |
print(f"Erreur API: {response.text}") # Debug
|
134 |
return None, f"⚠️ Erreur {response.status_code}: Ajustez les paramètres"
|
@@ -162,30 +135,42 @@ def create_interface():
|
|
162 |
label="Orientation"
|
163 |
)
|
164 |
|
165 |
-
# Étape 2: Création
|
166 |
with gr.Group():
|
167 |
gr.Markdown("### 🎨 Étape 2: Création Visuelle")
|
168 |
-
|
169 |
with gr.Row():
|
170 |
with gr.Column():
|
171 |
style = gr.Dropdown(
|
172 |
choices=list(ART_STYLES.keys()),
|
173 |
-
value="
|
174 |
label="Style artistique",
|
175 |
-
info="Choisissez
|
176 |
)
|
177 |
|
178 |
subject = gr.Textbox(
|
179 |
-
lines=1,
|
180 |
label="Sujet principal",
|
181 |
-
placeholder="Ex:
|
182 |
-
info="Décrivez
|
183 |
)
|
184 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
additional_details = gr.Textbox(
|
186 |
lines=2,
|
187 |
label="Détails additionnels (optionnel)",
|
188 |
-
placeholder="Ajoutez des détails
|
189 |
info="Plus de détails = meilleur résultat"
|
190 |
)
|
191 |
|
@@ -231,6 +216,8 @@ def create_interface():
|
|
231 |
orientation,
|
232 |
subject,
|
233 |
style,
|
|
|
|
|
234 |
quality,
|
235 |
creativity,
|
236 |
additional_details
|
|
|
4 |
import requests
|
5 |
import io
|
6 |
|
7 |
+
# Styles artistiques optimisés pour le texte
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
ART_STYLES = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
"Neo Vintage": {
|
10 |
+
"prompt_prefix": "vintage propaganda poster style, retro advertisement design",
|
11 |
+
"text_style": "clear vintage typography, screen printing style lettering, clean text layout",
|
12 |
"guidance": 12.5,
|
13 |
+
"steps": 70,
|
14 |
+
"negative_prompt": "blurry text, illegible writing, damaged letters, distorted fonts, gibberish"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
},
|
16 |
+
"Art Déco": {
|
17 |
+
"prompt_prefix": "art deco poster design, 1920s luxury advertisement style",
|
18 |
+
"text_style": "elegant art deco typography, decorative lettering, geometric text design",
|
19 |
+
"guidance": 13.0,
|
20 |
"steps": 75,
|
21 |
+
"negative_prompt": "modern fonts, messy text, unclear letters, random characters"
|
22 |
},
|
23 |
+
"Moderne": {
|
24 |
+
"prompt_prefix": "modern minimalist poster design, contemporary professional layout",
|
25 |
+
"text_style": "clean sans-serif typography, precise text placement, minimal design",
|
26 |
"guidance": 11.5,
|
27 |
+
"steps": 65,
|
28 |
+
"negative_prompt": "cluttered text, unreadable fonts, messy layout, poor typography"
|
29 |
+
},
|
30 |
+
"Pop Art": {
|
31 |
+
"prompt_prefix": "pop art style poster, comic book inspired design",
|
32 |
+
"text_style": "bold comic book typography, dynamic text placement, retro lettering",
|
33 |
+
"guidance": 11.0,
|
34 |
"steps": 60,
|
35 |
+
"negative_prompt": "subtle text, unclear typography, messy letters"
|
36 |
}
|
37 |
}
|
38 |
|
39 |
+
# CSS personnalisé
|
40 |
CUSTOM_CSS = """
|
41 |
.container { max-width: 1200px; margin: auto; }
|
42 |
.welcome { text-align: center; margin: 20px 0; padding: 20px; background: #1e293b; border-radius: 10px; }
|
43 |
.quality-controls { margin: 10px 0; padding: 10px; background: #2d3748; border-radius: 5px; }
|
44 |
+
.text-input { background: #2d3748; padding: 15px; border-radius: 5px; margin: 10px 0; }
|
45 |
"""
|
46 |
|
47 |
+
def generate_enhanced_prompt(subject, style, title="", subtitle="", additional_details=""):
|
48 |
+
"""Génère un prompt optimisé pour le texte"""
|
49 |
+
style_config = ART_STYLES[style]
|
50 |
+
|
51 |
+
# Construction du prompt de base
|
52 |
+
base_prompt = f"{style_config['prompt_prefix']}, {subject}"
|
53 |
+
|
54 |
+
# Ajout des éléments de texte si présents
|
55 |
+
text_elements = []
|
56 |
+
if title:
|
57 |
+
text_elements.append(f"with main title text '{title}'")
|
58 |
+
if subtitle:
|
59 |
+
text_elements.append(f"subtitle text '{subtitle}'")
|
60 |
+
|
61 |
+
text_prompt = ", ".join(text_elements)
|
62 |
+
if text_prompt:
|
63 |
+
base_prompt += f", {text_prompt}, {style_config['text_style']}"
|
64 |
|
|
|
|
|
|
|
|
|
65 |
if additional_details:
|
66 |
+
base_prompt += f", {additional_details}"
|
|
|
|
|
|
|
|
|
67 |
|
68 |
+
return base_prompt, style_config['negative_prompt']
|
69 |
|
70 |
+
def generate_image(format_size, orientation, subject, style, title, subtitle, quality, creativity, additional_details=""):
|
71 |
API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
|
72 |
headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
|
73 |
|
74 |
try:
|
75 |
+
# Dimensions optimisées
|
76 |
+
width, height = (768, 1024) if format_size == "A4" else (1024, 1024)
|
77 |
+
if orientation == "Paysage":
|
78 |
+
width, height = height, width
|
79 |
+
|
80 |
+
# Génération du prompt optimisé
|
81 |
+
enhanced_prompt, negative_prompt = generate_enhanced_prompt(
|
82 |
+
subject, style, title, subtitle, additional_details
|
83 |
+
)
|
84 |
|
85 |
+
print(f"Prompt: {enhanced_prompt}") # Debug
|
86 |
+
print(f"Negative prompt: {negative_prompt}") # Debug
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
|
|
|
|
|
|
|
88 |
# Configuration de la requête
|
89 |
payload = {
|
90 |
"inputs": enhanced_prompt,
|
|
|
92 |
"negative_prompt": negative_prompt,
|
93 |
"num_inference_steps": int(ART_STYLES[style]['steps'] * (quality/100)),
|
94 |
"guidance_scale": ART_STYLES[style]['guidance'] * (creativity/10),
|
95 |
+
"width": width,
|
96 |
+
"height": height
|
97 |
}
|
98 |
}
|
99 |
|
|
|
|
|
100 |
response = requests.post(API_URL, headers=headers, json=payload, timeout=60)
|
101 |
|
102 |
if response.status_code == 200:
|
103 |
image = Image.open(io.BytesIO(response.content))
|
104 |
+
return image, f"✨ Création {style} réussie avec texte intégré!"
|
105 |
else:
|
106 |
print(f"Erreur API: {response.text}") # Debug
|
107 |
return None, f"⚠️ Erreur {response.status_code}: Ajustez les paramètres"
|
|
|
135 |
label="Orientation"
|
136 |
)
|
137 |
|
138 |
+
# Étape 2: Création Visuelle
|
139 |
with gr.Group():
|
140 |
gr.Markdown("### 🎨 Étape 2: Création Visuelle")
|
|
|
141 |
with gr.Row():
|
142 |
with gr.Column():
|
143 |
style = gr.Dropdown(
|
144 |
choices=list(ART_STYLES.keys()),
|
145 |
+
value="Neo Vintage",
|
146 |
label="Style artistique",
|
147 |
+
info="Choisissez le style de votre affiche"
|
148 |
)
|
149 |
|
150 |
subject = gr.Textbox(
|
|
|
151 |
label="Sujet principal",
|
152 |
+
placeholder="Ex: loup, paysage urbain...",
|
153 |
+
info="Décrivez l'élément principal"
|
154 |
)
|
155 |
|
156 |
+
# Nouvelle section texte
|
157 |
+
with gr.Group(elem_classes="text-input"):
|
158 |
+
gr.Markdown("#### 📝 Texte de l'affiche")
|
159 |
+
title = gr.Textbox(
|
160 |
+
label="Titre principal",
|
161 |
+
placeholder="Texte principal qui apparaîtra sur l'affiche",
|
162 |
+
info="Ce texte sera intégré de manière lisible"
|
163 |
+
)
|
164 |
+
subtitle = gr.Textbox(
|
165 |
+
label="Sous-titre (optionnel)",
|
166 |
+
placeholder="Texte secondaire plus petit",
|
167 |
+
info="Texte complémentaire"
|
168 |
+
)
|
169 |
+
|
170 |
additional_details = gr.Textbox(
|
171 |
lines=2,
|
172 |
label="Détails additionnels (optionnel)",
|
173 |
+
placeholder="Ajoutez des détails pour enrichir l'image...",
|
174 |
info="Plus de détails = meilleur résultat"
|
175 |
)
|
176 |
|
|
|
216 |
orientation,
|
217 |
subject,
|
218 |
style,
|
219 |
+
title,
|
220 |
+
subtitle,
|
221 |
quality,
|
222 |
creativity,
|
223 |
additional_details
|