1

Cómo programar un chatbot para Telegram en Python

 

Saludos, humano. Hace algunos años, mantener una conversación verosímil con un robot parecía sólo posible en las películas y libros de ciencia ficción. Pero a día de hoy los chatbots (bots capaces de mantener conversaciones por chat con humanos) están de moda: los encontramos en asistencia al cliente, en webs de noticias, ayudando a los internautas de Stackoverflow

Hacer un chatbot que imite al ser humano es una faena difícil, pues se necesita dominar técnicas avanzadas de Procesamiento de Lenguaje Natural. Sin embargo, programar un chatbot que interprete frases muy simples puede conseguirse sin esfuerzo en unos pocos minutos. Y esto es justamente lo que hoy vas a aprender.


Telegram

Telegram es una aplicación de mensajería instantánea gratuita que presta especial atención a la velocidad y a la seguridad de sus mensajes.

El aspecto que nos interesa de Telegram son las herramientas que proporciona para crear y controlar chatbots. Telegram facilita mucho la tarea de comunicarse con la lógica del chatbot (el programa que hace de “cerebro”) y ofrece una API excelente para controlar todos los aspectos del bot.

Te recomiendo que antes de continuar descargues la versión de telegram para PC. No es obligatorio, pero te será más práctico para hablar con tu chatbot.


1. Contactar con Botfather

Botfather es el Chatbot oficial de Telegram para crear nuevos chatbots (lo cuál es bastante irónico). Escribiéndole unos pocos comandos, Botfather va a crear tu nuevo chatbot y te dará una clave única para que puedas controlarlo.

Empieza por iniciar una conversación con Botfather visitando este link. Tanto si estás en el móvil como en el PC, se ejecutará la aplicación de Telegram y se abrirá un chat con Botfather.

Pulsa el botón “Start” o escribe /start para iniciar la conversación con el chatbot. Recibirás como respuesta un mensaje que contiene todos los comandos básicos para configurar tu chatbot.

 

Puedes crear un nuevo chatbot escribiendo el comando /newbot. Te pedirá un nombre para tu chatbot: este nombre es el que verá la gente cuándo hable con él.

 

Como soy muy aficionado a las buenas novelas de ciencia ficción, he decidido ponerle el nombre de cierto robot asimoviano. Pero tú puedes bautizarlo con cualquier otro nombre que te guste.

 

Una vez hayas enviado el nombre de tu chatbot, Botfather te pedirá un nombre de usuario. Este es el nombre con que se identifica tu bot dentro de los servidores de Telegram, y tiene que acabar forzosamente en “bot”. Por ejemplo “TutorialGiskard_bot” o “GiskardRobot”.

 

Si el nombre de usuario introducido está libre, el chatbot se habrá creado con éxito y Botfather responderá con un mensaje así:

Enhorabuena, acabas de ser padre/madre

Este mensaje contiene dos puntos muy importantes:

  • El link para iniciar una conversación de Telegram con tu chatbot. En mi caso, el link es ‘t.me/TutorialGiskard_bot’.
  • El Token de acceso (en la imagen, es la clave que está en gris oscuro). Este es el código que necesitarás para acceder a tu chatbot y controlarlo. Copia el Token y guárdalo en un lugar seguro.

Bien, tu bot acaba de nacer. Pero si abres el link e inicias una conversación con el bot, verás que no responde. Esto es porque carece de cerebro: no has implementado ninguna lógica y por tanto es incapaz de procesar los mensajes que recibe.

Parece ser que el señor Giskard no es muy hablador

2. Comunicación con el bot

El chatbot se controla enviando peticiones HTTPS al servidor de Telegram, y para hacerlo no se necesitas escribir ningún programa en Python u otro lenguaje: es suficiente con abrir tu navegador web.

Cuándo te conectas a una página web escribiendo su URL en tu navegador, en realidad estás haciendo una petición HTTPS a un servidor (normalmente, para que te envíe la información necesaria para mostrar la página). Del mismo modo, uno se puede comunicar con el chatbot escribiendo la URL correcta en la barra del navegador.

La dirección URL de tu bot es:

https://api.telegram.org/bot<Token>/

(Sustituye “<Token>” por el código que te ha dado Botfather)

Para enviar una instrucción al bot hay que escribir el método que quiere llamarse al final de la URL. La Bot API de Telegram tiene una lista detallada de todos los comandos y métodos. Por ejemplo, para ver los mensajes que ha recibido el chatbot hay que llamar al método getUpdates:

https://api.telegram.org/bot<Token>/getUpdates

Aparecerá una página con todos los mensajes recibidos durante las últimas 24h. Estos mensajes llegan como un string JSON (parecido a un diccionario de python) y tu navegador se encarga de mostrarlo de forma ordenada:

Como puedes ver, el método getUpdates nos da toda la información de cada uno de los mensajes: nombre del remitente, su idioma, su identificador, fecha de envío…

Un dato muy importante es el identificador del chat. Cada vez que un usuario añade el chatbot a sus contactos de Telegram y le envía el mensaje /start, se crea un nuevo chat con un identificador único. En la imagen puedes ver que el chat que tengo abierto con el bot tiene el identificador 847428751.

Para hacer que el chatbot envíe una respuesta a un usuario en concreto, tienes que llamar al método sendMessage y pasarle como parámetros el texto y el identificador:

https://api.telegram.org/bot<Token>/sendMessage?text=Hola!&chat_id=<Chat_id>

(Cambia “<Token>” por tu código y “<Chat_id>” por el identificador del chat)

Al introducir la URL recibirás un mensaje diciendo “Hola!”

3. Programar la lógica

Creo que estaremos de acuerdo en que escribir una URL en el navegador cada vez que quieres procesar un mensaje no es precisamente la mejor forma de construir un chatbot. Además, estos bots se supone que deben funcionar solos, sin intervención humana…

Por tanto hay que escribir un programa que automatice la tarea de conectarse con el chatbot y leer/enviar mensajes. En esencia este programa hará lo mismo que has hecho hasta ahora: hacer peticiones HTTPS a una URL determinada. Pero ahora lo harás a través de un script en python y no con el navegador.

Para programar la lógica necesitarás dos librerías:

  • Requests, para gestionar las peticiones HTTPS al servidor de Telegram y poder leer/enviar mensajes. Si tienes Python 3 ya debería venir instalada.
  • Json, para codificar/descodificar datos en el estándar JSON. Esta librería ya viene por defecto con todas las versiones de Python.

Voy a poner varios códigos de ejemplo para que veas como leer, procesar y enviar mensajes.

Código 1 – Leer un mensaje

El primer programa hará una petición HTTPS al servidor para recoger todos los mensajes que hay almacenados y extraerá el texto, nombre del autor e id del último mensaje recibido. Acuérdate de cambiar el token que hay escrito por el de tu chatbot.

(Nota: para hacer las primeras pruebas envia sólo mensajes de texto a tu chatbot. De momento nada de Stickers, GIFS o imágenes)

"""
	Ejemplo 1 - Este programa escribe por Terminal el contenido del ultimo mensaje
		    que ha recibido el chatbot junto con el nombre del autor y la ID del chat.

	Escrito por Transductor
	www.robologs.net
"""

#Importar librerias
import json 
import requests

#Variables para el Token y la URL del chatbot
TOKEN = "751988420:AAHrzn7RXWxVQQNha0tQUzyouE5lUcPde1g" #Cambialo por tu token
URL = "https://api.telegram.org/bot" + TOKEN + "/"



def update():
	#Llamar al metodo getUpdates del bot haciendo una peticion HTTPS (se obtiene una respuesta codificada)
	respuesta = requests.get(URL + "getUpdates")

	#Decodificar la respuesta recibida a formato UTF8 (se obtiene un string JSON)
	mensajes_js = respuesta.content.decode("utf8")

	#Convertir el string de JSON a un diccionario de Python
	mensajes_diccionario = json.loads(mensajes_js)

	#Devolver este diccionario
	return mensajes_diccionario


def leer_mensaje():

	#Llamar update() y guardar el diccionario con los mensajes recientes
	mensajes = update()

	#Calcular el indice del ultimo mensaje recibido
	indice = len(mensajes["result"])-1

	#Extraer el texto, nombre de la persona e id del último mensaje recibido
	texto = mensajes["result"][indice]["message"]["text"]
	persona = mensajes["result"][indice]["message"]["from"]["first_name"]
	id_chat = mensajes["result"][indice]["message"]["chat"]["id"]

	#Mostrar esta informacion por pantalla
	print(persona + " (id: " + str(id_chat) + ") ha escrito: " + texto)


#Llamar a la funcion "leer_mensaje()"
leer_mensaje()

Este código tiene dos funciones principales:

  • La función update() llama al método getUpdates del chatbot y convierte el string Json recibido a un diccionario de python, mucho más fácil de manipular.
  • La función leer_mensaje() llama a la función update() para guardar todos los mensajes, y se queda con el nombre, identificador y contenido del último mensaje recibido.

Me gustaría clarificar la parte dónde se extrae el texto, nombre e id del mensaje:

texto = mensajes["result"][indice]["message"]["text"]
persona = mensajes["result"][indice]["message"]["from"]["first_name"]
id_chat = mensajes["result"][indice]["message"]["chat"]["id"]

El objeto ‘mensajes’ es un diccionario. Cada clave (“result”, “message”, “id”…) se corresponde con algún tipo de dato: un entero, vector, objeto… Accediendo a la clave se puede extraer el dato correspondiente.

    • [“result”] permite acceder a todos los resultados de la petición HTTPS (i.e. todos los mensajes que se han bajado).
    • El índice sirve para iterar y elegir con cuál de los mensajes quieres quedarte, cómo si se tratase de un vector. Tal y como se ha programado el script, la variable indice es la longitud del vector de resultados. Pero se podría poner un número entero: 0 para acceder al primer mensaje, 1 para acceder al segundo, etc.
    • [“message”] permite acceder a la información del mensaje en sí: fecha de envío, nombre del receptor y destinatario, id del mensaje…
    • Etc.

En la API de Telegram, bajo el apartado “Available Types”, puedes encontrar listadas cada una de las claves y lo que contienen.


Código 2 – Generar una respuesta

A partir de la información del mensaje recibido es posible generar una respuesta y enviarla al bot utilizando el método sendMessage, tal y como has hecho antes con el navegador.

"""
	Ejemplo 2 - Este segundo programa genera una respuesta si se recibe un mensaje con
		    las palabras "Hola" o "Adios"

	Escrito por Transductor
	www.robologs.net
"""

#Importar librerias
import json 
import requests

#Variables para el Token y la URL del chatbot
TOKEN = "751988420:AAHrzn7RXWxVQQNha0tQUzyouE5lUcPde1g" #Cambialo por tu token
URL = "https://api.telegram.org/bot" + TOKEN + "/"



def update():
	#Llamar al metodo getUpdates del bot
	respuesta = requests.get(URL + "getUpdates")

	#Decodificar la respuesta recibida a formato UTF8
	mensajes_js = respuesta.content.decode("utf8")

	#Convertir el string de JSON a un diccionario de Python
	mensajes_diccionario = json.loads(mensajes_js)

	#Devolver este diccionario
	return mensajes_diccionario


def leer_mensaje():

	#Guardar el diccionario con todos los mensajes recientes
	mensajes = update()

	#Calcular el indice del ultimo mensaje recibido
	indice = len(mensajes["result"])-1

	#Extraer el texto, nombre de la persona e id del último mensaje recibido
	texto = mensajes["result"][indice]["message"]["text"]
	persona = mensajes["result"][indice]["message"]["from"]["first_name"]
	id_chat = mensajes["result"][indice]["message"]["chat"]["id"]

	#Devolver la id, nombre y texto del mensaje
	return id_chat, persona, texto

def enviar_mensaje(idchat, texto):
	#Llamar el metodo sendMessage del bot, passando el texto y la id del chat
	requests.get(URL + "sendMessage?text=" + texto + "&amp;amp;chat_id=" + str(idchat))


#Llamar a la funcion "leer_mensaje()"
idchat, nombre, texto = leer_mensaje()

#Generar una respuesta a partir de la informacion del mensaje
if "Hola" in texto:
	texto_respuesta = "Hola, " + nombre + "!"
	enviar_mensaje(idchat, texto_respuesta)
elif "Adios" in texto:
	texto_respuesta = "Hasta pronto!"
	enviar_mensaje(idchat, texto_respuesta)

Como puedes ver, en este segundo código tan sólo se ha modificado la función leer_mensaje() para que devuelva la información del último mensaje. También se ha añadido una nueva función enviar_mensaje() que se encarga de hacer la petición HTTPS para enviar el mensaje al chatbot.

Código 3 – Offset

Ahora mismo el chatbot tiene dos problemas importantes.

El primero es que sólo funciona durante un instante al ejecutar el programa en python. El bot lee el último mensaje, lo contesta y sale del programa. Aparentemente esto podría solucionarse con un bucle infinito, pero en realidad no es tan sencillo. Amplia el Código 2 con este bucle y verás que el chatbot repite la misma respuesta infinitamente:

while(True):
	#Llamar a la funcion "leer_mensaje()"
	idchat, nombre, texto = leer_mensaje()

	#Generar una respuesta a partir de la informacion del mensaje
	if "Hola" in texto:
		texto_respuesta = "Hola, " + nombre + "!"
		enviar_mensaje(idchat, texto_respuesta)
	elif "Adios" in texto:
		texto_respuesta = "Hasta pronto!"
		enviar_mensaje(idchat, texto_respuesta)

Giskard saludando efusivamente

Esto ocurre porque el chatbot no tiene ninguna forma de saber qué mensajes ha contestado y cuáles no.

El segundo problema que tiene el chatbot es que al llamar a la función update(), el servidor envía como respuesta todos los mensajes que se han recibido en las últimas 24 horas, hayan sido contestados o no. Esto es muy ineficiente y podría llegar a colapsar el chatbot si se reciben muchos mensajes.

Entonces, ¿existe alguna forma de saber qué mensajes han sido contestados, y decirle a Telegram que sólo envíe aquéllos que todavía no han recibido respuesta?

El truco está en que cada mensaje tiene un identificador único y exclusivo para él. Éste identificador es un número entero que va aumentando secuencialmente a medida que se van enviando nuevos mensajes. Al llamar el método getUpdates, puedes añadir un parámetro offset al final de la URL y recibirás sólo los mensajes con id superior a este offset:

https://api.telegram.org/bot<Token>/getUpdates?offset=593963031

(Con esta URL sólo se recibirían los mensajes con ID igual o superior a 593963031)

El carácter ‘?’ en la URL indica el inicio de una lista de parámetros. Si quisieras pasar varios parámetros, tendrías que separarlos con el carácter ‘&’ (ver Código 4).

Habrá que hacer algunas modificaciones importantes respecto al código anterior:

  • La función update() ahora recibirá un parámetro offset, que se corresponderá al identificador del primer mensaje que queremos recibir.
  • La función leer_mensaje() recibirá como parámetro un mensaje y devolverá la id del chat, id del mensaje, el nombre del remitente y el texto.
  • Se ha creado una variable llamada ‘ultima_id’, que almacena la id del último mensaje respondido.
  • En el bucle principal se llama a la función update() para guardar todo el diccionario con los mensajes. Después, se itera este diccionario para generar una respuesta para cada uno de los mensajes y se actualiza la variable ‘ultima_id’ con el máximo de los identificadores de los mensajes procesados.

Parece rebuscado, pero en realidad el código es bastante sencillo:

"""
	Ejemplo 3 - Este tercer programa utiliza un offset para controlar
		    los mensajes se han contestado y los que no.

	Escrito por Transductor
	www.robologs.net
"""

#Importar librerias
import json 
import requests

#Variables para el Token y la URL del chatbot
TOKEN = "751988420:AAHrzn7RXWxVQQNha0tQUzyouE5lUcPde1g" #Cambialo por tu token
URL = "https://api.telegram.org/bot" + TOKEN + "/"



def update(offset):
	#Llamar al metodo getUpdates del bot, utilizando un offset
	respuesta = requests.get(URL + "getUpdates" + "?offset=" + str(offset))
	#Telegram devolvera todos los mensajes con id IGUAL o SUPERIOR al offset


	#Decodificar la respuesta recibida a formato UTF8
	mensajes_js = respuesta.content.decode("utf8")

	#Convertir el string de JSON a un diccionario de Python
	mensajes_diccionario = json.loads(mensajes_js)

	#Devolver este diccionario
	return mensajes_diccionario


def leer_mensaje(mensaje):

	#Extraer el texto, nombre de la persona e id del último mensaje recibido
	texto = mensaje["message"]["text"]
	persona = mensaje["message"]["from"]["first_name"]
	id_chat = mensaje["message"]["chat"]["id"]

	#Calcular el identificador unico del mensaje para calcular el offset
	id_update = mensaje["update_id"]

	#Devolver las dos id, el nombre y el texto del mensaje
	return id_chat, persona, texto, id_update

def enviar_mensaje(idchat, texto):
	#Llamar el metodo sendMessage del bot, passando el texto y la id del chat
	requests.get(URL + "sendMessage?text=" + texto + "&chat_id=" + str(idchat))



#Variable para almacenar la ID del ultimo mensaje procesado
ultima_id = 0

while(True):
	mensajes_diccionario = update(ultima_id)
	for i in mensajes_diccionario["result"]:

		#Llamar a la funcion "leer_mensaje()"
		idchat, nombre, texto, id_update = leer_mensaje(i)

		#Si la ID del mensaje es mayor que el ultimo, se guarda la ID + 1
		if id_update > (ultima_id-1):
			ultima_id = id_update + 1

		#Generar una respuesta a partir de la informacion del mensaje
		if "Hola" in texto:
			texto_respuesta = "Hola, " + nombre + "!"
		elif "Adios" in texto:
			texto_respuesta = "Hasta pronto!"
		else:
			texto_respuesta = "Has escrito: \"" + texto + "\""

		#Enviar la respuesta
		enviar_mensaje(idchat, texto_respuesta)

	#Vaciar el diccionario
	mensajes_diccionario = [] 

Fíjate que no guardamos la id del último mensaje, sino la id + 1. Esto es porque el offset indica el primer mensaje que quieres recibir, por tanto interesa guardar el identificador que venga justo después. Si no, al pasar este identificador a la función update() volverías a recibir mensajes que ya has contestado.

Código 4 – Reducir el número de peticiones

Otro problema que tiene el chatbot es que a cada vuelta del bucle está haciendo una petición HTTPS, y esto es muy ineficiente. Los humanos sóis lentos escribiendo (comparados con una máquina) y como el chatbot se conecta al servidor varias veces por segundo para comprobar si hay nuevos mensajes, la mayoría de las peticiones son vacías porque no hay novedades.

Para no gastar inútilmente recursos tanto de Telegram como de tu máquina, puedes utilizar Long Polling. Al hacer una conexión con el servidor, si no hay mensajes disponibles, la conexión se mantendrá hasta que llegue alguno (o hasta que se agote el tiempo de espera).

Esto se consigue pasando el parámetro timeout a la URL de getUpdates, que indica el tiempo de espera:

https://api.telegram.org/bot<Token>/getUpdates?timeout=200

(Un timeout de 100-200 sería un valor razonable)

En cuánto al programa de python, sólo habrá que cambiar la función update() del programa anterior:

def update(offset):
	#Llamar al metodo getUpdates del bot, utilizando un offset
	respuesta = requests.get(URL + "getUpdates" + "?offset=" + str(offset) + "&timeout=" + str(100))


	#Decodificar la respuesta recibida a formato UTF8
	mensajes_js = respuesta.content.decode("utf8")

	#Convertir el string de JSON a un diccionario de Python
	mensajes_diccionario = json.loads(mensajes_js)

	#Devolver este diccionario
	return mensajes_diccionario

Código 5 – Gifs, Stickers e imágenes

Si en algún momento durante este tutorial (y a pesar de mis recomendaciones en contra) has enviado un sticker o un GIF a tu chatbot, habrás visto que se bloquea. Ahora mismo el script sólo está preparado para procesar texto, y cuándo se envía otro tipo de contenido la clave “text” queda vacía.

En este último programa se ha definido una función info_mensaje(), que comprueba qué tipo de mensaje se ha recibido, y devuelve la información más relevante (nombre e identificadores). La función leer_mensaje() ahora sólo devuelve el texto.

Sabiendo qué tipo de mensaje se ha recibido, es posible generar una respuesta según si es un sticker, fotografía, animación…

"""
	Ejemplo 5 - Este programa comprueba el tipo de mensaje que se ha recibido
	Escrito por Transductor
	www.robologs.net
"""

#Importar librerias
import json 
import requests

#Variables para el Token y la URL del chatbot
TOKEN = "751988420:AAHrzn7RXWxVQQNha0tQUzyouE5lUcPde1g" #Cambialo por tu token
URL = "https://api.telegram.org/bot" + TOKEN + "/"



def update(offset):
	#Llamar al metodo getUpdates del bot, utilizando un offset
	respuesta = requests.get(URL + "getUpdates" + "?offset=" + str(offset) + "&timeout=" + str(100))


	#Decodificar la respuesta recibida a formato UTF8
	mensajes_js = respuesta.content.decode("utf8")

	#Convertir el string de JSON a un diccionario de Python
	mensajes_diccionario = json.loads(mensajes_js)

	#Devolver este diccionario
	return mensajes_diccionario

def info_mensaje(mensaje):

	#Comprobar el tipo de mensaje
	if "text" in mensaje["message"]:
		tipo = "texto"
	elif "sticker" in mensaje["message"]:
		tipo = "sticker"
	elif "animation" in mensaje["message"]:
		tipo = "animacion" #Nota: los GIF cuentan como animaciones
	elif "photo" in mensaje["message"]:
		tipo = "foto"
	else:
		# Para no hacer mas largo este ejemplo, el resto de tipos entran
		# en la categoria "otro"
		tipo = "otro"

	#Recoger la info del mensaje (remitente, id del chat e id del mensaje)
	persona = mensaje["message"]["from"]["first_name"]
	id_chat = mensaje["message"]["chat"]["id"]
	id_update = mensaje["update_id"]

	#Devolver toda la informacion
	return tipo, id_chat, persona, id_update

def leer_mensaje(mensaje):

	#Extraer el texto, nombre de la persona e id del último mensaje recibido
	texto = mensaje["message"]["text"]

	#Devolver las dos id, el nombre y el texto del mensaje
	return texto

def enviar_mensaje(idchat, texto):
	#Llamar el metodo sendMessage del bot, passando el texto y la id del chat
	requests.get(URL + "sendMessage?text=" + texto + "&chat_id=" + str(idchat))



#Variable para almacenar la ID del ultimo mensaje procesado
ultima_id = 0

while(True):
	mensajes_diccionario = update(ultima_id)
	for i in mensajes_diccionario["result"]:

		#Guardar la informacion del mensaje
		tipo, idchat, nombre, id_update = info_mensaje(i)

		#Generar una respuesta dependiendo del tipo de mensaje
		if tipo == "texto":
			texto = leer_mensaje(i)
			texto_respuesta = "Has escrito: \"" + texto + "\""
		elif tipo == "sticker":
			texto_respuesta = "Bonito sticker!"
		elif tipo == "animacion":
			texto_respuesta = "Me gusta este GIF!"
		elif tipo == "foto":
			texto_respuesta = "Bonita foto!"
		elif tipo == "otro":
			texto_respuesta = "Es otro tipo de mensaje"

		#Si la ID del mensaje es mayor que el ultimo, se guarda la ID + 1
		if id_update > (ultima_id-1):
			ultima_id = id_update + 1

		#Enviar la respuesta
		enviar_mensaje(idchat, texto_respuesta)

	#Vaciar el diccionario
	mensajes_diccionario = [] 

Ahora Giskard puede procesar tanto mensajes de texto como stickers e imágenes


En resumen

Bien, humano, hoy has aprendido a programar tu primer chatbot. En este tutorial he explicado cómo sentar los cimientos de tu robot; dotarlo de capacidad para analizar el lenguaje natural y generar respuestas con sentido es un tema más complicado que daría para otro artículo. Uno mucho más extenso.

Si te interesa este tema, tienes a tu disposición la librería ChatterBot, un motor para hacer chatbots en python que genera respuestas a conversaciones de tipo Chit-Chat (conversaciones banales). Otro día hablaré de esta librería y de cómo hacer un chatbot un poco más inteligente, pero por hoy lo dejamos aquí.

Espero que te haya gustado el artículo, y que hayas aprendido. Por supuesto, si tienes algun problema o hay errores en el tutorial, no dudes en dejarme un comentario.

Final de línea.

 

 

Tr4nsduc7or

Originariamente creado cómo un galvanómetro de bolsillo, Transductor tomó consciencia de si mismo y fue despedido cuando en vez cumplir con su trabajo se dedicó a pensar teorías filosóficas sobre los hilos de cobre, los electrones y el Sentido del efecto Joule en el Universo. Guarda cierto recelo a sus creadores por no comprender la esencia metafísica de las metáforas de su obra. Actualmente trabaja a media jornada cómo antena de radio, y dedica su tiempo libre a la electrónica recreativa y a la filosofía.

1
Deja un comentario

avatar
1 Hilos iniciados
0 Respuestas a hilos
0 Followers
 
Most reacted comment
Hottest comment thread
1 Nº autores comentarios
Jaquina Autores de comentarios recientes
más nuevos primero más antiguos primero
Jaquina
Humano
Jaquina

Gracias por el post!! Útil y explicado claramente!!!