Spaces:
Running
Running
""" | |
Reusable Telegramβbot preview router. | |
Exposes: | |
β’ GET / β HTML preview card | |
β’ GET /avatar.jpg β bot avatar (streamed, inβmemory) | |
To use: `from telegram_preview import router` and include it in your FastAPI app. | |
""" | |
import io | |
import os | |
import requests | |
from pathlib import Path | |
from typing import Optional | |
from fastapi import APIRouter, Response, Request | |
from fastapi.responses import HTMLResponse, StreamingResponse | |
from fastapi.templating import Jinja2Templates | |
from fastapi.staticfiles import StaticFiles # NEW | |
# βββ Locate templates folder absolute path ββββββββββββββββββββββββββββββββββββ | |
BASE_DIR = Path(__file__).resolve().parent | |
templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) | |
def include_in_app(app): | |
""" | |
Helper so the main application can pull in both router *and* static mount. | |
""" | |
app.include_router(router) | |
app.mount( | |
"/static", | |
StaticFiles(directory=str(BASE_DIR / "static")), | |
name="static", | |
) | |
# βββ Environment βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
TOKEN = os.getenv("BOT_TOKEN") | |
FALLBACK_IMG = "https://telegram.org/img/t_logo.png" | |
if not TOKEN: | |
raise RuntimeError("BOT_TOKEN environment variable not set") | |
API_ROOT = f"https://api.telegram.org/bot{TOKEN}" | |
router = APIRouter() | |
# βββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
def _get_description() -> str: | |
"""Try short β full β empty string.""" | |
try: | |
r = requests.get(f"{API_ROOT}/getMyShortDescription", timeout=5).json() | |
if (desc := r["result"].get("short_description")): | |
return desc | |
except Exception: | |
pass | |
try: | |
r = requests.get(f"{API_ROOT}/getMyDescription", timeout=5).json() | |
return r["result"].get("description", "") | |
except Exception: | |
return "" | |
def _fetch_avatar_bytes() -> Optional[bytes]: | |
"""Return the newest avatar as bytes, or None if missing/error.""" | |
try: | |
me = requests.get(f"{API_ROOT}/getMe", timeout=5).json() | |
user_id = me["result"]["id"] | |
photos = requests.get( | |
f"{API_ROOT}/getUserProfilePhotos", | |
params={"user_id": user_id, "limit": 1}, | |
timeout=5, | |
).json() | |
if photos["result"]["total_count"] == 0: | |
return None | |
file_id = photos["result"]["photos"][0][-1]["file_id"] | |
file_obj = requests.get( | |
f"{API_ROOT}/getFile", params={"file_id": file_id}, timeout=5 | |
).json() | |
file_path = file_obj["result"]["file_path"] | |
resp = requests.get( | |
f"https://api.telegram.org/file/bot{TOKEN}/{file_path}", timeout=10 | |
) | |
if resp.status_code == 200: | |
return resp.content | |
except Exception as exc: | |
print("Avatar fetch error:", exc) | |
return None | |
def _get_bot_identity() -> dict: | |
"""Return {'first_name': ..., 'username': ...} from getMe""" | |
try: | |
r = requests.get(f"{API_ROOT}/getMe", timeout=5).json() | |
return { | |
"first_name": r["result"].get("first_name", "Telegram Bot"), | |
"username": r["result"].get("username", "unknown_bot"), | |
} | |
except Exception: | |
return {"first_name": "Telegram Bot", "username": "unknown_bot"} | |
# βββ Routes ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
def bot_preview(request: Request): | |
description = _get_description() | |
identity = _get_bot_identity() | |
return templates.TemplateResponse( | |
"preview.html", | |
{ | |
"request": request, | |
"title": f"@{identity['username']}", | |
"username": identity["username"], | |
"first_name": identity["first_name"], | |
"description": description, | |
}, | |
) | |
def serve_avatar(): | |
"""Streams avatar JPEG or Telegram logo (PNG) as fallback.""" | |
data = _fetch_avatar_bytes() | |
if data: | |
return StreamingResponse(io.BytesIO(data), media_type="image/jpeg") | |
fallback = requests.get(FALLBACK_IMG, timeout=10) | |
return Response(content=fallback.content, media_type="image/png") | |