Hola a todos, Marcus aquí de ai7bot.com. Hoy quiero hablar sobre algo que ha estado resonando en mis proyectos de desarrollo personal últimamente: los bots de Telegram. Específicamente, quiero abordar cómo hacer que tu bot de Telegram no sea solo un respondedor, sino un programador. Olvídate de la simple cosa de “hola mundo”; vamos a construir un bot que recuerde cosas por ti y envíe mensajes a horas específicas. Piensa en él como tu asistente digital personal y silencioso, viviendo justo dentro de tus chats de Telegram.
Recuerdo que hace unos meses estaba tratando de coordinar una sesión semanal de D&D con mi grupo. Siempre olvidábamos quién estaba de anfitrión, a qué hora acordamos y qué bocadillos traía cada uno. Intentamos notas compartidas, calendarios, de todo. Pero el común denominador siempre era Telegram. En ese momento me di cuenta: ¿por qué no hacer un bot que simplemente nos recuerde? No solo un recordatorio aislado, sino algo recurrente, algo que se adapte. Esa pequeña frustración me llevó a un túnel de conejos, y lo que encontré fue sorprendentemente fácil de implementar una vez que superas la configuración inicial.
Más Allá de Respuestas Simples: El Poder de los Mensajes Programados
La mayoría de los bots básicos de Telegram son reactivos. Les envías un comando, ellos devuelven una respuesta. Eso es genial para consultas simples, pero no aprovecha realmente todo el potencial de un bot. La verdadera magia sucede cuando tu bot puede ser proactivo: cuando puede iniciar conversaciones, enviar actualizaciones o recordarte algo sin que tú tengas que molestarlo primero. Aquí es donde entran los mensajes programados.
Imagina un bot que:
- Recuerda a tu equipo sobre las reuniones diarias cinco minutos antes de que empiecen.
- Te envía un pronóstico del tiempo personalizado cada mañana a las 7 AM.
- Te notifica sobre plazos importantes para un proyecto.
- Te manda un recordatorio a tu grupo de D&D cada domingo a las 3 PM con un mensaje de “¡sesión empezando pronto!”
Las posibilidades son infinitas. ¿Y la mejor parte? No es tan complicado como podrías pensar. Vamos a utilizar Python, un lenguaje popular para el desarrollo de bots, y un par de bibliotecas confiables.
Lo Que Necesitaremos: Lo Esencial
Antes de entrar en el código, enumeremos nuestras herramientas:
- Python 3: Si no lo tienes, consíguelo. Es la columna vertebral de nuestro bot.
python-telegram-botlibrary: Esta es nuestra interfaz principal con la API de Bots de Telegram. Se encarga de toda la comunicación detallada.APSchedulerlibrary: Esta es la estrella del espectáculo para la programación. Nos permite ejecutar funciones en tiempos o intervalos específicos.
Puedes instalar las bibliotecas de Python usando pip:
pip install python-telegram-bot APScheduler
Y, por supuesto, necesitarás un token de bot de Telegram. Si aún no has creado un bot, dirígete a BotFather en Telegram, envíale /newbot, y sigue las instrucciones. Él te dará un token – ¡mantenlo seguro!
Configurando la Estructura Básica del Bot
Primero, pongamos nuestro bot básico de Telegram en funcionamiento. Esta parte debería ser familiar si has hecho algo de desarrollo de bots antes.
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
# Reemplaza con tu verdadero token de bot de BotFather
BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Envía un mensaje de saludo cuando se emite el comando /start."""
await update.message.reply_text("¡Hola! Soy tu bot de programación. Usa /help para ver lo que puedo hacer.")
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Envía un mensaje de ayuda."""
await update.message.reply_text("Puedo programar mensajes para ti. ¡Intenta /schedule para establecer un recordatorio!")
def main() -> None:
"""Inicia el bot."""
application = Application.builder().token(BOT_TOKEN).build()
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("help", help_command))
print("Bot iniciado y escuchando...")
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
Ejecuta este script, y si envías /start o /help a tu bot, deberías recibir una respuesta. Esta es nuestra base. Ahora, integremos el programador.
Presentando APScheduler: Tu Guardián del Tiempo
APScheduler significa “Programador Avanzado de Python.” Es una biblioteca poderosa que te permite programar funciones de Python para que se ejecuten en momentos, fechas o intervalos específicos. Usaremos su BlockingScheduler, que se ejecuta en el hilo principal de nuestra aplicación.
La idea central es esta: cuando un usuario le dice a nuestro bot que programe algo, almacenaremos esa solicitud y luego utilizaremos APScheduler para agregar un trabajo. Cuando llegue el momento, APScheduler ejecutará una función que envía el mensaje al usuario.
Programando Nuestro Primer Mensaje
Modifiquemos nuestro bot para incluir capacidades de programación. Comenzaremos con un comando simple, /schedule, que tomará un mensaje y una hora (por ejemplo, “en 5 minutos”).
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime, timedelta
import asyncio
# Reemplaza con tu verdadero token de bot
BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
# Inicializa el programador
scheduler = BlockingScheduler()
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Envía un mensaje de saludo."""
await update.message.reply_text("¡Hola! Soy tu bot de programación. Usa /help para ver lo que puedo hacer.")
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Envía un mensaje de ayuda."""
await update.message.reply_text(
"Puedo programar mensajes para ti. Intenta /schedule <minutes> <tu mensaje>.\n"
"Ejemplo: /schedule 5 ¡Recuerda comprar víveres!"
)
async def send_scheduled_message(chat_id: int, message_text: str, application: Application) -> None:
"""Envía el mensaje programado real."""
# Necesitamos obtener la instancia del bot para enviar mensajes fuera de un contexto de Update
await application.bot.send_message(chat_id=chat_id, text=message_text)
print(f"Mensaje programado enviado a {chat_id}: {message_text}")
async def schedule_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Programa un mensaje."""
if not context.args or len(context.args) < 2:
await update.message.reply_text(
"Uso: /schedule <minutes> <tu mensaje>.\n"
"Ejemplo: /schedule 5 ¡Recuerda comprar víveres!"
)
return
try:
minutes = int(context.args[0])
if minutes <= 0:
await update.message.reply_text("Los minutos deben ser un número positivo.")
return
message_to_schedule = " ".join(context.args[1:])
# Calcular el tiempo futuro
run_time = datetime.now() + timedelta(minutes=minutes)
# Agregar el trabajo al programador
# Necesitamos pasar la instancia de la aplicación para que send_scheduled_message pueda acceder a ella
scheduler.add_job(
send_scheduled_message,
'date',
run_date=run_time,
args=[update.effective_chat.id, message_to_schedule, context.application]
)
await update.message.reply_text(
f"¡Está bien, te recordaré en {minutes} minuto(s) a las {run_time.strftime('%H:%M:%S')}!"
)
print(f"Trabajo programado para {update.effective_chat.id} a las {run_time} con el mensaje: {message_to_schedule}")
except ValueError:
await update.message.reply_text("Por favor proporciona un número válido para minutos.")
except Exception as e:
await update.message.reply_text(f"Algo salió mal: {e}")
def main() -> None:
"""Inicia el bot y el programador."""
application = Application.builder().token(BOT_TOKEN).build()
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("help", help_command))
application.add_handler(CommandHandler("schedule", schedule_command))
# Inicia el programador en un hilo o proceso separado si necesitas un comportamiento no bloqueante
# Para simplicidad, lo ejecutaremos en el hilo principal con run_polling.
# El BlockingScheduler de APScheduler bloquea, por lo que necesitamos ejecutarlo de manera concurrente.
# Un patrón común es ejecutar el programador en un hilo separado.
# Comencemos el programador de una manera no bloqueante para uso en producción
# utilizando BackgroundScheduler o poniendo BlockingScheduler en un hilo separado.
# Para este ejemplo, ajustaremos ligeramente cómo se ejecuta main.
# El BlockingScheduler de APScheduler bloqueará el hilo principal.
# Para que funcione con application.run_polling() de python-telegram-bot,
# necesitamos asegurarnos de que el programador se ejecute sin bloquear las actualizaciones del bot.
# Una forma sencilla de hacer esto es usar BackgroundScheduler.
from apscheduler.schedulers.background import BackgroundScheduler
global scheduler # Reinicializa el programador para BackgroundScheduler
scheduler = BackgroundScheduler()
scheduler.start()
print("Bot iniciado y escuchando...")
application.run_polling(allowed_updates=Update.ALL_TYPES)
# Apagar el programador cuando se detiene el bot
scheduler.shutdown()
if __name__ == "__main__":
main()
Una nota rápida sobre BlockingScheduler contra BackgroundScheduler: En mis pruebas iniciales para este artículo, me di cuenta rápidamente de que BlockingScheduler (como su nombre indica) bloquea el hilo principal. Esto significa que tu bot no podría recibir nuevas actualizaciones de Telegram mientras el programador esté en funcionamiento. ¡No es ideal! La solución es usar BackgroundScheduler, que se ejecuta en su propio hilo, permitiendo que tu bot siga siendo receptivo. He actualizado la función main() en el fragmento anterior para reflejar esto.
Ahora, si ejecutas este script actualizado, puedes enviarle a tu bot algo como /schedule 1 ¡Recordatorio de prueba! y después de un minuto, tu bot debería enviarte “¡Recordatorio de prueba!”. ¿Qué tan genial es eso?
Haciendo que sea Más Flexible: Trabajos Recurrentes
Los recordatorios únicos son buenos, pero ¿qué pasa con los eventos recurrentes? APScheduler hace esto increíblemente fácil con sus desencadenadores interval y cron. Añadamos un comando para programar un mensaje cada X minutos.
# ... (importaciones e inicializaciones previas) ...
async def schedule_recurring_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Programa un mensaje recurrente."""
if not context.args or len(context.args) < 2:
await update.message.reply_text(
"Uso: /schedule_every <minutos> <tu mensaje>.\n"
"Ejemplo: /schedule_every 60 ¡Revisión horaria!"
)
return
try:
minutos_intervalo = int(context.args[0])
if minutos_intervalo <= 0:
await update.message.reply_text("Los minutos deben ser un número positivo.")
return
mensaje_a_programar = " ".join(context.args[1:])
chat_id = update.effective_chat.id
# Añadir el trabajo recurrente al programador
job_id = f"recurring_job_{chat_id}_{datetime.now().timestamp()}" # ID único para posible eliminación
scheduler.add_job(
send_scheduled_message,
'interval',
minutes=minutos_intervalo,
args=[chat_id, mensaje_a_programar, context.application],
id=job_id,
replace_existing=True # Opcional: reemplazar si el ID existe
)
await update.message.reply_text(
f"Está bien, te recordaré cada {minutos_intervalo} minuto(s) con: '{mensaje_a_programar}'"
)
print(f"Trabajo recurrente programado '{job_id}' para {chat_id} cada {minutos_intervalo} minutos.")
except ValueError:
await update.message.reply_text("Por favor, proporciona un número válido para los minutos.")
except Exception as e:
await update.message.reply_text(f"Algo salió mal: {e}")
# ... (añade este manejador en la función main() ...)
# application.add_handler(CommandHandler("schedule_every", schedule_recurring_command))
Recuerda añadir el nuevo manejador de comandos en tu función main():
def main() -> None:
# ... manejadores existentes ...
application.add_handler(CommandHandler("schedule_every", schedule_recurring_command))
# ... resto de main() ...
Ahora puedes decirle a tu bot /schedule_every 15 ¡No olvides estirarte! y te recordará puntualmente cada 15 minutos. Aquí es donde el recordatorio de la sesión de D&D realmente me convenció. Podía configurarlo una vez y funcionaría cada semana.
Manejo de Estado y Persistencia (Un Paso Siguiente Necesario)
Ahora mismo, si reinicias tu bot, todos los trabajos programados se pierden. Eso no es ideal para un programador confiable. Para un bot del mundo real, querrías almacenar estos trabajos programados en una base de datos (como SQLite, PostgreSQL o incluso un simple archivo JSON) y recargarlos cuando el bot se inicia. APScheduler tiene soporte incorporado para almacenes de trabajos, lo que hace que esto sea relativamente sencillo.
Para un bot de producción, recomendaría encarecidamente agregar un almacén de trabajos. Aquí tienes un esbozo conceptual de cómo integrarlo con SQLite:
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
# ... (resto de tus importaciones y código) ...
# En tu función main():
def main() -> None:
# ... configuración existente de la aplicación ...
jobstores = {
'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
# Re-inicializar el programador con almacenes de trabajos
global scheduler
scheduler = BackgroundScheduler(jobstores=jobstores)
scheduler.start()
# ... resto de main() ...
Cuando uses un almacén de trabajos, APScheduler maneja la serialización y deserialización de los trabajos. Esto significa que incluso si tu bot falla o se reinicia, recogerá todos sus trabajos antiguos justo donde los dejó. Esto es crucial para cualquier aplicación seria.
Conclusiones Accionables para Tu Propio Bot
Construir un bot que pueda programar mensajes abre un mundo completamente nuevo de posibilidades. Aquí tienes lo que he aprendido y lo que debes considerar:
- Comienza Simple: No intentes construir el programador más complejo de inmediato. Primero, haz que funcione un recordatorio único básico, luego añade trabajos recurrentes.
- Manejo de Errores es Clave: Los usuarios inevitablemente ingresarán comandos incorrectos o tiempos inválidos. Tu bot necesita ser lo suficientemente sólido para manejar esto con gracia. ¡Añade bloques
try-except! - La Persistencia es No Negociable: Para cualquier bot que esperas que funcione por más de unos minutos, necesitas almacenar los trabajos programados. Los almacenes de trabajos de
APSchedulerhacen esto fácil. SQLite es un excelente punto de partida para el almacenamiento local. - Feedback del Usuario: Siempre confirma con el usuario que su programación fue establecida. “Está bien, ¡te recordaré en 5 minutos!” genera confianza.
- Instrucciones Claras: Proporciona buenos mensajes de
/helpcon ejemplos. Ayuda a los usuarios a entender cómo interactuar con tu bot. - Considera Zonas Horarias: Para un bot global, las zonas horarias pueden ser una pesadilla.
APSchedulerpuede manejarlas, pero añade complejidad. Para un bot personal, podrías simplemente usar UTC o la hora local del servidor.
Este camino de un simple recordatorio de D&D a un bot programador más capaz ha sido increíblemente gratificante. Muestra que con algunas buenas bibliotecas y un poco de Python, puedes elevar tus bots de Telegram de simples respondedores a asistentes verdaderamente proactivos. ¡Inténtalo, experimenta y házmelo saber qué ideas geniales de programación se te ocurren!
¡Feliz construcción de bots!
🕒 Published:
Related Articles
- Meine Bots sind kein Gestrüpp: Hier ist meine Strategie
- Il divario delle competenze in intelligenza artificiale: non si tratta più solo di conoscere Python
- Quando Seu Rosto Se Torna a Cena do Crime de Outra Pessoa
- Nvidias KI-Herrschaft: Warum Arms neuer Chip nicht der Herausforderer ist, den Sie denken