Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,118 +1,103 @@
|
|
|
|
|
| 1 |
from fastapi import FastAPI, BackgroundTasks, HTTPException
|
| 2 |
from pydantic import BaseModel
|
| 3 |
from typing import Optional
|
|
|
|
| 4 |
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
|
|
|
| 7 |
app = FastAPI(title="Sofia AI Backend")
|
| 8 |
|
| 9 |
-
|
| 10 |
class MessageRequest(BaseModel):
|
| 11 |
platform: str
|
| 12 |
message: str
|
| 13 |
user_id: str
|
| 14 |
timestamp: Optional[str] = None
|
| 15 |
|
| 16 |
-
|
| 17 |
class ImageGenerationRequest(BaseModel):
|
| 18 |
prompt_type: Optional[str] = None
|
| 19 |
custom_prompt: Optional[str] = None
|
| 20 |
model: str = "black-forest-labs/FLUX.1-dev"
|
| 21 |
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
@app.get("/health")
|
| 24 |
async def health():
|
| 25 |
return {"status": "ok", "service": "sofia-ai-backend"}
|
| 26 |
|
| 27 |
-
|
| 28 |
@app.post("/webhook/message")
|
| 29 |
async def webhook_message(body: MessageRequest, background_tasks: BackgroundTasks):
|
| 30 |
-
|
| 31 |
-
background_tasks.add_task(
|
| 32 |
-
lambda: print(f"[Message] {body.platform}: {body.message} (user: {body.user_id})")
|
| 33 |
-
)
|
| 34 |
return {"status": "queued"}
|
| 35 |
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
# 2) Construir prompt final (basado en tipos de Sofia Rivera)
|
| 44 |
-
if body.custom_prompt:
|
| 45 |
-
final_prompt = body.custom_prompt
|
| 46 |
-
negative_prompt = ""
|
| 47 |
else:
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
"departamento de Miami con vista al mar, golden hour, estética influencer Instagram"
|
| 54 |
-
),
|
| 55 |
-
"negative": "borroso, de baja calidad, distorsionado, deformado, feo, mala anatomía",
|
| 56 |
-
},
|
| 57 |
-
"fitness": {
|
| 58 |
-
"prompt": (
|
| 59 |
-
"selfie de cuerpo completo en el espejo de Sofia Rivera, influencer latina fitness, "
|
| 60 |
-
"cuerpo atlético tonificado, sujetador deportivo negro, mallas de cintura alta, "
|
| 61 |
-
"gimnasio moderno con espejos, iluminación natural, estética fitness Instagram"
|
| 62 |
-
),
|
| 63 |
-
"negative": "borroso, de baja calidad, distorsionado, malas proporciones",
|
| 64 |
-
},
|
| 65 |
-
"premium_boudoir": {
|
| 66 |
-
"prompt": (
|
| 67 |
-
"selfie en el dormitorio de Sofia Rivera, influencer latina de 25 años, lencería de encaje "
|
| 68 |
-
"blanco, luz suave de la mañana a través de cortinas transparentes, cama lujosa con sábanas "
|
| 69 |
-
"de seda, expresión sensual y segura, estilo boudoir de buen gusto, fotografía profesional"
|
| 70 |
-
),
|
| 71 |
-
"negative": "explícito, borroso, de baja calidad, distorsionado",
|
| 72 |
-
},
|
| 73 |
-
"fashion": {
|
| 74 |
-
"prompt": (
|
| 75 |
-
"foto de estilo urbano de Sofia Rivera, influencer de moda latina, outfit moderno de Miami, "
|
| 76 |
-
"gafas de sol de diseñador, pose natural y segura, fondo urbano, golden hour, estética moda Instagram"
|
| 77 |
-
),
|
| 78 |
-
"negative": "borroso, de baja calidad, mala iluminación",
|
| 79 |
-
},
|
| 80 |
-
"beach": {
|
| 81 |
-
"prompt": (
|
| 82 |
-
"foto de estilo de vida de Sofia Rivera en la playa, influencer latina, Miami Beach al atardecer, "
|
| 83 |
-
"atuendo casual de playa, expresión natural feliz, vibraciones tropicales, contenido lifestyle Instagram"
|
| 84 |
-
),
|
| 85 |
-
"negative": "borroso, de baja calidad, distorsionado",
|
| 86 |
-
},
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
if body.prompt_type not in prompt_map:
|
| 90 |
-
raise HTTPException(status_code=400, detail=f"Unknown prompt_type: {body.prompt_type}")
|
| 91 |
-
|
| 92 |
-
final_prompt = prompt_map[body.prompt_type]["prompt"]
|
| 93 |
-
negative_prompt = prompt_map[body.prompt_type]["negative"]
|
| 94 |
-
|
| 95 |
-
# 3) Llamar al motor de generación REAL (generation.py)
|
| 96 |
image_path, status = generate_image_from_prompt(
|
| 97 |
prompt=final_prompt,
|
| 98 |
negative_prompt=negative_prompt,
|
| 99 |
-
model_name=
|
| 100 |
-
seed=None
|
| 101 |
)
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
|
| 115 |
if __name__ == "__main__":
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
from fastapi import FastAPI, BackgroundTasks, HTTPException
|
| 3 |
from pydantic import BaseModel
|
| 4 |
from typing import Optional
|
| 5 |
+
import uvicorn
|
| 6 |
|
| 7 |
+
# --- INTENTA IMPORTAR LA GENERACIÓN, SI FALLA USA UN MOCK (Para que no se rompa el Space) ---
|
| 8 |
+
try:
|
| 9 |
+
from generation import generate_image_from_prompt
|
| 10 |
+
except ImportError:
|
| 11 |
+
print("⚠️ ADVERTENCIA: No se encontró 'generation.py'. Usando modo simulación.")
|
| 12 |
+
def generate_image_from_prompt(prompt, negative_prompt, model_name, seed):
|
| 13 |
+
return None, "Error: Falta el archivo generation.py en el Space"
|
| 14 |
|
| 15 |
+
# --- CONFIGURACIÓN DE FASTAPI ---
|
| 16 |
app = FastAPI(title="Sofia AI Backend")
|
| 17 |
|
|
|
|
| 18 |
class MessageRequest(BaseModel):
|
| 19 |
platform: str
|
| 20 |
message: str
|
| 21 |
user_id: str
|
| 22 |
timestamp: Optional[str] = None
|
| 23 |
|
|
|
|
| 24 |
class ImageGenerationRequest(BaseModel):
|
| 25 |
prompt_type: Optional[str] = None
|
| 26 |
custom_prompt: Optional[str] = None
|
| 27 |
model: str = "black-forest-labs/FLUX.1-dev"
|
| 28 |
|
| 29 |
+
# --- DEFINICIÓN DE PROMPTS DE SOFÍA (TU ESTRATEGIA) ---
|
| 30 |
+
PROMPT_MAP = {
|
| 31 |
+
"lifestyle": {
|
| 32 |
+
"prompt": "foto selfie profesional con iPhone de Sofia Rivera, hermosa mujer latina cubanoamericana de 25 años, cabello largo oscuro y ondulado, sonrisa cálida, departamento de Miami con vista al mar, golden hour, estética influencer Instagram",
|
| 33 |
+
"negative": "borroso, de baja calidad, distorsionado, deformado, feo, mala anatomía",
|
| 34 |
+
},
|
| 35 |
+
"fitness": {
|
| 36 |
+
"prompt": "selfie de cuerpo completo en el espejo de Sofia Rivera, influencer latina fitness, cuerpo atlético tonificado, sujetador deportivo negro, mallas de cintura alta, gimnasio moderno con espejos, iluminación natural, estética fitness Instagram",
|
| 37 |
+
"negative": "borroso, de baja calidad, distorsionado, malas proporciones",
|
| 38 |
+
},
|
| 39 |
+
"premium_boudoir": {
|
| 40 |
+
"prompt": "selfie en el dormitorio de Sofia Rivera, influencer latina de 25 años, lencería de encaje blanco, luz suave de la mañana a través de cortinas transparentes, cama lujosa con sábanas de seda, expresión sensual y segura, estilo boudoir de buen gusto, fotografía profesional",
|
| 41 |
+
"negative": "explícito, borroso, de baja calidad, distorsionado",
|
| 42 |
+
},
|
| 43 |
+
"fashion": {
|
| 44 |
+
"prompt": "foto de estilo urbano de Sofia Rivera, influencer de moda latina, outfit moderno de Miami, gafas de sol de diseñador, pose natural y segura, fondo urbano, golden hour, estética moda Instagram",
|
| 45 |
+
"negative": "borroso, de baja calidad, mala iluminación",
|
| 46 |
+
},
|
| 47 |
+
"beach": {
|
| 48 |
+
"prompt": "foto de estilo de vida de Sofia Rivera en la playa, influencer latina, Miami Beach al atardecer, atuendo casual de playa, expresión natural feliz, vibraciones tropicales, contenido lifestyle Instagram",
|
| 49 |
+
"negative": "borroso, de baja calidad, distorsionado",
|
| 50 |
+
},
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
# --- ENDPOINTS DE API (PARA AUTOMATIZACIÓN FUTURA) ---
|
| 54 |
@app.get("/health")
|
| 55 |
async def health():
|
| 56 |
return {"status": "ok", "service": "sofia-ai-backend"}
|
| 57 |
|
|
|
|
| 58 |
@app.post("/webhook/message")
|
| 59 |
async def webhook_message(body: MessageRequest, background_tasks: BackgroundTasks):
|
| 60 |
+
background_tasks.add_task(lambda: print(f"[Message] {body.platform}: {body.message}"))
|
|
|
|
|
|
|
|
|
|
| 61 |
return {"status": "queued"}
|
| 62 |
|
| 63 |
+
# --- INTERFAZ VISUAL (PARA QUE GENERES TÚ MANUALMENTE) ---
|
| 64 |
+
def ui_generate(style_selection, custom_text):
|
| 65 |
+
# Seleccionar prompt
|
| 66 |
+
if style_selection == "Personalizado":
|
| 67 |
+
final_prompt = custom_text
|
| 68 |
+
negative_prompt = "borroso, mala calidad"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
else:
|
| 70 |
+
data = PROMPT_MAP.get(style_selection)
|
| 71 |
+
final_prompt = data["prompt"]
|
| 72 |
+
negative_prompt = data["negative"]
|
| 73 |
+
|
| 74 |
+
# Llamar a la generación
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
image_path, status = generate_image_from_prompt(
|
| 76 |
prompt=final_prompt,
|
| 77 |
negative_prompt=negative_prompt,
|
| 78 |
+
model_name="black-forest-labs/FLUX.1-dev",
|
| 79 |
+
seed=None
|
| 80 |
)
|
| 81 |
+
|
| 82 |
+
return image_path, final_prompt
|
| 83 |
+
|
| 84 |
+
# Crear la Interfaz con Gradio
|
| 85 |
+
with gr.Blocks(title="Sofia Rivera - Generador") as demo:
|
| 86 |
+
gr.Markdown("# 📸 Sofia AI Studio")
|
| 87 |
+
with gr.Row():
|
| 88 |
+
with gr.Column():
|
| 89 |
+
estilo = gr.Dropdown(choices=list(PROMPT_MAP.keys()) + ["Personalizado"], label="Estilo de Foto", value="lifestyle")
|
| 90 |
+
custom_prompt = gr.Textbox(label="Prompt Personalizado (si eliges arriba 'Personalizado')", placeholder="Escribe aquí...")
|
| 91 |
+
btn = gr.Button("Generar Foto", variant="primary")
|
| 92 |
+
with gr.Column():
|
| 93 |
+
resultado = gr.Image(label="Resultado")
|
| 94 |
+
debug_info = gr.Textbox(label="Prompt Usado", interactive=False)
|
| 95 |
+
|
| 96 |
+
btn.click(fn=ui_generate, inputs=[estilo, custom_prompt], outputs=[resultado, debug_info])
|
| 97 |
+
|
| 98 |
+
# MONTAR GRADIO SOBRE FASTAPI
|
| 99 |
+
# Esto hace que la ruta principal "/" muestre la interfaz visual
|
| 100 |
+
app = gr.mount_gradio_app(app, demo, path="/")
|
| 101 |
|
| 102 |
if __name__ == "__main__":
|
| 103 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
|
|