added RAG, Multiuser, TG bot

This commit is contained in:
2026-06-13 20:20:56 +00:00
parent 66e1b0e29e
commit c8a9429bed
142 changed files with 19901 additions and 8790 deletions
+143
View File
@@ -0,0 +1,143 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from aiogram import Bot
from bot.ha_client import HaClient
from bot.storage import LinkedUser, Storage
if TYPE_CHECKING:
pass
logger = logging.getLogger(__name__)
NOTICE_ROLES = frozenset({"notice", "character"})
TG_MAX_LEN = 4096
def split_telegram_message(text: str, limit: int = TG_MAX_LEN) -> list[str]:
if len(text) <= limit:
return [text]
chunks: list[str] = []
remaining = text
while remaining:
if len(remaining) <= limit:
chunks.append(remaining)
break
split_at = remaining.rfind("\n", 0, limit)
if split_at <= 0:
split_at = limit
chunks.append(remaining[:split_at])
remaining = remaining[split_at:].lstrip("\n")
return chunks
async def send_text(bot: Bot, chat_id: int, text: str) -> None:
for chunk in split_telegram_message(text):
await bot.send_message(chat_id, chunk)
async def advance_cursors(
storage: Storage,
client: HaClient,
user: LinkedUser,
) -> None:
sessions = await client.list_sessions()
for session in sessions:
session_id = int(session["id"])
after_id = await storage.get_last_message_id(user.telegram_id, session_id)
page = await client.get_messages(session_id, after_id=after_id or None, limit=100)
messages = page.get("messages") or []
max_id = after_id
for message in messages:
msg_id = int(message["id"])
max_id = max(max_id, msg_id)
if max_id > after_id:
await storage.set_last_message_id(user.telegram_id, session_id, max_id)
async def sync_notices_for_user(
bot: Bot,
storage: Storage,
ha_base_url: str,
user: LinkedUser,
*,
send: bool = True,
) -> None:
client = HaClient(ha_base_url, user.api_token)
try:
reminders = await client.get_reminders_snapshot()
pomodoro = await client.get_pomodoro_status()
except Exception:
logger.exception("Failed to fetch notify seq for telegram_id=%s", user.telegram_id)
reminders = {}
pomodoro = {}
reminder_seq = int(reminders.get("notify_seq") or 0)
pomodoro_seq = int((pomodoro.get("cycle") or {}).get("chat_notify_seq") or 0)
sessions = await client.list_sessions()
pending: list[tuple[int, str]] = []
for session in sessions:
session_id = int(session["id"])
after_id = await storage.get_last_message_id(user.telegram_id, session_id)
try:
page = await client.get_messages(session_id, after_id=after_id or None, limit=100)
except Exception:
logger.exception(
"Failed to fetch messages session_id=%s telegram_id=%s",
session_id,
user.telegram_id,
)
continue
messages = page.get("messages") or []
max_id = after_id
for message in messages:
msg_id = int(message["id"])
max_id = max(max_id, msg_id)
role = str(message.get("role") or "")
if role in NOTICE_ROLES and send:
content = str(message.get("content") or "").strip()
if content:
pending.append((msg_id, content))
if max_id > after_id:
await storage.set_last_message_id(user.telegram_id, session_id, max_id)
if send:
pending.sort(key=lambda item: item[0])
for _, content in pending:
try:
await send_text(bot, user.telegram_id, content)
except Exception:
logger.exception("Failed to send notice to telegram_id=%s", user.telegram_id)
await storage.update_seq(
user.telegram_id,
reminder_seq=reminder_seq,
pomodoro_seq=pomodoro_seq,
)
async def run_notify_worker(
bot: Bot,
storage: Storage,
ha_base_url: str,
poll_interval_sec: int,
) -> None:
import asyncio
logger.info("Notify worker started (interval=%ss)", poll_interval_sec)
while True:
users = await storage.list_linked_users()
for user in users:
try:
await sync_notices_for_user(bot, storage, ha_base_url, user, send=True)
except Exception:
logger.exception("Notify sync failed for telegram_id=%s", user.telegram_id)
await asyncio.sleep(poll_interval_sec)