appinitdev commited on
Commit
b423f68
·
verified ·
1 Parent(s): dfe9811

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -36
app.py CHANGED
@@ -2,39 +2,32 @@ 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. Configuración de URLs y Variables de Entorno
10
  API_URL = "https://api-inference.huggingface.co/models/joyfox/Qwen-Image-Edit-Cosplay"
11
  HF_TOKEN = os.getenv("HF_TOKEN")
12
 
13
- # 2. Inicializamos FastAPI de manera independiente
14
- io_app = fastapi.FastAPI()
15
-
16
- class CosplayPayload(BaseModel):
17
- data: list[str]
18
-
19
- @io_app.post("/api/predict")
20
- async def fusionar_cosplay(payload: CosplayPayload):
21
  if not HF_TOKEN:
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")
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
- prompt_texto = "把图2中动漫人物中的发型,服饰 and 装扮道具迁移到图1的真实人物,图1真实人物保持高度人脸一致性"
36
 
37
- # Payload JSON limpio para la API de Inferencia Serverless
38
  json_payload = {
39
  "inputs": {
40
  "text": prompt_texto,
@@ -50,37 +43,49 @@ async def fusionar_cosplay(payload: CosplayPayload):
50
  "Content-Type": "application/json"
51
  }
52
 
53
- print("[+] Enviando petición a la API de Inferencia de Hugging Face mediante el puente de Gradio...")
54
-
55
- # Petición HTTP POST síncrona
56
  respuesta = requests.post(API_URL, headers=headers, json=json_payload, timeout=110)
57
- print(f"[+] Respuesta recibida. Código de estado: {respuesta.status_code}")
58
 
59
  if respuesta.status_code == 200:
60
  content_type = respuesta.headers.get("content-type", "").lower()
61
 
 
62
  if "application/json" in content_type:
63
  return respuesta.json()
 
64
  else:
65
  imagen_procesada_base64 = base64.b64encode(respuesta.content).decode("utf-8")
66
  return {"data": f"data:image/jpeg;base64,{imagen_procesada_base64}"}
67
  else:
68
  print(f"[-] Error de la API de Inferencia: {respuesta.text}")
69
- raise fastapi.HTTPException(status_code=502, detail=f"HF API Error: {respuesta.status_code}")
70
 
71
- except fastapi.HTTPException as status_error:
72
- raise status_error
73
  except Exception as e:
74
- print("\n================= CRASH EN EL PROXY =================")
75
  traceback.print_exc()
76
  print("=====================================================\n")
77
- raise fastapi.HTTPException(status_code=500, detail=f"Crash interno: {str(e)}")
78
 
79
- # 3. Interfaz de Gradio (Obligatoria para que Hugging Face mantenga vivo el contenedor)
 
80
  with gr.Blocks() as demo:
81
  gr.Markdown("# Cosplay API Bridge Active 🎭")
82
- gr.Markdown("Este Space está corriendo un servidor FastAPI en segundo plano optimizado para peticiones desde Android.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
- # 4. Montamos la aplicación de FastAPI dentro de la instancia de Gradio 'demo'
85
- # El objeto final resultante se debe mapear de nuevo a la aplicación nativa para que la plataforma lo detecte.
86
- 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
+ # 1. Configuración de la API externa
8
  API_URL = "https://api-inference.huggingface.co/models/joyfox/Qwen-Image-Edit-Cosplay"
9
  HF_TOKEN = os.getenv("HF_TOKEN")
10
 
11
+ def fusionar_cosplay_bridge(imagen_real, imagen_ref):
12
+ """
13
+ Función puente que recibe las peticiones de Android a través de Gradio,
14
+ las reempaqueta con el formato de Qwen y llama a la API de Inferencia Serverless.
15
+ """
 
 
 
16
  if not HF_TOKEN:
17
+ print("[-] ERROR: El HF_TOKEN no está configurado en los Secrets del Space.")
18
+ raise gr.Error("Falta el token HF_TOKEN en el servidor.")
 
 
 
19
 
20
  try:
21
+ print("[+] Petición recibida desde Android a través del puente de Gradio...")
22
 
23
+ # Gradio maneja automáticamente los strings entrantes.
24
+ # Aseguramos que tengan el prefijo Data URI limpio para el modelo Qwen.
25
+ data_uri_real = imagen_real if imagen_real.startswith("data:") else f"data:image/jpeg;base64,{imagen_real}"
26
+ data_uri_ref = imagen_ref if imagen_ref.startswith("data:") else f"data:image/jpeg;base64,{imagen_ref}"
27
 
28
+ prompt_texto = "把图2中动漫人物中的发型,服饰和装扮道具迁移到图1的真实人物,图1真实人物保持高度人脸一致性"
29
 
30
+ # Payload JSON requerido por la API Serverless de Hugging Face
31
  json_payload = {
32
  "inputs": {
33
  "text": prompt_texto,
 
43
  "Content-Type": "application/json"
44
  }
45
 
46
+ print("[+] Enviando payload a la API de Inferencia...")
 
 
47
  respuesta = requests.post(API_URL, headers=headers, json=json_payload, timeout=110)
48
+ print(f"[+] Respuesta de Hugging Face recibida. Estado: {respuesta.status_code}")
49
 
50
  if respuesta.status_code == 200:
51
  content_type = respuesta.headers.get("content-type", "").lower()
52
 
53
+ # Si el modelo responde con JSON estructurado
54
  if "application/json" in content_type:
55
  return respuesta.json()
56
+ # Si responde directamente con los bytes crudos de la imagen procesada
57
  else:
58
  imagen_procesada_base64 = base64.b64encode(respuesta.content).decode("utf-8")
59
  return {"data": f"data:image/jpeg;base64,{imagen_procesada_base64}"}
60
  else:
61
  print(f"[-] Error de la API de Inferencia: {respuesta.text}")
62
+ raise gr.Error(f"HF API Error: {respuesta.status_code}")
63
 
 
 
64
  except Exception as e:
65
+ print("\n================= CRASH EN EL PUENTE =================")
66
  traceback.print_exc()
67
  print("=====================================================\n")
68
+ raise gr.Error(f"Crash interno en el servidor: {str(e)}")
69
 
70
+ # 2. Definición de la interfaz de Gradio
71
+ # Usamos gr.Text de tipo string para recibir el Base64 puro sin que Gradio intente guardarlo en disco de forma local.
72
  with gr.Blocks() as demo:
73
  gr.Markdown("# Cosplay API Bridge Active 🎭")
74
+ gr.Markdown("Este Space actúa como puente directo de red para peticiones móviles.")
75
+
76
+ # Declaramos los componentes de entrada/salida de forma invisible o visible para pruebas
77
+ input_real = gr.Textbox(visible=False)
78
+ input_ref = gr.Textbox(visible=False)
79
+ output_json = gr.JSON()
80
+
81
+ # Definimos la función asociada con un nombre de endpoint explícito (api_name)
82
+ btn = gr.Button("Procesar", visible=False)
83
+ btn.click(
84
+ fn=fusionar_cosplay_bridge,
85
+ inputs=[input_real, input_ref],
86
+ outputs=output_json,
87
+ api_name="predict"
88
+ )
89
 
90
+ # Lanzamos el entorno nativo de Gradio
91
+ demo.launch()