Como crear un chatbot con keras para Telegram
Un chatbot es un programa informático que puede simular una conversación con usuarios humanos a través de la mensajería instantánea. Esta tecnología tiene la capacidad de proporcionar al cliente medios, recibir pedidos y proporcionar información.
Durante los últimos años, los chatbots han estado dominando el mercado. Se están introduciendo en todas las industrias y casi todas las empresas los utilizan. Los chatbots se han convertido en una gran parte de nuestras vidas. Pero, ¿qué es lo que los hace tan importantes?
Estos te ayudan con tus tareas diarias, ya sea pedir comida u obtener información sobre un evento. Básicamente son un servicio autónomo que puede brindarte información en cualquier momento del día o de la noche.
Nosotros desarrollaremos un chatbot que sirva como un tipo de enciplodepia de filosofia y le podremos “FilosoraptorBot”.
Primeros Pasos
Para este chatbot usaremos la api de Telegram y para eso tenemos que hablar con el padre de todos los chatbots BotFather en Telegram, el nos dara un Token que es el que usaremos para poder acceder a nuestro bot.
Después, crearemos un ambiente virtual. Esto ayudara a aislar nuestro proyecto de el resto de ambientes en nuestro equipo.
$ python -m venv venv/
Ahora tenemos una carpeta “venv/” que contiene todas las librerías de Python que vamos a utilizar. Solo queda activarlo:
$ source venv/bin/activate
Las librerias que necesitaremos son:
– python-telegram-bot
– tensorflow
– nltk
Se pueden instalar las librerías en el ambiente virtual con el comando pip:
(venv) $ pip install python-telegram-bot
(venv) $ pip install tensorflow
(venv) $ pip install nltk
Así estaría estructurado nuestro proyecto:
.
├── app.py
├── telebot
│ ├── credentials.py
│ | .
│ | Aqui puedes agregar los archivos de entrenamiento
│ | .
│ └──
└── venv
en “credentials.py” vamos a necesitar las siguientes variables:
bor_token="El token que te dio BotFather"
bot_username: "El username que le pusiste"
Tambien se pueden agregar otro tipo de variables, como el url de la plataforma donde lo vas a subir.
Antes de meternos en al “app.py” prepararemos nuestro archivo para entrenar nuestro bot. Así que creamos “train_bot.py” e importaremos las siguientes librerías:
import nltk
nltk.download('punkt')
nltk.download('wordnet')
from nltk.stem import WordNetLemmatizerlemmatizer = WordNetLemmatizer()import json
import pickle
import random
import numpy as npfrom tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation, Dropout
from tensorflow.keras.optimizers import SGD
Tenemos bastantes elementos de la librería *nltk* (Natural Language Toolkit), y es porque contiene muchas herramientas que utilizaremos para la limpieza y preparación del texto para nuestro algoritmo, también utilizaremos json para obtener nuestros datos de entrenamiento, pickle para cargar nuestros archivos de tipo pickle, numpy para realizar cálculos de una manera eficiente y keras que es nuestro framework de deep learning que usaremos.
Proseguimos a inicializar las variables que necesitaremos:
words=[]
classes=[]
documents=[]
ignore_words=['?','!']
data_file=open('q&a.json').read()
intents = json.loads(data_file)
Bien, ya tenemos listo las variables que necesitaremos para almacenar nuestros datos de lenguaje natural. Como veras, hay un archivo “q&a.json” que es el que contiene nuestros “intents”, que es lo que utilizaremos para entrenar. Debería verse algo así:
{"intents":[
{"tag": "saludos",
"patterns":["Hola", "hola", "que onda", "como estas","Como Estas", "alguien ahi?", "buenos dias", "buenas"],
"responses": ["Hola, como estas?", "Hay dias en lo que simplemente existo", "Hola, como te encuentras hoy?"],
"context": [""]
},
{"tag": "despedida",
"patterns":["Adios", "adios", "nos vemos", "buena platica, bye", "bye", "hasta luego", "bai", "buenas noches"],
"responses": ["nos vemos!", "Que te vaya bien!", "Hasta la vista"],
"context": [""]
},
{"tag": "noanswer",
"patterns":[],
"responses": ["Lo sinto, pero no entiendo tu pregunta", "Necesito más informacion", "No te estoy entendiendo"],
"context": [""]
},
{"tag": "frase william",
"patterns":["que pinesas de lo bueno y lo malo?"],
"responses": ["No existe nada bueno ni malo; es el pensamiento humano el que lo hace parecer asi\\. \n \\-William Shakespeare"],
"context":[""]
},
{"tag":"biografia mileto",
"patterns":["quien era tales de mileto?"],
"responses": ["Tales de Mileto fue de los primeros pensadores en tener registros, ya que se cree que vivio entre 624\\-546 a\\.C\\. en Mileto, en la que hoy conocemos como Turquia\\. Aunque no se tenga ninguno de sus escritos, si es que existen, se le considera un gran pialar debido a sus menciones por parte de Aristoteles y Diógenes\\."],
"context":[""]
},
{"tag":"frase mileto",
"patterns":["de que esta compuesto la vida?"],
"responses": ["Mmm debe ser algo esencial para la vida, algo a partir de lo que pueda formarse todo, algo que se transforma\\. Todo es agua\\. \n \\-Tales de Mileto"],
"context":[""]
}
}
Como veras, mi chatbot hablara un poco sobre filósofos de la historia, pero no es necesario agregarlo para probarlo, con los primero 3 tipos de tags es suficiente.
Cargamos nuestros intents desde el json:
#Primero, importamos nuestros 'intents'
for intent in intents['intents']:
for pattern in intent['patterns']:
#tokenizamos cada palabra de nuestras preguntas
w = nltk.word_tokenize(pattern)
#Agregamos w a nuestras palabras
words.extend(w)
#añadimos a documents la dupla de (palabra tokenizada, nombre de la clase que pertenece)
documents.append((w, intent['tag']))
#agregamos los tags a classes para categorizarlas
if intent['tag'] not in classes:
classes.append(intent['tag'])
Después limpiamos y preparamos nuestros datos:
#limpiamos las palbras. En este caso solo son los caracteres '?' y '!' y ordenamos
words = [lemmatizer.lemmatize(w.lower()) for w in words if w not in ignore_words]
words = sorted(list(set(words)))
classes= sorted(list(set(classes)))
#Revisamos nuestras variables
print(len(documents), "documents")
print(len(classes), "classes", classes)
print(len(words), "unicas lemmatized words", words)#Volvemos nuestras variables 'dummys'
pickle.dump(words, open('words.pkl', 'wb'))
pickle.dump(classes, open('classes.pkl', 'wb'))
Lo que hicimos fue aplicar el “lemmatizer” que es básicamente simplificar nuestras palabras. Un ejemplo seria “caminando”, “caminaba”, “camino” las simplifica a “caminar” que seria la forma base.
Lo siguiente seria crear nuestros datos para modelo:
training=[]
output_empty=[0] * len(classes)
for doc in documents:
bag=[]
pattern_words= doc[0] #convertimos a minusculas nuestras palabras
pattern_words = [lemmatizer.lemmatize(word.lower()) for word in pattern_words] #agregamosnlas palabras claves que se encuentran en nuestras preguntas
for w in words:
bag.append(1) if w in pattern_words else bag.append(0) output_row = list(output_empty)
output_row[classes.index(doc[1])] = 1
training.append([bag, output_row])#entrenamos
random.shuffle(training)
training = np.array(training)
train_x = list(training[:,0])
train_y = list(training[:,1])
print("training data ceated")
Ya que tenemos nuestros datos, solo queda crear nuestra red para terminar nuestro modelo:
#Creamos nuestra red neuronal de 3 capas
model = Sequential()
model.add(Dense(128, input_shape=(len(train_x[0]),), activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(len(train_y[0],), activation='softmax'))
print(model.summary())sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])#Guardamos nuestro modelo y listo
hist = model.fit(np.array(train_x), np.array(train_y), epochs=200, batch_size=5, verbose=1)
model.save('chatbot_model.h5', hist)
print("model created")
Ya tenemos nuestro modelo!
Como podrás observar creamos una red neuronal de 3 capas, donde la primera tiene 128 neuronas, la segunda 64 y la ultima el número de “intents” de nuestro json. Y fue entrenado con el modelo de descenso de gradiente estocástico (SDG por sus siglas en ingles). Ahora solo quedaría configurar nuestro bot para que conteste con lo que aprendió.
Configuración del Bot
Para utilizar nuestro modelo tenemos que importar las siguiente librería. Ademas de otras para poder configurar nuestro bot correctamente:
import logging
import telegram
import json
import random
import nltk
import pickle
import numpy as np
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
from telebot.credentials import bot_token, bot_user_bot
from tensorflow.keras.models import load_model
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
Extraemos la información de nuestros archivos:
#Cargamos nuestros archivos
model = load_model('chatbot_model.h5')
intents = json.loads(open('q&a.json').read())
words = pickle.load(open('words.pkl', 'rb'))
classes = pickle.load(open('classes.pkl', 'rb'))
Para la configuración básica de nuestro bot usaremos lo siguiente:
(Recuerda que bot_token es la Token de nuestro bot que pusimos en nuestro archivo “credentials.py” que ahora importamos de ahi):
#Configuración del loggin
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger()
#TOKEN del bot
TOKEN = bot_token
Ahora haremos unas funciones para todo el procesamiento de los datos y el bot pueda mandárselo al usuario. La primera sera clean_up_sentence() que limpiara el texto introducido por el usuario, después bow() que tomara las sentencias ya procesadas y limpias para meterlas en una “bolsa” de palabras que serán utilizadas para predecir la clase a la que pertenecen.
def clean_up_sentence(sentence):
sentence_words = nltk.word_tokenize(sentence)
sentence_words = [lemmatizer.lemmatize(word.lower()) for word in sentence_words]
return sentence_wordsdef bow(sentence, words, show_details=True):
sentence_words = clean_up_sentence(sentence)
bag = [0]*len(words) for s in sentence_words:
for i,w in enumerate(words):
if w == s:
bag[i] = 1
if show_details:
print(f"found in bag: {w}")
return(np.array(bag))
Hacemos una función llamada predict_class() que como su nombre lo indica la usaremos para predecir en que clase pertenece la pregunta del usuario, usaremos un margen de error del 0.25 para intentar evadir el sobre-aprendizaje. Esta función regresara una lista con los “intents” y la probabilidad que tenga de coincidir. Y la función getResponse() toma la lista generada de “predict_class” y verifica el archivo json para generar la respuesta con la mayor probabilidad. Y finalmente chatbot_response() que simplemente tomara el mensaje del usuario y va predecir la clase del mensaje con la respuesta más probable:
def predict_class(sentence, model):
p = bow(sentence, words, show_details=False)
res = model.predict(np.array([p]))[0] ERROR_THRESHOLD=0.25
results = [[i, r] for i,r in enumerate(res) if r>ERROR_THRESHOLD]
results.sort(key=lambda x: x[1], reverse=True)
return_list=[] for r in results:
return_list.append({"intent": classes[r[0]], "probability": str(r[1])}) return return_listdef getResponse(ints, intents_json):
tag = ints[0]['intent']
list_of_intents=intents_json['intents'] for i in list_of_intents:
if i['tag'] == tag:
result = random.choice(i['responses'])
break
return resultdef chatbot_response(msg):
ints = predict_class(msg, model)
res = getResponse(ints, intents) return res
Ya tenemos las funciones necesarias para obtener las respuestas de nuestro modelo, pero el bot aun no esta listo. Hace falta una pequeña función que llamaremos echo() para que reciba el mensaje del usuario y mande la respuesta que predecimos:
def echo(update, context):
user_id = update.effective_user['id']
logger.info(f"El usuario {user_id}, a enviado un mensaje de texto.")
text = update.message.text if text != '':
res = chatbot_response(text)
context.bot.send_message(
chat_id=user_id,
parse_mode="MarkdownV2",
text=f"{res}")
Ya casi esta listo, solo falta unos detalles. Tendremos que crear nuestra variable “updater” que sirve para poder comunicarnos con nuestro bot. Y estará atenta de cada mensaje que se envié en el chat. No sera la forma más eficiente, pero es suficientemente practico para poder crear nuestro primer chatbot. También crearemos unos “manejadores” que serán los que llamaran a nuestra función “echo”:
#Enlace entre el updater con el bot
updater = Updater(my_bot.token, use_context=True)#Despachador
dp= updater.dispatcher#Manejadores
dp.add_handler(MessageHandler(Filters.text, echo))updater.start_polling()
print("Bot cargado")
updater.idle() #Para finalizar el bot con ctrl + c
Y LISTO! Ya terminamos nuestro primer chatbot, solo queda probarlo con el siguiente comando:
$ python app.py
Y si todo sale bien solo tendremos que enviarle un saludo a nuestro bot para que conteste con una de las respuestas que le proporcionamos:
Repositorio de Github:
GitHub – GerardoLeyvaConde/FilosoraptorBot: Chatbot de Telegram que sirve como enciplopedia de…
You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…
github.com
Autor: Gerardo Leyva Conde
Ten articles before and after
Telegram HTTP API With Python — Sending Messages Programatically – Telegram Group
How to keep content in Telegram channels ‘members-only’ – Telegram Group
5 Reasons Why You Should Change WhatsApp for Telegram – Telegram Group
Unmarshal Telegram Genie Bot. Unmarshal is proud to release the… – Telegram Group
HODLing in Bear Market (DAO). “When the going gets tough , the though… – Telegram Group
Come triangolare utenti Telegram attraverso l’uso di strumenti automatici – Telegram Group
Unboxing Cryptocurrencies — Getting Started – Telegram Group
Telegram — not the app 🙂 , the yesteryear’s service that was used in India – Telegram Group
data-rh=”true”>Scrypt-Adaptive-Nfactor – Alexander Chern – Medium – Telegram Group
How much to save for bitcoin?. Everyone has thought about purchasing a… – Telegram Group