Creando Chat-Bots con Telegram y Python

Por: Josue Soriano Publicado el: 2017-10-11 21:33:27, 26310

En los últimos días he estado indagando en la creación de un chatbot que reemplace el sistema de comunicacion del Alimentador de Mascotas el cual funciona por medio de Emails he indagando un poco me tope con los Chatbots de Telegram este sistema de chats permite programar un chat en telgram que responda segun lo que una persona le escriba al chat. Este sistema tiene una API Publica que permite utilizar cualquier lenguaje de programacion para poder crear un sistema de respuestas en base a las peticiones de los usuarios del chatbot.

 

Para este articulo, voy a desarrollar un chatbot que funcione de la siguiente manera:

  1. El chatbot se llamara "Joker504Bot" por lo que lo podran buscar en telegram con ese nombre.
  2. Cuando uno inicia un Bot por defecto Telegram manda el comando /start, cuando nuestro Bot reciba ese comando le vamos a contestar con los unicos dos comandos que va a poder realizar: /chucknorris y /numbertrivia.
  3. Cuando alguien envie el comando /chucknorris el bot le contestara con un chiste random de Chuck Norris, para ello vamos a utilizar la API Publica de Chistes de Chuck Norris (hasta la fecha, no puedo creer que alguien se tomara el tiempo de hacer esto)
  4. Con el comando /numbertrivia vamos hacer algo similar al anterior, sin embargo vamos a utilizar la api de Trivia de Numeros que nos retorna datos aleatorios de un numero en especifico.
  5. En caso de que se envie un texto o un comando que no sean ninguno de los tres anteriores se contestara con el mensaje "Comando no reconocido"

Antes de comenzar a programar debemos decirle a telegram que vamos a crear un nuevo bot; obiamente para esto necesitamos tener instalado telegram en nuestro Celular, en el APP de telegram utilizamos el buscador para localizar a BotFather (si estan viendo este articulo desde un celular, este link los llevara al chat directamente) Una vez aqui procedemos a la creación del Bot con el comando /newbot:

este comando nos pide dos cosas: El Nombre con el que se presentara el bot y el nombre de usuario del Bot, este ultimo debe ser sin espacios y debe terminar en "bot"; hecho esto nos dara el mensaje de finalizado y nos mostrara el accesso por medio de una clave (en este caso nos genero 419578624:AAGahgdR-3zKRmCBw-HKgLrQlC5UyKMQSlQ), esta clave es importante ya que es la que le daremos a nuestro codigo para que pueda responder a los usuarios y la podemos cambiar posteriormente utilizando otros comandos del BotFather, pero por los momentos vamos a dejar esta.

Con esto ya tenemos todo listo para poder hacer nuestro Bot, y para hacer el servicio que va a estar pendiente de lo que escriban nuestros usuarios; para ello vamos a utilizar como lenguaje de programacion Python y una libreria de clases llamada telepot.

Telepot es una libreria de objetos que nos permite comunicarnos por medio de funciones sencillas y con nombres similares a los que tiene la API de Telegram, para tener esta libreria podemos utilizar el instalador de paquetes de Python pip, para los usuarios de Windows les dejo este largo y aburrido tutorial (y de paso en Ingles) para instalar el lenguaje de programacion junto con su instalador de Paquetes; les garantizo que funciona muy bien en windows (ya lo probe, en algunos lugares me toca trabajar con windows). En sistemas operativos Linux basados en Debian basta con el comando:

$ sudo apt-get install build-essential python-dev python-smbus python-pip

Listo ahora que ya tenemos python y pip (ya sea en windows o en linux) podemos correr el siguiente comando para instalar las librerias de python que vamos a necesitar:

pip install telepot httplib2 html2text

Con lo anterior ya tenemos listo todo para poder hacer un archivo de python que se conecte a telegram, sin embargo antes de conectarnos a telegram vamos a definir las funciones que permiten conectarse a las apis de Chuck Norris y de Trivia Number. Para que no se pierdad (como lo hice yo cuando estaba tratando de entender el lenguaje) en python no existen corchetes ni, puntos y comas al final de cada linea, el lenguaje consiste en escribir una linea de codigo, y si las lineas siguientes pertenecen a una estructura de control de flujo (condiciones, ciclos o casos), se utiliza un sistema de sangrias, que pueden ser espacios o tabulaciones, en lo personal prefiero las tabulaciones, les dejo el ejemplo de las funciones:

import httplib2
import json
import html2text

# Función que consigue bromas de Chuck Norris de Internet. Utiliza un HTTP GET y luego un analizador JSON
def getChuckNorrisQuote():
    # La base de datos donde se almacenan las bromas
    ICNDB="http://api.icndb.com/jokes/random"
    # Realizar una solicitud HTTP para obtener la respuesta (resp) y el contenido (content)
    resp, content = httplib2.Http().request(ICNDB)
    # El contenido está en el siguiente formato JSON y necesita ser analizado:
    # {u'type': u'success', u'value' : {u'joke': 'Texto del chiste', u'id': 238, u'categories': []}}
    parsed_content = json.loads(content)
    joke = "\n\n** Chiste Random de Chuck Norris **:\n" + html2text.html2text(parsed_content['value']['joke'])
    return joke
    

# Función que obtiene un número trivial de Internet. Utiliza un HTTP GET y luego un analizador JSON
def getNumberTrivia():
    # La base de datos donde se almacenan las trivia
    NUMDB="http://numbersapi.com/random/trivia?json"
    # Realizar una solicitud HTTP para obtener la respuesta (resp) y el contenido (content)
    resp, content = httplib2.Http().request(NUMDB)
    # El contenido está en el siguiente formato JSON y necesita ser analizado:
    # {u'text': u'Texto de la trivia', u'type' : u'trivia, u'number': , u'found': True}
    parsed_content = json.loads(content)
    trivia = "\n\n** Curiosidad del Numero " + str(parsed_content['number']) + " **\n"
    trivia = trivia + parsed_content['text']
    return trivia

Explicando un poco el codigo anterior: las primeras tres lineas importan a nuestro programa las clases necesarias para poder ejecutar nuestras funciones, en las lineas "def" estamos declarando la funcion al final se colocan dos puntos ":" para decirle al codigo que lo que sigue acontinuacion se ejecutara cuando se llame la funcion correspondiente, por ello las siguientes lineas van tabuladas a la derecha.

Ahora ya que tenemos las funciones necesarias vamos a hacer una funcion que se encargara de contestar los chats de nuestro BOT utilizando las funciones anteriores, el resultado final seria:

# coding=utf8
import time
import telepot
import httplib2
import json
import html2text
from telepot.loop import MessageLoop

#Variables Globales
BOTKEY = "419578624:AAGahgdR-3zKRmCBw-HKgLrQlC5UyKMQSlQ" #aqui debe ir la llave generada por el botfather
bot = telepot.Bot(BOTKEY)

# Función que consigue bromas de Chuck Norris de Internet. Utiliza un HTTP GET y luego un analizador JSON
def getChuckNorrisQuote():
    # La base de datos donde se almacenan las bromas
    ICNDB="http://api.icndb.com/jokes/random"
    # Realizar una solicitud HTTP para obtener la respuesta (resp) y el contenido (content)
    resp, content = httplib2.Http().request(ICNDB)
    # El contenido está en el siguiente formato JSON y necesita ser analizado:
    # {u'type': u'success', u'value' : {u'joke': 'Texto del chiste', u'id': 238, u'categories': []}}
    parsed_content = json.loads(content)
    joke = "\n\n** Chiste Random de Chuck Norris **:\n" + html2text.html2text(parsed_content['value']['joke'])
    return joke
    

# Función que obtiene un número trivial de Internet. Utiliza un HTTP GET y luego un analizador JSON
def getNumberTrivia():
    # La base de datos donde se almacenan las trivia
    NUMDB="http://numbersapi.com/random/trivia?json"
    # Realizar una solicitud HTTP para obtener la respuesta (resp) y el contenido (content)
    resp, content = httplib2.Http().request(NUMDB)
    # El contenido está en el siguiente formato JSON y necesita ser analizado:
    # {u'text': u'Texto de la trivia', u'type' : u'trivia, u'number': , u'found': True}
    parsed_content = json.loads(content)
    trivia = "\n\n** Curiosidad del Numero " + str(parsed_content['number']) + " **\n"
    trivia = trivia + parsed_content['text']
    return trivia

def botSupervisor(msg):
	content_type, chat_type, chat_id = telepot.glance(msg)
	#Este es un comentario
	if content_type == 'text':
		MENSAJE = msg['text']
		
		if MENSAJE == "/start":
			bot.sendMessage(chat_id, "Bienvenido a Joker 504 Bot utiliza los siguientes comandos: \n/chucknorris\n/numbertrivia")	
		elif MENSAJE == "/chucknorris":
			#llamamos la funcion  getChuckNorrisQuote() y almacenamos el chiste en la variable joke:
			joke = getChuckNorrisQuote();
			#Enviamos el valor de la variable joke por medio de mensaje
			bot.sendMessage(chat_id, joke)
		elif MENSAJE == "/numbertrivia":
			#llamamos la funcion  getNumberTrivia() y almacenamos el chiste en la variable joke:
			trivia = getNumberTrivia();
			#Enviamos el valor de la variable trivia por medio de mensaje
			bot.sendMessage(chat_id, trivia)
		else:
			bot.sendMessage(chat_id, "No entiendo lo que pides")

#Programa principal
try:
	MessageLoop(bot, botSupervisor).run_as_thread()
	
	while True:
		time.sleep(10)

except KeyboardInterrupt:
	print "Proceso cancelado por el Usuario"

except SystemExit:
	print "Error al iniciar el proceso" 

Expliquemos un poco lo anterior, comencemos con las primeras lineas:

# coding=utf8
import time
import telepot
import httplib2
import json
import html2text
from telepot.loop import MessageLoop

Estas las primeras lineas nos sirven, como mencione anteriormente, para llamar los objetos necesarios para que nuestro programa funcione, en el caso del from telepot.loop import MessageLoop estoy refiriendo un objeto especifico que se encuentra desntro de la libreria telepot.loop, este objeto MessageLoop nos ayudara a crear un ciclo infinito que va estar revisando constantemente lo que las personas escriban al chat; ahora las lineas de las variables:

#Variables Globales
BOTKEY = "419578624:AAGahgdR-3zKRmCBw-HKgLrQlC5UyKMQSlQ" #aqui debe ir la llave generada por el botfather
bot = telepot.Bot(BOTKEY)

La variable BOTKEY tendra llave con la que nos conectamos a nuestro BOT y la variable bot sera la variable encargada de crear el ciclo infinito que mencione anteriormente; las siguientes lineas corresponden a las funciones getChuckNorrisQuote() y getNumberTrivia() que se encargaran de hacer las solicitudes de los chistes y trivias; posterior a esto llegamos a la funcion botSupervisor(msg) esta funcion sera la que se ejecutara de forma infinita hasta que nosotros cancelemos el programa con la combinacion Ctrl+C:

def botSupervisor(msg):
	content_type, chat_type, chat_id = telepot.glance(msg)
	#Este es un comentario
	if content_type == 'text':
		MENSAJE = msg['text']
		
		if MENSAJE == "/start":
			bot.sendMessage(chat_id, "Bienvenido a Joker 504 Bot utiliza los siguientes comandos: \n/chucknorris\n/numbertrivia")	
		elif MENSAJE == "/chucknorris":
			#llamamos la funcion  getChuckNorrisQuote() y almacenamos el chiste en la variable joke:
			joke = getChuckNorrisQuote();
			#Enviamos el valor de la variable joke por medio de mensaje
			bot.sendMessage(chat_id, joke)
		elif MENSAJE == "/numbertrivia":
			#llamamos la funcion  getNumberTrivia() y almacenamos el chiste en la variable joke:
			trivia = getNumberTrivia();
			#Enviamos el valor de la variable trivia por medio de mensaje
			bot.sendMessage(chat_id, trivia)
		else:
			bot.sendMessage(chat_id, "No entiendo lo que pides")

La funcion trabaja con las siguientes variables:

  • msg: Es declarada como parametro de la funcion, es el mensaje que recibe el Bot cuando un usuario le escribe.
  • content_type: define que tipo de mensaje es, si el mensaje solamente es texto esta variable es igual a "text" sin embargo pueden llegar stikers o emojis.
  • chat_type: define si el chat es privado o si es un grupo; esta variable no la usamos pero la funcion telepot.glance la envia.
  • chat_id: Es el numero identificador que se vincula a un chat especifico, cuando contestamos, le decimos que le conteste al mismo chat que escribio.

Las siguientes instrucciones definen que para proseguir se requiere que el mensaje sea unicamente texto: if content_type == 'text':

lo siguiente sera Evaluar el texto enviado, para ello tenemos la condicion que evalua si es /start, /chucknorris, /numbertrivia o cualquer otro texto lo descartamos en el else:

		else:
			bot.sendMessage(chat_id, "No entiendo lo que pides")

la funcion bot.sendMessage se encarga de enviar el texto al usuario que tenga un chat_id especifico.

Por ultimo necesitmos ejecutar la funcion anterior por medio del loop infinito, para ello creamos un try (intento) que ejecutara la funcion botSupervisor(msg) de manera infinita hasta que se cancele el programa o el programa genere un error:
 

#Programa principal
try:
	MessageLoop(bot, botSupervisor).run_as_thread()
	
	while True:
		time.sleep(10)

except KeyboardInterrupt:
	print "Proceso cancelado por el Usuario"

except SystemExit:
	print "Error al iniciar el proceso" 

Para ejecutarlo se guarda el archivo, yo lo nombre joker504bot.py y lo ejecutamos en la termina, con esto, estamos listos para probarlo desde nuestro telefono:

$ python joker504bot.py

Como les mencione anteriormente, la idea de aprender esto es combinar este conocimiento con el Script del alimentador de Mascotas para que ahora este funcione por medio de comandos de un ChatBot, espero mi proximo articulo trate sobre este cambio.

Si te Gusto compartelo:

Comentar

Debes ingresar para poder comentar, accede AQUI. Registrate AQUI

Comentarios