File size: 4,123 Bytes
558806d
 
 
 
 
 
 
 
 
 
 
 
 
 
0543a64
 
 
 
558806d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8878b61
558806d
 
 
 
 
 
 
 
 
 
8878b61
558806d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21f4a40
558806d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c6f046
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558806d
 
 
 
 
 
 
 
0543a64
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
"""
FastAPI Telegram Bot with Google Apps Script Proxy

This implementation uses Google Apps Script as a proxy to bypass
HuggingFace's restrictions on Telegram API calls.
"""

import httpx
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel
import uvicorn
import asyncio
from contextlib import asynccontextmanager

from src.telegram_bot.config import Config
from src.telegram_bot.logger import main_logger as logger
from src.telegram_bot.tg_models import TelegramUpdate
from src.telegram_bot.telegram_bot_service import TelegramBotService


# Global bot service instance
bot_service = TelegramBotService()


# FastAPI lifespan management
@asynccontextmanager
async def lifespan(app: FastAPI):
    """Manage application lifespan"""
    # Startup
    logger.info("Starting up application...")

    if not Config.validate():
        raise RuntimeError("Invalid configuration")

    await bot_service.initialize()
    logger.info("Application startup complete")

    yield

    # Shutdown
    logger.info("Shutting down application...")
    await bot_service.cleanup()
    logger.info("Application shutdown complete")


# FastAPI app
app = FastAPI(
    title="Financial News Telegram Bot",
    description="A Telegram bot for financial news with Google Apps Script proxy",
    version="0.0.1",
    lifespan=lifespan
)


@app.get("/")
async def root():
    """Root endpoint for health checks"""
    return {
        "status": "running",
        "message": "Financial News Telegram Bot",
        "version": "0.0.1",
        "bot_configured": bool(Config.BOT_TOKEN),
        "proxy_configured": bool(Config.GOOGLE_APPS_SCRIPT_URL)
    }


@app.get("/health")
async def health_check():
    """Detailed health check"""
    return {
        "status": "healthy",
        "timestamp": "2025-01-01T00:00:00Z",
        "services": {
            "bot": "online",
            "proxy": "configured" if Config.GOOGLE_APPS_SCRIPT_URL else "not_configured"
        }
    }


@app.post(f"/webhook/{Config.WEBHOOK_SECRET}")
async def webhook(request: Request):
    """
    Webhook endpoint for Telegram updates
    URL: https://your-space.hf.space/webhook/{WEBHOOK_SECRET}
    """
    try:
        json_data = await request.json()
        logger.info(f"Received webhook data: {json_data}")

        # Validate update structure
        update = TelegramUpdate(**json_data)

        # Process update asynchronously
        asyncio.create_task(bot_service.process_update(update))

        return {"ok": True}

    except Exception as e:
        logger.error(f"Webhook error: {e}")
        raise HTTPException(status_code=400, detail="Invalid update format")


@app.get("/webhook_info")
async def webhook_info():
    """Get webhook configuration info"""
    return {
        "webhook_url": f"https://your-space-id.hf.space/webhook/{Config.WEBHOOK_SECRET}",
        "instructions": [
            "1. Deploy this app to HuggingFace Spaces",
            "2. Set up Google Apps Script proxy",
            "3. Set webhook URL using Telegram Bot API",
            "4. Test with /hello command"
        ]
    }


@app.post("/test_message")
async def test_message(chat_id: int, message: str = "Hello World!"):
    """Test endpoint to send a message (for debugging)"""
    try:
        result = await bot_service.send_message_via_proxy(chat_id, message)
        return {"success": True, "result": result}
    except Exception as e:
        logger.error(f"Test message failed: {e}")
        raise HTTPException(status_code=500, detail=str(e))


def main() -> None:
    """Main entry point for the FastAPI app"""
    if not Config.validate():
        logger.error("Invalid configuration. Exiting...")
        return

    logger.info(f"Starting Financial News Bot on port {Config.PORT}")
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=Config.PORT,
        log_level="info"
    )


# Development server
if __name__ == "__main__":
    logger.info(f"Starting Financial News Bot on port {Config.PORT}")
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=Config.PORT,
        log_level="info"
    )