|
import tkinter as tk |
|
from tkinter import ttk, scrolledtext, messagebox |
|
from PIL import Image, ImageTk |
|
import os |
|
from datetime import datetime |
|
import json |
|
import requests |
|
from io import BytesIO |
|
import base64 |
|
import time |
|
|
|
class DrawingTutorialApp: |
|
def __init__(self, root): |
|
self.root = root |
|
self.root.title("Générateur de Tutoriel de Dessin") |
|
|
|
|
|
self.API_URL = "https://api-inference.huggingface.co/models/stabilityai/sdxl-turbo" |
|
|
|
|
|
|
|
self.setup_styles() |
|
|
|
|
|
self.current_step = 0 |
|
self.generated_images = [] |
|
self.steps_description = [] |
|
|
|
|
|
self.create_interface() |
|
|
|
def setup_styles(self): |
|
style = ttk.Style() |
|
style.configure('TButton', padding=5) |
|
style.configure('TFrame', padding=5) |
|
|
|
def create_interface(self): |
|
|
|
main_frame = ttk.Frame(self.root) |
|
main_frame.pack(expand=True, fill='both', padx=10, pady=10) |
|
|
|
|
|
desc_frame = ttk.LabelFrame(main_frame, text="Description du dessin") |
|
desc_frame.pack(fill='x', pady=5) |
|
|
|
self.description_text = scrolledtext.ScrolledText(desc_frame, height=4) |
|
self.description_text.pack(fill='x', padx=5, pady=5) |
|
|
|
|
|
control_frame = ttk.Frame(main_frame) |
|
control_frame.pack(fill='x', pady=5) |
|
|
|
ttk.Button(control_frame, text="Générer les étapes", |
|
command=self.generate_steps).pack(side='left', padx=5) |
|
|
|
ttk.Button(control_frame, text="Étape précédente", |
|
command=self.previous_step).pack(side='left', padx=5) |
|
|
|
ttk.Button(control_frame, text="Étape suivante", |
|
command=self.next_step).pack(side='left', padx=5) |
|
|
|
|
|
self.display_frame = ttk.LabelFrame(main_frame, text="Aperçu de l'étape") |
|
self.display_frame.pack(fill='both', expand=True, pady=5) |
|
|
|
self.image_label = ttk.Label(self.display_frame) |
|
self.image_label.pack(padx=5, pady=5) |
|
|
|
|
|
self.step_description = ttk.Label(self.display_frame, |
|
text="Aucune étape générée", |
|
wraplength=400) |
|
self.step_description.pack(padx=5, pady=5) |
|
|
|
|
|
self.progress_label = ttk.Label(main_frame, text="") |
|
self.progress_label.pack(pady=5) |
|
|
|
def query_image(self, prompt): |
|
"""Génère une image via l'API Hugging Face""" |
|
try: |
|
response = requests.post( |
|
self.API_URL, |
|
headers=self.headers, |
|
json={ |
|
"inputs": prompt, |
|
"parameters": { |
|
"num_inference_steps": 1, |
|
"guidance_scale": 0.0, |
|
} |
|
} |
|
) |
|
|
|
|
|
if response.status_code != 200: |
|
raise Exception(f"Erreur API: {response.status_code}") |
|
|
|
|
|
if response.status_code == 200 and "error" in response.json(): |
|
if "currently loading" in response.json()["error"]: |
|
print("Modèle en cours de chargement, attente...") |
|
time.sleep(20) |
|
return self.query_image(prompt) |
|
|
|
|
|
image_bytes = response.content |
|
image = Image.open(BytesIO(image_bytes)) |
|
return image |
|
|
|
except Exception as e: |
|
print(f"Erreur lors de la génération d'image: {e}") |
|
messagebox.showerror("Erreur", f"Erreur lors de la génération d'image: {e}") |
|
return None |
|
|
|
def generate_steps(self): |
|
description = self.description_text.get("1.0", "end-1c") |
|
if not description: |
|
messagebox.showwarning("Attention", "Veuillez entrer une description") |
|
return |
|
|
|
|
|
steps = [ |
|
{ |
|
"name": "Esquisse de base et formes géométriques", |
|
"prompt": f"basic sketch with geometric shapes of {description}, lineart, sketch style, black and white" |
|
}, |
|
{ |
|
"name": "Ajout des détails principaux", |
|
"prompt": f"detailed sketch of {description}, more defined lines, black and white drawing" |
|
}, |
|
{ |
|
"name": "Affinement des lignes", |
|
"prompt": f"refined line drawing of {description}, clean lines, professional sketch" |
|
}, |
|
{ |
|
"name": "Ajout des ombres de base", |
|
"prompt": f"shaded sketch of {description}, basic shadows and values, grayscale" |
|
}, |
|
{ |
|
"name": "Colorisation de base", |
|
"prompt": f"basic colored version of {description}, flat colors, simple coloring" |
|
}, |
|
{ |
|
"name": "Ajout des détails de couleur", |
|
"prompt": f"detailed colored drawing of {description}, with shading and color details" |
|
}, |
|
{ |
|
"name": "Finalisation et mise en valeur", |
|
"prompt": f"final polished illustration of {description}, complete with details and professional finish" |
|
} |
|
] |
|
|
|
|
|
self.generated_images = [] |
|
self.steps_description = [] |
|
|
|
|
|
for i, step in enumerate(steps): |
|
self.progress_label.configure( |
|
text=f"Génération de l'étape {i+1}/{len(steps)}: {step['name']}") |
|
self.root.update() |
|
|
|
image = self.query_image(step['prompt']) |
|
if image: |
|
self.generated_images.append(image) |
|
self.steps_description.append(f"{step['name']}\n{step['prompt']}") |
|
else: |
|
messagebox.showerror("Erreur", f"Échec de la génération pour l'étape {i+1}") |
|
continue |
|
|
|
if self.generated_images: |
|
self.progress_label.configure(text="Génération terminée!") |
|
self.current_step = 0 |
|
self.update_display() |
|
else: |
|
self.progress_label.configure(text="Échec de la génération") |
|
|
|
def update_display(self): |
|
if not self.generated_images: |
|
return |
|
|
|
image = self.generated_images[self.current_step] |
|
|
|
image = image.resize((400, 400), Image.Resampling.LANCZOS) |
|
photo = ImageTk.PhotoImage(image) |
|
self.image_label.configure(image=photo) |
|
self.image_label.image = photo |
|
|
|
step_text = f"Étape {self.current_step + 1}/{len(self.generated_images)}\n" |
|
step_text += self.steps_description[self.current_step] |
|
self.step_description.configure(text=step_text) |
|
|
|
def previous_step(self): |
|
if self.current_step > 0: |
|
self.current_step -= 1 |
|
self.update_display() |
|
|
|
def next_step(self): |
|
if self.current_step < len(self.generated_images) - 1: |
|
self.current_step += 1 |
|
self.update_display() |
|
|
|
def main(): |
|
root = tk.Tk() |
|
app = DrawingTutorialApp(root) |
|
root.mainloop() |
|
|
|
if __name__ == "__main__": |
|
main() |