← Back
"""
AlphaPulse Bot — Command & Callback Handlers
"""

import logging

from telegram import Update
from telegram.ext import ContextTypes

from ai import AICommentary
from fetcher import ContentFetcher

logger = logging.getLogger(__name__)


class CommandHandlers:
    """All /command and inline button callback handlers."""

    def __init__(self, fetcher: ContentFetcher):
        self.fetcher = fetcher

    # ── Slash commands ────────────────────────────────────────────────────────

    async def cmd_price(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """/price — Live BTC + ETH + SOL prices."""
        prices = await self.fetcher.fetch_prices()
        if not prices:
            await update.message.reply_text("⚠️ Could not fetch prices right now. Try again later.")
            return
        btc_a = '▲' if prices['btc_change'] > 0 else '▼'
        eth_a = '▲' if prices['eth_change'] > 0 else '▼'
        sol_a = '▲' if prices.get('sol_change', 0) > 0 else '▼'
        text = (
            f"💹 <b>Live Prices</b>\n\n"
            f"₿ BTC  <b>${prices['btc_price']:,.0f}</b>  {btc_a} {prices['btc_change']:+.1f}%\n"
            f"⟠ ETH  <b>${prices['eth_price']:,.0f}</b>  {eth_a} {prices['eth_change']:+.1f}%\n"
            f"◎ SOL  <b>${prices['sol_price']:,.2f}</b>  {sol_a} {prices.get('sol_change', 0):+.1f}%\n\n"
            f"<i>Source: CoinGecko</i>"
        )
        await update.message.reply_text(text, parse_mode='HTML')

    async def cmd_fear(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """/fear — Current Fear & Greed Index."""
        fg = await self.fetcher.fetch_fear_greed()
        if not fg:
            await update.message.reply_text("⚠️ Could not fetch Fear & Greed index. Try again later.")
            return
        text = AICommentary.fear_greed_text(fg['value'], fg['classification'])
        await update.message.reply_text(
            f"🎚️ <b>Fear & Greed Index</b>\n\n{text}\n\n<i>Source: alternative.me</i>",
            parse_mode='HTML'
        )

    async def cmd_stats(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """/stats — Top 5 gainers & losers (24h)."""
        gainers, losers = await self.fetcher.fetch_top_movers()
        if not gainers and not losers:
            await update.message.reply_text("⚠️ Could not fetch top movers. Try again later.")
            return
        lines = ["🏆 <b>Top Movers (24h)</b>", ""]
        if gainers:
            lines.append("🟢 <b>Gainers</b>")
            for c in gainers[:5]:
                pct = c['price_change_percentage_24h'] or 0
                lines.append(f"  {c['symbol'].upper()}  +{pct:.1f}%")
        if losers:
            lines += ["", "🔴 <b>Losers</b>"]
            for c in losers[:5]:
                pct = c['price_change_percentage_24h'] or 0
                lines.append(f"  {c['symbol'].upper()}  {pct:.1f}%")
        await update.message.reply_text('\n'.join(lines), parse_mode='HTML')

    async def cmd_trending(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """/trending — Today's top trending coins."""
        coins = await self.fetcher.fetch_trending()
        if not coins:
            await update.message.reply_text("⚠️ Could not fetch trending coins. Try again later.")
            return
        lines = ["🔥 <b>Trending Now</b>", ""]
        medals = ['🥇', '🥈', '🥉', '4️⃣', '5️⃣', '6️⃣', '7️⃣']
        for i, c in enumerate(coins[:7]):
            rank = f"#{c['rank']}" if c['rank'] != '?' else ''
            lines.append(f"{medals[i]}  <b>{c['symbol']}</b> {c['name']}  {rank}")
        lines.append("\n<i>Source: CoinGecko</i>")
        await update.message.reply_text('\n'.join(lines), parse_mode='HTML')

    async def cmd_help(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """/help — Available commands."""
        text = (
            "🤖 <b>AlphaPulseXP Commands</b>\n\n"
            "/price    — Live BTC + ETH prices\n"
            "/fear     — Crypto Fear & Greed Index\n"
            "/stats    — Top 5 gainers & losers (24h)\n"
            "/trending — Today's trending coins\n"
            "/help     — This message\n\n"
            "📢 Channel: @alphapulsexp"
        )
        await update.message.reply_text(text, parse_mode='HTML')

    # ── Inline button callbacks ───────────────────────────────────────────────

    async def btn_price(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Inline button: 📊 Price."""
        query = update.callback_query
        prices = await self.fetcher.fetch_prices()
        if not prices:
            await query.answer("⚠️ Could not fetch prices", show_alert=True)
            return
        btc_a = '▲' if prices['btc_change'] > 0 else '▼'
        eth_a = '▲' if prices['eth_change'] > 0 else '▼'
        sol_a = '▲' if prices.get('sol_change', 0) > 0 else '▼'
        text = (
            f"₿ BTC ${prices['btc_price']:,.0f} {btc_a}{prices['btc_change']:+.1f}%\n"
            f"⟠ ETH ${prices['eth_price']:,.0f} {eth_a}{prices['eth_change']:+.1f}%\n"
            f"◎ SOL ${prices['sol_price']:,.2f} {sol_a}{prices.get('sol_change', 0):+.1f}%"
        )
        await query.answer(text, show_alert=True)

    async def btn_fear(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Inline button: 😱 Fear."""
        query = update.callback_query
        fg = await self.fetcher.fetch_fear_greed()
        if not fg:
            await query.answer("⚠️ Could not fetch Fear & Greed", show_alert=True)
            return
        text = AICommentary.fear_greed_text(fg['value'], fg['classification'])
        await query.answer(text.replace('\n', ' | '), show_alert=True)

    async def btn_trending(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Inline button: 🔥 Trending."""
        query = update.callback_query
        coins = await self.fetcher.fetch_trending()
        if not coins:
            await query.answer("⚠️ Could not fetch trending coins", show_alert=True)
            return
        medals = ['🥇', '🥈', '🥉', '4️⃣', '5️⃣', '6️⃣', '7️⃣']
        lines = [f"{medals[i]} {c['symbol']} {c['name']}" for i, c in enumerate(coins[:5])]
        await query.answer('\n'.join(lines), show_alert=True)

📜 Git History

a09f02fchore: initial commit — version control setup5 weeks ago
Show last diff
Loading...