File size: 11,715 Bytes
27e4a6a
d4fba6d
4816388
9e8f5e5
 
4816388
9e8f5e5
 
 
 
bc1f498
9e8f5e5
 
 
 
 
 
 
d95dbe9
32fdddd
9e8f5e5
 
8b0fc18
 
9e8f5e5
980ffaa
481dde5
b99630c
 
 
9e8f5e5
 
b99630c
9e8f5e5
 
b99630c
 
9e8f5e5
 
 
 
6b3d1c3
fc85da7
8b0fc18
 
9e8f5e5
 
7bf5a19
fc85da7
6b3d1c3
9e8f5e5
 
6b3d1c3
9e8f5e5
 
 
 
6b3d1c3
9e8f5e5
 
 
 
 
 
 
 
 
 
 
 
8fe1e3d
 
 
 
 
 
b99630c
 
 
 
 
 
 
 
 
 
 
 
 
9e8f5e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf3ba40
9e8f5e5
 
 
 
b99630c
 
 
 
 
 
9e8f5e5
 
 
 
 
 
 
 
 
 
 
 
7c78be7
b99630c
 
 
 
 
 
 
 
 
 
 
7c78be7
b99630c
 
7c78be7
 
6b3d1c3
b99630c
 
 
 
 
 
 
 
 
9e8f5e5
 
 
8c1a558
9e8f5e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b99630c
 
 
 
 
 
 
 
 
9e8f5e5
c62ce13
9e8f5e5
 
 
 
 
c62ce13
9e8f5e5
cfcfa32
53635c2
9e8f5e5
 
 
8b0fc18
 
174c9a8
9e8f5e5
 
 
 
 
 
 
b99630c
 
 
c62ce13
9e8f5e5
b99630c
 
9e8f5e5
b99630c
 
 
53635c2
b99630c
 
9e8f5e5
b99630c
 
 
 
9e8f5e5
b99630c
9e8f5e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99a5876
 
afe217f
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
from pathlib import Path
from PIL import Image
import streamlit as st
import insightface
from insightface.app import FaceAnalysis
from huggingface_hub import InferenceClient, AsyncInferenceClient
import asyncio
import os
import random
import numpy as np
import yaml

try:
    with open("config.yaml", "r") as file:
        credentials = yaml.safe_load(file)
except Exception as e:
    st.error(f"Error al cargar el archivo de configuración: {e}")
    credentials = {"username": "", "password": ""}

MAX_SEED = np.iinfo(np.int32).max
client = AsyncInferenceClient()
llm_client = InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1")
DATA_PATH = Path("./data")
DATA_PATH.mkdir(exist_ok=True)
PREDEFINED_SEED = random.randint(0, MAX_SEED)
HF_TOKEN_UPSCALER = os.environ.get("HF_TOKEN_UPSCALER")

if not HF_TOKEN_UPSCALER:
    st.warning("HF_TOKEN_UPSCALER no está configurado. Algunas funcionalidades pueden no funcionar.")

def get_upscale_finegrain(prompt, img_path, upscale_factor):
    try:
        upscale_client = InferenceClient("finegrain/finegrain-image-enhancer", hf_token=HF_TOKEN_UPSCALER)
        result = upscale_client.predict(input_image=handle_file(img_path), prompt=prompt, upscale_factor=upscale_factor)
        return result[1] if isinstance(result, list) and len(result) > 1 else None
    except Exception as e:
        st.error(f"Error al mejorar la imagen: {e}")
        return None

def authenticate_user(username, password):
    return username == credentials["username"] and password == credentials["password"]

def prepare_face_app():
    app = FaceAnalysis(name='buffalo_l')
    app.prepare(ctx_id=0, det_size=(640, 640))
    swapper = insightface.model_zoo.get_model('onix.onnx')
    return app, swapper

app, swapper = prepare_face_app()

def sort_faces(faces):
    return sorted(faces, key=lambda x: x.bbox[0])

def get_face(faces, face_id):
    if not faces or len(faces) < face_id:
        raise ValueError("Rostro no disponible.")
    return faces[face_id - 1]

def swap_faces(source_image, source_face_index, destination_image, destination_face_index):
    faces = sort_faces(app.get(source_image))
    source_face = get_face(faces, source_face_index)
    
    res_faces = sort_faces(app.get(destination_image))
    if destination_face_index > len(res_faces) or destination_face_index < 1:
        raise ValueError("Índice de rostro de destino no válido.")
    
    res_face = get_face(res_faces, destination_face_index)
    result = swapper.get(destination_image, res_face, source_face, paste_back=True)
    return result

async def generate_image(prompt, width, height, seed, model_name):
    if seed == -1:
        seed = random.randint(0, MAX_SEED)
    image = await client.text_to_image(prompt=prompt, height=height, width=width, model=model_name)
    return image, seed

async def gen(prompts, width, height, model_name, num_variants=1, use_enhanced=True):
    images = []
    try:
        for idx, prompt in enumerate(prompts):
            seed = random.randint(0, MAX_SEED)
            image, seed = await generate_image(prompt, width, height, seed, model_name)
            image_path = save_image(image, f"generated_image_{seed}.jpg")
            if image_path:
                st.success(f"Imagen {idx + 1} generada")
                images.append(str(image_path))
    except Exception as e:
        st.error(f"Error al generar imágenes: {e}")
    return images

def list_saved_images():
    return list(DATA_PATH.glob("*.jpg"))

def display_gallery():
    st.header("Galería de Imágenes Guardadas")
    images = list_saved_images()
    if images:
        cols = st.columns(8)  
        for i, image_file in enumerate(images):
            with cols[i % 8]:  
                st.image(str(image_file), caption=image_file.name, use_column_width=True)
                prompt = get_prompt_for_image(image_file.name)  
                st.write(prompt[:300])  

                if st.button(f"FaceSwap", key=f"select_{i}_{image_file.name}"):
                    st.session_state['generated_image_path'] = str(image_file)
                    st.success("Imagen seleccionada")

                if st.button(f"Borrar", key=f"delete_{i}_{image_file.name}"):
                    if os.path.exists(image_file):
                        os.remove(image_file)
                        st.success("Imagen borrada")
                        display_gallery()
                    else:
                        st.warning("La imagen no existe.")
    else:
        st.info("No hay imágenes guardadas.")

def save_prompt(prompt):
    with open(DATA_PATH / "prompts.txt", "a") as f:
        f.write(prompt + "\n")
        st.success("Prompt guardado.")

def run_async(func, *args):
    return asyncio.run(func(*args))

async def improve_prompt(prompt):
    try:
        instructions = [
            "With my idea create a vibrant description for a detailed txt2img prompt, 300 characters max.",
            "With my idea write a creative and detailed text-to-image prompt in English, 300 characters max.",
            "With my idea generate a descriptive and visual txt2img prompt in English, 300 characters max.",
            "With my idea describe a photorealistic with illumination txt2img prompt in English, 300 characters max.",
            "With my idea give a realistic and elegant txt2img prompt in English, 300 characters max.",
            "With my idea conform a visually dynamic and surreal txt2img prompt in English, 300 characters max.",
            "With my idea realize an artistic and cinematic txt2img prompt in English, 300 characters max.",
            "With my idea make a narrative and immersive txt2img prompt in English, 300 characters max."
        ]
        instruction = random.choice(instructions)
        formatted_prompt = f"{prompt}: {instruction}"
        response = llm_client.text_generation(formatted_prompt, max_new_tokens=100)
        return response['generated_text'][:100] if 'generated_text' in response else response.strip()
    except Exception as e:
        return f"Error mejorando el prompt: {e}"

async def generate_variations(prompt, num_variants, use_enhanced):
    prompts = set() 
    while len(prompts) < num_variants:
        if use_enhanced:
            enhanced_prompt = await improve_prompt(prompt)
            prompts.add(enhanced_prompt)
        else:
            prompts.add(prompt)
    return list(prompts)

def get_prompt_for_image(image_name):
    prompts = {}
    try:
        with open(DATA_PATH / "prompts.txt", "r") as f:
            for line in f:
                if line.startswith(image_name):
                    prompts[image_name] = line.split(": ", 1)[1].strip()
    except FileNotFoundError:
        return "No hay prompt asociado."
    
    return prompts.get(image_name, "No hay prompt asociado.")

def login_form():
    st.title("Iniciar Sesión")
    username = st.text_input("Usuario", value="admin")
    password = st.text_input("Contraseña", value="flux3x", type="password") 
    if st.button("Iniciar Sesión"):
        if authenticate_user(username, password):
            st.success("Autenticación exitosa.")
            st.session_state['authenticated'] = True
        else:
            st.error("Credenciales incorrectas. Intenta de nuevo.")

def save_image(image, filename):
    try:
        image_path = DATA_PATH / filename
        image.save(image_path)
        return image_path
    except Exception as e:
        st.error(f"Error al guardar la imagen: {e}")
        return None

def upload_image_to_gallery():
    uploaded_image = st.sidebar.file_uploader("Sube una imagen a la galería", type=["jpg", "jpeg", "png"])
    if uploaded_image:
        image = Image.open(uploaded_image)
        image_path = save_image(image, f"{uploaded_image.name}")
        if image_path:
            save_prompt("uploaded by user")
            st.sidebar.success(f"Imagen subida: {image_path}")

async def main():
    st.set_page_config(layout="wide")

    if 'authenticated' not in st.session_state or not st.session_state['authenticated']:
        login_form()
        return

    st.title("Flux +Upscale +Prompt Enhancer +FaceSwap")
    generated_image_path = st.session_state.get('generated_image_path')
    st.header("Generador de Imágenes")
    prompt = st.sidebar.text_area("Descripción de la imagen", height=150, max_chars=500)
    format_option = st.sidebar.selectbox("Formato", ["9:16", "16:9"])
    model_option = st.sidebar.selectbox("Modelo", ["black-forest-labs/FLUX.1-schnell", "black-forest-labs/FLUX.1-dev"])
    prompt_checkbox = st.sidebar.checkbox("Prompt Enhancer")
    upscale_checkbox = st.sidebar.checkbox("Escalar imagen")
    width, height = (360, 640) if format_option == "9:16" else (640, 360) if format_option == "16:9" else (640, 640)
    
    num_variants = st.sidebar.slider("Número de imágenes a generar", 1, 8, 1) if prompt_checkbox else 1
    
    if prompt_checkbox:
        with st.spinner("Generando prompts mejorados..."):
            prompts = await generate_variations(prompt, num_variants, True)
    else:
        prompts = [prompt] 

    upload_image_to_gallery()

    if st.sidebar.button("Generar Imágenes"):
        with st.spinner("Generando imágenes..."):
            try:
                results = await gen(prompts, width, height, model_option, num_variants, prompt_checkbox)
                st.session_state['generated_image_paths'] = results
                for result in results:
                    st.image(result, caption="Imagen Generada")
            except Exception as e:
                st.error(f"Error al generar las imágenes: {str(e)}")

    if generated_image_path:
        if upscale_checkbox:
            with st.spinner("Escalando imagen..."):
                try:
                    upscale_image_path = get_upscale_finegrain("Upscale", generated_image_path, 2)
                    if upscale_image_path:
                        st.image(upscale_image_path, caption="Imagen Escalada")
                except Exception as e:
                    st.error(f"Error al escalar la imagen: {str(e)}")

        st.header("Intercambio de Rostros")
        source_image_file = st.file_uploader("Imagen de Origen", type=["jpg", "jpeg", "png"])

        if source_image_file is not None:
            try:
                source_image = Image.open(source_image_file)
            except Exception as e:
                st.error(f"Error al cargar la imagen de origen: {str(e)}")
                source_image = None
        else:
            source_image = Image.open("face.jpg")

        source_face_index = st.number_input('Posición del Rostro', min_value=1, value=1, key="source_face_index")
        destination_face_index = st.number_input('Posición del Rostro de Destino', min_value=1, value=1, key="destination_face_index")

        if st.button("Intercambiar Rostros"):
            try:
                destination_image = Image.open(generated_image_path)
                result_image = swap_faces(np.array(source_image), source_face_index, np.array(destination_image), destination_face_index)
                swapped_image = Image.fromarray(result_image)
                
                swapped_image_path = save_image(swapped_image, f"swapped_image_{PREDEFINED_SEED}.jpg")
                if swapped_image_path:
                    st.image(swapped_image, caption="Intercambio de Rostro")
                    os.remove(generated_image_path)
                else:
                    st.warning("La imagen intercambiada ya existe en la galería.")
            except Exception as e:
                st.error(f"Ocurrió un error al intercambiar rostros: {str(e)}")

    display_gallery()

if __name__ == "__main__":
    asyncio.run(main())