96 lines
2.6 KiB
Python
96 lines
2.6 KiB
Python
from html import escape
|
|
from uuid import uuid4
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from telegram import InlineQueryResultArticle, InputTextMessageContent, Message, Update
|
|
from telegram.constants import ParseMode
|
|
from telegram.ext import ContextTypes
|
|
|
|
from .ai import AIClient
|
|
from .config import HTML_FORMATS, MAX_TELEGRAM_MESSAGE_LENGTH
|
|
from .speech import SpeechTranscriber
|
|
from .storage import AssistantStorage
|
|
|
|
|
|
def make_article(
|
|
title: str,
|
|
text: str,
|
|
parse_mode: str | None = None,
|
|
) -> InlineQueryResultArticle:
|
|
return InlineQueryResultArticle(
|
|
id=f"inline_{uuid4()}",
|
|
title=title,
|
|
input_message_content=InputTextMessageContent(text, parse_mode=parse_mode),
|
|
)
|
|
|
|
|
|
def build_inline_results(query: str) -> list[InlineQueryResultArticle]:
|
|
escaped_query = escape(query)
|
|
|
|
return [
|
|
make_article("Caps", query.upper()),
|
|
*[
|
|
make_article(title, f"<{tag}>{escaped_query}</{tag}>", ParseMode.HTML)
|
|
for title, tag in HTML_FORMATS
|
|
],
|
|
]
|
|
|
|
|
|
def get_storage(context: ContextTypes.DEFAULT_TYPE) -> AssistantStorage:
|
|
return context.application.bot_data["storage"]
|
|
|
|
|
|
def get_ai_client(context: ContextTypes.DEFAULT_TYPE) -> AIClient:
|
|
return context.application.bot_data["ai_client"]
|
|
|
|
|
|
def get_tz(context: ContextTypes.DEFAULT_TYPE) -> ZoneInfo:
|
|
return context.application.bot_data["timezone"]
|
|
|
|
|
|
def get_speech_recognizer(context: ContextTypes.DEFAULT_TYPE) -> SpeechTranscriber:
|
|
return context.application.bot_data["speech_recognizer"]
|
|
|
|
|
|
def get_voice_max_duration(context: ContextTypes.DEFAULT_TYPE) -> int:
|
|
return int(context.application.bot_data["voice_max_duration"])
|
|
|
|
|
|
def command_text(context: ContextTypes.DEFAULT_TYPE) -> str:
|
|
return " ".join(context.args).strip()
|
|
|
|
|
|
def require_user_id(update: Update) -> int | None:
|
|
if update.effective_user:
|
|
return int(update.effective_user.id)
|
|
return None
|
|
|
|
|
|
async def reply_long(message: Message, text: str) -> None:
|
|
chunks = [
|
|
text[index : index + MAX_TELEGRAM_MESSAGE_LENGTH]
|
|
for index in range(0, len(text), MAX_TELEGRAM_MESSAGE_LENGTH)
|
|
] or [""]
|
|
|
|
for chunk in chunks:
|
|
await message.reply_text(chunk)
|
|
|
|
|
|
async def edit_or_reply(message: Message, text: str) -> None:
|
|
chunks = [
|
|
text[index : index + MAX_TELEGRAM_MESSAGE_LENGTH]
|
|
for index in range(0, len(text), MAX_TELEGRAM_MESSAGE_LENGTH)
|
|
] or [""]
|
|
|
|
await message.edit_text(chunks[0])
|
|
for chunk in chunks[1:]:
|
|
await message.reply_text(chunk)
|
|
|
|
|
|
def parse_positive_int(value: str) -> int | None:
|
|
try:
|
|
parsed = int(value)
|
|
except ValueError:
|
|
return None
|
|
return parsed if parsed > 0 else None
|