#!/usr/bin/env python3 """ Standalone Telegram notification helper for FRANKENSTALLM 3B training. Usage: python3 scripts/telegram_notify.py "Your message here" python3 scripts/telegram_notify.py "Bold message" --parse-mode HTML Function API: from scripts.telegram_notify import send_telegram send_telegram("message text") """ import os import sys import json import urllib.request import urllib.parse import urllib.error import logging from typing import Optional # ─── Configuration ──────────────────────────────────────────────────────────── BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "") CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "") TIMEOUT = 15 # seconds MAX_MSG_LEN = 4096 # Telegram limit logging.basicConfig( level=logging.WARNING, format="%(asctime)s [telegram_notify] %(levelname)s: %(message)s", ) log = logging.getLogger("telegram_notify") def send_telegram( message: str, parse_mode: str = "HTML", token: str = BOT_TOKEN, chat_id: str = CHAT_ID, disable_web_page_preview: bool = True, ) -> bool: """ Send a Telegram message via Bot API using urllib (curl-free). Args: message: Text to send (HTML or Markdown depending on parse_mode). parse_mode: "HTML" or "Markdown" or "" (plain). token: Bot token (defaults to module-level BOT_TOKEN). chat_id: Recipient chat/channel ID. disable_web_page_preview: Suppress link previews. Returns: True on success, False on any error. """ if not message: log.warning("Empty message — skipping send.") return False # Truncate if over Telegram limit, with notice if len(message) > MAX_MSG_LEN: truncated_notice = "\n\n[message truncated]" if parse_mode == "HTML" else "\n\n[message truncated]" message = message[: MAX_MSG_LEN - len(truncated_notice)] + truncated_notice url = f"https://api.telegram.org/bot{token}/sendMessage" payload: dict = { "chat_id": chat_id, "text": message, "disable_web_page_preview": disable_web_page_preview, } if parse_mode: payload["parse_mode"] = parse_mode data = urllib.parse.urlencode(payload).encode("utf-8") try: req = urllib.request.Request( url, data=data, method="POST", headers={"Content-Type": "application/x-www-form-urlencoded"}, ) with urllib.request.urlopen(req, timeout=TIMEOUT) as resp: body = resp.read().decode("utf-8") result = json.loads(body) if result.get("ok"): return True else: log.error("Telegram API error: %s", result.get("description", result)) return False except urllib.error.HTTPError as e: try: err_body = e.read().decode("utf-8") except Exception: err_body = str(e) log.error("HTTP %d from Telegram: %s", e.code, err_body) return False except urllib.error.URLError as e: log.error("Network error sending Telegram message: %s", e.reason) return False except json.JSONDecodeError as e: log.error("Failed to parse Telegram response: %s", e) return False except Exception as e: # noqa: BLE001 log.error("Unexpected error in send_telegram: %s", e) return False def send_telegram_safe(message: str, **kwargs) -> bool: """ Wrapper that catches ALL exceptions — guaranteed never to crash the caller. Suitable for embedding in training loops where stability is critical. """ try: return send_telegram(message, **kwargs) except Exception as e: # noqa: BLE001 log.error("send_telegram_safe caught unhandled exception: %s", e) return False # ─── CLI entry point ────────────────────────────────────────────────────────── if __name__ == "__main__": import argparse parser = argparse.ArgumentParser( description="Send a Telegram message from the command line." ) parser.add_argument("message", nargs="?", help="Message text to send") parser.add_argument( "--parse-mode", default="HTML", choices=["HTML", "Markdown", "MarkdownV2", ""], help="Telegram parse_mode (default: HTML)", ) parser.add_argument( "--token", default=BOT_TOKEN, help="Override bot token" ) parser.add_argument( "--chat-id", default=CHAT_ID, help="Override chat ID" ) args = parser.parse_args() # Allow piped stdin if no positional arg given if args.message is None: if not sys.stdin.isatty(): args.message = sys.stdin.read().strip() else: parser.print_help() sys.exit(1) ok = send_telegram( args.message, parse_mode=args.parse_mode, token=args.token, chat_id=args.chat_id, ) if ok: print("Telegram message sent successfully.") sys.exit(0) else: print("ERROR: Failed to send Telegram message.", file=sys.stderr) sys.exit(1)