mann / telegramchat.py
gcharanteja
mcp integration
af49805
Raw
History Blame Contribute Delete
2.95 kB
import logging
import threading
from typing import Callable, Optional
import telebot
class TelegramChatService:
def __init__(self, llm_factory: Callable, token: str, logger: Optional[logging.Logger] = None, jira_connector=None):
self._llm_factory = llm_factory
self._token = token
self._logger = logger or logging.getLogger(__name__)
self._jira_connector = jira_connector
self._bot: Optional[telebot.TeleBot] = None
self._llm = None
self._thread: Optional[threading.Thread] = None
self._lock = threading.Lock()
self._running = False
def _ensure_bot(self) -> telebot.TeleBot:
if self._bot is not None:
return self._bot
bot = telebot.TeleBot(self._token, parse_mode=None)
@bot.message_handler(commands=["start"])
def on_start(message):
bot.reply_to(message, "Telegram chat is ready. Send me a message.")
@bot.message_handler(func=lambda message: True)
def on_text(message):
text = (message.text or "").strip()
if not text:
bot.reply_to(message, "Please send a non-empty message.")
return
try:
answer = None
if self._jira_connector is not None:
answer = self._jira_connector.maybe_handle(text)
if answer is None:
if self._llm is None:
self._llm = self._llm_factory()
answer = self._llm.invoke(text)
bot.reply_to(message, str(answer).strip())
except Exception as exc:
self._logger.exception("Failed to handle Telegram message")
bot.reply_to(message, f"Error: {exc}")
self._bot = bot
return bot
def _poll(self) -> None:
bot = self._ensure_bot()
try:
bot.delete_webhook(drop_pending_updates=False)
bot.infinity_polling(timeout=20, long_polling_timeout=20, skip_pending=True)
except Exception:
self._logger.exception("Telegram polling crashed")
finally:
with self._lock:
self._running = False
def start(self) -> bool:
with self._lock:
if self._running:
return False
if not self._token:
raise ValueError("Missing TELEGRAM_TOKEN")
self._running = True
self._thread = threading.Thread(target=self._poll, daemon=True)
self._thread.start()
return True
def stop(self) -> bool:
with self._lock:
if not self._running:
return False
self._running = False
if self._bot is not None:
self._bot.stop_polling()
return True
@property
def is_running(self) -> bool:
with self._lock:
return self._running