salomonsky commited on
Commit
9e8f5e5
1 Parent(s): 7c78be7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +210 -167
app.py CHANGED
@@ -1,201 +1,244 @@
1
- import os
2
- import random
3
- import asyncio
4
- import numpy as np
5
  from pathlib import Path
6
  from PIL import Image
7
- from insightface.app import FaceAnalysis
8
  import streamlit as st
 
 
9
  from huggingface_hub import InferenceClient, AsyncInferenceClient
10
- from gradio_client import Client, handle_file
 
 
 
11
  import yaml
12
- import insightface
 
 
 
 
 
 
13
 
14
  MAX_SEED = np.iinfo(np.int32).max
 
 
15
  DATA_PATH = Path("./data")
16
  DATA_PATH.mkdir(exist_ok=True)
 
17
  HF_TOKEN_UPSCALER = os.environ.get("HF_TOKEN_UPSCALER")
18
- client, llm_client = AsyncInferenceClient(), InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1")
19
 
20
- try:
21
- credentials = yaml.safe_load(open("config.yaml"))
22
- except Exception as e:
23
- st.error(f"Error al cargar config: {e}")
24
- credentials = {"username": "", "password": ""}
 
 
 
 
 
25
 
26
  def prepare_face_app():
27
  app = FaceAnalysis(name='buffalo_l')
28
  app.prepare(ctx_id=0, det_size=(640, 640))
29
- return app, insightface.model_zoo.get_model('onix.onnx')
 
30
 
31
  app, swapper = prepare_face_app()
32
 
33
- async def generate_image(prompt, model, w, h, scale, steps, seed):
34
- seed = random.randint(0, MAX_SEED) if seed == -1 else seed
35
- image = await client.text_to_image(prompt=prompt, height=h, width=w, guidance_scale=scale, num_inference_steps=steps, model=model)
36
- return image, seed if not isinstance(image, str) else (None, None)
37
 
38
- def get_upscale_finegrain(prompt, img_path, upscale_factor):
39
- try:
40
- result = Client("finegrain/finegrain-image-enhancer", hf_token=HF_TOKEN_UPSCALER).predict(input_image=handle_file(img_path), prompt=prompt, upscale_factor=upscale_factor)
41
- return result[1] if isinstance(result, list) and len(result) > 1 else None
42
- except Exception:
43
- return None
44
 
45
- async def gen(prompt, basemodel, w, h, scales, steps, seed, upscale_factor, process_upscale, process_enhancer, language):
46
- combined_prompt = f"{prompt} {await improve_prompt(prompt, language)}" if process_enhancer else prompt
47
- image, seed = await generate_image(combined_prompt, basemodel, w, h, scales, steps, seed)
48
- if image is None: return ["Error al generar imagen", None, combined_prompt]
49
- image_path = save_image(image, seed)
50
- prompt_file_path = save_prompt(combined_prompt, seed)
51
- if process_upscale:
52
- upscale_image_path = get_upscale_finegrain(combined_prompt, image_path, upscale_factor)
53
- if upscale_image_path:
54
- Image.open(upscale_image_path).save(DATA_PATH / f"upscale_image_{seed}.jpg", format="JPEG")
55
- image_path.unlink()
56
- return [str(DATA_PATH / f"upscale_image_{seed}.jpg"), str(prompt_file_path)]
57
- return [str(image_path), str(prompt_file_path)]
58
-
59
- async def improve_prompt(prompt, language):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  try:
61
- instruction_en = "With this idea, describe in English a detailed txt2img prompt in 500 characters at most, add illumination, atmosphere, cinematic elements, and characters if need it..."
62
- instruction_es = "Con esta idea, describe en español un prompt detallado de txt2img en un máximo de 500 caracteres, con iluminación, atmósfera, elementos cinematográficos y en su caso personajes..."
63
- instruction = instruction_en if language == "en" else instruction_es
64
  formatted_prompt = f"{prompt}: {instruction}"
65
  response = llm_client.text_generation(formatted_prompt, max_new_tokens=500)
66
- improved_text = response['generated_text'].strip() if 'generated_text' in response else response.strip()
67
- return improved_text[:500] if len(improved_text) > 500 else improved_text
68
  except Exception as e:
69
  return f"Error mejorando el prompt: {e}"
70
 
71
- def save_image(image, seed):
72
- if image.mode == 'RGBA': image = image.convert('RGB')
73
- image_path = DATA_PATH / f"image_{seed}.jpg"
74
- image.save(image_path, format="JPEG")
75
- return image_path
76
-
77
- def save_prompt(prompt_text, seed):
78
- prompt_file_path = DATA_PATH / f"prompt_{seed}.txt"
79
- open(prompt_file_path, "w").write(prompt_text)
80
- return prompt_file_path
81
-
82
- def get_storage():
83
- files = [file for file in DATA_PATH.glob("*.jpg") if file.is_file()]
84
- total_size = sum([file.stat().st_size for file in files]) / (1024.0 ** 3)
85
- return files, f"Uso total: {total_size:.3f} GB"
86
-
87
- def delete_image(image_path):
88
- try:
89
- Path(image_path).unlink()
90
- st.success(f"Imagen {image_path} borrada.")
91
- except Exception as e:
92
- st.error(f"Error al borrar imagen: {e}")
93
-
94
- def delete_all_images():
95
- for file in DATA_PATH.glob("*.jpg"):
96
- file.unlink()
97
- st.success("Todas las imágenes han sido borradas.")
98
-
99
- def authenticate_user(username, password, credentials):
100
- return username == credentials["username"] and password == credentials["password"]
101
-
102
- def login_form(credentials):
103
- if 'authenticated' not in st.session_state:
104
- st.session_state['authenticated'] = False
105
- if not st.session_state['authenticated']:
106
- username = st.text_input("Usuario")
107
- password = st.text_input("Contraseña", type='password')
108
- if st.button("Iniciar Sesión"):
109
- if authenticate_user(username, password, credentials):
110
- st.session_state['authenticated'] = True
111
- st.success("Inicio de sesión exitoso.")
112
- else:
113
- st.error("Credenciales incorrectas.")
114
-
115
- def upload_image():
116
- uploaded_file = st.sidebar.file_uploader("Sube una imagen", type=["png", "jpg", "jpeg"])
117
- if uploaded_file:
118
- image_path = DATA_PATH / uploaded_file.name
119
- with open(image_path, "wb") as f:
120
- f.write(uploaded_file.getbuffer())
121
- st.sidebar.success(f"Imagen {uploaded_file.name} cargada correctamente.")
122
- return image_path, save_prompt("#uploadedbyuser", image_path.stem)
123
- return None
124
-
125
- def gallery():
126
- files, usage = get_storage()
127
- st.sidebar.write(f"{usage}")
128
- if st.sidebar.button("Borrar Todas las Imágenes"):
129
- delete_all_images()
130
- cols = st.columns(6)
131
- for idx, file in enumerate(files):
132
- with cols[idx % 6]:
133
- st.image(str(file))
134
- try:
135
- prompt_file_path = DATA_PATH / f"prompt_{file.stem.split('_')[-1]}.txt"
136
- st.write(f"Prompt: {open(prompt_file_path).read()}")
137
- except FileNotFoundError:
138
- st.write("Prompt no encontrado.")
139
- st.button(f"Borrar Imagen {file.name}", on_click=delete_image, args=(file,))
140
- if st.button(f"Swap Face en {file.name}"):
141
- upload_source_and_swap(file)
142
-
143
- def upload_source_and_swap(image_path):
144
- source_image = st.file_uploader("Sube la imagen source para face swap", type=["png", "jpg", "jpeg"])
145
- if source_image:
146
- source_image_path = DATA_PATH / source_image.name
147
- with open(source_image_path, "wb") as f:
148
- f.write(source_image.getbuffer())
149
- st.success(f"Imagen source {source_image.name} cargada correctamente.")
150
- dest_face_index = st.slider("Selecciona la posición de la cara destino", 1, 4, 1)
151
- swapped_image_path = face_swap(image_path, source_image_path, dest_face_index)
152
- if swapped_image_path:
153
- st.image(str(swapped_image_path), caption="Imagen con Face Swap", use_column_width=True)
154
-
155
- def face_swap(image_path, source_image_path, dest_face_index):
156
  try:
157
- img_dest, img_src = Image.open(image_path), Image.open(source_image_path)
158
- faces = app.get(img_src)
159
- if not faces:
160
- st.error("No se encontraron caras en la imagen source.")
161
- return None
162
- swapped_img = swapper.get(img_dest, faces[0], dest_index=dest_face_index - 1) # Convertir a índice base 0
163
- swapped_img_path = DATA_PATH / f"swapped_{Path(image_path).stem}.jpg"
164
- swapped_img.save(swapped_img_path, format="JPEG")
165
- Path(image_path).unlink()
166
- return swapped_img_path
167
- except Exception as e:
168
- st.error(f"Error en face swap: {e}")
169
- return None
170
-
171
- async def main():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  st.set_page_config(layout="wide")
173
- login_form(credentials)
174
- if not st.session_state['authenticated']:
175
- st.warning("Por favor, inicia sesión para acceder a la aplicación.")
176
  return
177
 
178
- prompt = st.sidebar.text_input("Descripción de la imagen", max_chars=900)
179
- process_enhancer, language = st.sidebar.checkbox("Mejorar Prompt", value=False), st.sidebar.selectbox("Idioma", ["en", "es"])
180
- basemodel, format_option, process_upscale = st.sidebar.selectbox("Modelo Base", ["black-forest-labs/FLUX.1-DEV", "black-forest-labs/FLUX.1-schnell"]), st.sidebar.selectbox("Formato", ["9:16", "16:9"]), st.sidebar.checkbox("Procesar Escalador", value=False)
181
- upscale_factor, scales, steps, seed = st.sidebar.selectbox("Factor de Escala", [2, 4, 8], index=0), st.sidebar.slider("Escalado", 1, 20, 10), st.sidebar.slider("Pasos", 1, 100, 20), st.sidebar.number_input("Semilla", value=-1)
182
- destination_face_position = st.sidebar.slider("Posición de la Cara de Destino", 1, 4, 1)
183
-
184
- w, h = (720, 1280) if format_option == "9:16" else (1280, 720)
185
- upload_image()
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
- image_path, prompt_file_path = None, None
188
  if st.sidebar.button("Generar Imagen"):
189
- with st.spinner("Generando..."):
190
- image_path, prompt_file_path = await gen(prompt, basemodel, w, h, scales, steps, seed, upscale_factor, process_upscale, process_enhancer, language)
191
- if image_path:
192
- st.image(image_path, caption="Imagen Generada")
193
- st.write(f"Prompt: {open(prompt_file_path).read()}")
194
-
195
- if image_path:
196
- st.success("Imagen generada y almacenada.")
197
-
198
- gallery()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
  if __name__ == "__main__":
201
- asyncio.run(main())
 
 
 
 
 
1
  from pathlib import Path
2
  from PIL import Image
 
3
  import streamlit as st
4
+ import insightface
5
+ from insightface.app import FaceAnalysis
6
  from huggingface_hub import InferenceClient, AsyncInferenceClient
7
+ import asyncio
8
+ import os
9
+ import random
10
+ import numpy as np
11
  import yaml
12
+
13
+ try:
14
+ with open("config.yaml", "r") as file:
15
+ credentials = yaml.safe_load(file)
16
+ except Exception as e:
17
+ st.error(f"Error al cargar el archivo de configuración: {e}")
18
+ credentials = {"username": "", "password": ""}
19
 
20
  MAX_SEED = np.iinfo(np.int32).max
21
+ client = AsyncInferenceClient()
22
+ llm_client = InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1")
23
  DATA_PATH = Path("./data")
24
  DATA_PATH.mkdir(exist_ok=True)
25
+ PREDEFINED_SEED = random.randint(0, MAX_SEED)
26
  HF_TOKEN_UPSCALER = os.environ.get("HF_TOKEN_UPSCALER")
 
27
 
28
+ def get_upscale_finegrain(prompt, img_path, upscale_factor):
29
+ try:
30
+ upscale_client = Client("finegrain/finegrain-image-enhancer", hf_token=HF_TOKEN_UPSCALER)
31
+ result = upscale_client.predict(input_image=handle_file(img_path), prompt=prompt, upscale_factor=upscale_factor)
32
+ return result[1] if isinstance(result, list) and len(result) > 1 else None
33
+ except Exception:
34
+ return None
35
+
36
+ def authenticate_user(username, password):
37
+ return username == credentials["username"] and password == credentials["password"]
38
 
39
  def prepare_face_app():
40
  app = FaceAnalysis(name='buffalo_l')
41
  app.prepare(ctx_id=0, det_size=(640, 640))
42
+ swapper = insightface.model_zoo.get_model('onix.onnx')
43
+ return app, swapper
44
 
45
  app, swapper = prepare_face_app()
46
 
47
+ def sort_faces(faces):
48
+ return sorted(faces, key=lambda x: x.bbox[0])
 
 
49
 
50
+ def get_face(faces, face_id):
51
+ if not faces or len(faces) < face_id:
52
+ raise ValueError("Rostro no disponible.")
53
+ return faces[face_id - 1]
 
 
54
 
55
+ def swap_faces(source_image, source_face_index, destination_image, destination_face_index):
56
+ faces = sort_faces(app.get(source_image))
57
+ source_face = get_face(faces, source_face_index)
58
+
59
+ res_faces = sort_faces(app.get(destination_image))
60
+ if destination_face_index > len(res_faces) or destination_face_index < 1:
61
+ raise ValueError("Índice de rostro de destino no válido.")
62
+
63
+ res_face = get_face(res_faces, destination_face_index)
64
+ result = swapper.get(destination_image, res_face, source_face, paste_back=True)
65
+ return result
66
+
67
+ async def generate_image(prompt, width, height, seed, model_name):
68
+ if seed == -1:
69
+ seed = PREDEFINED_SEED
70
+ image = await client.text_to_image(prompt=prompt, height=height, width=width, model=model_name)
71
+ return image, seed
72
+
73
+ async def gen(prompt, width, height, model_name):
74
+ seed = PREDEFINED_SEED
75
+ image, seed = await generate_image(prompt, width, height, seed, model_name)
76
+ image_path = save_image(image, f"generated_image_{seed}.jpg", prompt)
77
+ return str(image_path)
78
+
79
+ def list_saved_images():
80
+ return list(DATA_PATH.glob("*.jpg"))
81
+
82
+ def display_gallery():
83
+ st.header("Galería de Imágenes Guardadas")
84
+ images = list_saved_images()
85
+ if images:
86
+ cols = st.columns(8)
87
+ for i, image_file in enumerate(images):
88
+ with cols[i % 8]:
89
+ st.image(str(image_file), caption=image_file.name, use_column_width=True)
90
+ prompt = get_prompt_for_image(image_file.name)
91
+ st.write(prompt[:300])
92
+
93
+ if st.button(f"Usar", key=f"select_{i}_{image_file.name}"):
94
+ st.session_state['generated_image_path'] = str(image_file)
95
+ st.success("Imagen seleccionada")
96
+
97
+ if st.button(f"Borrar", key=f"delete_{i}_{image_file.name}"):
98
+ os.remove(image_file)
99
+ st.success("Imagen borrada")
100
+ display_gallery()
101
+ else:
102
+ st.info("No hay imágenes guardadas.")
103
+
104
+ def save_prompt(prompt):
105
+ with open(DATA_PATH / "prompts.txt", "a") as f:
106
+ f.write(prompt + "\n")
107
+ st.success("Prompt guardado.")
108
+
109
+ def run_async(func, *args):
110
+ return asyncio.run(func(*args))
111
+
112
+ async def improve_prompt(prompt):
113
  try:
114
+ instruction = ("With this idea, describe in English a detailed txt2img prompt in 500 characters at most, add illumination, atmosphere, cinematic elements, and characters if needed...")
 
 
115
  formatted_prompt = f"{prompt}: {instruction}"
116
  response = llm_client.text_generation(formatted_prompt, max_new_tokens=500)
117
+ return response['generated_text'][:500] if 'generated_text' in response else response.strip()
 
118
  except Exception as e:
119
  return f"Error mejorando el prompt: {e}"
120
 
121
+ def save_image(image, file_name, prompt=None):
122
+ image_path = DATA_PATH / file_name
123
+ if image_path.exists():
124
+ st.warning(f"La imagen '{file_name}' ya existe en la galería. No se guardó.")
125
+ return None
126
+ else:
127
+ image.save(image_path, format="JPEG")
128
+ if prompt:
129
+ save_prompt(f"{file_name}: {prompt}")
130
+ return image_path
131
+
132
+ def get_prompt_for_image(image_name):
133
+ prompts = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  try:
135
+ with open(DATA_PATH / "prompts.txt", "r") as f:
136
+ for line in f:
137
+ if line.startswith(image_name):
138
+ prompts[image_name] = line.split(": ", 1)[1].strip()
139
+ except FileNotFoundError:
140
+ return "No hay prompt asociado."
141
+
142
+ return prompts.get(image_name, "No hay prompt asociado.")
143
+
144
+ def login_form():
145
+ st.title("Iniciar Sesión")
146
+ username = st.text_input("Usuario", value="admin")
147
+ password = st.text_input("Contraseña", value="flux3x", type="password")
148
+ if st.button("Iniciar Sesión"):
149
+ if authenticate_user(username, password):
150
+ st.success("Autenticación exitosa.")
151
+ st.session_state['authenticated'] = True
152
+ else:
153
+ st.error("Credenciales incorrectas. Intenta de nuevo.")
154
+
155
+ def upload_image_to_gallery():
156
+ uploaded_image = st.file_uploader("Sube una imagen a la galería", type=["jpg", "jpeg", "png"])
157
+ if uploaded_image:
158
+ image = Image.open(uploaded_image)
159
+ image_path = save_image(image, f"{uploaded_image.name}")
160
+ if image_path:
161
+ save_prompt("uploaded by user")
162
+ st.success(f"Imagen subida: {image_path}")
163
+
164
+ def main():
165
  st.set_page_config(layout="wide")
166
+
167
+ if 'authenticated' not in st.session_state or not st.session_state['authenticated']:
168
+ login_form()
169
  return
170
 
171
+ st.title("Generador Flux")
172
+ generated_image_path = st.session_state.get('generated_image_path')
173
+ st.header("Generador de Imágenes")
174
+ prompt = st.sidebar.text_area("Descripción de la imagen", height=150, max_chars=500)
175
+ format_option = st.sidebar.selectbox("Formato", ["9:16", "16:9"])
176
+ model_option = st.sidebar.selectbox("Modelo", ["black-forest-labs/FLUX.1-schnell", "black-forest-labs/FLUX.1-dev"])
177
+ prompt_checkbox = st.sidebar.checkbox("Prompt Enhancer")
178
+ upscale_checkbox = st.sidebar.checkbox("Escalar imagen")
179
+ width, height = (720, 1280) if format_option == "9:16" else (1280, 720)
180
+ upload_image_to_gallery()
181
+
182
+ if prompt_checkbox:
183
+ with st.spinner("Mejorando el prompt..."):
184
+ try:
185
+ improved_prompt = run_async(improve_prompt, prompt)
186
+ except Exception as e:
187
+ st.error(f"Error al mejorar el prompt: {str(e)}")
188
+ improved_prompt = prompt
189
+ else:
190
+ improved_prompt = prompt
191
 
 
192
  if st.sidebar.button("Generar Imagen"):
193
+ with st.spinner("Generando imagen..."):
194
+ try:
195
+ result = run_async(gen, improved_prompt, width, height, model_option) # Usar el improved_prompt
196
+ st.session_state['generated_image_path'] = result
197
+ st.image(result, caption="Imagen Generada")
198
+ except Exception as e:
199
+ st.error(f"Error al generar la imagen: {str(e)}")
200
+
201
+ if generated_image_path:
202
+ if upscale_checkbox:
203
+ with st.spinner("Escalando imagen..."):
204
+ try:
205
+ upscale_image_path = get_upscale_finegrain("Upscale", generated_image_path, 2)
206
+ if upscale_image_path:
207
+ st.image(upscale_image_path, caption="Imagen Escalada")
208
+ except Exception as e:
209
+ st.error(f"Error al escalar la imagen: {str(e)}")
210
+
211
+ st.header("Intercambio de Rostros")
212
+ source_image_file = st.file_uploader("Imagen de Origen", type=["jpg", "jpeg", "png"])
213
+
214
+ if source_image_file is not None:
215
+ try:
216
+ source_image = Image.open(source_image_file)
217
+ except Exception as e:
218
+ st.error(f"Error al cargar la imagen de origen: {str(e)}")
219
+ source_image = None
220
+ else:
221
+ source_image = Image.open("face.jpg")
222
+
223
+ source_face_index = st.number_input('Posición del Rostro', min_value=1, value=1, key="source_face_index")
224
+ destination_face_index = st.number_input('Posición del Rostro de Destino', min_value=1, value=1, key="destination_face_index")
225
+
226
+ if st.button("Intercambiar Rostros"):
227
+ try:
228
+ destination_image = Image.open(generated_image_path)
229
+ result_image = swap_faces(np.array(source_image), source_face_index, np.array(destination_image), destination_face_index)
230
+ swapped_image = Image.fromarray(result_image)
231
+
232
+ swapped_image_path = save_image(swapped_image, f"swapped_image_{PREDEFINED_SEED}.jpg")
233
+ if swapped_image_path:
234
+ st.image(swapped_image, caption="Intercambio de Rostro")
235
+ os.remove(generated_image_path)
236
+ else:
237
+ st.warning("La imagen intercambiada ya existe en la galería.")
238
+ except Exception as e:
239
+ st.error(f"Ocurrió un error al intercambiar rostros: {str(e)}")
240
+
241
+ display_gallery()
242
 
243
  if __name__ == "__main__":
244
+ main()