Carley1234 commited on
Commit
8a50ed5
·
verified ·
1 Parent(s): de4324c

Upload 3 files

Browse files
Files changed (2) hide show
  1. app.py +92 -36
  2. requirements.txt +3 -2
app.py CHANGED
@@ -1,11 +1,12 @@
1
- # space-artist-image/app.py
2
  from fastapi import FastAPI, HTTPException
3
  from fastapi.middleware.cors import CORSMiddleware
4
- from fastapi.responses import FileResponse
5
  from pydantic import BaseModel
6
- import torch
7
- from diffusers import AutoPipelineForText2Image
8
  import os
 
 
9
 
10
  # Inicializar la aplicación FastAPI
11
  app = FastAPI()
@@ -20,53 +21,108 @@ app.add_middleware(
20
  allow_headers=["*"], # Permite todas las cabeceras
21
  )
22
 
23
- # --- Configuración del Modelo ---
24
- # Usaremos un modelo muy pequeño y rápido, optimizado para CPU.
25
- # "Lykon/dreamshaper-8-lcm" es una buena opción para prototipos rápidos.
26
- model_id = "Lykon/dreamshaper-8-lcm"
27
- pipe = AutoPipelineForText2Image.from_pretrained(
 
28
  model_id,
29
- torch_dtype=torch.float32, # Usamos float32 para CPU
30
- variant="fp32"
31
  )
32
- # No moveremos el pipeline a CUDA, se quedará en CPU.
 
 
 
33
 
34
  # --- Definición de la Petición ---
35
- class ImageRequest(BaseModel):
36
  prompt: str
37
 
38
- # --- Endpoint de la API ---
39
- @app.post("/generate-image/")
40
- async def generate_image(request: ImageRequest):
41
  """
42
- Recibe un prompt de texto y genera una imagen.
 
43
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  try:
45
- prompt = request.prompt
46
- print(f"Recibido prompt: {prompt}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- # Generar la imagen
49
- # Usamos pocas iteraciones para que sea rápido en CPU
50
- image = pipe(
51
- prompt=prompt,
52
- num_inference_steps=4,
53
- guidance_scale=7.5
54
- ).images[0]
55
 
56
- # Guardar la imagen temporalmente
57
- output_path = "generated_image.png"
58
- image.save(output_path)
59
 
60
- print(f"Imagen generada y guardada en {output_path}")
 
 
 
 
61
 
62
- # Devolver la imagen como un archivo
63
- return FileResponse(output_path, media_type="image/png")
 
64
 
65
- except Exception as e:
66
- print(f"Error durante la generación de imagen: {e}")
67
- raise HTTPException(status_code=500, detail="Error al generar la imagen.")
68
 
69
  # --- Endpoint de Bienvenida ---
70
  @app.get("/")
71
  def read_root():
72
- return {"status": "Servicio de generación de imágenes 'El Artista' está en línea."}
 
1
+ # space-orchestrator/app.py
2
  from fastapi import FastAPI, HTTPException
3
  from fastapi.middleware.cors import CORSMiddleware
 
4
  from pydantic import BaseModel
5
+ import requests
6
+ import json
7
  import os
8
+ from transformers import AutoTokenizer, AutoModelForCausalLM
9
+ import torch
10
 
11
  # Inicializar la aplicación FastAPI
12
  app = FastAPI()
 
21
  allow_headers=["*"], # Permite todas las cabeceras
22
  )
23
 
24
+ # --- Configuración del Modelo de Lenguaje ---
25
+ # Usaremos un LLM muy pequeño, ideal para clasificación de intenciones y CPU.
26
+ # "microsoft/phi-2" es una buena opción de tamaño reducido.
27
+ model_id = "microsoft/phi-2"
28
+ tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
29
+ model = AutoModelForCausalLM.from_pretrained(
30
  model_id,
31
+ torch_dtype=torch.float32, # float32 para CPU
32
+ trust_remote_code=True
33
  )
34
+
35
+ # --- URL del Servicio de Imágenes ---
36
+ # IMPORTANTE: Deberás reemplazar esto con la URL de tu Space de imágenes una vez que lo despliegues.
37
+ IMAGE_SERVICE_URL = os.getenv("IMAGE_SERVICE_URL", "http://localhost:8001/generate-image/")
38
 
39
  # --- Definición de la Petición ---
40
+ class ChatRequest(BaseModel):
41
  prompt: str
42
 
43
+ # --- Lógica del "Código Secreto" ---
44
+ def generate_llm_response(user_prompt: str):
 
45
  """
46
+ Usa el LLM para decidir si el usuario quiere una imagen o solo chatear.
47
+ Devuelve una respuesta estructurada (nuestro "código secreto").
48
  """
49
+ # Un prompt de sistema simple para guiar al LLM
50
+ system_prompt = (
51
+ "Eres Carl, un asistente de IA. Tu trabajo es determinar si el usuario quiere generar una imagen o simplemente chatear. "
52
+ "Si el usuario quiere una imagen, responde en formato JSON con la clave 'action' como 'generate_image' y 'prompt' con el texto para la imagen. "
53
+ "Si el usuario solo quiere chatear, responde con la clave 'action' como 'chat' y 'response' con tu respuesta en texto. "
54
+ "Ejemplo para imagen: {\"action\": \"generate_image\", \"prompt\": \"un astronauta en un caballo\"}. "
55
+ "Ejemplo para chat: {\"action\": \"chat\", \"response\": \"¡Hola! ¿Cómo puedo ayudarte hoy?\"}."
56
+ )
57
+
58
+ full_prompt = f"{system_prompt}\n\nUsuario: {user_prompt}\nCarl:"
59
+
60
+ inputs = tokenizer(full_prompt, return_tensors="pt", return_attention_mask=False)
61
+
62
+ # Generar la respuesta
63
+ outputs = model.generate(**inputs, max_length=200)
64
+ text_output = tokenizer.batch_decode(outputs)[0]
65
+
66
+ # Extraer solo la respuesta JSON de Carl
67
  try:
68
+ # Buscamos el inicio del JSON
69
+ json_part = text_output.split("Carl:")[1].strip()
70
+ # Limpiamos cualquier texto extra que el modelo pueda añadir después del JSON
71
+ if "}" in json_part:
72
+ json_part = json_part.split("}")[0] + "}"
73
+
74
+ response_json = json.loads(json_part)
75
+ return response_json
76
+ except (json.JSONDecodeError, IndexError) as e:
77
+ print(f"Error al decodificar la respuesta del LLM: {e}")
78
+ print(f"Texto de salida problemático: {text_output}")
79
+ # Si el LLM falla, damos una respuesta por defecto
80
+ return {"action": "chat", "response": "No pude entender tu petición. ¿Podrías reformularla?"}
81
+
82
+ # --- Endpoint de la API ---
83
+ @app.post("/chat/")
84
+ async def chat_with_carl(request: ChatRequest):
85
+ """
86
+ Recibe un prompt del usuario, lo procesa con el LLM y actúa en consecuencia.
87
+ """
88
+ user_prompt = request.prompt
89
+ print(f"Recibido prompt del usuario: {user_prompt}")
90
+
91
+ # 1. Obtener la respuesta estructurada del LLM
92
+ structured_response = generate_llm_response(user_prompt)
93
+ action = structured_response.get("action")
94
+
95
+ if action == "generate_image":
96
+ # 2. El LLM decidió generar una imagen
97
+ image_prompt = structured_response.get("prompt", "una imagen aleatoria")
98
+ print(f"LLM decidió generar una imagen con el prompt: '{image_prompt}'")
99
+
100
+ try:
101
+ # 3. Llamar a la API del servicio de imágenes
102
+ response_from_artist = requests.post(IMAGE_SERVICE_URL, json={"prompt": image_prompt})
103
 
104
+ if response_from_artist.status_code == 200:
105
+ # Si la respuesta es exitosa, devolvemos la imagen directamente
106
+ return {"type": "image", "content": response_from_artist.content.hex()}
107
+ else:
108
+ raise HTTPException(status_code=500, detail="El servicio de imágenes falló.")
 
 
109
 
110
+ except requests.exceptions.RequestException as e:
111
+ print(f"Error al conectar con el servicio de imágenes: {e}")
112
+ raise HTTPException(status_code=500, detail="No se pudo conectar con el servicio de imágenes.")
113
 
114
+ elif action == "chat":
115
+ # 4. El LLM decidió solo chatear
116
+ chat_response = structured_response.get("response", "No sé qué decir.")
117
+ print(f"LLM decidió chatear con la respuesta: '{chat_response}'")
118
+ return {"type": "text", "content": chat_response}
119
 
120
+ else:
121
+ # 5. Respuesta por defecto si el LLM no se comporta
122
+ return {"type": "text", "content": "Hubo un error al procesar tu solicitud."}
123
 
 
 
 
124
 
125
  # --- Endpoint de Bienvenida ---
126
  @app.get("/")
127
  def read_root():
128
+ return {"status": "Servicio orquestador 'El Cerebro' está en línea."}
requirements.txt CHANGED
@@ -2,7 +2,8 @@ fastapi
2
  uvicorn
3
  pydantic
4
  torch
5
- diffusers
6
  transformers
7
  accelerate
8
- Pillow
 
 
 
2
  uvicorn
3
  pydantic
4
  torch
 
5
  transformers
6
  accelerate
7
+ requests
8
+ einops
9
+ sentencepiece