โ ะะฐะทะฐะด#!/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()