File size: 6,441 Bytes
0996984
c8bec5c
 
 
0996984
188c43b
c8669ac
33408e4
80dc654
deee24c
998a64b
7513002
 
0996984
7513002
c8bec5c
2ad51f4
d8acf02
 
 
 
 
 
 
 
c5510e6
 
d8acf02
2ad51f4
c8bec5c
188c43b
c8bec5c
d8acf02
 
188c43b
d8acf02
2516959
d8acf02
c8bec5c
13d2767
 
d8acf02
c8bec5c
d8acf02
c8bec5c
0996984
80dc654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c8bec5c
80dc654
 
 
 
 
 
 
c2cb482
c8bec5c
80dc654
 
 
d8acf02
 
 
 
 
 
 
 
 
80dc654
 
d8acf02
2516959
80dc654
d8acf02
 
 
3b87ce2
80dc654
 
 
 
 
 
 
 
 
c2cb482
 
80dc654
 
 
c2cb482
80dc654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d8acf02
c2cb482
d8acf02
 
 
 
2ad51f4
d8acf02
 
 
c2cb482
c8bec5c
80dc654
 
 
d8acf02
80dc654
 
0996984
80dc654
 
 
 
 
c8bec5c
80dc654
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import spaces
import torch
import gradio as gr
from diffusers import FluxPipeline
from huggingface_hub import hf_hub_download, login
import random
import os

# Authentification
hf_token = os.getenv("HF_TOKEN")
print(f"Token trouvé : {bool(hf_token)}")
if hf_token:
    login(token=hf_token)
    print("✅ Authentifié")

model_id = "black-forest-labs/FLUX.1-schnell"

# Prompt par défaut
DEFAULT_PROMPT = "A stunning portrait of a woman with flowing red hair, piercing green eyes, natural lighting, ultra detailed, 8k quality, professional photography"

# Note: FLUX.1-schnell n'utilise PAS de LoRA par défaut
# Le modèle de base est déjà optimisé pour la génération rapide
# Si vous voulez ajouter des LoRA, utilisez des repositories communautaires comme:
# - XLabs-AI/flux-RealismLora
# - Shakker-Labs/FLUX.1-dev-LoRA-collections
# Abzaloff/Flux_Art_Fusion
# XLabs-AI/flux-RealismLora
# etc.

lora_repo = None
lora_path = None

def load_lora(repo_id, filename):
    """Charge un LoRA depuis un repository HuggingFace"""
    global lora_repo, lora_path
    if not repo_id or not filename:
        return "Abzaloff/Flux_Art_Fusion"
    
    try:
        lora_path = hf_hub_download(repo_id=repo_id, filename=filename)
        lora_repo = repo_id
        return f"✅ LoRA chargé : {repo_id}/{filename}"
    except Exception as e:
        return f"❌ Erreur : {str(e)}\n\nVérifiez que le repository contient bien ce fichier."

@spaces.GPU(duration=120)
def generate(prompt, negative_prompt="", width=1024, height=1024, steps=4, seed=-1, lora_scale=0.8):
    try:
        # Initialisation du pipeline
        pipe = FluxPipeline.from_pretrained(
            model_id, 
            torch_dtype=torch.bfloat16
        )
        pipe.to("cuda")
        
        # Chargement du LoRA si disponible
        if lora_repo and lora_path:
            pipe.load_lora_weights(lora_path)
            pipe.fuse_lora(lora_scale=lora_scale)
        
        # Optimisation mémoire
        pipe.enable_model_cpu_offload()
        
        # Génération du seed
        if seed == -1:
            seed = random.randint(0, 2**32 - 1)
        generator = torch.Generator("cuda").manual_seed(seed)
        
        # Génération de l'image
        image = pipe(
            prompt=prompt,
            negative_prompt=negative_prompt if negative_prompt else None,
            height=height,
            width=width,
            num_inference_steps=steps,
            guidance_scale=0.0,
            generator=generator,
            max_sequence_length=256
        ).images[0]
        
        # Nettoyage de la mémoire
        del pipe
        torch.cuda.empty_cache()
        
        return image
    
    except Exception as e:
        print(f"❌ Erreur de génération : {str(e)}")
        raise gr.Error(f"Erreur : {str(e)}")

# Interface Gradio
with gr.Blocks(title="Flux Schnell + LoRA") as demo:
    gr.Markdown("# 🎨 Générateur Flux Schnell + LoRA")
    gr.Markdown(f"**Modèle :** `{model_id}`")
    
    with gr.Row():
        with gr.Column():
            # LoRA
            gr.Markdown("### 🎨 Ajouter un LoRA (optionnel)")
            gr.Markdown("""
            ⚠️ **Important** : Le modèle de base FLUX.1-schnell fonctionne **sans LoRA**.
            
            Si vous voulez ajouter un style avec un LoRA, utilisez des repositories communautaires :
            - `XLabs-AI/flux-RealismLora` (fichier: `lora.safetensors`)
            - `Shakker-Labs/FLUX.1-dev-LoRA-add-details` (fichier: `FLUX-dev-lora-add_details.safetensors`)
            """)
            
            lora_repo_input = gr.Textbox(
                label="Repository LoRA",
                placeholder="Ex: XLabs-AI/flux-RealismLora",
                value="Abzaloff/Flux_Art_Fusion"
            )
            lora_filename = gr.Textbox(
                label="Nom du fichier LoRA",
                placeholder="Ex: lora.safetensors",
                value="Flux_Art_fusion_v1_fp16_00001_.safetensors"
            )
            load_btn = gr.Button("Charger LoRA")
            lora_status = gr.Textbox(label="Status", interactive=False)
            
            # Paramètres
            gr.Markdown("### Paramètres de génération")
            prompt = gr.Textbox(
                label="Prompt",
                placeholder="Décrivez votre image...",
                lines=3,
                value=DEFAULT_PROMPT
            )
            negative_prompt = gr.Textbox(
                label="Negative Prompt (optionnel)",
                placeholder="blurry, low quality, distorted, ugly",
                lines=2
            )
            
            with gr.Row():
                width = gr.Slider(512, 2048, 1024, step=64, label="Largeur")
                height = gr.Slider(512, 2048, 1024, step=64, label="Hauteur")
            
            with gr.Row():
                steps = gr.Slider(1, 10, 4, step=1, label="Steps")
                seed = gr.Number(label="Seed (-1 = aléatoire)", value=-1)
                lora_scale = gr.Slider(0, 1, 0.8, step=0.1, label="LoRA Scale")
            
            generate_btn = gr.Button("🚀 Générer", variant="primary")
        
        with gr.Column():
            output_image = gr.Image(label="Image générée", type="pil")
            gr.Markdown("### 💡 Conseils")
            gr.Markdown("""
            - **Modèle de base** : FLUX.1-schnell (rapide, sans LoRA nécessaire)
            - **Steps recommandés** : 4 pour Schnell
            - **Résolution** : 1024x1024 par défaut
            - **LoRA Scale** : 0.8 pour un effet équilibré (ajustez entre 0-1)
            
            **Exemples de repositories LoRA compatibles :**
            - [XLabs-AI/flux-RealismLora](https://huggingface.co/XLabs-AI/flux-RealismLora)
            - [Shakker-Labs collections](https://huggingface.co/Shakker-Labs)
            """)
    
    # Actions
    load_btn.click(
        fn=load_lora,
        inputs=[lora_repo_input, lora_filename],
        outputs=lora_status
    )
    
    generate_btn.click(
        fn=generate,
        inputs=[prompt, negative_prompt, width, height, steps, seed, lora_scale],
        outputs=output_image
    )

# Lancement avec gestion propre de l'event loop
if __name__ == "__main__":
    demo.queue()  # Active la file d'attente
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        show_error=True,
        quiet=False
    )