"""Telegram notification service.""" import os import logging from typing import Optional import httpx logger = logging.getLogger(__name__) TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") DEFAULT_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID") # Family group MATT_CHAT_ID = os.getenv("TELEGRAM_MATTS_ID", "8386527252") class TelegramNotifier: """Send Telegram notifications to family group or Matt directly.""" def __init__(self): self.token = TELEGRAM_BOT_TOKEN self.base_url = f"https://api.telegram.org/bot{self.token}" if self.token else None self.client = httpx.AsyncClient(timeout=30.0) if self.token else None async def send( self, message: str, chat_id: Optional[str] = None, parse_mode: str = "HTML", disable_notification: bool = False ) -> dict: """Send a message to Telegram. Args: message: Text to send (HTML allowed) chat_id: Target chat (defaults to family group) parse_mode: "HTML" or "Markdown" disable_notification: Send silently if True Returns: Telegram API response dict """ if not self.client: logger.warning("Telegram not configured, message not sent") return {"ok": False, "error": "not_configured"} chat_id = chat_id or DEFAULT_CHAT_ID if not chat_id: logger.error("No chat_id specified and no default configured") return {"ok": False, "error": "no_chat_id"} payload = { "chat_id": chat_id, "text": message, "parse_mode": parse_mode, "disable_notification": disable_notification } try: response = await self.client.post( f"{self.base_url}/sendMessage", json=payload ) response.raise_for_status() result = response.json() if result.get("ok"): logger.info(f"Telegram sent to {chat_id}") else: logger.error(f"Telegram API error: {result}") return result except Exception as e: logger.error(f"Failed to send Telegram: {e}") return {"ok": False, "error": str(e)} async def to_matt(self, message: str, **kwargs) -> dict: """Send directly to Matt's DM.""" return await self.send(message, chat_id=MATT_CHAT_ID, **kwargs) async def to_family(self, message: str, **kwargs) -> dict: """Send to family group.""" return await self.send(message, chat_id=DEFAULT_CHAT_ID, **kwargs) async def send_with_buttons( self, message: str, reply_markup: dict, chat_id: Optional[str] = None, parse_mode: str = "HTML" ) -> dict: """Send a message with inline keyboard buttons to Telegram. Args: message: Text to send (HTML allowed) reply_markup: Inline keyboard JSON (e.g., {"inline_keyboard": [[...]]}) chat_id: Target chat (defaults to family group) parse_mode: "HTML" or "Markdown" Returns: Telegram API response dict """ if not self.client: logger.warning("Telegram not configured, message not sent") return {"ok": False, "error": "not_configured"} chat_id = chat_id or DEFAULT_CHAT_ID if not chat_id: logger.error("No chat_id specified and no default configured") return {"ok": False, "error": "no_chat_id"} import json payload = { "chat_id": chat_id, "text": message, "parse_mode": parse_mode, "reply_markup": json.dumps(reply_markup) } try: response = await self.client.post( f"{self.base_url}/sendMessage", json=payload ) response.raise_for_status() result = response.json() if result.get("ok"): logger.info(f"Telegram buttons sent to {chat_id}") else: logger.error(f"Telegram API error: {result}") return result except Exception as e: logger.error(f"Failed to send Telegram with buttons: {e}") return {"ok": False, "error": str(e)} async def close(self): if self.client: await self.client.aclose()