Spaces:
vcollos
/
Runtime error

vcollos commited on
Commit
373241b
·
verified ·
1 Parent(s): aa48c1d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +185 -9
app.py CHANGED
@@ -1,9 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  @spaces.GPU(duration=80)
2
- def run_lora(prompt, cfg_scale, steps, randomize_seed, seed, width, height, lora_option, lora_scale_1, lora_scale_2, progress=gr.Progress(track_tqdm=True)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  if randomize_seed:
4
  seed = random.randint(0, MAX_SEED)
5
  generator = torch.Generator(device="cuda").manual_seed(seed)
6
 
 
 
 
 
 
 
 
 
7
  # Trunca o prompt para 77 tokens para evitar erro do CLIP
8
  prompt_tokens = prompt.split()[:77]
9
  prompt = " ".join(prompt_tokens)
@@ -11,22 +123,34 @@ def run_lora(prompt, cfg_scale, steps, randomize_seed, seed, width, height, lora
11
  # Define qual LoRA usar com base na seleção do usuário
12
  selected_loras = []
13
  adapter_weights = []
14
-
 
15
  if lora_option == "Paula":
16
  selected_loras.append("Paula")
17
  adapter_weights.append(lora_scale_1)
 
 
18
  elif lora_option == "Vivi":
19
  selected_loras.append("Vivi")
20
  adapter_weights.append(lora_scale_2)
 
 
21
  elif lora_option == "Ambos":
22
  selected_loras = ["Paula", "Vivi"]
23
- # Ajusta os pesos para garantir equilíbrio
24
- total_scale = lora_scale_1 + lora_scale_2
25
- adapter_weights = [lora_scale_1 / total_scale, lora_scale_2 / total_scale]
 
 
26
 
27
  pipe.set_adapters(selected_loras, adapter_weights)
 
 
 
 
 
28
 
29
- # Gera a imagem com precisão de 16 bits para tentar melhorar a nitidez
30
  with torch.autocast("cuda"):
31
  image = pipe(
32
  prompt=prompt,
@@ -34,7 +158,8 @@ def run_lora(prompt, cfg_scale, steps, randomize_seed, seed, width, height, lora
34
  guidance_scale=cfg_scale,
35
  width=width,
36
  height=height,
37
- generator=generator
 
38
  ).images[0]
39
 
40
  # Define um nome único para a imagem
@@ -54,13 +179,16 @@ def run_lora(prompt, cfg_scale, steps, randomize_seed, seed, width, height, lora
54
  # Salva todos os metadados no Supabase
55
  try:
56
  response = supabase.table("images").insert({
57
- "prompt": prompt,
 
 
58
  "cfg_scale": cfg_scale,
59
  "steps": steps,
60
  "seed": seed,
61
  "lora_option": lora_option,
62
  "lora_scale_1": lora_scale_1,
63
  "lora_scale_2": lora_scale_2,
 
64
  "image_url": image_url,
65
  "created_at": datetime.utcnow().isoformat()
66
  }).execute()
@@ -73,4 +201,52 @@ def run_lora(prompt, cfg_scale, steps, randomize_seed, seed, width, height, lora
73
  except Exception as e:
74
  print(f"❌ Erro ao salvar metadados no Supabase: {e}")
75
 
76
- return image, seed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces
2
+ import gradio as gr
3
+ import torch
4
+ from PIL import Image
5
+ from diffusers import DiffusionPipeline
6
+ import random
7
+ import os
8
+ import json
9
+ import io
10
+ import uuid
11
+ from gradio_client import Client as client_gradio
12
+ from supabase import create_client, Client
13
+ from datetime import datetime
14
+ import requests
15
+
16
+ # Inicializa Supabase
17
+ url: str = os.getenv('SUPABASE_URL')
18
+ key: str = os.getenv('SUPABASE_KEY')
19
+ supabase: Client = create_client(url, key)
20
+
21
+ # Obtém token da Hugging Face
22
+ hf_token = os.getenv("HF_TOKEN")
23
+
24
+ # Inicializa o modelo base FLUX.1-dev
25
+ base_model = "black-forest-labs/FLUX.1-dev"
26
+ pipe = DiffusionPipeline.from_pretrained(
27
+ base_model,
28
+ torch_dtype=torch.float16,
29
+ use_safetensors=True
30
+ )
31
+
32
+ # Move o modelo para GPU
33
+ pipe.to("cuda")
34
+
35
+ # Definição dos LoRA e Trigger Words
36
+ lora_models = {
37
+ "Paula": {
38
+ "repo": "vcollos/Paula2",
39
+ "weights": "Paula P.safetensors",
40
+ "trigger_word": "paula, woman with long blonde hair" # Trigger word para Paula (mulher)
41
+ },
42
+ "Vivi": {
43
+ "repo": "vcollos/Vivi",
44
+ "weights": "Vivi.safetensors",
45
+ "trigger_word": "vivi, man with dark hair" # Trigger word corrigida para Vivi (homem)
46
+ }
47
+ }
48
+
49
+ # Carrega os LoRAs disponíveis
50
+ for name, details in lora_models.items():
51
+ try:
52
+ pipe.load_lora_weights(details["repo"], weight_name=details["weights"], adapter_name=name)
53
+ print(f"✅ LoRA {name} carregado")
54
+ except Exception as e:
55
+ print(f"❌ Erro ao carregar o LoRA {name}: {e}")
56
+
57
+ # Define seed máximo
58
+ MAX_SEED = 2**32 - 1
59
+
60
+ def upload_image_to_supabase(image, filename):
61
+ """ Faz upload da imagem para o Supabase Storage e retorna a URL pública. """
62
+ img_bytes = io.BytesIO()
63
+ image.save(img_bytes, format="PNG")
64
+ img_bytes.seek(0) # Move para o início do arquivo
65
+
66
+ storage_path = f"images/{filename}"
67
+
68
+ try:
69
+ # Faz upload da imagem para o Supabase
70
+ supabase.storage.from_("images").upload(storage_path, img_bytes.getvalue(), {"content-type": "image/png"})
71
+
72
+ # Retorna a URL pública da imagem
73
+ base_url = f"{url}/storage/v1/object/public/images"
74
+ return f"{base_url}/{storage_path}"
75
+ except Exception as e:
76
+ print(f"❌ Erro no upload da imagem: {e}")
77
+ return None
78
+
79
  @spaces.GPU(duration=80)
80
+ def translate_text(text, source_lang="pt", target_lang="en"):
81
+ """
82
+ Traduz o texto de português para inglês usando a API do LibreTranslate.
83
+ Se a tradução falhar, retorna o texto original.
84
+ """
85
+ try:
86
+ # Usa a API pública do LibreTranslate
87
+ url = "https://libretranslate.com/translate"
88
+ payload = {
89
+ "q": text,
90
+ "source": source_lang,
91
+ "target": target_lang,
92
+ "format": "text"
93
+ }
94
+ response = requests.post(url, json=payload)
95
+
96
+ if response.status_code == 200:
97
+ return response.json()["translatedText"]
98
+ else:
99
+ print(f"❌ Erro na tradução (código {response.status_code}): {response.text}")
100
+ return text
101
+
102
+ except Exception as e:
103
+ print(f"❌ Erro ao traduzir texto: {e}")
104
+ return text
105
+
106
+ def run_lora(prompt, cfg_scale, steps, randomize_seed, seed, width, height, lora_option, lora_scale_1, lora_scale_2, cross_attention_scale, auto_translate, progress=gr.Progress(track_tqdm=True)):
107
  if randomize_seed:
108
  seed = random.randint(0, MAX_SEED)
109
  generator = torch.Generator(device="cuda").manual_seed(seed)
110
 
111
+ original_prompt = prompt # Guarda o prompt original para metadados
112
+
113
+ # Traduz o prompt se a opção estiver habilitada
114
+ if auto_translate:
115
+ translated_prompt = translate_text(prompt)
116
+ print(f"📝 Prompt traduzido: {translated_prompt}")
117
+ prompt = translated_prompt
118
+
119
  # Trunca o prompt para 77 tokens para evitar erro do CLIP
120
  prompt_tokens = prompt.split()[:77]
121
  prompt = " ".join(prompt_tokens)
 
123
  # Define qual LoRA usar com base na seleção do usuário
124
  selected_loras = []
125
  adapter_weights = []
126
+
127
+ # Modificado para melhorar a mescla de personagens
128
  if lora_option == "Paula":
129
  selected_loras.append("Paula")
130
  adapter_weights.append(lora_scale_1)
131
+ prompt = f"{lora_models['Paula']['trigger_word']} {prompt}"
132
+
133
  elif lora_option == "Vivi":
134
  selected_loras.append("Vivi")
135
  adapter_weights.append(lora_scale_2)
136
+ prompt = f"{lora_models['Vivi']['trigger_word']} {prompt}"
137
+
138
  elif lora_option == "Ambos":
139
  selected_loras = ["Paula", "Vivi"]
140
+ adapter_weights = [lora_scale_1, lora_scale_2]
141
+
142
+ # Quando usando ambos, adiciona trigger words específicas para cada personagem
143
+ # e ajusta o prompt para indicar que ambos devem aparecer na mesma cena
144
+ prompt = f"{lora_models['Paula']['trigger_word']} and {lora_models['Vivi']['trigger_word']} together, a woman and a man, {prompt}"
145
 
146
  pipe.set_adapters(selected_loras, adapter_weights)
147
+
148
+ # Ajusta a cross-attention quando usando ambos os LoRAs
149
+ cross_attention_kwargs = {}
150
+ if lora_option == "Ambos" and cross_attention_scale != 1.0:
151
+ cross_attention_kwargs = {"scale": cross_attention_scale}
152
 
153
+ # Gera a imagem com precisão de 16 bits
154
  with torch.autocast("cuda"):
155
  image = pipe(
156
  prompt=prompt,
 
158
  guidance_scale=cfg_scale,
159
  width=width,
160
  height=height,
161
+ generator=generator,
162
+ cross_attention_kwargs=cross_attention_kwargs
163
  ).images[0]
164
 
165
  # Define um nome único para a imagem
 
179
  # Salva todos os metadados no Supabase
180
  try:
181
  response = supabase.table("images").insert({
182
+ "prompt": original_prompt, # Salva o prompt original
183
+ "full_prompt": prompt, # Salva o prompt completo com trigger words
184
+ "translated": auto_translate, # Indica se o prompt foi traduzido
185
  "cfg_scale": cfg_scale,
186
  "steps": steps,
187
  "seed": seed,
188
  "lora_option": lora_option,
189
  "lora_scale_1": lora_scale_1,
190
  "lora_scale_2": lora_scale_2,
191
+ "cross_attention_scale": cross_attention_scale,
192
  "image_url": image_url,
193
  "created_at": datetime.utcnow().isoformat()
194
  }).execute()
 
201
  except Exception as e:
202
  print(f"❌ Erro ao salvar metadados no Supabase: {e}")
203
 
204
+ return image, seed
205
+
206
+ # Interface Gradio
207
+ gr_theme = os.getenv("THEME")
208
+ with gr.Blocks(theme=gr_theme) as app:
209
+ gr.Markdown("# Paula & Vivi Image Generator")
210
+
211
+ with gr.Row():
212
+ with gr.Column(scale=2):
213
+ prompt = gr.TextArea(label="Prompt", placeholder="Digite um prompt (máx 77 caracteres)", lines=3)
214
+ generate_button = gr.Button("Gerar")
215
+
216
+ with gr.Accordion("Configurações Básicas", open=True):
217
+ cfg_scale = gr.Slider(label="CFG Scale", minimum=1, maximum=20, step=0.5, value=3.5)
218
+ steps = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=32)
219
+ width = gr.Slider(label="Width", minimum=256, maximum=1024, step=64, value=768)
220
+ height = gr.Slider(label="Height", minimum=256, maximum=1024, step=64, value=1024)
221
+ randomize_seed = gr.Checkbox(False, label="Randomize seed")
222
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=556215326)
223
+
224
+ with gr.Accordion("Configurações de LoRA", open=True):
225
+ lora_option = gr.Radio(["Nenhum", "Paula", "Vivi", "Ambos"], label="Escolha o LoRA", value="Ambos")
226
+ lora_scale_1 = gr.Slider(label="LoRA Scale (Paula)", minimum=0, maximum=1, step=0.01, value=0.8)
227
+ lora_scale_2 = gr.Slider(label="LoRA Scale (Vivi)", minimum=0, maximum=1, step=0.01, value=0.8)
228
+ cross_attention_scale = gr.Slider(label="Cross-Attention Scale", minimum=0.1, maximum=1.5, step=0.05, value=1.0,
229
+ info="Ajuste para controlar o balanceamento dos LoRAs (útil no modo 'Ambos')")
230
+ auto_translate = gr.Checkbox(True, label="Traduzir automaticamente para inglês",
231
+ info="Traduz o prompt do português para o inglês antes de gerar a imagem")
232
+
233
+ with gr.Column(scale=2):
234
+ result = gr.Image(label="Generated Image")
235
+ gr.Markdown("""
236
+ ### Dicas para gerar imagens com ambos personagens:
237
+ 1. Use o modo "Ambos" com valores balanceados (ex: 0.8 para ambos os LoRAs)
238
+ 2. Inclua no prompt termos como "um homem e uma mulher juntos", "duas pessoas", etc.
239
+ 3. Lembre-se: Paula é uma mulher loira e Vivi é um homem de cabelo escuro
240
+ 4. Seu prompt será automaticamente traduzido para inglês (se a opção estiver ativada)
241
+ 5. Ajuste o Cross-Attention Scale para valores como 0.9 ou 1.1 para equilibrar a influência
242
+ 6. Experimente com seeds diferentes até encontrar uma que funcione bem
243
+ """)
244
+
245
+ generate_button.click(
246
+ run_lora,
247
+ inputs=[prompt, cfg_scale, steps, randomize_seed, seed, width, height, lora_option, lora_scale_1, lora_scale_2, cross_attention_scale, auto_translate],
248
+ outputs=[result, seed],
249
+ )
250
+
251
+ app.queue()
252
+ app.launch(share=True)