added RAG, Multiuser, TG bot

This commit is contained in:
2026-06-14 06:26:16 +00:00
parent c8a9429bed
commit 0c8ab6018a
24 changed files with 1280 additions and 479 deletions
+76
View File
@@ -0,0 +1,76 @@
from __future__ import annotations
import logging
import re
from aiogram import Bot
from aiogram.types import BufferedInputFile
from bot.ha_client import HaClient
from bot.tg_util import send_text, split_telegram_message
logger = logging.getLogger(__name__)
IMAGE_MD_RE = re.compile(r"!\[([^\]]*)\]\(([^)]+)\)")
TG_CAPTION_MAX = 1024
def parse_notice_content(content: str) -> tuple[str, list[str]]:
image_paths: list[str] = []
def _replace(match: re.Match[str]) -> str:
image_paths.append(match.group(2).strip())
return ""
text = IMAGE_MD_RE.sub(_replace, content)
text = _plain_markdown(text)
return text, image_paths
def _plain_markdown(text: str) -> str:
text = re.sub(r"```[^\n]*\n(.*?)```", r"\1", text, flags=re.DOTALL)
text = re.sub(r"\*\*([^*]+)\*\*", r"\1", text)
text = re.sub(r"\*([^*]+)\*", r"\1", text)
text = re.sub(r"__([^_]+)__", r"\1", text)
text = re.sub(r"`([^`]+)`", r"\1", text)
text = re.sub(r"\n{3,}", "\n\n", text)
return text.strip()
async def send_notice_content(
bot: Bot,
chat_id: int,
content: str,
client: HaClient,
*,
ha_api_base: str,
) -> None:
caption, image_paths = parse_notice_content(content)
if not image_paths:
await send_text(bot, chat_id, caption or content)
return
caption_chunks = split_telegram_message(caption, TG_CAPTION_MAX) if caption else []
first_caption = caption_chunks[0] if caption_chunks else None
for index, image_path in enumerate(image_paths):
try:
image_bytes = await client.download_media(image_path, ha_api_base=ha_api_base)
except Exception:
logger.exception("Failed to download image %s for chat_id=%s", image_path, chat_id)
fallback = f"{caption}\n\n(не удалось загрузить: {image_path})".strip()
await send_text(bot, chat_id, fallback or image_path)
return
cap = first_caption if index == 0 else None
await bot.send_photo(
chat_id,
BufferedInputFile(image_bytes, filename="image.png"),
caption=cap or None,
)
if len(caption_chunks) > 1:
for extra in caption_chunks[1:]:
await send_text(bot, chat_id, extra)
elif caption and not first_caption and len(caption) > TG_CAPTION_MAX:
await send_text(bot, chat_id, caption)