-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchatbot.py
110 lines (88 loc) · 3.69 KB
/
chatbot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import random
import json
import pickle
import numpy as np
import torch
import nltk
from nltk.stem import WordNetLemmatizer
from keras.models import load_model
from sentence_transformers import SentenceTransformer, util
# Inicialización del lematizador y carga del modelo de embeddings
lemmatizador = WordNetLemmatizer()
modelo_embeddings = SentenceTransformer('all-MiniLM-L6-v2')
# Colores para la consola
AZUL = '\033[94m'
VERDE = '\033[92m'
RESET = '\033[0m'
# Cargar los archivos generados y el modelo del chatbot
with open('intents.json', encoding='utf-8') as archivo:
intenciones = json.load(archivo)
palabras = pickle.load(open('words.pkl', 'rb'))
clases = pickle.load(open('classes.pkl', 'rb'))
modelo = load_model('chatbot_model.keras')
# Preparar embeddings para cada patrón en intents.json
patrones = []
etiquetas = []
for intencion in intenciones['intents']:
for patron in intencion['patterns']:
patrones.append(patron)
etiquetas.append(intencion['tag'])
embeddings_patrones = modelo_embeddings.encode(patrones)
# Extraer palabras clave de los intents
keywords_por_etiqueta = {}
for intencion in intenciones['intents']:
keywords_por_etiqueta[intencion['tag']] = intencion.get('keywords', [])
# Procesa las palabras de entrada
def limpiar_oracion(oracion):
palabras_oracion = nltk.word_tokenize(oracion)
palabras_oracion = [lematizador.lemmatize(palabra.lower()) for palabra in palabras_oracion]
return palabras_oracion
# Convierte la entrada en un bag of words
def bolsa_de_palabras(oracion):
palabras_oracion = limpiar_oracion(oracion)
bolsa = [0] * len(palabras)
for p in palabras_oracion:
for i, palabra in enumerate(palabras):
if palabra == p:
bolsa[i] = 1
return np.array(bolsa)
# Nueva función para predecir clase usando embeddings y similaridad de frases
def predecir_clase(oracion, umbral=0.5):
# Embedding de la oración del usuario
embedding_oracion = modelo_embeddings.encode(oracion)
# Filtrar patrones por palabras clave
posibles_intents = []
for tag, keywords in keywords_por_etiqueta.items():
if not keywords or any(keyword.lower() in oracion.lower() for keyword in keywords):
posibles_intents.append(tag)
if not posibles_intents:
return "desconocido"
# Crear un subconjunto de embeddings y etiquetas
indices_validos = [i for i, etiqueta in enumerate(etiquetas) if etiqueta in posibles_intents]
embeddings_validos = embeddings_patrones[indices_validos]
etiquetas_validas = [etiquetas[i] for i in indices_validos]
# Calcula similitud para los intents filtrados
similitudes = util.pytorch_cos_sim(embedding_oracion, embeddings_validos)[0]
indice_mejor_match = torch.argmax(similitudes).item()
# Si la similitud máxima supera el umbral, devuelve la clase correspondiente
if similitudes[indice_mejor_match] > umbral:
return etiquetas_validas[indice_mejor_match]
return "desconocido"
# Obtén una respuesta aleatoria
def obtener_respuesta(etiqueta, intenciones_json):
for intencion in intenciones_json['intents']:
if intencion['tag'] == etiqueta:
return random.choice(intencion['responses'])
return "Lo siento, no tengo una respuesta para eso."
# Función principal para responder
def responder(mensaje):
intencion = predecir_clase(mensaje)
if intencion == "desconocido":
return "Lo siento, no entiendo la pregunta. ¿Podrías formularla de otra manera?"
else:
return obtener_respuesta(intencion, intenciones)
# Ciclo de ejecución
print("\n")
while True:
mensaje = input(f"{AZUL}\nTú: {RESET}")
print(f"{VERDE}Bot: {responder(mensaje)}{RESET}")