|
import gradio as gr |
|
import os |
|
from PIL import Image, ImageDraw, ImageFont |
|
import requests |
|
import io |
|
|
|
|
|
SUBJECT_PROMPTS = { |
|
"insectes": { |
|
"libellule": "hyper realistic dragonfly in flight with translucent wings, iridescent body, macro photography, detailed insect illustration, natural lighting, entomological precision", |
|
"papillon": "detailed butterfly with intricate wing patterns, highly detailed macro photography, precise lepidoptera illustration", |
|
"scarabée": "detailed beetle with shiny carapace, precise entomological macro photography" |
|
}, |
|
"animaux": { |
|
"loup": "majestic wolf portrait, detailed fur texture, highly detailed wild canine features, expressive eyes, professional wildlife photography", |
|
"lion": "majestic lion portrait, detailed mane, powerful feline features, dramatic lighting, professional wildlife photography", |
|
"renard": "elegant fox portrait, detailed fur texture, cunning vulpine features, professional wildlife photography" |
|
} |
|
} |
|
|
|
|
|
ART_STYLES = { |
|
"Illustration Pro": { |
|
"prompt_prefix": "professional high-end illustration, perfect composition, editorial quality artwork", |
|
"style_modifiers": "sharp clean lines, elegant design, magazine quality finish", |
|
"guidance": 13.5, |
|
"steps": 70, |
|
"negative_prompt": "amateur, sketchy, rough, unfinished, low quality" |
|
}, |
|
"Neo Vintage": { |
|
"prompt_prefix": "vintage style poster art, retro illustration, classic design aesthetic", |
|
"style_modifiers": "halftone texture, limited color palette, aged paper effect, vintage typography", |
|
"guidance": 12.5, |
|
"steps": 65, |
|
"negative_prompt": "modern, digital, glossy, contemporary" |
|
}, |
|
"Art Moderne": { |
|
"prompt_prefix": "modern art style, contemporary design, abstract artistic interpretation", |
|
"style_modifiers": "geometric shapes, bold colors, minimalist composition", |
|
"guidance": 11.0, |
|
"steps": 60, |
|
"negative_prompt": "classical, photorealistic, traditional" |
|
}, |
|
"Dark Fantasy": { |
|
"prompt_prefix": "dark fantasy art style, atmospheric mood, dramatic fantasy illustration", |
|
"style_modifiers": "mystical atmosphere, dramatic lighting, ethereal quality", |
|
"guidance": 14.0, |
|
"steps": 75, |
|
"negative_prompt": "cheerful, bright, realistic photo, mundane" |
|
}, |
|
"Pop Art": { |
|
"prompt_prefix": "pop art style illustration, bold graphic design, comic book aesthetic", |
|
"style_modifiers": "vibrant colors, halftone dots, bold outlines, Warhol-inspired", |
|
"guidance": 11.5, |
|
"steps": 60, |
|
"negative_prompt": "realistic, subtle, painterly, traditional" |
|
} |
|
} |
|
|
|
CUSTOM_CSS = """ |
|
.container { max-width: 1200px; margin: auto; } |
|
.welcome { text-align: center; margin: 20px 0; padding: 20px; background: #1e293b; border-radius: 10px; } |
|
.quality-controls { margin: 10px 0; padding: 10px; background: #2d3748; border-radius: 5px; } |
|
.style-info { padding: 10px; background: #2d3748; border-radius: 5px; margin-top: 10px; } |
|
""" |
|
|
|
def enhance_prompt(subject, style, additional_details=""): |
|
"""Améliore le prompt avec des détails spécifiques""" |
|
|
|
base_prompt = None |
|
for category, subjects in SUBJECT_PROMPTS.items(): |
|
if subject.lower() in subjects: |
|
base_prompt = subjects[subject.lower()] |
|
break |
|
|
|
if not base_prompt: |
|
base_prompt = f"highly detailed {subject}" |
|
|
|
|
|
if additional_details: |
|
base_prompt = f"{base_prompt}, {additional_details}" |
|
|
|
|
|
style_config = ART_STYLES[style] |
|
final_prompt = f"{style_config['prompt_prefix']}, {base_prompt}, {style_config['style_modifiers']}" |
|
|
|
return final_prompt, style_config['negative_prompt'] |
|
|
|
def generate_image(format_size, orientation, subject, style, quality, creativity, additional_details=""): |
|
API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0" |
|
headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"} |
|
|
|
try: |
|
|
|
base_width = 1024 |
|
base_height = 1024 |
|
|
|
if orientation == "Portrait": |
|
if format_size in ["A4", "A3"]: |
|
base_width = 768 |
|
base_height = 1024 |
|
else: |
|
if format_size in ["A4", "A3"]: |
|
base_width = 1024 |
|
base_height = 768 |
|
|
|
|
|
enhanced_prompt, negative_prompt = enhance_prompt(subject, style, additional_details) |
|
|
|
print(f"Prompt final: {enhanced_prompt}") |
|
print(f"Prompt négatif: {negative_prompt}") |
|
|
|
|
|
payload = { |
|
"inputs": enhanced_prompt, |
|
"parameters": { |
|
"negative_prompt": negative_prompt, |
|
"num_inference_steps": int(ART_STYLES[style]['steps'] * (quality/100)), |
|
"guidance_scale": ART_STYLES[style]['guidance'] * (creativity/10), |
|
"width": base_width, |
|
"height": base_height |
|
} |
|
} |
|
|
|
print(f"Paramètres de génération: {payload}") |
|
|
|
response = requests.post(API_URL, headers=headers, json=payload, timeout=60) |
|
|
|
if response.status_code == 200: |
|
image = Image.open(io.BytesIO(response.content)) |
|
return image, f"✨ Création {style} réussie!" |
|
else: |
|
print(f"Erreur API: {response.text}") |
|
return None, f"⚠️ Erreur {response.status_code}: Ajustez les paramètres" |
|
|
|
except Exception as e: |
|
print(f"Exception: {str(e)}") |
|
return None, f"⚠️ Erreur: {str(e)}" |
|
|
|
def create_interface(): |
|
with gr.Blocks(css=CUSTOM_CSS) as app: |
|
gr.HTML(""" |
|
<div class="welcome"> |
|
<h1>🤖 Equity Artisan 3.0</h1> |
|
<p>Créez des affiches professionnelles étape par étape avec notre assistant créatif augmenté.</p> |
|
</div> |
|
""") |
|
|
|
with gr.Column(elem_classes="container"): |
|
|
|
with gr.Group(): |
|
gr.Markdown("### 📏 Étape 1: Format et Orientation") |
|
with gr.Row(): |
|
format_choice = gr.Dropdown( |
|
choices=["A4", "A3", "A2", "A1", "A0"], |
|
value="A4", |
|
label="Format" |
|
) |
|
orientation = gr.Radio( |
|
choices=["Portrait", "Paysage"], |
|
value="Portrait", |
|
label="Orientation" |
|
) |
|
|
|
|
|
with gr.Group(): |
|
gr.Markdown("### 🎨 Étape 2: Création Visuelle") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
style = gr.Dropdown( |
|
choices=list(ART_STYLES.keys()), |
|
value="Illustration Pro", |
|
label="Style artistique", |
|
info="Choisissez votre style d'illustration" |
|
) |
|
|
|
subject = gr.Textbox( |
|
lines=1, |
|
label="Sujet principal", |
|
placeholder="Ex: libellule, loup, paysage...", |
|
info="Décrivez le sujet principal" |
|
) |
|
|
|
additional_details = gr.Textbox( |
|
lines=2, |
|
label="Détails additionnels (optionnel)", |
|
placeholder="Ajoutez des détails spécifiques pour enrichir l'image...", |
|
info="Plus de détails = meilleur résultat" |
|
) |
|
|
|
with gr.Group(elem_classes="quality-controls"): |
|
quality = gr.Slider( |
|
minimum=30, |
|
maximum=50, |
|
value=35, |
|
step=5, |
|
label="Qualité", |
|
info="Influence le niveau de détail" |
|
) |
|
|
|
creativity = gr.Slider( |
|
minimum=5, |
|
maximum=15, |
|
value=7.5, |
|
step=0.5, |
|
label="Créativité", |
|
info="Balance entre fidélité et créativité" |
|
) |
|
|
|
generate_btn = gr.Button("✨ Générer", variant="primary") |
|
clear_btn = gr.Button("🗑️ Effacer", variant="secondary") |
|
|
|
image_output = gr.Image( |
|
label="Aperçu", |
|
type="pil" |
|
) |
|
|
|
|
|
status = gr.Textbox( |
|
label="Status", |
|
interactive=False, |
|
value="Prêt à générer" |
|
) |
|
|
|
|
|
generate_btn.click( |
|
generate_image, |
|
inputs=[ |
|
format_choice, |
|
orientation, |
|
subject, |
|
style, |
|
quality, |
|
creativity, |
|
additional_details |
|
], |
|
outputs=[image_output, status] |
|
) |
|
|
|
clear_btn.click( |
|
lambda: (None, "Image effacée"), |
|
outputs=[image_output, status] |
|
) |
|
|
|
return app |
|
|
|
if __name__ == "__main__": |
|
app = create_interface() |
|
app.launch() |