โ† ะะฐะทะฐะด
#!/usr/bin/env python3 """ AlphaPulseXP Telegram Bot v7.0 Modular architecture โ€” see individual modules for details. Modules: config.py โ€” Configuration & constants utils.py โ€” Utility functions (now_van, stable_id, build_hashtags) database.py โ€” SQLite persistence fetcher.py โ€” Content fetching (RSS, CoinGecko, Reddit) ai.py โ€” AI commentary via OpenRouter poster.py โ€” Telegram message formatting & sending commands.py โ€” /command and inline button handlers scheduler.py โ€” Main scheduling loop """ import sys import json import asyncio import logging from aiohttp import web from telegram.ext import Application, CommandHandler, CallbackQueryHandler from config import CONFIG from commands import CommandHandlers from scheduler import AlphaPulseBot # โ”€โ”€โ”€ Logging โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[logging.FileHandler('bot.log'), logging.StreamHandler()] ) logger = logging.getLogger(__name__) # โ”€โ”€โ”€ Entry Point โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ def main(): if not CONFIG['bot_token']: print("Error: TELEGRAM_BOT_TOKEN not set in environment") sys.exit(1) if not CONFIG['openrouter_key']: print("Error: OPENROUTER_API_KEY not set in environment") sys.exit(1) bot_instance = AlphaPulseBot() cmd_handlers = CommandHandlers(bot_instance.fetcher) # Build Application for command handling (polling runs alongside scheduler) app = Application.builder().token(CONFIG['bot_token']).build() # Slash commands app.add_handler(CommandHandler("price", cmd_handlers.cmd_price)) app.add_handler(CommandHandler("fear", cmd_handlers.cmd_fear)) app.add_handler(CommandHandler("stats", cmd_handlers.cmd_stats)) app.add_handler(CommandHandler("trending", cmd_handlers.cmd_trending)) app.add_handler(CommandHandler("help", cmd_handlers.cmd_help)) # Inline button callbacks app.add_handler(CallbackQueryHandler(cmd_handlers.btn_price, pattern="^cb_price$")) app.add_handler(CallbackQueryHandler(cmd_handlers.btn_fear, pattern="^cb_fear$")) app.add_handler(CallbackQueryHandler(cmd_handlers.btn_trending, pattern="^cb_trending$")) # โ”€โ”€ Health HTTP server โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ health_port = int(CONFIG.get('health_port', 8090)) async def health_handler(request): stats = bot_instance.db.get_health_stats() stats['status'] = 'ok' stats['version'] = '8.2' stats['uptime_cycles'] = bot_instance.cycle_count return web.json_response(stats) async def analytics_handler(request): days = int(request.query.get('days', 7)) data = bot_instance.db.get_analytics(days) return web.json_response(data) async def run_all(): # Start health HTTP server health_app = web.Application() health_app.router.add_get('/health', health_handler) health_app.router.add_get('/analytics', analytics_handler) runner = web.AppRunner(health_app) await runner.setup() site = web.TCPSite(runner, '0.0.0.0', health_port) await site.start() logger.info(f"Health endpoint running on :{health_port}/health") await app.initialize() await app.start() await app.updater.start_polling(drop_pending_updates=True) logger.info("Command polling started (/price /fear /stats /trending /help)") await bot_instance.run() # blocks forever # cleanup (reached only on KeyboardInterrupt propagated up) await runner.cleanup() await app.updater.stop() await app.stop() await app.shutdown() try: asyncio.run(run_all()) except KeyboardInterrupt: logger.info("Bot stopped by user") sys.exit(0) except Exception as e: logger.error(f"Fatal error: {e}") sys.exit(1) if __name__ == '__main__': main()