appinitdev commited on
Commit
b9d7395
·
verified ·
1 Parent(s): b24e52f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -61
app.py CHANGED
@@ -2,40 +2,30 @@ import os
2
  import base64
3
  import traceback
4
  import requests
5
- import fastapi
6
  import gradio as gr
7
- from pydantic import BaseModel
8
 
9
- # 1. Inicializamos FastAPI de manera independiente
10
- io_app = fastapi.FastAPI()
11
 
12
- class CosplayPayload(BaseModel):
13
- data: list[str]
14
-
15
- @io_app.post("/api/predict")
16
- async def fusionar_cosplay(payload: CosplayPayload):
17
- # 🌟 CRÍTICO: Buscamos la variable de entorno directamente ADENTRO de la función
18
- # Esto asegura que FastAPI lea el Secret inyectado en tiempo de ejecución en cada request.
19
- token_dinamico = os.getenv("HF_TOKEN")
20
 
21
- if not token_dinamico:
22
- print("[-] ERROR: El HF_TOKEN no está configurado en las variables (Secrets) del Space.")
23
- raise fastapi.HTTPException(status_code=500, detail="Falta el token HF_TOKEN en el servidor.")
24
-
25
- if len(payload.data) < 2:
26
- raise fastapi.HTTPException(status_code=400, detail="Se requieren exactamente 2 imágenes.")
27
 
28
  try:
29
  print("[+] Petición recibida desde Android. Procesando cadenas Base64...")
30
 
31
- # Aseguramos el prefijo Data URI para el JSON de Qwen
32
- data_uri_real = payload.data[0] if payload.data[0].startswith("data:") else f"data:image/jpeg;base64,{payload.data[0]}"
33
- data_uri_ref = payload.data[1] if payload.data[1].startswith("data:") else f"data:image/jpeg;base64,{payload.data[1]}"
34
 
35
- # 🌟 Optimización del prompt para el modelo Qwen (removiendo el 'and' híbrido)
36
  prompt_texto = "把图2中动漫人物中的发型,服饰和装扮道具迁移到图1的真实人物,图1真实人物保持高度人脸一致性"
37
 
38
- # Payload JSON limpio para la API de Inferencia Serverless
39
  json_payload = {
40
  "inputs": {
41
  "text": prompt_texto,
@@ -47,14 +37,11 @@ async def fusionar_cosplay(payload: CosplayPayload):
47
  }
48
 
49
  headers = {
50
- "Authorization": f"Bearer {token_dinamico}",
51
  "Content-Type": "application/json"
52
  }
53
 
54
- print("[+] Enviando petición a la API de Inferencia de Hugging Face mediante el puente...")
55
-
56
- # Petición HTTP POST síncrona externa con un timeout prudente
57
- API_URL = "https://api-inference.huggingface.co/models/joyfox/Qwen-Image-Edit-Cosplay"
58
  respuesta = requests.post(API_URL, headers=headers, json=json_payload, timeout=110)
59
  print(f"[+] Respuesta recibida. Código de estado: {respuesta.status_code}")
60
 
@@ -68,43 +55,23 @@ async def fusionar_cosplay(payload: CosplayPayload):
68
  return {"data": f"data:image/jpeg;base64,{imagen_procesada_base64}"}
69
  else:
70
  print(f"[-] Error de la API de Inferencia: {respuesta.text}")
71
- raise fastapi.HTTPException(status_code=502, detail=f"HF API Error: {respuesta.status_code}")
72
 
73
- except fastapi.HTTPException as status_error:
74
- raise status_error
75
  except Exception as e:
76
  print("\n================= CRASH EN EL PROXY =================")
77
  traceback.print_exc()
78
  print("=====================================================\n")
79
- raise fastapi.HTTPException(status_code=500, detail=f"Crash interno: {str(e)}")
80
 
81
- # 2. Función puente exclusiva para que la interfaz web de Gradio pueda probarse manualmente si lo deseas
82
- def prueba_desde_interfaz_web(real_b64, ref_b64):
83
- token_gradio = os.getenv("HF_TOKEN")
84
- if not token_gradio:
85
- return "Error: Agrega el HF_TOKEN en Settings -> Secrets antes de presionar Submit."
86
-
87
- # Redirigimos la lógica interna de Gradio a la misma lógica de negocio de la función principal
88
- try:
89
- import asyncio
90
- class FakePayload:
91
- data = [real_b64, ref_b64]
92
- res = asyncio.run(fusionar_cosplay(FakePayload()))
93
- return str(res)
94
- except Exception as err:
95
- return f"Error en la prueba web: {str(err)}"
96
-
97
- # 3. Interfaz de Gradio (Obligatoria para la plataforma)
98
- with gr.Blocks() as demo:
99
- gr.Markdown("# Cosplay API Bridge Active 🎭")
100
- gr.Markdown("Este Space está corriendo un servidor FastAPI en segundo plano optimizado para peticiones desde Android.")
101
-
102
- with gr.Row(visible=False): # Dejamos la interfaz visual minimizada o para logs internos
103
- txt_real = gr.Textbox(label="Real")
104
- txt_ref = gr.Textbox(label="Ref")
105
- btn_sub = gr.Button("Submit")
106
- txt_out = gr.Textbox(label="Output")
107
- btn_sub.click(fn=prueba_desde_interfaz_web, inputs=[txt_real, txt_ref], outputs=txt_out)
108
 
109
- # 4. Montamos la aplicación de FastAPI dentro de la instancia de Gradio 'demo'
110
- app = gr.mount_gradio_app(io_app, demo, path="/")
 
 
2
  import base64
3
  import traceback
4
  import requests
 
5
  import gradio as gr
 
6
 
7
+ # Configuración de URLs y Variables de Entorno
8
+ API_URL = "https://api-inference.huggingface.co/models/joyfox/Qwen-Image-Edit-Cosplay"
9
 
10
+ def fusionar_cosplay(imagen_real, imagen_ref):
11
+ # Forzamos la lectura del Secret de forma dinámica dentro de la petición
12
+ hf_token = os.getenv("HF_TOKEN")
 
 
 
 
 
13
 
14
+ if not hf_token:
15
+ print("[-] ERROR: El HF_TOKEN no está configurado en los Secrets del Space.")
16
+ raise gr.Error("Falta el token HF_TOKEN en el servidor.")
 
 
 
17
 
18
  try:
19
  print("[+] Petición recibida desde Android. Procesando cadenas Base64...")
20
 
21
+ # Validamos y aseguramos el prefijo Data URI para el JSON de Qwen
22
+ data_uri_real = imagen_real if imagen_real.startswith("data:") else f"data:image/jpeg;base64,{imagen_real}"
23
+ data_uri_ref = imagen_ref if imagen_ref.startswith("data:") else f"data:image/jpeg;base64,{imagen_ref}"
24
 
25
+ # Prompt optimizado monolingüe para evitar fallos de contexto en Qwen
26
  prompt_texto = "把图2中动漫人物中的发型,服饰和装扮道具迁移到图1的真实人物,图1真实人物保持高度人脸一致性"
27
 
28
+ # Payload JSON para la API de Inferencia Serverless
29
  json_payload = {
30
  "inputs": {
31
  "text": prompt_texto,
 
37
  }
38
 
39
  headers = {
40
+ "Authorization": f"Bearer {hf_token}",
41
  "Content-Type": "application/json"
42
  }
43
 
44
+ print("[+] Enviando petición a la API de Inferencia de Hugging Face...")
 
 
 
45
  respuesta = requests.post(API_URL, headers=headers, json=json_payload, timeout=110)
46
  print(f"[+] Respuesta recibida. Código de estado: {respuesta.status_code}")
47
 
 
55
  return {"data": f"data:image/jpeg;base64,{imagen_procesada_base64}"}
56
  else:
57
  print(f"[-] Error de la API de Inferencia: {respuesta.text}")
58
+ raise gr.Error(f"HF API Error: {respuesta.status_code}")
59
 
 
 
60
  except Exception as e:
61
  print("\n================= CRASH EN EL PROXY =================")
62
  traceback.print_exc()
63
  print("=====================================================\n")
64
+ raise gr.Error(f"Crash interno: {str(e)}")
65
 
66
+ # Creamos una interfaz nativa limpia.
67
+ # Esto le dice a Gradio 6 que cree automáticamente un endpoint HTTP POST estándar en /api/predict
68
+ demo = gr.Interface(
69
+ fn=fusionar_cosplay,
70
+ inputs=[gr.Textbox(label="Imagen Real"), gr.Textbox(label="Imagen Referencia")],
71
+ outputs=gr.JSON(label="Resultado"),
72
+ api_name="predict"
73
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
+ # Arrancamos apagando el SSR experimental para evitar el proxy intermedio de Node.js
76
+ if __name__ == "__main__":
77
+ demo.launch(ssr_mode=False)