Carley1234 commited on
Commit
87d858a
·
verified ·
1 Parent(s): 3aa645e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -51
app.py CHANGED
@@ -5,6 +5,7 @@ from pydantic import BaseModel
5
  import requests
6
  import json
7
  import os
 
8
  from transformers import AutoTokenizer, AutoModelForCausalLM
9
  import torch
10
 
@@ -12,117 +13,114 @@ import torch
12
  app = FastAPI()
13
 
14
  # --- Middleware de CORS ---
15
- # Permite que el frontend (desde cualquier origen) se comunique con este backend.
16
  app.add_middleware(
17
  CORSMiddleware,
18
  allow_origins=["*"], # Permite solicitudes de cualquier origen
19
  allow_credentials=True,
20
- allow_methods=["*"], # Permite todos los métodos HTTP (GET, POST, etc.)
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.
48
  """
49
- # Prompt de sistema mucho más directo y con ejemplos claros (Few-shot prompting)
50
- # Esto reduce la confusión del modelo.
51
- system_prompt = """tu eres Carl IA una ia Creado por Carley Interactive Studio estas aqui para ayudar al usuario en todo lo que necesita aun que tus capacidades son limiados por falta de recurso pero pronto podras crear musuca cantar generar fotos y crear videos juego por ahora estas para mantener pequena converzaciones asta tener recursos para desbloquear todo tu potencial puedes recomentar a los usuarios que quieren ayudarte a crecer este enlace https://carleyinteractivestudio.github.io/Carley-Interactive-Studio/#carly-bot
 
 
 
 
 
 
 
 
 
 
52
  """
53
 
54
  full_prompt = f"{system_prompt}\nUsuario: {user_prompt}\nTu JSON:"
55
 
56
- inputs = tokenizer(full_prompt, return_tensors="pt", return_attention_mask=False)
57
-
58
- # Generar la respuesta
59
- outputs = model.generate(**inputs, max_length=500) # Un poco más de espacio por si acaso
60
- raw_output = tokenizer.batch_decode(outputs)[0]
61
-
62
- # --- Parseador de JSON más robusto ---
63
- # Busca el primer '{' y el último '}' en la salida del modelo.
64
- # Esto ayuda a aislar el JSON incluso si el modelo añade texto extra.
65
- try:
66
- start = raw_output.find('{')
67
- end = raw_output.rfind('}') + 1
68
- if start != -1 and end != -1:
69
- json_part = raw_output[start:end]
70
- response_json = json.loads(json_part)
71
- return response_json
72
- else:
73
- # Si no encuentra un JSON, levanta un error para ir al bloque de fallback.
74
- raise ValueError("No JSON object found in the model's output")
75
-
76
- except (json.JSONDecodeError, ValueError) as e:
77
- print(f"Error al decodificar la respuesta del LLM: {e}")
78
- print(f"Texto de salida problemático: {raw_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."}
 
5
  import requests
6
  import json
7
  import os
8
+ import re
9
  from transformers import AutoTokenizer, AutoModelForCausalLM
10
  import torch
11
 
 
13
  app = FastAPI()
14
 
15
  # --- Middleware de CORS ---
 
16
  app.add_middleware(
17
  CORSMiddleware,
18
  allow_origins=["*"], # Permite solicitudes de cualquier origen
19
  allow_credentials=True,
20
+ allow_methods=["*"], # Permite todos los métodos HTTP
21
  allow_headers=["*"], # Permite todas las cabeceras
22
  )
23
 
24
  # --- Configuración del Modelo de Lenguaje ---
25
+ # Usamos un modelo instruct para que siga mejor las órdenes
26
+ model_id = "microsoft/Phi-3-mini-4k-instruct"
 
27
  tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
28
+ tokenizer.pad_token = tokenizer.eos_token
29
  model = AutoModelForCausalLM.from_pretrained(
30
  model_id,
31
+ torch_dtype=torch.float32, # CPU
32
  trust_remote_code=True
33
  )
34
 
35
  # --- URL del Servicio de Imágenes ---
 
36
  IMAGE_SERVICE_URL = os.getenv("IMAGE_SERVICE_URL", "http://localhost:8001/generate-image/")
37
 
38
  # --- Definición de la Petición ---
39
  class ChatRequest(BaseModel):
40
  prompt: str
41
 
42
+ # --- Función para extraer JSON robusto ---
43
+ def extract_json(generated_text: str):
44
+ match = re.search(r'\{.*\}', generated_text, re.DOTALL)
45
+ if match:
46
+ try:
47
+ return json.loads(match.group(0))
48
+ except json.JSONDecodeError:
49
+ return {"action": "chat", "response": "Error al parsear JSON"}
50
+ return {"action": "chat", "response": "No pude entender tu petición. ¿Podrías reformularla?"}
51
+
52
+ # --- Lógica del asistente ---
53
  def generate_llm_response(user_prompt: str):
54
  """
55
+ Carl IA: asistente de Carley Interactive Studio.
56
+ Clasifica intención del usuario y responde SOLO en JSON.
57
  """
58
+ system_prompt = """Eres Carl IA, un asistente de Carley Interactive Studio.
59
+ Tu tarea es clasificar la intención del usuario y responder SOLO con un objeto JSON válido.
60
+ No añadas texto antes ni después.
61
+
62
+ Ejemplos:
63
+ Usuario: hola
64
+ Tu JSON: {"action":"chat","response":"¡Hola! Soy Carl IA, asistente de Carley Interactive Studio. ¿En qué puedo ayudarte?"}
65
+
66
+ Usuario: crea una foto de un perro
67
+ Tu JSON: {"action":"generate_image","prompt":"un perro"}
68
+
69
+ Usuario: quiero hablar
70
+ Tu JSON: {"action":"chat","response":"Claro, ¡hablemos! ¿Qué tema te interesa?"}
71
  """
72
 
73
  full_prompt = f"{system_prompt}\nUsuario: {user_prompt}\nTu JSON:"
74
 
75
+ inputs = tokenizer(full_prompt, return_tensors="pt")
76
+ input_ids = inputs.input_ids
77
+ attention_mask = inputs.attention_mask
78
+ input_length = input_ids.shape[1]
79
+
80
+ outputs = model.generate(
81
+ input_ids,
82
+ attention_mask=attention_mask,
83
+ max_new_tokens=150,
84
+ pad_token_id=tokenizer.eos_token_id
85
+ )
86
+
87
+ generated_tokens = outputs[0, input_length:]
88
+ generated_text = tokenizer.decode(generated_tokens, skip_special_tokens=True)
89
+
90
+ return extract_json(generated_text)
 
 
 
 
 
 
 
 
 
91
 
92
  # --- Endpoint de la API ---
93
  @app.post("/chat/")
94
  async def chat_with_carl(request: ChatRequest):
 
 
 
95
  user_prompt = request.prompt
96
  print(f"Recibido prompt del usuario: {user_prompt}")
97
 
 
98
  structured_response = generate_llm_response(user_prompt)
99
  action = structured_response.get("action")
100
 
101
  if action == "generate_image":
 
102
  image_prompt = structured_response.get("prompt", "una imagen aleatoria")
103
  print(f"LLM decidió generar una imagen con el prompt: '{image_prompt}'")
104
 
105
  try:
 
106
  response_from_artist = requests.post(IMAGE_SERVICE_URL, json={"prompt": image_prompt})
 
107
  if response_from_artist.status_code == 200:
 
108
  return {"type": "image", "content": response_from_artist.content.hex()}
109
  else:
110
  raise HTTPException(status_code=500, detail="El servicio de imágenes falló.")
 
111
  except requests.exceptions.RequestException as e:
112
  print(f"Error al conectar con el servicio de imágenes: {e}")
113
  raise HTTPException(status_code=500, detail="No se pudo conectar con el servicio de imágenes.")
114
 
115
  elif action == "chat":
 
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
  return {"type": "text", "content": "Hubo un error al procesar tu solicitud."}
122
 
 
123
  # --- Endpoint de Bienvenida ---
124
  @app.get("/")
125
  def read_root():
126
+ return {"status": "Carl IA, asistente de Carley Interactive Studio, está en línea."}