Skip to content

Commit

Permalink
Actualización de chatbot_laura: cambios en apps.py, consumers.py, vie…
Browse files Browse the repository at this point in the history
…ws.py y lógica añadida
  • Loading branch information
Blaister9 committed Oct 3, 2024
1 parent efe137f commit 7bb7bc0
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 141 deletions.
1 change: 1 addition & 0 deletions backend/chatbot_laura/apps.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#/home/epaz/Documentos/2_Conversation/backend/chatbot_laura/apps.py
from django.apps import AppConfig


Expand Down
123 changes: 123 additions & 0 deletions backend/chatbot_laura/chatbot_laura_logic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import os
import pandas as pd
import numpy as np
import faiss
import pickle
from openai import AsyncOpenAI, OpenAIError
from dotenv import load_dotenv
import logging

# Configurar logging
logger = logging.getLogger(__name__)

load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# Inicializar el cliente de OpenAI de forma asíncrona
client = AsyncOpenAI(api_key=OPENAI_API_KEY)


class ChatbotLauraLogic:
def __init__(self):
base_dir = os.path.dirname(os.path.abspath(__file__))
self.embedding_file = os.path.join(base_dir, 'embeddings.pkl')
self.index_file = os.path.join(base_dir, 'faiss_index.index')
self.json_file = os.path.join(base_dir, 'preguntas_respuestas_procesadasV1.json')
self.df = None
self.embeddings = None
self.index = None
self.load_or_generate_index()

def load_or_generate_index(self):
try:
if os.path.exists(self.embedding_file) and os.path.exists(self.index_file):
logger.info("Cargando embeddings y FAISS index desde archivo...")
self.embeddings = self.load_embeddings(self.embedding_file)
self.index = faiss.read_index(self.index_file)
else:
logger.info("Generando nuevos embeddings y FAISS index...")
self.df = self.load_and_process_data(self.json_file)
if self.df is not None:
self.generate_faiss_index()
else:
raise ValueError("Error al cargar el DataFrame desde el archivo JSON.")
except Exception as e:
logger.error(f"Error en load_or_generate_index: {str(e)}")
raise

def load_embeddings(self, file_name):
try:
with open(file_name, 'rb') as f:
return pickle.load(f)
except Exception as e:
logger.error(f"Error al cargar embeddings: {str(e)}")
raise

def load_and_process_data(self, json_file):
try:
with open(json_file, "r") as file:
data = json.load(file)
processed_data = []
for item in data:
if item['type'] == 'qa':
text_for_embedding = f"{item['content']['pregunta']} {item['content']['respuesta']}"
processed_data.append({
'text_for_embedding': text_for_embedding,
'full_content': item['content'],
'type': 'qa',
'url': item.get('url', ''),
'metadata': item.get('metadata', {})
})
elif item['type'] == 'info':
text_for_embedding = f"{item['content']['titulo']} {item['content'].get('descripcion', '')}"
processed_data.append({
'text_for_embedding': text_for_embedding,
'full_content': item['content'],
'type': 'info',
'url': item.get('url', ''),
'metadata': item.get('metadata', {})
})
return pd.DataFrame(processed_data)
except Exception as e:
logger.error(f"Error al procesar el archivo JSON: {str(e)}")
return None

def generate_faiss_index(self):
try:
self.df['embedding'] = self.df['text_for_embedding'].apply(lambda x: self.get_embedding(x))
embedding_matrix = np.array(self.df['embedding'].tolist()).astype('float32')
embedding_matrix /= np.linalg.norm(embedding_matrix, axis=1)[:, None]
self.index = faiss.IndexFlatIP(embedding_matrix.shape[1])
self.index.add(embedding_matrix)
except Exception as e:
logger.error(f"Error al generar el índice FAISS: {str(e)}")
raise

async def get_embedding(self, text, model="text-embedding-ada-002"):
try:
response = await client.embeddings.create(input=text, model=model)
return response.data[0].embedding
except OpenAIError as e:
logger.error(f"Error al obtener embedding: {str(e)}")
raise

async def search(self, query, k=3):
try:
query_embedding = np.array(await self.get_embedding(query)).astype('float32')
query_embedding /= np.linalg.norm(query_embedding)
D, I = self.index.search(np.array([query_embedding]), k)
results = []
for i in range(k):
result = self.df.iloc[I[0][i]]
results.append({
'pregunta': result['full_content'].get('pregunta', ''),
'respuesta': result['full_content'].get('respuesta', ''),
'url': result['url'],
'type': result['type'],
'metadata': result['metadata'],
'similarity_score': float(D[0][i])
})
return results
except Exception as e:
logger.error(f"Error en la búsqueda: {str(e)}")
raise
33 changes: 20 additions & 13 deletions backend/chatbot_laura/consumers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# chatbot_laura/consumers.py
# chatbot_laura/consumers.py
import json
import logging
from channels.generic.websocket import AsyncWebsocketConsumer
from .views import ChatbotLauraView
from .chatbot_laura_logic import ChatbotLauraLogic

logger = logging.getLogger(__name__)

Expand All @@ -22,24 +21,32 @@ async def disconnect(self, close_code):
async def receive(self, text_data):
try:
text_data_json = json.loads(text_data)
mensaje = text_data_json.get('mensaje', '')

mensaje = text_data_json.get('mensaje', '')
if not mensaje:
await self.send(text_data=json.dumps({'error': 'El mensaje no puede estar vacío'}))
return

logger.info(f"Mensaje recibido para Laura Chatbot: {mensaje}")

# Usar ChatbotLauraView para procesar el mensaje
chatbot_view = ChatbotLauraView()
resultados = await chatbot_view.search(mensaje) # FAISS busca el mensaje

# Procesar los resultados a través de GPT-4
respuesta_gpt4 = await generar_respuesta_gpt4(resultados)

# Enviar la respuesta de GPT-4 al cliente

# Usar la lógica de ChatbotLauraLogic para procesar el mensaje
chatbot_logic = ChatbotLauraLogic()
resultados = await chatbot_logic.search(mensaje)

# Procesar resultados para hacerlos más legibles
formatted_resultados = [
{
'pregunta': res.get('pregunta', 'Sin pregunta'),
'respuesta': res.get('respuesta', 'Sin respuesta'),
'url': res.get('url', ''),
'similarity_score': res.get('similarity_score', 0)
}
for res in resultados
]

# Enviar respuesta
await self.send(text_data=json.dumps({
'respuesta': respuesta_gpt4
'resultados': formatted_resultados
}))
except Exception as e:
logger.error(f"Error en receive para Laura Chatbot: {e}")
Expand Down
134 changes: 6 additions & 128 deletions backend/chatbot_laura/views.py
Original file line number Diff line number Diff line change
@@ -1,146 +1,24 @@
import os
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .chatbot_laura_logic import ChatbotLauraLogic
import json
import logging
from .gpt4_integration import generar_respuesta_gpt4
import pandas as pd
import numpy as np
import faiss
import pickle
from openai import OpenAI
from dotenv import load_dotenv

# Configurar logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

load_dotenv()
client = OpenAI(api_key=os.getenv('OPENAI_API_KEY')) # Configura tu clave de API


class ChatbotLauraView:
def __init__(self):
base_dir = os.path.dirname(os.path.abspath(__file__))
self.embedding_file = os.path.join(base_dir, 'embeddings.pkl')
self.index_file = os.path.join(base_dir, 'faiss_index.index')
self.json_file = os.path.join(base_dir, 'preguntas_respuestas_procesadasV1.json')
self.df = None
self.embeddings = None
self.index = None
self.load_or_generate_index()

def get_embedding(self, text, model="text-embedding-ada-002"):
try:
# Usamos directamente la función de OpenAI para obtener embeddings
response = client.embeddings.create(input=text, model=model)
return response.data[0].embedding
except Exception as e:
logger.error(f"Error al obtener embedding: {str(e)}")
raise

def load_or_generate_index(self):
try:
if os.path.exists(self.embedding_file) and os.path.exists(self.index_file):
logger.info("Cargando embeddings y FAISS index desde archivo...")
self.embeddings = self.load_embeddings(self.embedding_file)
self.index = faiss.read_index(self.index_file)
else:
logger.info("Generando nuevos embeddings y FAISS index...")
self.df = self.load_and_process_data(self.json_file)
if self.df is not None:
self.generate_faiss_index()
else:
raise ValueError("Error al cargar el DataFrame desde el archivo JSON.")
except Exception as e:
logger.error(f"Error en load_or_generate_index: {str(e)}")
raise

def load_embeddings(self, file_name):
try:
with open(file_name, 'rb') as f:
return pickle.load(f)
except Exception as e:
logger.error(f"Error al cargar embeddings: {str(e)}")
raise

def load_and_process_data(self, json_file):
try:
with open(json_file, "r") as file:
data = json.load(file)
processed_data = []
for item in data:
if item['type'] == 'qa':
text_for_embedding = f"{item['content']['pregunta']} {item['content']['respuesta']}"
processed_data.append({
'text_for_embedding': text_for_embedding,
'full_content': item['content'],
'type': 'qa',
'url': item.get('url', ''),
'metadata': item.get('metadata', {})
})
elif item['type'] == 'info':
text_for_embedding = f"{item['content']['titulo']} {item['content'].get('descripcion', '')}"
processed_data.append({
'text_for_embedding': text_for_embedding,
'full_content': item['content'],
'type': 'info',
'url': item.get('url', ''),
'metadata': item.get('metadata', {})
})
return pd.DataFrame(processed_data)
except Exception as e:
logger.error(f"Error al procesar el archivo JSON: {str(e)}")
return None

def generate_faiss_index(self):
try:
self.df['embedding'] = self.df['text_for_embedding'].apply(lambda x: self.get_embedding(x))
embedding_matrix = np.array(self.df['embedding'].tolist()).astype('float32')
embedding_matrix /= np.linalg.norm(embedding_matrix, axis=1)[:, None]
self.index = faiss.IndexFlatIP(embedding_matrix.shape[1])
self.index.add(embedding_matrix)
except Exception as e:
logger.error(f"Error al generar el índice FAISS: {str(e)}")
raise

def search(self, query, k=3):
try:
query_embedding = np.array(self.get_embedding(query)).astype('float32')
query_embedding /= np.linalg.norm(query_embedding)
D, I = self.index.search(np.array([query_embedding]), k)
results = []
for i in range(k):
result = self.df.iloc[I[0][i]]
results.append({
'content': result['full_content'],
'url': result['url'],
'type': result['type'],
'metadata': result['metadata'],
'similarity_score': float(D[0][i])
})
return results
except Exception as e:
logger.error(f"Error en la búsqueda: {str(e)}")
raise

# La función que maneja solicitudes POST y pasa los resultados por GPT-4 antes de enviarlos
@api_view(['POST'])
@csrf_exempt
async def chatbot_laura_view(request):
try:
data = json.loads(request.body)
query = data.get('mensaje', '')
if not query:
return JsonResponse({'error': 'No se proporcionó el mensaje'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'error': 'No se proporcionó el mensaje'}, status=status.HTTP_400_BAD_REQUEST)

chatbot_view = ChatbotLauraView()
resultados = chatbot_view.search(query) # Primero busca en FAISS
# Ahora pasamos los resultados por GPT-4
chatbot_logic = ChatbotLauraLogic()
resultados = await chatbot_logic.search(query)

# Aquí se podría usar GPT-4 para refinar la respuesta
respuesta_gpt4 = await generar_respuesta_gpt4(resultados)

return Response({'respuesta': respuesta_gpt4}, status=status.HTTP_200_OK)
Expand Down

0 comments on commit 7bb7bc0

Please sign in to comment.