Add Translator Bot for Telegram

This commit is contained in:
Manuel Vergara 2024-07-11 02:54:47 +02:00
parent 5821636a01
commit fbecbbf0a1
6 changed files with 320 additions and 14 deletions

View File

@ -0,0 +1,10 @@
FROM python:3.10-alpine
WORKDIR /app
COPY . /app/
RUN pip install -r requirements.txt
CMD ["python", "translator.py"]

View File

@ -0,0 +1,19 @@
# config.py
# Este módulo gestiona la configuración y la carga de variables de entorno.
import os
from dotenv import load_dotenv
# Cargar las variables de entorno desde el archivo .env
load_dotenv('.env')
# Obtener el token del bot y el ID del chat de grupo desde las variables de entorno
BOT_TOKEN = os.getenv('BOT_TOKEN')
GROUP_CHAT_ID = os.getenv('GROUP_CHAT_ID')
# Validar que las variables de entorno estén configuradas
if not BOT_TOKEN or not GROUP_CHAT_ID:
raise AssertionError("Por favor, configura las variables de entorno BOT_TOKEN y GROUP_CHAT_ID")
# Convertir GROUP_CHAT_ID a entero
GROUP_CHAT_ID = int(GROUP_CHAT_ID)

View File

@ -0,0 +1,63 @@
"""
# Ejemplo de uso del logger
if __name__ == "__main__":
logger.info('Logger configurado correctamente.')
logger.debug('Este es un mensaje de depuración.')
logger.warning('Este es un mensaje de advertencia.')
logger.error('Este es un mensaje de error.')
logger.critical('Este es un mensaje crítico.')
"""
# logger.py
# Este módulo configura el logging con rotación de archivos.
import logging
import os
from logging.handlers import RotatingFileHandler
def setup_logger():
# Crear el directorio de logs si no existe
log_directory = 'logs'
if not os.path.exists(log_directory):
os.makedirs(log_directory)
# Ruta del archivo de log
log_file = os.path.join(log_directory, 'bot.log')
# Formato de los mensajes de log
log_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# Configurar RotatingFileHandler
# maxBytes: tamaño máximo del archivo de log en bytes (5MB en este caso)
# backupCount: número máximo de archivos de respaldo
file_handler = RotatingFileHandler(
log_file, maxBytes=5*1024*1024, backupCount=5)
file_handler.setFormatter(log_formatter)
file_handler.setLevel(logging.INFO)
# Configurar StreamHandler para la consola
console_handler = logging.StreamHandler()
console_handler.setFormatter(log_formatter)
# Puedes cambiar este nivel según tus necesidades
console_handler.setLevel(logging.DEBUG)
# Configurar el logger
logger = logging.getLogger('telegram_bot')
# Configurar el nivel del logger a DEBUG para capturar todos los mensajes
logger.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# Evitar que los mensajes se dupliquen en el log
logger.propagate = False
return logger
# Inicializar el logger
logger = setup_logger()

View File

@ -0,0 +1,3 @@
python-telegram-bot==21.3
translate==3.6.1
python-dotenv==1.0.1

View File

@ -0,0 +1,211 @@
"""
Este módulo contiene el código para un bot de Telegram que realiza tareas de traducción.
El bot utiliza la API de Telegram Bot para interactuar con los usuarios y la API de Google Translate para la traducción.
La función principal inicializa el bot y comienza a escuchar los mensajes entrantes.
Para ejecutar el bot, asegúrese de tener las credenciales y la configuración de la API necesarias configuradas en el módulo `config`.
Extraido del tutorial de youtube y luego actualizado: https://www.youtube.com/watch?v=8buZAq148gk&ab_channel=SBDeveloper
Autor: manuelver
"""
import signal
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import ApplicationBuilder, MessageHandler, CommandHandler, CallbackContext, filters, CallbackQueryHandler
from translate import Translator
import config
from logger import logger
def def_handler(sig, frame):
"""
Función manejadora de señales para salir del programa de manera elegante.
"""
logger.info("Saliendo del programa...")
exit(1)
# Configurar el manejador de señal para SIGINT (Ctrl+C)
signal.signal(signal.SIGINT, def_handler)
async def select_origin_lang(update: Update, context: CallbackContext) -> None:
"""
Función para seleccionar el idioma de origen para la traducción.
"""
keyboard = [
[
InlineKeyboardButton("Español", callback_data='es'),
InlineKeyboardButton("Catalán", callback_data='ca'),
InlineKeyboardButton("English", callback_data='en'),
InlineKeyboardButton("Français", callback_data='fr')
],
[
InlineKeyboardButton("Deutsch", callback_data='de'),
InlineKeyboardButton("Italiano", callback_data='it'),
InlineKeyboardButton("Português", callback_data='pt')
],
[
InlineKeyboardButton("Русский (Ruso)", callback_data='ru'),
InlineKeyboardButton("日本語 (Japonés)", callback_data='ja'),
InlineKeyboardButton("中文 (Chino)", callback_data='zh')
],
[
InlineKeyboardButton("(Árabe) العربية", callback_data='ar'),
InlineKeyboardButton("हिन्दी (Hindi)", callback_data='hi'),
InlineKeyboardButton("עברית (Hebreo)", callback_data='he')
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
'Por favor, selecciona el idioma de origen:', reply_markup=reply_markup)
async def select_dest_lang(update: Update, context: CallbackContext) -> None:
"""
Función para seleccionar el idioma de destino para la traducción.
"""
keyboard = [
[
InlineKeyboardButton("Español", callback_data='es'),
InlineKeyboardButton("Catalán", callback_data='ca'),
InlineKeyboardButton("English", callback_data='en'),
InlineKeyboardButton("Français", callback_data='fr')
],
[
InlineKeyboardButton("Deutsch", callback_data='de'),
InlineKeyboardButton("Italiano", callback_data='it'),
InlineKeyboardButton("Português", callback_data='pt')
],
[
InlineKeyboardButton("Русский (Ruso)", callback_data='ru'),
InlineKeyboardButton("日本語 (Japonés)", callback_data='ja'),
InlineKeyboardButton("中文 (Chino)", callback_data='zh')
],
[
InlineKeyboardButton("(Árabe) العربية", callback_data='ar'),
InlineKeyboardButton("हिन्दी (Hindi)", callback_data='hi'),
InlineKeyboardButton("עברית (Hebreo)", callback_data='he')
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
f'Por favor, selecciona el idioma de destino:', reply_markup=reply_markup)
async def button(update: Update, context: CallbackContext) -> None:
"""
Función para manejar los botones de idioma seleccionados.
"""
query = update.callback_query
await query.answer()
if 'origin_lang' not in context.user_data:
context.user_data['origin_lang'] = query.data
await query.edit_message_text(text=f"Idioma de origen seleccionado.\n\nAhora selecciona el idioma de destino con el comando /langTo")
await select_dest_lang(update, context)
else:
context.user_data['dest_lang'] = query.data
await query.edit_message_text(text=f"Idioma de destino seleccionado.\n\nEnvía tu texto para traducir.")
logger.info(f"Idioma seleccionado: {query.data}")
async def lang_translator(user_input, from_lang, to_lang):
try:
translator = Translator(from_lang=from_lang, to_lang=to_lang)
translation = translator.translate(user_input)
return translation
except TranslationError as e:
logger.error(f"Error en la traducción: {str(e)}")
return "Error en la traducción. Por favor, intenta de nuevo más tarde."
except Exception as e:
logger.error(f"Error inesperado al traducir el texto: {str(e)}")
return "Error inesperado al traducir el texto."
async def reply(update: Update, context: CallbackContext):
user_input = update.message.text
from_lang = context.user_data.get(
'origin_lang', 'es') # Español por defecto
to_lang = context.user_data.get('dest_lang', 'en') # Inglés por defecto
translation = await lang_translator(user_input, from_lang, to_lang)
await update.message.reply_text(translation)
logger.info(f"Mensaje recibido: {user_input}")
logger.info(f"Texto traducido: {translation}")
async def start(update: Update, context: CallbackContext):
await update.message.reply_text("¡Hola! Soy un bot de traducción.\n\nSi necesitas ayuda: /help.")
logger.info("Comando /start recibido.")
async def help_command(update: Update, context: CallbackContext):
"""
Función para mostrar los comandos disponibles.
"""
commands = [
"/start - Iniciar el bot",
"/langFrom - Seleccionar idioma de origen",
"/langTo - Seleccionar idioma de destino",
"/help - Mostrar este mensaje de ayuda"
]
help_text = "\n".join(commands)
await update.message.reply_text(f"El idioma por defecto origen es español y el de destino el Inglés.\nPuedes configurar otras opciones.\nUna vez lo tengas listo tan solo tienes que enviar el texto con el idioma origen.\n\nOpciones:\n{help_text}")
logger.info("Comando /help recibido.")
def main():
"""
Función principal para inicializar el bot y comenzar a escuchar los mensajes.
"""
api = config.BOT_TOKEN
application = ApplicationBuilder().token(api).build()
# Manejadores de comandos y mensajes
application.add_handler(CommandHandler('start', start))
application.add_handler(CommandHandler('langFrom', select_origin_lang))
application.add_handler(CommandHandler('langTo', select_dest_lang))
application.add_handler(CommandHandler('help', help_command))
application.add_handler(CommandHandler('command', help_command))
application.add_handler(MessageHandler(
filters.TEXT & ~filters.COMMAND, reply))
application.add_handler(CallbackQueryHandler(button))
# Iniciar el bot
logger.info("Bot iniciado.")
# Iniciar el bucle de eventos
application.run_polling()
if __name__ == '__main__':
try:
main()
except Exception as e:
logger.error(f'Error en la ejecución del bot: {str(e)}')
except KeyboardInterrupt:
def_handler(None, None)

View File

@ -1,16 +1,16 @@
# Bots de Telegram
| Nombre | Descripción | Nivel |
| ---------------------------------------------------- | ----------------------------------------- | ---------- |
| [Bot que devuelve id del bot](./01_id_bot/id_bot.py) | Bot que devuelve el id del bot | básico |
| [Bot pruebas](./02_pruebas_bot/bot.py) | Bot que devuelve mensajes básicos | básico |
| **Bot de traducción** (próximamente) | Bot que traduce mensajes a varios idiomas | intermedio |
| **Bot de clima** (próximamente) | Bot que devuelve el clima de una ciudad | intermedio |
| **Bot de noticias** (próximamente) | Bot que devuelve noticias de última hora | intermedio |
| **Bot de mareas** (próximamente) | Bot que devuelve información de mareas | avanzado |
| **Bot de juegos** (próximamente) | Bot con juegos de adivinanzas y preguntas | avanzado |
| **Bot de películas** (próximamente) | Bot que devuelve información de películas | avanzado |
| **Bot de series** (próximamente) | Bot que devuelve información de series | avanzado |
| **Bot de libros** (próximamente) | Bot que devuelve información de libros | avanzado |
| **Bot de recetas** (próximamente) | Bot que devuelve recetas de cocina | avanzado |
| **Bot de deportes** (próximamente) | Bot que devuelve información de deportes | avanzado |
| Nombre | Descripción | Nivel |
| ----------------------------------------- | ----------------------------------------- | ---------- |
| [Bot id del chat](./01_id_bot/) | Bot que devuelve el id del bot | básico |
| [Bot mensajes](./02_pruebas_bot/) | Bot que devuelve mensajes básicos. Loggin | intermedio |
| [Bot de traducción](./03_translator_bot/) | Bot que traduce mensajes a varios idiomas | avanzado |
| **Bot de clima** (próximamente) | Bot que devuelve el clima de una ciudad | intermedio |
| **Bot de noticias** (próximamente) | Bot que devuelve noticias de última hora | intermedio |
| **Bot de mareas** (próximamente) | Bot que devuelve información de mareas | avanzado |
| **Bot de juegos** (próximamente) | Bot con juegos de adivinanzas y preguntas | avanzado |
| **Bot de películas** (próximamente) | Bot que devuelve información de películas | avanzado |
| **Bot de series** (próximamente) | Bot que devuelve información de series | avanzado |
| **Bot de libros** (próximamente) | Bot que devuelve información de libros | avanzado |
| **Bot de recetas** (próximamente) | Bot que devuelve recetas de cocina | avanzado |
| **Bot de deportes** (próximamente) | Bot que devuelve información de deportes | avanzado |