From c3a4d45678b039f5d5bf84e0573a98a43c58fc06 Mon Sep 17 00:00:00 2001 From: Verum Date: Tue, 25 Feb 2025 15:02:38 +0700 Subject: [PATCH] =?UTF-8?q?1.0=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20/help=20=D0=BA=D0=B0=D0=BA=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B0=20=D0=BA=D0=BB=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=B0=D1=82=D1=83=D1=80,=20=D0=B8=20=D1=81=D0=BE=D1=85?= =?UTF-8?q?=D0=B7=D0=B4=D0=B0=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=BE=D0=B3=D0=BE=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F=20reply=5Fkb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BotCode/keyboards/inline_kb/__init__.py | 2 +- .../keyboards/inline_kb/start_inline_kb.py | 2 +- BotCode/keyboards/reply_kb/__init__.py | 1 + BotCode/keyboards/reply_kb/help_reply_kb.py | 28 +++++ BotCode/routers/commands/user_cmd/help_cmd.py | 6 +- .../routers/commands/user_cmd/start_cmd.py | 2 +- BotLibrary/samples/__init__.py | 3 +- ...eyboards_sample.py => inline_kb_sample.py} | 12 +- BotLibrary/samples/reply_kb_sample.py | 103 ++++++++++++++++++ BotLibrary/samples/user_cmd_class.py | 16 +++ ProjectsFiles/configs/.env | 4 +- 11 files changed, 162 insertions(+), 17 deletions(-) create mode 100644 BotCode/keyboards/reply_kb/help_reply_kb.py rename BotLibrary/samples/{keyboards_sample.py => inline_kb_sample.py} (71%) create mode 100644 BotLibrary/samples/reply_kb_sample.py diff --git a/BotCode/keyboards/inline_kb/__init__.py b/BotCode/keyboards/inline_kb/__init__.py index 80b74a0..51714e8 100644 --- a/BotCode/keyboards/inline_kb/__init__.py +++ b/BotCode/keyboards/inline_kb/__init__.py @@ -2,4 +2,4 @@ # Инициализация модуля inline_kb, для inline-клавиатур # Экспортирование модулей во внешние слои проекта -from start_inline_kb import get_start_kb +from .start_inline_kb import get_start_kb diff --git a/BotCode/keyboards/inline_kb/start_inline_kb.py b/BotCode/keyboards/inline_kb/start_inline_kb.py index baad589..fedf233 100644 --- a/BotCode/keyboards/inline_kb/start_inline_kb.py +++ b/BotCode/keyboards/inline_kb/start_inline_kb.py @@ -9,7 +9,7 @@ __all__ = ("get_start_kb",) # Функция создания клавиатуры def get_start_kb(row_width : int = 1): buttons = [ - ("Я Новичок!", None, "novice_cbd"), + ("Я Новичок!", "https://t.me/+3DOBTGhBIEc4ZThi", "novice_cbd"), ("Где я?", None, "where_i_am_cbd"), ("Мне уже известен этот феномен..", None, "menu"), ] diff --git a/BotCode/keyboards/reply_kb/__init__.py b/BotCode/keyboards/reply_kb/__init__.py index e8c26b2..9399f68 100644 --- a/BotCode/keyboards/reply_kb/__init__.py +++ b/BotCode/keyboards/reply_kb/__init__.py @@ -2,3 +2,4 @@ # Инициализация модуля reply_kb, для reply-клавиатур # Экспортирование модулей во внешние слои проекта +from .help_reply_kb import * diff --git a/BotCode/keyboards/reply_kb/help_reply_kb.py b/BotCode/keyboards/reply_kb/help_reply_kb.py new file mode 100644 index 0000000..02fc2ea --- /dev/null +++ b/BotCode/keyboards/reply_kb/help_reply_kb.py @@ -0,0 +1,28 @@ +# BotCode/keyboards/reply_kb/help_reply_kb.py +# Создание reply-клавиатуры на команду: /start с использованием всех возможностей + +from aiogram.types import ReplyKeyboardMarkup +from BotLibrary import BaseReplyKeyboard + +# Настройка экспорта в модули +__all__ = ("get_help_kb",) + +# Функция создания клавиатуры +def get_help_kb(row_width: int = 1, resize_kb: bool = True, one_time_kb: bool = True) -> ReplyKeyboardMarkup: + buttons = [ + ["Я Новичок!"], # Простая текстовая кнопка + [("Укажи местоположение", "location")], # Запрос геолокации + [("Поделись контактом", "contact")], # Запрос контакта + [("Выбери друзей", "users", {"request_id": 1, "max_quantity": 2})], # Запрос списка пользователей + [("Выбери чат", "chat", {"request_id": 2, "chat_is_channel": False})], # Запрос чата + [("Создай опрос", "poll")], # Запрос создания опроса + [("Создай квиз", "quiz")], # Запрос создания квиза + [("Открыть руководство", "web_app", {"url": "https://example.com/guide"})], # Запуск веб-приложения + [("Поделись пользователем", "user", {"request_id": 3, "user_is_premium": True})], # Запрос конкретного пользователя + ] + return BaseReplyKeyboard( + buttons, + resize_keyboard=resize_kb, + one_time_keyboard=one_time_kb, + row_width=row_width # Передаем row_width в класс + ).get_keyboard() diff --git a/BotCode/routers/commands/user_cmd/help_cmd.py b/BotCode/routers/commands/user_cmd/help_cmd.py index 5156676..4b7539a 100644 --- a/BotCode/routers/commands/user_cmd/help_cmd.py +++ b/BotCode/routers/commands/user_cmd/help_cmd.py @@ -2,7 +2,7 @@ # Работа с командой /help, для вывода помощи пользователю from BotLibrary import CommandHandler -from BotCode.keyboards import get_start_kb +from BotCode.keyboards import get_help_kb # Создание команды /help с нужными параметрами @@ -11,7 +11,7 @@ help_cmd = CommandHandler( description="Получить помощь", keywords=["help", "info", "помощь", "инфо", "информация", "рудз", "штащ", "byaj", "gjvjom", "byajhvfwbz"], callbackdata="keywords", - keyboard=get_start_kb, + keyboard=get_help_kb, text_msg="Привет! Это команда помощи. Тут ты можешь узнать, как пользоваться ботом.", - media="gif", path_to_media="https://t.me/c/2442589033/74653" + #media="", path_to_media="" ) diff --git a/BotCode/routers/commands/user_cmd/start_cmd.py b/BotCode/routers/commands/user_cmd/start_cmd.py index 6a24508..27b4e52 100644 --- a/BotCode/routers/commands/user_cmd/start_cmd.py +++ b/BotCode/routers/commands/user_cmd/start_cmd.py @@ -8,7 +8,7 @@ from BotCode.keyboards import get_start_kb start_cmd = CommandHandler( name="start", description="Добро пожаловать!", - keywords=["start"], + keywords=["start", "старт", "cnfhn", "ыефке", "пуск", "gecr", "on"], keyboard=get_start_kb, media="photo", path_to_media=[ diff --git a/BotLibrary/samples/__init__.py b/BotLibrary/samples/__init__.py index 1ad15bb..c4f0a2e 100644 --- a/BotLibrary/samples/__init__.py +++ b/BotLibrary/samples/__init__.py @@ -3,4 +3,5 @@ # Экспортирование модулей во внешние слои проекта from .user_cmd_class import * -from .keyboards_sample import * \ No newline at end of file +from .inline_kb_sample import * +from .reply_kb_sample import * diff --git a/BotLibrary/samples/keyboards_sample.py b/BotLibrary/samples/inline_kb_sample.py similarity index 71% rename from BotLibrary/samples/keyboards_sample.py rename to BotLibrary/samples/inline_kb_sample.py index 9f56a39..75beee7 100644 --- a/BotLibrary/samples/keyboards_sample.py +++ b/BotLibrary/samples/inline_kb_sample.py @@ -1,11 +1,7 @@ -# BotCode/keyboards/inline_kb/base_inline_kb.py -# Базовый класс для создания инлайн-клавиатур - -from aiogram.types import InlineKeyboardMarkup +from aiogram.types import InlineKeyboardMarkup, ReplyKeyboardRemove from aiogram.utils.keyboard import InlineKeyboardBuilder from typing import List, Tuple, Optional - class BaseInlineKeyboard: def __init__(self, buttons: List[Tuple[str, Optional[str], Optional[str]]], row_width: int = 1): """ @@ -17,8 +13,8 @@ class BaseInlineKeyboard: def get_keyboard(self) -> InlineKeyboardMarkup: """ - Создаёт инлайн-клавиатуру. - :return: объект InlineKeyboardMarkup + Создаёт инлайн-клавиатуру и возвращает её вместе с объектом для удаления reply-клавиатуры. + :return: кортеж (InlineKeyboardMarkup, ReplyKeyboardRemove) """ ikb = InlineKeyboardBuilder() for text, url, callback_data in self.buttons: @@ -28,4 +24,4 @@ class BaseInlineKeyboard: ikb.button(text=text, callback_data=callback_data) ikb.adjust(self.row_width) - return ikb.as_markup() + return ikb.as_markup() \ No newline at end of file diff --git a/BotLibrary/samples/reply_kb_sample.py b/BotLibrary/samples/reply_kb_sample.py new file mode 100644 index 0000000..6cb42bc --- /dev/null +++ b/BotLibrary/samples/reply_kb_sample.py @@ -0,0 +1,103 @@ +# BotCode/keyboards/reply_kb/base_reply_kb.py +# Базовый класс для создания reply-клавиатур с расширенными возможностями и поддержкой row_width + +from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, KeyboardButtonPollType, WebAppInfo, KeyboardButtonRequestUsers, KeyboardButtonRequestChat, KeyboardButtonRequestUser +from aiogram.utils.keyboard import ReplyKeyboardBuilder +from typing import List, Union, Tuple, Optional, Dict, Any + +class BaseReplyKeyboard: + def __init__( + self, + buttons: List[List[Union[str, Tuple[str, str, Optional[Dict[str, Any]]]]]], + resize_keyboard: bool = True, + one_time_keyboard: bool = False, + row_width: int = 1 # Добавляем row_width как параметр + ): + """ + :param buttons: список кнопок, каждая из которых может быть: + - строкой (обычная кнопка с текстом) + - кортежем (текст, тип кнопки, дополнительные параметры). + Типы кнопок: "location", "contact", "users", "chat", "poll", "quiz", "web_app", "user". + Дополнительные параметры: словарь с настройками (опционально). + :param resize_keyboard: изменять ли размер клавиатуры под содержимое. + :param one_time_keyboard: скрывать ли клавиатуру после нажатия. + :param row_width: количество кнопок в одной строке (если требуется динамическое распределение). + """ + self.buttons = buttons + self.resize_keyboard = resize_keyboard + self.one_time_keyboard = one_time_keyboard + self.row_width = row_width + + def get_keyboard(self) -> ReplyKeyboardMarkup: + """ + Создаёт reply-клавиатуру с поддержкой всех типов кнопок и динамическим распределением по row_width. + :return: объект ReplyKeyboardMarkup + """ + rkb = ReplyKeyboardBuilder() + + # Преобразуем вложенные списки в плоский список для динамического распределения + flat_buttons = [button for row in self.buttons for button in row] + + # Разбиваем кнопки на строки с учетом row_width + for i in range(0, len(flat_buttons), self.row_width): + row = flat_buttons[i:i + self.row_width] + buttons = [] + for button in row: + if isinstance(button, tuple): + text, button_type = button[0], button[1] + params = button[2] if len(button) > 2 else {} + + if button_type == "location": + buttons.append(KeyboardButton(text=text, request_location=True)) + elif button_type == "contact": + buttons.append(KeyboardButton(text=text, request_contact=True)) + elif button_type == "users": + buttons.append(KeyboardButton( + text=text, + request_users=KeyboardButtonRequestUsers( + request_id=params.get("request_id", 1), + user_is_bot=params.get("user_is_bot"), + user_is_premium=params.get("user_is_premium"), + max_quantity=params.get("max_quantity", 1) + ) + )) + elif button_type == "chat": + buttons.append(KeyboardButton( + text=text, + request_chat=KeyboardButtonRequestChat( + request_id=params.get("request_id", 1), + chat_is_channel=params.get("chat_is_channel", False), + chat_is_forum=params.get("chat_is_forum"), + chat_has_username=params.get("chat_has_username"), + chat_is_created=params.get("chat_is_created") + ) + )) + elif button_type == "poll": + buttons.append(KeyboardButton( + text=text, + request_poll=KeyboardButtonPollType(type="regular") + )) + elif button_type == "quiz": + buttons.append(KeyboardButton( + text=text, + request_poll=KeyboardButtonPollType(type="quiz") + )) + elif button_type == "web_app": + buttons.append(KeyboardButton( + text=text, + web_app=WebAppInfo(url=params.get("url", "")) + )) + elif button_type == "user": + buttons.append(KeyboardButton( + text=text, + request_user=KeyboardButtonRequestUser( + request_id=params.get("request_id", 1), + user_is_bot=params.get("user_is_bot"), + user_is_premium=params.get("user_is_premium") + ) + )) + else: + buttons.append(KeyboardButton(text=button)) + rkb.row(*buttons) + + return rkb.as_markup(resize_keyboard=self.resize_keyboard, one_time_keyboard=self.one_time_keyboard) \ No newline at end of file diff --git a/BotLibrary/samples/user_cmd_class.py b/BotLibrary/samples/user_cmd_class.py index f670c24..d5ea90b 100644 --- a/BotLibrary/samples/user_cmd_class.py +++ b/BotLibrary/samples/user_cmd_class.py @@ -80,6 +80,22 @@ class CommandHandler: chat_id=message.chat.id, action=ChatAction.TYPING, ) + elif self.media == "quiz": + # Отправка викторины (quiz) + await message.reply_poll( + question=self.text_msg, # Текст сообщения используется как вопрос викторины + options=["Вариант 1", "Вариант 2"], # Заглушка, варианты нужно задавать отдельно + is_anonymous=True, + type="quiz", + correct_option_id=0, # Первый вариант по умолчанию правильный + reply_markup=self.keyboard() if self.keyboard else None, + disable_notification=self.disable_notification + ) + if self.chat_action: + await message.bot.send_chat_action( + chat_id=message.chat.id, + action=ChatAction.TYPING, + ) else: if self.media == "photo" and len(self.path_to_media) > 1: # Отправка медиагруппы для фотографий diff --git a/ProjectsFiles/configs/.env b/ProjectsFiles/configs/.env index c4a15e3..5198bf0 100644 --- a/ProjectsFiles/configs/.env +++ b/ProjectsFiles/configs/.env @@ -3,8 +3,8 @@ # Токены от ботов телеграмма BOT_TOKEN=7193685715:AAHFEnFreZGLQcHj8_wdWYJ2FLPrB-A-hzY -BOT1_TOKEN=8076305634:AAGNoo4N-WVP9mbeD76G7SLClSsySw23nGw -BOT2_TOKEN= +BOT1_TOKEN=7193685715:AAHFEnFreZGLQcHj8_wdWYJ2FLPrB-A-hzY +BOT2_TOKEN=8076305634:AAGNoo4N-WVP9mbeD76G7SLClSsySw23nGw # Ключи от API API_KEY=КЛЮЧ_ОТ_СТОРОННЕГО_API