edullm / core /llm /llm_manager.py
JairoDanielMT's picture
Upload 21 files
f6cb78b verified
raw
history blame
3.78 kB
# core/llm/llm_manager.py
import os
import base64
from openai import OpenAI
from dotenv import load_dotenv
from loguru import logger
load_dotenv(dotenv_path="config/.env")
class LLMManager:
"""Gestor de interacción con modelos de lenguaje compatibles con la API de OpenAI."""
def __init__(self):
self.api_key = os.getenv("LLM_API_KEY")
self.base_url = os.getenv("LLM_BASE_URL")
self.model = os.getenv("LLM_MODEL_NAME")
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
self.prompt_system = self._load_system_prompt()
def _load_system_prompt(self) -> str:
"""Carga el prompt del sistema desde 'config/prompt_system.txt'."""
path_system_prompt = os.getenv("PATH_SYSTEM_PROMPT")
try:
with open(path_system_prompt, "r", encoding="utf-8") as f:
logger.info("✅ Prompt del sistema cargado correctamente.")
return f.read().strip()
except FileNotFoundError:
logger.warning(
f"⚠️ No se encontró '{path_system_prompt}'. Se usará un prompt por defecto."
)
return "Eres un asistente educativo del MINEDU."
def _encode_image(self, image_bytes: bytes) -> str:
"""Convierte bytes de imagen a Base64."""
logger.debug("🔄 Codificando imagen a Base64.")
return base64.b64encode(image_bytes).decode("utf-8")
def generate_response(
self, user_query: str, context: str = "", image: bytes = None
) -> str:
"""Genera respuesta multimodal (texto + imagen) o solo texto."""
try:
logger.info("🔹 Generando respuesta para la consulta del usuario.")
messages = []
# Añadir prompt del sistema
if self.prompt_system:
messages.append({"role": "system", "content": self.prompt_system})
# Si es imagen (multimodal)
if image:
logger.debug("🖼️ Procesando entrada multimodal con imagen.")
base64_image = self._encode_image(image)
messages.append(
{
"role": "user",
"content": [
{
"type": "text",
"text": user_query
if user_query
else "Describe esta imagen con enfoque educativo.",
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{base64_image}"
},
},
],
}
)
else:
# Solo texto, con posible contexto
full_prompt = user_query
if context:
logger.debug("➕ Añadiendo contexto al mensaje.")
full_prompt = f"{context}\n\nPregunta: {user_query}"
messages.append({"role": "user", "content": full_prompt})
# Llamada al modelo
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
)
logger.success("✅ Respuesta generada correctamente.")
return response.choices[0].message.content
except Exception as e:
logger.error(f"❌ Error al generar respuesta: {str(e)}")
return f"Error al generar respuesta: {str(e)}"