Download RSS_AI_Engine/Serving_Module/internal/telegram_gateway.py from Biraboro/RRas-ai-engine: direct link, hf CLI and curl.
- Browser
- Download file 6.33 kB
-
https://huggingface.co/Biraboro/RRas-ai-engine/resolve/main/RSS_AI_Engine/Serving_Module/internal/telegram_gateway.py
- Command line
-
hf download hf://Biraboro/RRas-ai-engine/RSS_AI_Engine/Serving_Module/internal/telegram_gateway.py
-
curl -L -o telegram_gateway.py https://huggingface.co/Biraboro/RRas-ai-engine/resolve/main/RSS_AI_Engine/Serving_Module/internal/telegram_gateway.py
6.33 kB
| """Live Telegram bot (PRIVATE to Serving_Module) - started when TELEGRAM_BOT_TOKEN is set in .env. | |
| Plain HTTPS long-polling through `requests` (no extra dependency, works in Codespaces / Kaggle / a 1 GB VPS). | |
| Commands: /thinking /non_thinking /max_thinking (per-chat mode) /mode /teach सवाल | जवाब /clear /help | |
| Every other message is answered by the model in the chat's current mode. | |
| """ | |
| from __future__ import annotations | |
| import threading | |
| import time | |
| from typing import Dict, List, Optional | |
| from .inference_engine import MODES, InferenceEngine, normalise_mode | |
| API = "https://api.telegram.org" | |
| LIMIT = 4000 # Telegram hard limit is 4096 characters | |
| HELP = ("RSS AI bot\n" | |
| "/thinking - reason step by step first\n" | |
| "/non_thinking - fast direct answers (default)\n" | |
| "/max_thinking - longest, most careful reasoning\n" | |
| "/mode - show the current mode\n" | |
| "/teach सवाल | जवाब - teach me something right now\n" | |
| "/clear - forget this conversation") | |
| def _chunks(text: str, size: int = LIMIT) -> List[str]: | |
| text = text.strip() or "(empty answer)" | |
| out: List[str] = [] | |
| while len(text) > size: | |
| cut = text.rfind("\n", 0, size) | |
| cut = cut if cut > size // 2 else size | |
| out.append(text[:cut]) | |
| text = text[cut:].lstrip("\n") | |
| out.append(text) | |
| return out | |
| class TelegramGateway: | |
| def __init__(self, token: str, chat_id: str, engine: InferenceEngine, session=None, api_base: str = API, | |
| poll_timeout: int = 25): | |
| import requests | |
| self.token, self.chat_id, self.engine = token.strip(), str(chat_id or "").strip(), engine | |
| self.http = session or requests.Session() | |
| self.base = f"{api_base}/bot{self.token}" | |
| self.poll_timeout = poll_timeout | |
| self.modes: Dict[str, str] = {} | |
| self.offset = 0 | |
| self.stop = threading.Event() | |
| self.bot_name = "?" | |
| # ------------------------------------------------------------------ api | |
| def call(self, method: str, payload: Optional[dict] = None, timeout: int = 40) -> dict: | |
| reply = self.http.post(f"{self.base}/{method}", json=payload or {}, timeout=timeout) | |
| data = reply.json() | |
| if not data.get("ok"): | |
| raise RuntimeError(f"telegram {method} failed: {data.get('description', reply.status_code)}") | |
| return data | |
| def verify(self) -> bool: | |
| try: | |
| self.bot_name = self.call("getMe", timeout=15)["result"].get("username", "?") | |
| return True | |
| except Exception as exc: | |
| print(f" [telegram] token check failed: {type(exc).__name__}: {exc}") | |
| return False | |
| def send(self, chat_id, text: str) -> None: | |
| for part in _chunks(text): | |
| try: | |
| self.call("sendMessage", {"chat_id": chat_id, "text": part}, timeout=30) | |
| except Exception as exc: | |
| print(f" [telegram] send failed: {exc}") | |
| def notify_start(self) -> None: | |
| if self.chat_id: | |
| self.send(self.chat_id, "RSS AI is online ✅\nModes: /thinking /non_thinking /max_thinking\nSend any message to chat.") | |
| # ------------------------------------------------------------------ handling | |
| def handle(self, message: dict) -> None: | |
| chat = message.get("chat", {}).get("id") | |
| text = (message.get("text") or "").strip() | |
| if chat is None or not text: | |
| return | |
| key = str(chat) | |
| mode = self.modes.get(key, "non_thinking") | |
| if text.startswith("/"): | |
| command, _, rest = text.partition(" ") | |
| command = command.split("@", 1)[0].lower() | |
| if command in ("/start", "/help"): | |
| self.send(chat, HELP + f"\n\ncurrent mode: {mode}") | |
| elif command.lstrip("/") in MODES: | |
| self.modes[key] = command.lstrip("/") | |
| self.send(chat, f"mode -> {self.modes[key]}") | |
| elif command == "/mode": | |
| chosen = normalise_mode(rest) | |
| if chosen: | |
| self.modes[key] = chosen | |
| self.send(chat, f"mode -> {self.modes.get(key, mode)}") | |
| elif command == "/clear": | |
| self.engine.reset(key) | |
| self.send(chat, "conversation cleared.") | |
| elif command == "/teach": | |
| question, sep, answer = rest.partition("|") | |
| self.send(chat, self.engine.teach(question, answer) if sep else "format: /teach सवाल | जवाब") | |
| else: | |
| self.send(chat, "unknown command - /help") | |
| return | |
| try: | |
| self.call("sendChatAction", {"chat_id": chat, "action": "typing"}, timeout=10) | |
| except Exception: | |
| pass | |
| try: | |
| result = self.engine.generate(text, mode=mode, session=key) | |
| except Exception as exc: | |
| self.send(chat, f"⚠️ error: {type(exc).__name__}: {exc}") | |
| return | |
| reply = result["answer"] | |
| if result["thinking"]: | |
| reply = f"💭 {result['thinking']}\n\n✅ {result['answer']}" | |
| self.send(chat, reply) | |
| def run(self, max_updates: Optional[int] = None) -> None: | |
| print(f" [telegram] bot @{self.bot_name} is live - press Ctrl+C to stop") | |
| handled, backoff = 0, 2 | |
| while not self.stop.is_set(): | |
| try: | |
| data = self.call("getUpdates", {"offset": self.offset, "timeout": self.poll_timeout, | |
| "allowed_updates": ["message"]}, timeout=self.poll_timeout + 15) | |
| backoff = 2 | |
| except KeyboardInterrupt: | |
| break | |
| except Exception as exc: | |
| print(f" [telegram] poll error ({type(exc).__name__}: {exc}); retry in {backoff}s") | |
| time.sleep(backoff) | |
| backoff = min(backoff * 2, 60) | |
| continue | |
| for update in data.get("result", []): | |
| self.offset = update["update_id"] + 1 | |
| if "message" in update: | |
| self.handle(update["message"]) | |
| handled += 1 | |
| if max_updates is not None and handled >= max_updates: | |
| return |