FundingRate / app /services /telegram_bot.py
Cuong2004's picture
Switch Telegram bot to webhook mode for HF Spaces
8120515
"""Telegram Bot with webhook mode for HF Spaces."""
import asyncio
from telegram import Update, Bot
from telegram.ext import Application, CommandHandler, ContextTypes
from fastapi import Request
from app.config import get_settings
class TelegramBot:
"""Telegram bot with webhook handlers."""
_app: Application = None
_bot: Bot = None
_started = False
_webhook_url: str = None
@classmethod
async def setup(cls, webhook_base_url: str = None):
"""
Setup the Telegram bot (webhook mode).
Call this during app startup.
"""
settings = get_settings()
if not settings.telegram_bot_token:
print("Telegram bot: Not configured (no token)")
return False
try:
cls._bot = Bot(token=settings.telegram_bot_token)
cls._app = Application.builder().token(settings.telegram_bot_token).build()
# Add handlers
cls._app.add_handler(CommandHandler("start", cls._handle_start))
cls._app.add_handler(CommandHandler("help", cls._handle_help))
cls._app.add_handler(CommandHandler("chatid", cls._handle_chatid))
cls._app.add_handler(CommandHandler("top", cls._handle_top))
cls._app.add_handler(CommandHandler("watchlist", cls._handle_watchlist))
# Initialize app (but don't start polling)
await cls._app.initialize()
# Set webhook if URL provided
if webhook_base_url:
cls._webhook_url = f"{webhook_base_url}/api/v1/telegram/webhook"
await cls._bot.set_webhook(url=cls._webhook_url)
print(f"Telegram bot: Webhook set to {cls._webhook_url}")
cls._started = True
print("Telegram bot: Initialized successfully")
return True
except Exception as e:
print(f"Telegram bot: Failed to setup ({e.__class__.__name__}: {e})")
cls._app = None
cls._bot = None
cls._started = False
return False
@classmethod
async def process_update(cls, update_data: dict):
"""Process incoming webhook update."""
if not cls._app or not cls._started:
return False
try:
update = Update.de_json(update_data, cls._bot)
await cls._app.process_update(update)
return True
except Exception as e:
print(f"Telegram bot: Error processing update ({e})")
return False
@classmethod
async def shutdown(cls):
"""Shutdown the bot."""
if cls._app and cls._started:
try:
# Remove webhook
if cls._bot:
await cls._bot.delete_webhook()
await cls._app.shutdown()
print("Telegram bot: Shutdown complete")
except Exception as e:
print(f"Telegram bot: Error during shutdown ({e})")
@classmethod
async def _handle_start(cls, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle /start command."""
chat_id = update.effective_chat.id
message = (
f"πŸš€ <b>MEXC FR Report Bot</b>\n\n"
f"πŸ“ Your Chat ID: <code>{chat_id}</code>\n\n"
f"Copy this Chat ID and add it to your .env file:\n"
f"<code>TELEGRAM_CHAT_ID={chat_id}</code>\n\n"
f"<b>Commands:</b>\n"
f"/top - Get Top 5 FR coins\n"
f"/watchlist - Get watchlist coins\n"
f"/chatid - Get your chat ID\n"
f"/help - Show help"
)
await update.message.reply_text(message, parse_mode="HTML")
@classmethod
async def _handle_help(cls, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle /help command."""
message = (
"πŸ“– <b>MEXC FR Report Bot Help</b>\n\n"
"<b>Commands:</b>\n"
"/start - Start bot and get chat ID\n"
"/top - Get Top 5 positive/negative FR\n"
"/watchlist - Get watched coins FR\n"
"/chatid - Get your chat ID\n\n"
"<b>Auto notifications:</b>\n"
"Every hour the bot will send:\n"
"β€’ Top 5 highest FR (short opportunity)\n"
"β€’ Top 5 lowest FR (long opportunity)\n"
"β€’ Your watchlist coins update"
)
await update.message.reply_text(message, parse_mode="HTML")
@classmethod
async def _handle_chatid(cls, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle /chatid command."""
chat_id = update.effective_chat.id
await update.message.reply_text(
f"πŸ“ Your Chat ID: <code>{chat_id}</code>",
parse_mode="HTML"
)
@classmethod
async def _handle_top(cls, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle /top command - send top FR coins."""
from app.services.telegram_service import get_telegram_service
service = get_telegram_service()
chat_id = update.effective_chat.id
await service.send_top_fr_notification(chat_id=chat_id)
@classmethod
async def _handle_watchlist(cls, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle /watchlist command - send watchlist coins."""
from app.services.telegram_service import get_telegram_service
service = get_telegram_service()
chat_id = update.effective_chat.id
success = await service.send_watchlist_notification(chat_id=chat_id)
if not success:
await update.message.reply_text(
"πŸ“­ Watchlist is empty. Add coins via API:\n"
"<code>POST /api/v1/watchlist</code>",
parse_mode="HTML"
)
def get_telegram_bot():
return TelegramBot