File size: 6,377 Bytes
67cf156
 
 
 
 
67c785a
67cf156
 
a156819
 
67c785a
67cf156
fe216f3
 
 
67cf156
 
67c785a
 
 
 
 
 
 
 
a156819
67cf156
67c785a
 
 
67cf156
 
 
 
 
67c785a
 
 
 
67cf156
67c785a
67cf156
 
 
67c785a
 
67cf156
a156819
 
67c785a
 
 
 
 
 
 
a156819
67cf156
67c785a
7debc6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67c785a
7debc6c
 
 
 
 
67c785a
67cf156
67c785a
 
 
 
fe216f3
67c785a
 
a156819
 
67c785a
a156819
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67c785a
 
 
 
 
 
a156819
 
 
 
 
 
67c785a
 
a156819
67c785a
a156819
67c785a
 
 
 
 
a156819
 
 
67c785a
a156819
 
67c785a
a156819
 
 
 
 
 
 
67c785a
 
 
 
 
a156819
67c785a
 
 
fe216f3
67c785a
 
 
 
fe216f3
 
67c785a
 
 
 
a156819
 
9a1cb80
 
 
 
 
 
 
c391088
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import logging
import os
from typing import Any

from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
from dotenv import load_dotenv
from src.financial_news_requester import fetch_comp_financial_news
from fastapi import FastAPI, Request
import uvicorn
import httpx

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

load_dotenv()

# Fix 1: Use consistent token name (BOT_TOKEN is standard for HF Spaces)
BOT_TOKEN = os.getenv("BOT_TOKEN") or os.getenv("TELEGRAM_TOKEN")
if not BOT_TOKEN:
    logger.error("BOT_TOKEN not found! Please add it in Space Settings > Repository secrets")
    raise ValueError("BOT_TOKEN not found in environment variables")

# Fix 2: Correct SPACE_ID format
SPACE_ID = os.environ.get('SPACE_ID', 'researchengineering-news_sentiment_analyzer')
PORT = int(os.environ.get('PORT', 7860))

# Fix 3: Create application GLOBALLY so webhook can access it
application = Application.builder().token(BOT_TOKEN).build()


def format_news_for_telegram(news_json: list[dict[str, Any]]) -> str:
    message = ""
    for item in news_json:
        message += (
            f"πŸ“° <b>{item.get('headline', 'No headline')}</b>\n"
            f"πŸ“ {item.get('summary', 'No summary')}\n"
            f"🏷️ Source: {item.get('source', 'Unknown')}\n"
            f"πŸ”— <a href=\"{item.get('url', '#')}\">Read more</a>\n\n"
        )
    return message if message else "No news available."


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("Hello! I'm your Financial News Bot. Use /run to get latest news.")


async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Handle /help command"""
    await update.message.reply_text(
        "πŸ€– Available commands:\n"
        "/start - Start the bot\n"
        "/help - Show this help\n"
        "/run - Get latest financial news"
    )


async def run_crew(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("Fetching latest financial news...")
    try:
        feed = fetch_comp_financial_news()
        logger.info(f"Processed: {len(feed)} news items")
        formatted_news = format_news_for_telegram(feed)
        # Split message if too long (Telegram limit is 4096 characters)
        if len(formatted_news) > 4000:
            # Split by news items, not by character count
            items = formatted_news.split('\n\n')
            chunk = ""
            for item in items:
                if len(chunk) + len(item) + 2 > 4000:
                    await update.message.reply_text(chunk, parse_mode='HTML')
                    chunk = ""
                chunk += item + "\n\n"
            if chunk:
                await update.message.reply_text(chunk, parse_mode='HTML')
        else:
            await update.message.reply_text(formatted_news, parse_mode='HTML')
    except Exception as e:
        logger.error(f"Error in run_crew: {e}")
        await update.message.reply_text(f"Sorry, there was an error fetching news: {str(e)}")


# Add handlers to the global application
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("help", help_command))
application.add_handler(CommandHandler("run", run_crew))

# Create FastAPI app
app = FastAPI(title="Financial News Bot", description="Telegram bot for financial news")


@app.post(f"/{BOT_TOKEN}")
async def webhook(request: Request):
    """Handle incoming webhook from Telegram"""
    try:
        # Get the update from Telegram
        json_data = await request.json()
        update = Update.de_json(json_data, application.bot)

        # Process the update
        await application.process_update(update)

        return {"status": "ok"}
    except Exception as e:
        logger.error(f"Error processing update: {e}")
        return {"status": "error", "message": str(e)}


@app.get("/")
async def root():
    """Health check endpoint"""
    return {
        "status": "Financial News Bot is running!",
        "webhook_url": f"https://{SPACE_ID}.hf.space/{BOT_TOKEN[:10]}...",
        "space_id": SPACE_ID,
        "available_endpoints": ["/", "/set_webhook", "/webhook_info"]
    }


@app.get("/set_webhook")
async def set_webhook():
    """Manually set the webhook (call this once after deployment)"""
    try:
        webhook_url = f"https://{SPACE_ID}.hf.space/{BOT_TOKEN}"
        set_webhook_url = f"https://api.telegram.org/bot{BOT_TOKEN}/setWebhook"

        logger.info(f"Setting webhook to: {webhook_url}")

        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.post(set_webhook_url, json={
                "url": webhook_url,
                "drop_pending_updates": True
            })
            result = response.json()

        if result.get("ok"):
            logger.info("Webhook set successfully!")
            return {"status": "success", "webhook_url": webhook_url, "result": result}
        else:
            logger.error(f"Failed to set webhook: {result}")
            return {"status": "error", "result": result}

    except Exception as e:
        logger.error(f"Error setting webhook: {e}")
        return {"status": "error", "message": str(e)}


@app.get("/webhook_info")
async def webhook_info():
    """Get current webhook information"""
    try:
        info_url = f"https://api.telegram.org/bot{BOT_TOKEN}/getWebhookInfo"

        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.get(info_url)
            result = response.json()

        return result
    except Exception as e:
        logger.error(f"Error getting webhook info: {e}")
        return {"status": "error", "message": str(e)}


@app.get("/health")
async def health():
    """Additional health check"""
    return {"status": "healthy", "bot_token_set": bool(BOT_TOKEN)}


if __name__ == "__main__":
    logger.info(f"Starting Financial News Bot on port {PORT}")
    logger.info(f"Bot token: {BOT_TOKEN[:10]}..." if BOT_TOKEN else "No token set")
    logger.info(f"Space ID: {SPACE_ID}")
    logger.info(f"Webhook URL will be: https://{SPACE_ID}.hf.space/{BOT_TOKEN[:10]}...")
    logger.info("After deployment, visit /set_webhook to configure the webhook")

    uvicorn.run(app, host="0.0.0.0", port=PORT)
    #application.run_polling()