
Hola Habr! Permítanme presentarme: mi nombre es Sergey Agaltsov y soy un "programador de vida". Esto significa que durante mucho tiempo he sido gerente de TI, y en absoluto un programador de profesión, pero uso la programación todo el tiempo, tanto en mi actividad principal como en mi afición. Como solía decir uno de mis antiguos jefes: "¡Seryoga! ¡Te has vuelto a meter en la programación!" Es cierto, no puedo decir que él o alguien más haya estado muy insatisfecho con esto.
Después de la aparición de la API de Bot en el mensajero TamTam, yo, como programador verdadero y, por lo tanto, perezoso, creé 2 bibliotecas de Python para trabajar con él:
- API de cliente abierto (en lo sucesivo, OAC): inicialmente lo generó utilizando el generador OpenAPI basado en el esquema API, luego lo adaptó teniendo en cuenta las características del generador;
- el shell para este cliente es TamTamBot (en adelante, TTB), que simplifica el trabajo con OAC.
Entonces había un cierto SDK de TamTam Python.
Primero hice esto "para mí, para el alma", pero también sugerí que la comunidad de TamTam, si lo desea, lo use. Pero, como saben, ni una sola buena acción queda sin castigo: a las personas se les pidió que escribieran un artículo de capacitación. Y aquí estoy con este artículo. En él, te diré cómo desarrollar un bot simple usando estas bibliotecas.
Desafío
Desarrolle un bot diseñado para simplificar las acciones de los desarrolladores de bot. El bot debería funcionar en el modo de sondeo permanente del estado bot-api (sondeo largo). En este artículo, el bot será entrenado para mostrar el interior del mensaje que se le envió, y también configurado para que coincida con la funcionalidad desarrollada.
Se entiende que el lector ha instalado Python 3 , git , conectado al entorno de desarrollo PyCharm (el entorno de desarrollo puede ser diferente, pero la historia se basará en PyCharm). Comprender los conceptos básicos de OOP es deseable.
Obtener un token bot
El token se obtiene a través de una llamada al bot especializado @PrimeBot
Encontramos este bot en TamTam, ingresamos el comando / create y respondemos las preguntas:
- Ingrese el nombre corto único del bot en letras latinas: este es el nombre de usuario del bot por el cual estará disponible a través de @ o mediante un enlace del formulario
https://tt.me/username
. No hay restricciones especiales en el nombre de usuario. En particular, la palabra bot es opcional. - Ingrese un nombre: este es el nombre para mostrar del bot. Aquí ya puedes usar el alfabeto cirílico.
Si todo se ingresa correctamente, el bot creado se agregará a los contactos y, a cambio, recibiremos un token, una secuencia de caracteres de la forma: HDyDvomx6TfsXkgwfFCUY410fv-vbf4XVjr8JVSUu4c.
Configuración inicial
MostrarCrea un directorio:
mkdir ttBotDevHelper
Ve a ella:
cd ttBotDevHelper/
Inicializamos el repositorio git:
git init
Descargue las bibliotecas necesarias, agregándolas como submódulos de git:
git submodule add https://github.com/asvbkr/openapi_client.git openapi_client git submodule add https://github.com/asvbkr/TamTamBot.git TamTamBot
Abrimos el directorio creado en PyCharm (por ejemplo, desde el explorador en el menú contextual "Abrir carpeta como proyecto PyCharm") y creamos un archivo que contendrá nuestro bot - Archivo / Nuevo / Archivo Python. En el cuadro de diálogo que aparece, ingrese el nombre - ttBotDevHelper, y responda positivamente a la pregunta de agregar a git.
Ahora necesitamos crear un entorno virtual para nuestro proyecto.
Para crear un entorno virtual, seleccione Archivo / Configuración y seleccione la subclave Intérprete de proyecto en la pestaña del proyecto. A continuación, a la derecha, haga clic en el ícono de ajustes y seleccione Agregar:

PyCharm ofrecerá su propia opción de alojamiento.

Tiene sentido estar de acuerdo con él.
Después de crear el entorno virtual, se abrirá la pantalla anterior, pero ya contendrá información sobre el entorno creado. En esta pantalla, debe instalar los paquetes necesarios haciendo clic en el icono "+" a la derecha e ingresando los nombres de los paquetes:
Luego agregamos el archivo .gitignore al proyecto, excluyendo los archivos que no son necesarios en git, con los siguientes contenidos:
venv/ .idea/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class *.log *.log.* .env ttb.sqlite3
Agregue una variable de entorno llamada TT_BOT_API_TOKEN
, en la que indicamos el valor del token de nuestro bot recibido de https://tt.me/primebot y reinicie PyCharm.
(!) En lugar de agregar una variable de entorno directamente al entorno del sistema operativo, PyCharm utiliza de manera óptima un archivo .env especial. Su configuración se discutirá a continuación.
Felicitaciones, ahora puede pasar a la parte más interesante: escribir su bot.
Lanzamiento simple de bot
Abra el archivo ttBotDevHelper.py y escriba las primeras líneas:
Aquí creamos nuestra clase de bot basada en la clase TamTamBot.
PyCharm sugiere que la clase BotDevHelper contiene métodos abstractos que deben implementarse. Presione Alt-Intro en el nombre de la clase, seleccione "Implementar métodos abstractos", seleccione todos los métodos (2 de ellos) propuestos por PyCharm y haga clic en Aceptar. Como resultado, se agregarán dos métodos de propiedad vacía: token y descripción. Modificamos el código resultante de la siguiente manera:
La propiedad token
devuelve el token de nuestro bot, cuyo valor se toma de la variable de entorno TT_BOT_API_TOKEN
. La propiedad de description
devuelve una descripción ampliada de nuestro bot, que se mostrará a los usuarios.
El código al final del archivo es necesario para ejecutar nuestro bot en el modo de encuesta de estado.
Observo que la clase base TamTamBot
implica el uso del servidor web django para trabajar en modo de TamTamBot
web. Pero ahora la tarea es más simple y no necesitamos django, que es lo que informamos en la línea set_use_django(False)
. Aquí, se llama al método polling()
para el objeto de nuestra clase, que asegura la operación en el modo requerido.
El mínimo necesario está hecho. Este código ya está funcionando bastante. Ejecútalo para correr. Para hacer esto, presione la combinación de teclas Ctrl-Shift-F10.
Si no agregó una variable de entorno anteriormente, directamente al sistema operativo, se producirá un error con el mensaje "No access_token" al inicio. Para solucionarlo, configure PyCharm para usar el archivo .env.
Muestra comoCrea un archivo de texto .env. Su contenido en nuestro caso debe ser el siguiente:
TT_BOT_API_TOKEN=__
Ahora necesita conectarlo a la configuración de inicio en PyCharm:
Seleccionamos Ejecutar / Editar configuración y en la pestaña EnvFile conectamos nuestro archivo .env:

Luego haga clic en Aplicar.
Después de iniciar el bot, puede ir a TamTam, abrir un diálogo con nuestro bot y hacer clic en el botón "Inicio". El bot reportará información sobre sus superpoderes ocultos. Esto significa que el bot está funcionando. Mientras el bot funciona en modo de demostración, en el que hay 4 comandos disponibles. Solo échales un vistazo.
A pesar de la pronunciada opinión del bot sobre su frialdad, insinúa tímidamente el hecho de que hasta ahora no puede hacer nada. Enseñarle todo lo necesario para la conquista del mundo es nuestra tarea.
Recibir un mensaje fuente y enviar un mensaje de respuesta con una representación interna del mensaje fuente
Bloquearemos el método receive_text()
, cuyo control se transfiere al enviar texto al chat con el bot:
def receive_text(self, update): res = self.msg.send_message(NewMessageBody(f' : {update.message}', link=update.link), user_id=update.user_id) return bool(res)
El objeto de update
de la clase UpdateCmn
, que se pasa a este método, contiene información útil y, en particular, todo lo que ahora necesitamos:
update.message
: un objeto que contiene el mensaje en sí;update.link
: enlace de respuesta listo para este mensaje;update.user_id
: identificador del usuario que envió el mensaje.
Para enviar un mensaje desde el bot, utilizamos la variable self.msg
, que contiene el objeto MessagesApi
que implementa la funcionalidad descrita en la sección de mensajes de la descripción de la API . Este objeto contiene el método send_message()
que send_message()
, que proporciona el envío de mensajes. Como mínimo, este método debe pasar un objeto de la clase NewMessageBody
y el destino, la ID de usuario, en nuestro caso.
A su vez, un objeto de la clase NewMessageBody
en este caso se crea transmitiendo una representación textual del objeto del mensaje fuente y un enlace de respuesta al mensaje fuente.
Reiniciamos nuestro bot y verificamos en un diálogo con el bot que el bot genera una respuesta a cualquiera de nuestros mensajes que contienen la representación interna del objeto del mensaje fuente.
El código fuente de este estado está aquí .
Agregar un nuevo comando bot con un parámetro: muestra la representación interna del mensaje por su identificador
Al desarrollar bots, a menudo se requiere mirar la representación interna de un mensaje utilizando uno o más identificadores de mensaje conocidos (id. De mensaje - mediados). Agregue esta funcionalidad a nuestro bot. Para hacer esto, primero, sacamos en un método separado la funcionalidad de generar información sobre la representación interna de los mensajes:
def view_messages(self, update, list_mid, link=None): res = False msgs = self.msg.get_messages(message_ids=list_mid) if msgs: for msg in msgs.messages: r = self.msg.send_message(NewMessageBody(f' {msg.body.mid}:\n`{msg}`'[:NewMessageBody.MAX_BODY_LENGTH], link=link), user_id=update.user_id) res = res or r return res
En este método, pasamos una lista de mid.
Para obtener objetos de mensaje, utilizamos el método self.msg.get_messages
, que devuelve una lista de objetos en la propiedad de mensajes.
Además, una representación textual de cada uno de los mensajes recibidos se envía a nuestro diálogo en mensajes separados. Para evitar errores, el texto del mensaje generado se trunca por la constante de la longitud máxima del mensaje: NewMessageBody.MAX_BODY_LENGTH
.
Luego agregue un método que procese el comando. Llamémoslo vmp . Puede pasar la lista intermedia al comando con un espacio.
TTB está diseñado para que el controlador de comandos se cree como un método con el nombre cmd_handler_%s
, donde% s es el nombre del comando. Es decir para el comando vmp, el método se llamará cmd_handler_vmp
. Un objeto de la clase UpdateCmn
se pasa al controlador de comandos. Además, para un comando, puede contener la propiedad cmd_args
, que contiene un diccionario de líneas y palabras que se ingresaron con el comando
El código se verá así:
def cmd_handler_vmp(self, update): res = None if not update.this_cmd_response:
Reiniciamos el bot. Ahora, si escribe un comando en el diálogo del bot como: /vmp mid1 mid2
(puede tomar sus comprobaciones previas mid), a cambio obtenemos dos mensajes con una representación interna de los objetos de mensaje de origen, para cada uno de los mid transmitidos.
El código fuente de este estado está aquí .
Modificación de un comando bot para trabajar con una respuesta de texto
También puede intentar reenviar el mensaje desde otro canal / chat. Pero en este caso, solo se mostrará lo que está contenido en el mensaje fuente en diálogo con el bot. En particular, al enviar un mensaje, la información del botón no se guarda.
Pero, ¿qué pasa si queremos ver información sobre el mensaje original? En este caso, debe tomar la mitad del mensaje reenviado.
Para implementar este modo, modificamos el comando vmp para que cuando se llame sin parámetros, espere que se reenvíe el mensaje, y luego toma la mitad del mensaje enviado y muestra información al respecto.
(!) Para el funcionamiento correcto de esta funcionalidad, el bot debe tener permiso para leer desde el canal / fuente de chat.
Modificamos el código de comando de la siguiente manera:
def cmd_handler_vmp(self, update): res = None if not update.this_cmd_response:
Y desde con este enfoque, el riesgo aumenta debido a la falta de acceso a los mensajes, luego en el método view_messages()
agregamos una verificación para verificar el cumplimiento del número de mensajes solicitados / recibidos:
def view_messages(self, update, list_mid, link=None): res = False msgs = self.msg.get_messages(message_ids=list_mid) if msgs:
Reiniciamos el bot, le damos el comando / vmp, y después de que se muestra el mensaje sobre la necesidad de reenviar, reenviamos el mensaje desde el canal / chat. Si el bot tiene los derechos para leer mensajes en este canal / chat, se mostrará una representación textual del objeto de mensaje reenviado. Si no hay acceso, el bot informará de un posible problema y esperará el reenvío desde la fuente correcta.
Establecer propiedades de bot
Ahora queda por aportar brillo. Cerremos la propiedad about
, que devuelve el texto que muestra el bot cuando comienza a funcionar, así como el comando / start.
@property def about(self): return ' .'
Bloquearemos el método get_commands()
, que devuelve la lista de comandos de nuestro bot, que aparece en el diálogo con el bot.
def get_commands(self):
Desactivemos la propiedad main_menu_buttons, que devuelve la lista de botones en el menú principal, llamada por el comando / menu.
def main_menu_buttons(self):
Reiniciamos el bot, nos aseguramos de que todo esté en orden. Felicitaciones, tu primer bot fue creado y, a pesar de algunos juguetes, ha exigido bastante funcionalidad.
El código fuente de este estado está aquí .
El trabajo @devhelpbot bot se puede ver aquí .
Eso es todo por ahora. Si el tema es de interés, en los siguientes artículos puedo considerar el desarrollo posterior del bot. Por ejemplo, agregar botones personalizados (en particular, Sí / No) y procesarlos, enviar varios tipos de contenido (archivos, fotos, etc.), trabajar en modo webhook, etc.
Por cierto, puedes hacer preguntas rápidamente en un chat especial . Sugerencias directas / ideas allí.