From 104e91373c0c315060860e04c2d34d72b9a96887 Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:58:18 +0300 Subject: [PATCH 01/13] Starting REFACTORING!!! --- README.md | 3 + bozenka/database/__init__.py | 4 +- bozenka/database/tables/telegram.py | 12 ++-- bozenka/features/__init__.py | 58 +++++++++++++++++++ .../telegram/handlers/queries/setup.py | 6 +- .../utils/simpler/lists_of_content.py | 24 ++++---- .../utils/simpler/solution_simpler.py | 46 +++++++-------- 7 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 bozenka/features/__init__.py diff --git a/README.md b/README.md index 0ea2dd2..6e0f2af 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,11 @@ +[![CodeFactor](https://www.codefactor.io/repository/github/kittyneverdies/bozenka/badge)](https://www.codefactor.io/repository/github/kittyneverdies/bozenka) + [Telegram Channel](https://t.me/bozodevelopment/) +

Telegram Instance

diff --git a/bozenka/database/__init__.py b/bozenka/database/__init__.py index 8e6d30f..a982e1f 100644 --- a/bozenka/database/__init__.py +++ b/bozenka/database/__init__.py @@ -1,5 +1,5 @@ -__all__ = ["MainModel", "get_async_engine", "get_sessions_maker", "Users", "get_user_info", "generate_url"] +__all__ = ["MainModel", "get_async_engine", "get_sessions_maker", "TelegramUsers", "get_user_info", "generate_url"] from .main import MainModel from .engine import get_async_engine, get_sessions_maker, generate_url -from bozenka.database.tables.telegram import Users, get_user_info +from bozenka.database.tables.telegram import TelegramUsers, get_user_info diff --git a/bozenka/database/tables/telegram.py b/bozenka/database/tables/telegram.py index 255156c..f83b208 100644 --- a/bozenka/database/tables/telegram.py +++ b/bozenka/database/tables/telegram.py @@ -7,7 +7,7 @@ from sqlalchemy.orm import sessionmaker from bozenka.database.main import MainModel -class Users(MainModel): +class TelegramUsers(MainModel): """ Telegram users table, contains: @@ -30,7 +30,7 @@ class Users(MainModel): return f"" -class ChatSettings(MainModel): +class TelegramChatSettings(MainModel): """ Telegram of chat settings table, contains: @@ -69,8 +69,8 @@ async def get_chat_configuration(chat_id: int, session: async_sessionmaker): """ async with session() as session: async with session.begin(): - (await session.execute(select(ChatSettings).where(ChatSettings.chat_id == chat_id))) - return (await session.execute(select(ChatSettings).where(ChatSettings.chat_id == chat_id))).one_or_none() + (await session.execute(select(TelegramChatSettings).where(TelegramChatSettings.chat_id == chat_id))) + return (await session.execute(select(TelegramChatSettings).where(TelegramChatSettings.chat_id == chat_id))).one_or_none() async def get_chat_config_value(chat_id: int, session: async_sessionmaker, setting) -> bool: @@ -83,7 +83,7 @@ async def get_chat_config_value(chat_id: int, session: async_sessionmaker, setti """ async with session() as session: async with session.begin(): - rows = (await session.execute(select(setting.db_name).where(ChatSettings.chat_id == chat_id))).one() + rows = (await session.execute(select(setting.db_name).where(TelegramChatSettings.chat_id == chat_id))).one() return rows[0] @@ -97,6 +97,6 @@ async def get_user_info(user_id: int, chat_id: int, session: async_sessionmaker) """ async with session() as session: async with session.begin(): - return (await session.execute(select(Users).where(Users.user_id == user_id and Users.chat_id == chat_id))).one_or_none() + return (await session.execute(select(TelegramUsers).where(TelegramUsers.user_id == user_id and TelegramUsers.chat_id == chat_id))).one_or_none() diff --git a/bozenka/features/__init__.py b/bozenka/features/__init__.py new file mode 100644 index 0000000..a6b7365 --- /dev/null +++ b/bozenka/features/__init__.py @@ -0,0 +1,58 @@ +from typing import Callable + +from aiogram.filters import CommandObject +from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery +from sqlalchemy.ext.asyncio import async_sessionmaker + +from bozenka.database.tables.telegram import TelegramChatSettings + + +class LineralFeature: + """ + A classic class of lineral (basic) + feature of bozenka. IN FUTURE! + """ + + cmd_description: str = "Your description of command" + + @NotImplemented + async def generate_telegram_inline_keyboard(self) -> InlineKeyboardMarkup: + """ + Generates a special telegram keyboard (menu) + :return: Inline Keyboard + """ + pass + + @NotImplemented + async def telegram_command_handler(self, msg: Message, cmd: CommandObject, session_maker: async_sessionmaker) -> None: + """ + A special telegram handler for command (if exist) + :param msg: Telegram message object + :param cmd: Aiogram command object + :param session_maker: Async session maker object of SQLAlchemy + :return: Nothing + """ + pass + + @NotImplemented + async def telegram_callback_handler(self, call: CallbackQuery, callback_data, session_maker: async_sessionmaker) -> None: + """ + A special telegram handler for command (if exist) + :param call: Telegram callbackquery object + :param callback_data: A custom callback data created by callback factory + :param session_maker: Async session maker object of SQLAlchemy + :return: Nothing + """ + pass + + def __init__(self): + """ + All information about feature + will be inside this function + """ + self.cmd_description: str = "Your description of command" + # Telegram feature settings + self.telegram_setting = TelegramChatSettings.text_generation + self.telegram_commands: list[str | None] = ["test"] + self.telegram_cmd_avaible = True # Is a feature have a commands + self.telegram_callback_factory = None diff --git a/bozenka/instances/telegram/handlers/queries/setup.py b/bozenka/instances/telegram/handlers/queries/setup.py index 3352c64..e56239a 100644 --- a/bozenka/instances/telegram/handlers/queries/setup.py +++ b/bozenka/instances/telegram/handlers/queries/setup.py @@ -2,7 +2,7 @@ from aiogram.types import CallbackQuery, Message from sqlalchemy import select, Update from sqlalchemy.ext.asyncio import async_sessionmaker -from bozenka.database.tables.telegram import ChatSettings, get_chat_config_value +from bozenka.database.tables.telegram import TelegramChatSettings, get_chat_config_value from bozenka.instances.telegram.utils.callbacks_factory import SetupCategory, SetupFeature, SetupAction from bozenka.instances.telegram.utils.keyboards import setup_category_keyboard, setup_feature_keyboard from bozenka.instances.telegram.utils.simpler import list_of_features @@ -62,10 +62,10 @@ async def inline_feature_edited(call: CallbackQuery, callback_data: SetupAction, """ async with session_maker() as session: async with session.begin(): - await session.execute(Update(ChatSettings) + await session.execute(Update(TelegramChatSettings) .values({list_of_features[callback_data.feature_category][callback_data.feature_index].settings_name: callback_data.action == "enable"}) - .where(ChatSettings.chat_id == call.message.chat.id)) + .where(TelegramChatSettings.chat_id == call.message.chat.id)) await call.message.edit_text( list_of_features[callback_data.feature_category][callback_data.feature_index].description, reply_markup=await setup_feature_keyboard(category=callback_data.feature_category, diff --git a/bozenka/instances/telegram/utils/simpler/lists_of_content.py b/bozenka/instances/telegram/utils/simpler/lists_of_content.py index 216a6c0..34327aa 100644 --- a/bozenka/instances/telegram/utils/simpler/lists_of_content.py +++ b/bozenka/instances/telegram/utils/simpler/lists_of_content.py @@ -6,7 +6,7 @@ from g4f import Provider from g4f.Provider import RetryProvider from varname import nameof -from bozenka.database.tables.telegram import ChatSettings +from bozenka.database.tables.telegram import TelegramChatSettings @dataclass @@ -52,7 +52,7 @@ list_of_features = { "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота.", callback_name="pins", settings_name="pins", - db_name=ChatSettings.pins + db_name=TelegramChatSettings.pins ), BaseFeature( name="Модерация чата 🕵️", @@ -72,7 +72,7 @@ list_of_features = { "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота.", callback_name="moderation", settings_name="moderation", - db_name=ChatSettings.moderation + db_name=TelegramChatSettings.moderation ), BaseFeature( name="Работа с Форумом 💬", @@ -87,7 +87,7 @@ list_of_features = { "включен форум", callback_name="topics", settings_name="topics", - db_name=ChatSettings.topics + db_name=TelegramChatSettings.topics ), BaseFeature( name="Приглашения в Чат ✉", @@ -96,7 +96,7 @@ list_of_features = { "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота.", callback_name="invites", settings_name="invite_generator", - db_name=ChatSettings.invite_generator + db_name=TelegramChatSettings.invite_generator ), BaseFeature( name="Результаты в лс ✉", @@ -105,7 +105,7 @@ list_of_features = { "Никаких особых прав у бота не требует.", callback_name="results_in_dm", settings_name="results_in_dm", - db_name=ChatSettings.results_in_dm + db_name=TelegramChatSettings.results_in_dm ), BaseFeature( name="Оповещение об ограничении 🗯", @@ -114,7 +114,7 @@ list_of_features = { "Никаких особых прав у бота не требует.", callback_name="restrict_notification", settings_name="restrict_notification", - db_name=ChatSettings.restrict_notification + db_name=TelegramChatSettings.restrict_notification ) ], "Members": [ @@ -124,7 +124,7 @@ list_of_features = { "\nПриветсвенные сообщения новым и ушедшим пользователям.", callback_name="welcome", settings_name="welcome_messages", - db_name=ChatSettings.welcome_messages + db_name=TelegramChatSettings.welcome_messages ), BaseFeature( name="Оповещение о муте 📬", @@ -132,7 +132,7 @@ list_of_features = { "\nОповещает пользователя в личных сообщениях, что тот был: замучен, размучен, забанен, разбанен", callback_name="notify", settings_name="restrict_notification", - db_name=ChatSettings.restrict_notification + db_name=TelegramChatSettings.restrict_notification ) ], "Devs": [ @@ -143,7 +143,7 @@ list_of_features = { "/hi, /hello, /privet и т.п., отвечая приветсвием на сообщение пользователя.", callback_name="hi", settings_name="hi_command", - db_name=ChatSettings.hi_command + db_name=TelegramChatSettings.hi_command ), BaseFeature( name="ИИ ЧатБот 🤖", @@ -156,7 +156,7 @@ list_of_features = { "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘", callback_name="gtm", settings_name="gpt_conversations", - db_name=ChatSettings.text_generation + db_name=TelegramChatSettings.text_generation ), BaseFeature( name="Генерация изображений 📸", @@ -164,7 +164,7 @@ list_of_features = { "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘", callback_name="gpm", settings_name="123", - db_name=ChatSettings.image_generation + db_name=TelegramChatSettings.image_generation ) ] diff --git a/bozenka/instances/telegram/utils/simpler/solution_simpler.py b/bozenka/instances/telegram/utils/simpler/solution_simpler.py index 4107cf1..a501cca 100644 --- a/bozenka/instances/telegram/utils/simpler/solution_simpler.py +++ b/bozenka/instances/telegram/utils/simpler/solution_simpler.py @@ -12,8 +12,8 @@ from aiogram.types import ChatPermissions, CallbackQuery from sqlalchemy import Update from sqlalchemy.ext.asyncio import async_sessionmaker -from bozenka.database import get_user_info, Users -from bozenka.database.tables.telegram import get_chat_configuration, ChatSettings +from bozenka.database import get_user_info, TelegramUsers +from bozenka.database.tables.telegram import get_chat_configuration, TelegramChatSettings from bozenka.instances.telegram.utils.callbacks_factory import BanData, UnbanData, MuteData, UnmuteData @@ -59,7 +59,7 @@ class SolutionSimpler: return finally: if not await get_user_info(user_id=data.user_id_ban, chat_id=call.message.chat.id, session=session): - new_user = Users( + new_user = TelegramUsers( user_id=data.user_id_ban, chat_id=call.message.chat.id, is_banned=True, @@ -74,9 +74,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_banned=True, ban_reason=None) - .where(Users.user_id == data.user_id_ban and Users.chat_id == call.message.chat.id)) + .where(TelegramUsers.user_id == data.user_id_ban and TelegramUsers.chat_id == call.message.chat.id)) @staticmethod async def ban_user(msg: types.Message, cmd: CommandObject, session: async_sessionmaker) -> dict[str, None | str | bool]: @@ -125,7 +125,7 @@ class SolutionSimpler: return config finally: if not await get_user_info(user_id=msg.reply_to_message.from_user.id, chat_id=msg.chat.id, session=session): - new_user = Users( + new_user = TelegramUsers( user_id=msg.reply_to_message.from_user.id, chat_id=msg.chat.id, is_banned=True, @@ -140,9 +140,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_banned=True, ban_reason=None if config["reason"] == "" else config["reason"]) - .where(Users.user_id == msg.reply_to_message.from_user.id and Users.chat_id == msg.chat.id)) + .where(TelegramUsers.user_id == msg.reply_to_message.from_user.id and TelegramUsers.chat_id == msg.chat.id)) return config @staticmethod @@ -158,9 +158,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_banned=False, ban_reason=None) - .where(Users.user_id == data.user_id_unban and Users.chat_id == call.message.chat.id) + .where(TelegramUsers.user_id == data.user_id_unban and TelegramUsers.chat_id == call.message.chat.id) ) @staticmethod @@ -179,9 +179,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_banned=False, ban_reason=None) - .where(Users.user_id == msg.from_user.id and Users.chat_id == msg.chat.id) + .where(TelegramUsers.user_id == msg.from_user.id and TelegramUsers.chat_id == msg.chat.id) ) @staticmethod @@ -227,7 +227,7 @@ class SolutionSimpler: if info is None: print("TTTTT") print(info) - new_user = Users( + new_user = TelegramUsers( user_id=data.user_id_mute, chat_id=call.message.chat.id, is_banned=None, @@ -242,9 +242,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_muted=True, mute_reason=None) - .where(Users.user_id == data.user_id_mute and Users.chat_id == call.message.chat.id)) + .where(TelegramUsers.user_id == data.user_id_mute and TelegramUsers.chat_id == call.message.chat.id)) @staticmethod async def mute_user(msg: types.Message, cmd: CommandObject, session: async_sessionmaker) -> dict[str, None | str | bool]: @@ -282,7 +282,7 @@ class SolutionSimpler: level=logging.INFO) finally: if not await get_user_info(user_id=msg.reply_to_message.from_user.id, chat_id=msg.chat.id, session=session): - new_user = Users( + new_user = TelegramUsers( user_id=msg.reply_to_message.from_user.id, chat_id=msg.chat.id, is_banned=None, @@ -297,9 +297,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_muted=True, mute_reason=None if config["reason"] == "" else config["reason"]) - .where(Users.user_id == msg.reply_to_message.from_user.id and Users.chat_id == msg.chat.id)) + .where(TelegramUsers.user_id == msg.reply_to_message.from_user.id and TelegramUsers.chat_id == msg.chat.id)) return config @staticmethod @@ -318,9 +318,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_muted=False, mute_reason=None, ) - .where(Users.user_id == data.user_id_unmute and Users.chat_id == call.message.chat.id) + .where(TelegramUsers.user_id == data.user_id_unmute and TelegramUsers.chat_id == call.message.chat.id) ) @staticmethod @@ -341,9 +341,9 @@ class SolutionSimpler: async with session() as session: async with session.begin(): await session.execute( - Update(Users) + Update(TelegramUsers) .values(is_muted=False, mute_reason=None, ) - .where(Users.user_id == msg.from_user.id and Users.chat_id == msg.chat.id) + .where(TelegramUsers.user_id == msg.from_user.id and TelegramUsers.chat_id == msg.chat.id) ) @staticmethod @@ -411,7 +411,7 @@ class SolutionSimpler: chat_data = await get_chat_configuration(msg.chat.id, session) print(chat_data) if not chat_data: - new_chat_data = ChatSettings(chat_id=msg.chat.id) + new_chat_data = TelegramChatSettings(chat_id=msg.chat.id) async with session() as session: async with session.begin(): await session.merge(new_chat_data) -- 2.30.2 From 4839b94cbcdcbc4b6feec05a04a09ab318bea25f Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:41:50 +0300 Subject: [PATCH 02/13] Contin refactoring pt. 2 --- bozenka/features/__init__.py | 26 +- bozenka/features/admin/__init__.py | 0 bozenka/features/admin/invite.py | 0 bozenka/features/admin/moderation.py | 469 ++++++++++++++++++ bozenka/features/admin/pins.py | 104 ++++ bozenka/features/admin/topics.py | 152 ++++++ bozenka/features/basic/__init__.py | 0 bozenka/features/basic/setup.py | 0 bozenka/features/basic/start.py | 225 +++++++++ bozenka/features/user/__init__.py | 0 bozenka/features/user/image_generation.py | 0 bozenka/features/user/text_generation.py | 0 bozenka/features/user/welcome.py | 0 .../telegram/handlers/main/__init__.py | 4 + .../telegram/utils/callbacks_factory/start.py | 2 +- .../telegram/utils/middleware/__init__.py | 10 +- .../telegram/utils/middleware/antiflood.py | 16 + .../telegram/utils/middleware/retry.py | 28 -- 18 files changed, 998 insertions(+), 38 deletions(-) create mode 100644 bozenka/features/admin/__init__.py create mode 100644 bozenka/features/admin/invite.py create mode 100644 bozenka/features/admin/moderation.py create mode 100644 bozenka/features/admin/pins.py create mode 100644 bozenka/features/admin/topics.py create mode 100644 bozenka/features/basic/__init__.py create mode 100644 bozenka/features/basic/setup.py create mode 100644 bozenka/features/basic/start.py create mode 100644 bozenka/features/user/__init__.py create mode 100644 bozenka/features/user/image_generation.py create mode 100644 bozenka/features/user/text_generation.py create mode 100644 bozenka/features/user/welcome.py diff --git a/bozenka/features/__init__.py b/bozenka/features/__init__.py index a6b7365..401b1df 100644 --- a/bozenka/features/__init__.py +++ b/bozenka/features/__init__.py @@ -1,5 +1,6 @@ from typing import Callable +from aiogram import Dispatcher from aiogram.filters import CommandObject from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery from sqlalchemy.ext.asyncio import async_sessionmaker @@ -7,15 +8,16 @@ from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import TelegramChatSettings -class LineralFeature: +class BasicFeature: """ A classic class of lineral (basic) feature of bozenka. IN FUTURE! """ - cmd_description: str = "Your description of command" - @NotImplemented + ''' + Here is example of code you can add: + async def generate_telegram_inline_keyboard(self) -> InlineKeyboardMarkup: """ Generates a special telegram keyboard (menu) @@ -23,10 +25,10 @@ class LineralFeature: """ pass - @NotImplemented async def telegram_command_handler(self, msg: Message, cmd: CommandObject, session_maker: async_sessionmaker) -> None: """ A special telegram handler for command (if exist) + It is just an example :param msg: Telegram message object :param cmd: Aiogram command object :param session_maker: Async session maker object of SQLAlchemy @@ -34,17 +36,17 @@ class LineralFeature: """ pass - @NotImplemented async def telegram_callback_handler(self, call: CallbackQuery, callback_data, session_maker: async_sessionmaker) -> None: """ A special telegram handler for command (if exist) + It is just an example :param call: Telegram callbackquery object :param callback_data: A custom callback data created by callback factory :param session_maker: Async session maker object of SQLAlchemy :return: Nothing """ pass - + ''' def __init__(self): """ All information about feature @@ -56,3 +58,15 @@ class LineralFeature: self.telegram_commands: list[str | None] = ["test"] self.telegram_cmd_avaible = True # Is a feature have a commands self.telegram_callback_factory = None + self.telegram_message_handlers = { + """ + Format is + Handler: [Filters] + """ + } + self.telegram_callback_handlers = { + """ + Format is + Handler: [Filters] + """ + } diff --git a/bozenka/features/admin/__init__.py b/bozenka/features/admin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/features/admin/invite.py b/bozenka/features/admin/invite.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/features/admin/moderation.py b/bozenka/features/admin/moderation.py new file mode 100644 index 0000000..4e39e53 --- /dev/null +++ b/bozenka/features/admin/moderation.py @@ -0,0 +1,469 @@ +import logging + +from aiogram import F +from aiogram.enums import ChatType, ChatMemberStatus +from aiogram.filters import Command, CommandObject +from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, InlineKeyboardButton +from aiogram.utils.keyboard import InlineKeyboardBuilder +from sqlalchemy.ext.asyncio import async_sessionmaker + +from bozenka.database.tables.telegram import get_chat_config_value +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import HelpCategory, HelpBackCategory, HelpFeature, HelpBack, \ + UnbanData, BanData, UnmuteData, MuteData +from bozenka.instances.telegram.utils.keyboards import help_category_keyboard, help_keyboard, \ + help_feature_keyboard, gpt_categories_keyboard, ban_keyboard, delete_keyboard, mute_keyboard, unmute_keyboard, \ + unban_keyboard +from bozenka.instances.telegram.utils.simpler import list_of_features, SolutionSimpler +from bozenka.instances.version import build, is_updated + + +class Moderation(BasicFeature): + """ + A class of moderation related feature + All staff related to it will be here + """ + cmd_description: str = "Basic command to show main menu" + + @staticmethod + async def telegram_ban_callback_handler(call: CallbackQuery, callback_data: BanData, + session_maker: async_sessionmaker) -> None: + """ + CallbackQuery handler, what bannes users after callback + :param call: CallBackQuery telegram object + :param callback_data: BanData object + :param session_maker: AsyncSessionmaker object + :return: None + """ + clicked_user = await call.message.chat.get_member(call.from_user.id) + banned_user = await call.message.chat.get_member(int(callback_data.user_id_ban)) + + send_notification = await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]) + + if call.from_user.id != callback_data.user_id_clicked \ + and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: + return + await SolutionSimpler.inline_ban_user(call=call, data=callback_data, session=session_maker) + + if not banned_user.is_member and banned_user.status == ChatMemberStatus.KICKED: + await call.answer("Уже заблокирован ✅") + else: + await call.answer("Успешно заблокирован ✅") + + await call.message.edit_text( + "Удача ✅\n" + f"{banned_user.user.mention_html('Этот пользователь')} был заблокирован {call.from_user.mention_html('этим пользователем')}.", + reply_markup=ban_keyboard(admin_id=call.from_user.id, ban_id=banned_user.user.id) + ) + + if send_notification: + await call.message.bot.send_message( + chat_id=banned_user.user.id, + text=f"{banned_user.user.mention_html('Вы')} были заблокированы {call.from_user.mention_html('этим пользователем')} в чате {call.message.chat.id}.", + reply_markup=delete_keyboard(admin_id=banned_user.user.id) + ) + + logging.log(msg=f"Banned user @{banned_user.user.full_name} user_id=f{banned_user.user.id}", level=logging.INFO) + + @staticmethod + async def telegram_unban_callback_handler(call: CallbackQuery, callback_data: UnbanData, + session_maker: async_sessionmaker) -> None: + """ + CallbackQuery handler, what unbannes users after callback + :param call: CallBackQuery telegram object + :param callback_data: UnbanData object + :param session_maker: AsyncSessionmaker object + :return: None + """ + clicked_user = await call.message.chat.get_member(call.from_user.id) + unbanned_user = await call.message.chat.get_member(int(callback_data.user_id_unban)) + + if call.from_user.id != callback_data.user_id_clicked \ + and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: + return + + await SolutionSimpler.inline_unban_user(call=call, data=callback_data, session=session_maker) + + if unbanned_user.is_member and unbanned_user.status != ChatMemberStatus.KICKED: + await call.answer("Уже разблокирован ✅") + else: + await call.answer("Успешно разблокирован ✅") + await call.message.edit_text( + "Удача ✅\n" + f"{unbanned_user.user.mention_html('Этот пользователь')} был разблокирован {call.from_user.mention_html('этим пользователем')}.", + reply_markup=unban_keyboard(admin_id=call.from_user.id, ban_id=unbanned_user.user.id) + ) + + if await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]): + await call.message.bot.send_message( + chat_id=unbanned_user.user.id, + text=f"{unbanned_user.user.mention_html('Вы')} были разблокирован {call.from_user.mention_html('этим пользователем')} в чате {call.message.chat.id}.", + reply_markup=delete_keyboard(admin_id=unbanned_user.user.id) + ) + + logging.log(msg=f"Unbanned user @{unbanned_user.user.full_name} user_id=f{unbanned_user.user.id}", + level=logging.INFO) + + @staticmethod + async def telegram_ban_cmd_handler(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None: + """ + /ban command function, supports time and reasons. + :param msg: Message telegram object + :param command: Object of telegram command + :param session_maker: Session maker object of SqlAlchemy + :return: Nothing + """ + banned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) + send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][4]) + send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]) + + where_send = { + True: msg.from_user.id, + False: msg.chat.id + } + + if banned_user.status == ChatMemberStatus.KICKED: + await msg.bot.send_message(chat_id=where_send[send_to_dm], + text="Ошибка ❌\n" + "Этот пользователь уже удален из группы", + reply_markup=delete_keyboard(msg.from_user.id)) + return + + config = await SolutionSimpler.ban_user(msg, command, session_maker) + if config["reason"] and config["ban_time"]: + await msg.bot.send_message(chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} " + f"был заблокирован {msg.from_user.mention_html('этим пользователем')}.\n" + f"По причине {config['reason']}, до даты {config['ban_time']}", + reply_markup=ban_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) + if send_notification: + await msg.bot.send_message(chat_id=banned_user.user.id, + text="Вы " + f"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате {msg.chat.title}.\n" + f"По причине {config['reason']}, до даты {config['ban_time']}", + reply_markup=delete_keyboard(admin_id=banned_user.user.id)) + elif config["reason"]: + await msg.bot.send_message(chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} " + f"был заблокирован {msg.reply_to_message.from_user.mention_html('этим пользователем')}.\n" + f"По причине {config['reason']}.", + reply_markup=ban_keyboard(admin_id=msg.from_user.id, + ban_id=msg.reply_to_message.from_user.id)) + if send_notification: + await msg.bot.send_message(chat_id=banned_user.user.id, + text=f"Вы " + f"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате {msg.chat.title}.\n" + f"По причине {config['reason']}.", + reply_markup=delete_keyboard(admin_id=banned_user.user.id)) + elif config["ban_time"]: + await msg.bot.send_message(chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} " + f"был заблокирован {msg.from_user.mention_html('этим пользователем')}, до даты {config['ban_time']}", + reply_markup=ban_keyboard(admin_id=msg.from_user.id, + ban_id=msg.reply_to_message.from_user.id)) + if send_notification: + await msg.bot.send_message(chat_id=banned_user.user.id, + text=f"Вы " + f"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате {msg.chat.title}.\n" + f"До даты {config['ban_time']}.", + reply_markup=delete_keyboard(admin_id=banned_user.user.id)) + else: + await msg.bot.send_message(chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')}" + f" был заблокирован {msg.from_user.mention_html('этим пользователем')}.", + reply_markup=ban_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) + if send_notification: + await msg.bot.send_message(chat_id=banned_user.user.id, + text=f"Вы " + f"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате " + f"{msg.chat.title}.\n", + reply_markup=delete_keyboard(admin_id=banned_user.user.id)) + + @staticmethod + async def telegram_unban_cmd_handler(msg: Message, command: CommandObject, + session_maker: async_sessionmaker) -> None: + """ + /unban command function + :param msg: Message telegram object + :param command: Object of telegram command + :param session_maker: Session maker object of SqlAlchemy + """ + await SolutionSimpler.unban_user(msg, session_maker) + + unbanned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) + send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][4]) + send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]) + + where_send = { + True: msg.from_user.id, + False: msg.chat.id + } + + if unbanned_user.is_member and unbanned_user.status != ChatMemberStatus.KICKED: + await msg.bot.send_message( + chat_id=where_send[send_to_dm], + text="Ошибка ❌\n" + "Этот пользователь не находится в бане.", + reply_markup=delete_keyboard(admin_id=msg.from_user.id) + ) + return + elif not command.text: + await msg.bot.send_message( + chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} был разблокирован " + f"{msg.from_user.mention_html('этим пользователем')}.\n", + reply_markup=unban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id) + ) + if send_notification: + await msg.bot.send_message( + chat_id=unbanned_user.user.id, + text=f"{msg.reply_to_message.from_user.mention_html('Вы')} " + f"был разблокированы {msg.from_user.mention_html('этим пользователем')} в чате {msg.chat.title}.\n", + reply_markup=delete_keyboard(admin_id=unbanned_user.user.id) + ) + else: + await msg.bot.send_message( + chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"Пользователь {msg.reply_to_message.from_user.mention_html()} был разблокирован пользователем {msg.from_user.mention_html()}.\n" + f"По причине {CommandObject.text}.", + reply_markup=delete_keyboard(admin_id=unbanned_user.user.id) + ) + if send_notification: + await msg.bot.send_message( + chat_id=unbanned_user.user.id, + text=f"{msg.reply_to_message.from_user.mention_html('Вы')} " + f"был разблокированы {msg.from_user.mention_html('этим пользователем')} в чате {msg.chat.title}.\n" + f"По причине {CommandObject.text}", + reply_markup=delete_keyboard(admin_id=unbanned_user.user.id) + ) + + @staticmethod + async def telegram_mute_callback_handler(call: CallbackQuery, callback_data: MuteData, + session_maker: async_sessionmaker) -> None: + """ + Query, what mutes users after callback + :param call: CallBackQuery telegram object + :param callback_data: BanData object + :param session_maker: AsyncSessionmaker object + :return: + """ + clicked_user = await call.message.chat.get_member(call.from_user.id) + muted_user = await call.message.chat.get_member(int(callback_data.user_id_mute)) + + if call.from_user.id != callback_data.user_id_clicked \ + and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: + return + await SolutionSimpler.inline_mute_user(call=call, data=callback_data, session=session_maker) + + if not muted_user.can_send_messages and muted_user.status == ChatMemberStatus.RESTRICTED: + await call.answer("Уже замучен ✅") + else: + await call.answer("Успешно замучен ✅") + + await call.message.edit_text( + "Удача ✅\n" + f"{muted_user.user.mention_html('Этот пользователь')} был замучен {call.from_user.mention_html('этим пользователем')}.", + reply_markup=mute_keyboard(admin_id=call.from_user.id, mute_id=callback_data.user_id_mute) + ) + + send_notification = await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]) + if send_notification: + await call.message.bot.send_message( + chat_id=muted_user.user.id, + text=f"{muted_user.user.mention_html('Вы')} были замучены {call.from_user.mention_html('этим пользователем')} в чате {call.message.chat.id}.", + reply_markup=delete_keyboard(admin_id=muted_user.user.id) + ) + + logging.log(msg=f"Muted user @{muted_user.user.full_name} user_id=f{muted_user.user.id}", level=logging.INFO) + + @staticmethod + async def telegram_unmute_callback_handler(call: CallbackQuery, callback_data: UnmuteData, + session_maker: async_sessionmaker) -> None: + """ + Query, what unbannes users after callback + :param call: CallBackQuery telegram object + :param callback_data: UnbanData object + :param session_maker: AsyncSessionmaker object + :return: + """ + clicked_user = await call.message.chat.get_member(call.from_user.id) + unmuted_user = await call.message.chat.get_member(int(callback_data.user_id_unmute)) + if call.from_user.id != callback_data.user_id_clicked \ + and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: + return + + await SolutionSimpler.inline_unmute_user(call=call, data=callback_data, session=session_maker) + + if unmuted_user.can_send_messages or unmuted_user.status == ChatMemberStatus.RESTRICTED: + await call.answer("Уже размучен ✅") + else: + await call.answer("Успешно размучен ✅") + await call.message.edit_text( + "Удача ✅\n" + f"{unmuted_user.user.mention_html('Этот пользователь')} был размучен {call.from_user.mention_html('этим пользователем')}.", + reply_markup=unmute_keyboard(admin_id=call.from_user.id, unmute_id=unmuted_user.user.id) + ) + + send_notification = await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]) + if send_notification: + await call.message.bot.send_message( + chat_id=unmuted_user.user.id, + text=f"{unmuted_user.user.mention_html('Вы')} были размучены {call.from_user.mention_html('этим пользователем')} в чате {call.message.chat.id}.", + reply_markup=delete_keyboard(admin_id=unmuted_user.user.id) + ) + + logging.log(msg=f"Unbanned user @{unmuted_user.user.full_name} user_id=f{unmuted_user.user.id}", + level=logging.INFO) + + @staticmethod + async def telegram_mute_cmd_handler(msg: Message, command: CommandObject, + session_maker: async_sessionmaker) -> None: + """ + Handler of command /mute + Restricts member from using chat + :param msg: Message telegram object + :param command: Object of telegram command + :param session_maker: Session maker object of SqlAlchemy + :return: Nothing + """ + mute_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) + + send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][4]) + send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]) + + where_send = { + True: msg.from_user.id, + False: msg.chat.id + } + + if mute_user.status == ChatMemberStatus.LEFT or mute_user.status == ChatMemberStatus.KICKED: + return + config = await SolutionSimpler.mute_user(msg, command, session_maker) + if config["mute_time"] and config["reason"] != "": + await msg.bot.send_message( + chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" + f"По причине {config['reason']}, до даты {config['mute_time']}", + reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + if send_notification: + await msg.bot.send_message( + chat_id=mute_user.user.id, + text=f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n" + f"По причине {config['reason']}, до даты {config['mute_time']}", + reply_markup=delete_keyboard(admin_id=mute_user.user.id)) + + elif config["reason"] != "": + await msg.bot.send_message( + chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" + f"По причине {config['reason']}.", + reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + if send_notification: + await msg.bot.send_message( + chat_id=mute_user.user.id, + text=f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n" + f"По причине {config['reason']}.", + reply_markup=delete_keyboard(admin_id=mute_user.user.id)) + elif config["mute_time"]: + await msg.bot.send_message( + chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" + f"До даты {config['mute_time']}", + reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + if send_notification: + await msg.bot.send_message( + chat_id=mute_user.user.id, + text=f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n" + f"До даты {config['mute_time']}", + reply_markup=delete_keyboard(admin_id=mute_user.user.id)) + else: + await msg.bot.send_message( + chat_id=where_send[send_to_dm], + text="Удача ✅\n" + f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n", + reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + if send_notification: + await msg.bot.send_message( + chat_id=mute_user.user.id, + text=f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " + f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n", + reply_markup=delete_keyboard(admin_id=mute_user.user.id)) + + @staticmethod + async def telegram_unmute_cmd_handler(msg: Message, session_maker: async_sessionmaker) -> None: + """ + Handler of command /unmute + Gives access member to send messages into chat + :param msg: Message telegram object + :param session_maker: Session maker object of SqlAlchemy + :return: Nothing + """ + await SolutionSimpler.unmute_user(msg, session_maker) + + send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][4]) + send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, + setting=list_of_features["Admin"][5]) + + where_send = { + True: msg.from_user.id, + False: msg.chat.id + } + + await msg.bot.send_message( + user_id=where_send[send_to_dm], + text="Удача ✅" + f"{msg.from_user.mention_html('Этот пользователь')} разрешил писать\n" + f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}", + reply_markup=unmute_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) + if send_notification: + await msg.bot.send_message( + user_id=msg.reply_to_message.from_user.id, + text=f"{msg.from_user.mention_html('Этот пользователь')} разрешил писать\n" + f"сообщения {msg.reply_to_message.from_user.mention_html('вам')}", + reply_markup=delete_keyboard(admin_id=msg.reply_to_message.from_user.id)) + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + self.cmd_description: str = "Your description of command" + # Telegram feature settings + self.telegram_setting = None + self.telegram_commands: list[str | None] = ["start"] + self.telegram_cmd_avaible = True # Is a feature have a commands + self.telegram_callback_factory = None + self.telegram_message_handlers = { + # Your message handlers + } + self.telegram_callback_handlers = { + # Start menu + } diff --git a/bozenka/features/admin/pins.py b/bozenka/features/admin/pins.py new file mode 100644 index 0000000..55b551e --- /dev/null +++ b/bozenka/features/admin/pins.py @@ -0,0 +1,104 @@ +from aiogram.types import Message, CallbackQuery + +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg +from bozenka.instances.telegram.utils.keyboards import unpin_msg_keyboard, delete_keyboard, pin_msg_keyboard +from bozenka.instances.telegram.utils.simpler import SolutionSimpler + + +class Pins(BasicFeature): + """ + A class of pins related commands + All staff related to it will be here + """ + + @staticmethod + async def telegram_pin_callback_handler(call: CallbackQuery, callback_data: PinMsg) -> None: + """ + Query, what pins message + :param call: + :param callback_data: + :return: + """ + if callback_data.user_id == call.from_user.id: + return + + await call.message.chat.pin_message(message_id=callback_data.msg_id) + await call.message.edit_text("Удача ✅\n" + "Сообщение было закреплено 📌", + reply_markup=pin_msg_keyboard(user_id=call.from_user.id, + msg_id=callback_data.msg_id)) + + @staticmethod + async def telegram_unpin_callback_handler(call: CallbackQuery, callback_data: UnpinMsg) -> None: + """ + Query, what unpins message + :param call: + :param callback_data: + :return: + """ + if callback_data.user_id == call.from_user.id: + return + + await call.message.chat.pin_message(message_id=callback_data.msg_id) + await call.message.edit_text("Удача ✅\n" + "Сообщение было откреплено 📌", + reply_markup=unpin_msg_keyboard(user_id=call.from_user.id, + msg_id=callback_data.msg_id)) + + @staticmethod + async def telegram_pin_cmd(msg: Message) -> None: + """ + /pin command function, pins replied command + :param msg: Message telegram object + :return: Nothing + """ + await SolutionSimpler.pin_msg(msg) + await msg.answer("Удача ✅\n" + "Сообщение было закреплено 📌", + reply_markup=pin_msg_keyboard(msg_id=msg.reply_to_message.message_id, + user_id=msg.from_user.id)) + + @staticmethod + async def telegram_unpin_cmd(msg: Message) -> None: + """ + /unpin command function, unpins replied command + :param msg: Message telegram object + :return: Nothing + """ + await SolutionSimpler.unpin_msg(msg) + await msg.answer("Удача ✅\n" + "Сообщение было откреплено 📌", + reply_markup=unpin_msg_keyboard(msg_id=msg.reply_to_message.message_id, + user_id=msg.from_user.id)) + + @staticmethod + async def telegram_unpinall_cmd(msg: Message) -> None: + """ + /unpin_all command function, unpins all messages in chat + :param msg: Message telegram object + :return: Nothing + """ + await SolutionSimpler.unpin_all_messages(msg) + await msg.answer("Удача ✅\n" + "Все сообщения были откреплены 📌", + reply_markup=delete_keyboard(admin_id=msg.from_user.id)) + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + self.cmd_description: str = "Your description of command" + # Telegram feature settings + self.telegram_setting = None + self.telegram_commands: list[str | None] = ["start"] + self.telegram_cmd_avaible = True # Is a feature have a commands + self.telegram_callback_factory = None + self.telegram_message_handlers = { + + } + self.telegram_callback_handlers = { + + } diff --git a/bozenka/features/admin/topics.py b/bozenka/features/admin/topics.py new file mode 100644 index 0000000..b81187d --- /dev/null +++ b/bozenka/features/admin/topics.py @@ -0,0 +1,152 @@ +from aiogram import F, Bot +from aiogram.enums import ChatType +from aiogram.filters import Command +from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, InlineKeyboardButton +from aiogram.utils.keyboard import InlineKeyboardBuilder + +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import HelpCategory, HelpBackCategory, HelpFeature, HelpBack, \ + PinMsg, UnpinMsg, CloseThread, OpenThread +from bozenka.instances.telegram.utils.keyboards import help_category_keyboard, help_keyboard, \ + help_feature_keyboard, gpt_categories_keyboard, unpin_msg_keyboard, delete_keyboard, pin_msg_keyboard, \ + close_thread_keyboard, open_thread_keyboard +from bozenka.instances.telegram.utils.simpler import list_of_features, SolutionSimpler +from bozenka.instances.version import build, is_updated + + +class Threads(BasicFeature): + """ + A class of topics / threads related commands + All staff related to it will be here + """ + + @staticmethod + async def telegram_close_topic_cmd_handler(msg: Message, bot: Bot) -> None: + """ + /close command function. Closing thread + :param msg: Message telegram object + :param bot: Object of telegram bot + :return: Nothing + """ + config = await SolutionSimpler.close_topic(msg=msg) + await msg.answer(config[0], + reply_markup=close_thread_keyboard(user_id=msg.from_user.id) + if config[1] else delete_keyboard(msg.from_user.id)) + + @staticmethod + async def telegram_reopen_topic_cmd_handler(msg: Message, bot: Bot) -> None: + """ + /open command function. Opens thread + :param msg: Message telegram object + :param bot: Object of telegram bot + :return: Nothing + """ + config = await SolutionSimpler.open_topic(msg=msg) + await msg.answer(config[0], + reply_markup=open_thread_keyboard(user_id=msg.from_user.id) + if config[1] else delete_keyboard(msg.from_user.id)) + + @staticmethod + async def telegram_close_general_topic_cmd_handler(msg: Message, bot: Bot) -> None: + """ + /close_general command function. Closes general thread + :param msg: Message telegram object + :param bot: Object of telegram bot + :return: Nothing + """ + config = await SolutionSimpler.close_general_topic(msg=msg) + await msg.answer(config[0], + reply_markup=close_thread_keyboard(user_id=msg.from_user.id) + if config[1] else delete_keyboard(msg.from_user.id)) + + @staticmethod + async def telegram_reopen_general_topic_cmd(msg: Message, bot: Bot) -> None: + """ + /open_general command function. Opens general thread + :param msg: Message telegram object + :param bot: Object of telegram bot + :return: Nothing + """ + config = await SolutionSimpler.open_general_topic(msg=msg) + await msg.answer(config[0], + reply_markup=open_thread_keyboard(user_id=msg.from_user.id) + if config[1] else delete_keyboard(msg.from_user.id)) + + @staticmethod + async def telegram_hide_general_topic_cmd_handler(msg: Message, bot: Bot) -> None: + """ + /hide_general command function. Hides general thread + :param msg: Message telegram object + :param bot: Object of telegram bot + :return: Nothing + """ + config = await SolutionSimpler.hide_general_topic(msg=msg) + await msg.answer(config[0], + reply_markup=delete_keyboard(msg.from_user.id)) + + @staticmethod + async def telegram_unhide_general_topic_cmd(msg: Message, bot: Bot) -> None: + """ + /show_general command function. Shows back general thread. + :param msg: Message telegram object + :param bot: Object of telegram bot + :return: Nothing + """ + config = await SolutionSimpler.show_general_topic(msg=msg) + await msg.answer(config[0], + reply_markup=delete_keyboard(msg.from_user.id)) + + @staticmethod + async def telegram_close_thread_callback_handler(call: CallbackQuery, callback_data: CloseThread) -> None: + """ + Query, what close thread + :param call: CallbackQuery object + :param callback_data: ClosetThread object + :return: None + """ + + if callback_data.user_id != call.from_user.id or not call.message.chat.is_forum: + return + config = await SolutionSimpler.close_topic(msg=call.message, call=call) + await call.message.edit_text( + config[0], + reply_markup=close_thread_keyboard(user_id=call.from_user.id) if config[1] else + delete_keyboard(admin_id=call.from_user.id) + ) + + @staticmethod + async def inline_open_thread(call: CallbackQuery, callback_data: OpenThread) -> None: + """ + Query, what opens thread + :param call: CallbackQuery object + :param callback_data: OpenThread + :return: None + """ + + if callback_data.user_id != call.from_user.id or not call.message.chat.is_forum: + return + config = await SolutionSimpler.open_topic(msg=call.message, call=call) + await call.message.edit_text( + config[0], + reply_markup=open_thread_keyboard(user_id=call.from_user.id) if config[1] else + delete_keyboard(admin_id=call.from_user.id) + ) + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + self.cmd_description: str = "Your description of command" + # Telegram feature settings + self.telegram_setting = None + self.telegram_commands: list[str | None] = ["start"] + self.telegram_cmd_avaible = True # Is a feature have a commands + self.telegram_callback_factory = None + self.telegram_message_handlers = { + + } + self.telegram_callback_handlers = { + + } diff --git a/bozenka/features/basic/__init__.py b/bozenka/features/basic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/features/basic/setup.py b/bozenka/features/basic/setup.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/features/basic/start.py b/bozenka/features/basic/start.py new file mode 100644 index 0000000..c7e38c6 --- /dev/null +++ b/bozenka/features/basic/start.py @@ -0,0 +1,225 @@ +from aiogram import F +from aiogram.enums import ChatType +from aiogram.filters import Command +from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, InlineKeyboardButton +from aiogram.utils.keyboard import InlineKeyboardBuilder + +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import HelpCategory, HelpBackCategory, HelpFeature, HelpBack +from bozenka.instances.telegram.utils.keyboards import help_category_keyboard, help_keyboard, \ + help_feature_keyboard, gpt_categories_keyboard +from bozenka.instances.telegram.utils.simpler import list_of_features +from bozenka.instances.version import build, is_updated + + +class Start(BasicFeature): + """ + A class of /start command + All staff related to it will be here + """ + cmd_description: str = "Basic command to show main menu" + main_text = """ +Привет 👋 +Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах. + +Вот что ты можешь сделать с помощью меню: +• Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него. +• Функционал: показывает список доступных функций и команд, которые я могу выполнить. +• О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота. +• О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота. +• Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию. +• Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта + +Вот нужные ссылки обо мне: +• Канал с новостями об разработке +• Исходный код на Github + +Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже. +Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала. +Удачного использования! + """ + telegram_main_menu = InlineKeyboardMarkup( + inline_keyboard=[ + [InlineKeyboardButton(text="Добавить в ваш групповой чат 🔌", callback_data="addtochat")], + [InlineKeyboardButton(text="Информация об функционале бота 🔨", callback_data="functional")], + [InlineKeyboardButton(text="Об данном проекте ℹ️", callback_data="aboutdevs")], + [InlineKeyboardButton(text="О данном запущенном экзепляре ℹ️", callback_data="aboutbot")], + [InlineKeyboardButton(text="Начать диалог с текстовым ИИ 🤖", callback_data="dialogai")], + [InlineKeyboardButton(text="Начать генерацию изображений 🖼", callback_data="dialogimage")], + ] + ) + + # There starting a help category of handlers + # It's related to one of menus + # Showing information about features, will be remade later :D + @staticmethod + async def back_help_categories_handler(call: CallbackQuery, callback_data: HelpBack) -> None: + """ + Query, what shows list of features to get support back. + :param call: CallbackQuery object + :param callback_data: Helpback class + :return: None + """ + await call.message.edit_text("Выберите категорию, по которой нужна помощь:", + reply_markup=help_keyboard()) + await call.answer() + + @staticmethod + async def help_features_handler(call: CallbackQuery, callback_data: HelpCategory | HelpBackCategory) -> None: + """ + Handler of CallbackQuery, what shows list of features to get support. + :param call: CallbackQuery object + :param callback_data: HelpCategory or HelpBack class + :return: None + """ + await call.message.edit_text("Выберите функцию, по которой нужна помощь", + reply_markup=help_category_keyboard(category=callback_data.category_name)) + await call.answer() + + @staticmethod + async def feature_info_handler(call: CallbackQuery, callback_data: HelpFeature) -> None: + """ + Handler of CallbackQuery, what shows information about bozenka feature + :param call: CallbackQuery ojbect + :param callback_data: HelpFeature object + :return: None + """ + await call.message.edit_text( + list_of_features[callback_data.feature_category][callback_data.feature_index].description, + reply_markup=help_feature_keyboard(category=callback_data.feature_category)) + await call.answer() + + @staticmethod + async def help_menu_handler(call: CallbackQuery) -> None: + """ + Handler of CallbackQuery, what shows menu of help + :param call: CallbackQuery object + :return: None + """ + await call.message.edit_text("Выберите категорию функций, по которой вам нужна помощь 🤖", + reply_markup=help_keyboard()) + await call.answer() + + @staticmethod + async def add_to_menu_handler(call: CallbackQuery) -> None: + """ + Handler of CallbackQuery, what shows a link to add bozenka into user group chat + :param call: CallbackQuery object + :return: None + """ + # Getting bot + me = await call.message.bot.me() + + # Generating special keyboard + kb = InlineKeyboardBuilder() + kb.button(text="Добавить в ваш груповой чат 🔌", + url="https://t.me/" + f"{me.username}?" + "startgroup&" + "admin=promote_members+delete_messages+restrict_members+invite_users+pin_messages+manage_video_chats") + kb.row(InlineKeyboardButton(text="Вернуться 🔙", callback_data="back")) + + # Answering + await call.message.edit_text("Чтобы добавить бозеньку в ваш групповой чат, нажмите на кнопку под сообщением:", + reply_markup=kb.as_markup()) + await call.answer() + + @staticmethod + async def about_instance_callback_handler(call: CallbackQuery) -> None: + """ + Handler of CallbackQuery, what shows information about current running instance + :param call: CallbackQuery object + :return: Nothing + """ + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text="Вернуться 🔙", callback_data="back") + ]]) + me = await call.message.bot.get_me() + update_status = {False: "требуется обновление бота 🔼", + True: "обновление не требуется, последняя версия ✅"} + await call.message.edit_text( + f"Информация об данном запущенном экземпляре бозеньки:\n" + f"Аккаунт бота: {me.mention_html()}\n" + f"Запущенная версия бота {build}\n", + f"Нужно ли обновление: {update_status[is_updated]}", + reply_markup=kb) + await call.answer() + + @staticmethod + async def about_developers_handler(call: CallbackQuery) -> None: + """ + Handler of CallbackQuery, what shows information about bozenka & it's development + :param call: CallbackQuery object + :return: Nothing + """ + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text="Вернуться 🔙", callback_data="back") + ]]) + await call.message.edit_text(""" + Бозенька - это мультифункциональный (в будущем кроссплатформенный) бот.\n + Он умеет работать с групповыми чатами и готовыми нейронными сетями для генерации текста и изображений. + Бозенька разрабатывается коммандой, которая состоит на данный момент из одного человека.\n + Исходный код проекта\n + Исходный код находится под лицензией GPL-3.0, исходный код проекта можно посмотреть всегда здесь + Канал с новостями разработки находится здесь + """, reply_markup=kb, disable_web_page_preview=True) + + @staticmethod + async def start_dialog_handler(call: CallbackQuery) -> None: + """ + Handler of CallbackQuery, what shows list of Categories, avaible to use as chatbot + :param call: CallbackQuery object + :return: Nothing + """ + await call.message.edit_text("Пожалуста, выберите сервиc / библиотеку, через которую вы будете общаться", + reply_markup=gpt_categories_keyboard + (user_id=call.from_user.id)) + + async def start_callback_handler(self, call: CallbackQuery) -> None: + """ + /start command function handler. Just back it by clicking on button. + Shows menu and basic information about bozenka + :param call: Message telegram object + :return: Nothing + """ + await call.message.edit_text(self.main_text, + reply_markup=self.telegram_main_menu, disable_web_page_preview=True) + + async def start_cmd_handler(self, msg: Message) -> None: + """ + /start command function handler + Shows menu and basic information about bozenka + :param msg: Message telegram object + :return: Nothing + """ + await msg.answer(self.main_text, + reply_markup=self.telegram_main_menu, disable_web_page_preview=True) + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + self.cmd_description: str = "Your description of command" + # Telegram feature settings + self.telegram_setting = None + self.telegram_commands: list[str | None] = ["start"] + self.telegram_cmd_avaible = True # Is a feature have a commands + self.telegram_callback_factory = None + self.telegram_message_handlers = { + self.start_cmd_handler: [Command(commands=["start"]), F.chat.type == ChatType.PRIVATE], + + } + self.telegram_callback_handlers = { + # Start menu + self.start_dialog_handler: [F.data == "dialogai"], + self.add_to_menu_handler: [F.data == "addtochat"], + self.about_developers_handler: [F.data == "aboutdevs"], + self.about_instance_callback_handler: [F.data == "aboutbot"], + self.start_callback_handler: [F.data == "back"], + # Help menu + self.feature_info_handler: [HelpFeature.filter() or HelpBackCategory.filter()], + self.help_menu_handler: [HelpCategory.filter() or HelpBack.filter(F.back_to == "category")], + + } diff --git a/bozenka/features/user/__init__.py b/bozenka/features/user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/features/user/image_generation.py b/bozenka/features/user/image_generation.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/features/user/text_generation.py b/bozenka/features/user/text_generation.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/features/user/welcome.py b/bozenka/features/user/welcome.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/instances/telegram/handlers/main/__init__.py b/bozenka/instances/telegram/handlers/main/__init__.py index aef1768..43f3947 100644 --- a/bozenka/instances/telegram/handlers/main/__init__.py +++ b/bozenka/instances/telegram/handlers/main/__init__.py @@ -19,7 +19,11 @@ def register_main_cmd(router: Router) -> None: logging.log(msg="Registering main related commands", level=logging.INFO) # Start command handler + """ router.message.register(start_cmd, Command(commands=["start"]), F.chat.type == ChatType.PRIVATE) + """ + + router.message.register(start_cmd, *[Command(commands=["start"]), F.chat.type == ChatType.PRIVATE]) # Registering command /setup router.message.register(setup_cmd, Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE)) diff --git a/bozenka/instances/telegram/utils/callbacks_factory/start.py b/bozenka/instances/telegram/utils/callbacks_factory/start.py index a4ef63d..0c4048d 100644 --- a/bozenka/instances/telegram/utils/callbacks_factory/start.py +++ b/bozenka/instances/telegram/utils/callbacks_factory/start.py @@ -28,7 +28,7 @@ class HelpBackCategory(CallbackData, prefix="hbc"): Callback data to back to list of features in one of categories in menu """ - back_to_category: str + category_name: str class BackStart(CallbackData, prefix="start"): diff --git a/bozenka/instances/telegram/utils/middleware/__init__.py b/bozenka/instances/telegram/utils/middleware/__init__.py index a2f4542..4b6f273 100644 --- a/bozenka/instances/telegram/utils/middleware/__init__.py +++ b/bozenka/instances/telegram/utils/middleware/__init__.py @@ -3,8 +3,7 @@ import logging from aiogram import Router, Dispatcher from bozenka.instances.telegram.utils.middleware.antiflood import MessageThrottlingMiddleware, \ - CallbackThrottlingMiddleware -from bozenka.instances.telegram.utils.middleware.retry import RetryMessageMiddleware, RetryCallbackMiddleware + CallbackThrottlingMiddleware, CounterMiddleware def register_middlewares(dp: Dispatcher) -> None: @@ -16,8 +15,13 @@ def register_middlewares(dp: Dispatcher) -> None: logging.log(msg=f"Registering middlewares of bot", level=logging.INFO) # Throttling middlewares - dp.message.middleware.register(MessageThrottlingMiddleware) + + """ + dp.message.middleware(CounterMiddleware) dp.callback_query.middleware(CallbackThrottlingMiddleware) # Retry middlewares + """ + """ dp.error.middleware(RetryMessageMiddleware) dp.error.middleware(RetryCallbackMiddleware) + """ diff --git a/bozenka/instances/telegram/utils/middleware/antiflood.py b/bozenka/instances/telegram/utils/middleware/antiflood.py index c683343..2332079 100644 --- a/bozenka/instances/telegram/utils/middleware/antiflood.py +++ b/bozenka/instances/telegram/utils/middleware/antiflood.py @@ -5,6 +5,22 @@ from aiogram.types import Update, Message, CallbackQuery from cachetools import TTLCache +class CounterMiddleware(BaseMiddleware): + def __init__(self) -> None: + self.counter = 0 + + async def __call__( + self, + handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]], + event: Message, + data: Dict[str, Any], + **kwargs: Any + ) -> Any: + self.counter += 1 + print(self.counter) + return await handler(event, data) + + class MessageThrottlingMiddleware(BaseMiddleware): """ This middleware is skidded from public codes diff --git a/bozenka/instances/telegram/utils/middleware/retry.py b/bozenka/instances/telegram/utils/middleware/retry.py index 0fbd268..d8198a8 100644 --- a/bozenka/instances/telegram/utils/middleware/retry.py +++ b/bozenka/instances/telegram/utils/middleware/retry.py @@ -6,31 +6,3 @@ from aiogram.exceptions import TelegramRetryAfter from aiogram.types import Message, ErrorEvent, Update, CallbackQuery -class RetryMessageMiddleware(BaseMiddleware): - """ - Protects from user don't get update by message - """ - - async def __call__( - self, - handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]], - event: ErrorEvent[TelegramRetryAfter, Update], - data: Dict[str, Any] - ) -> Any: - time.sleep(event.exception.retry_after) - return await handler(event.update.message, data) - - -class RetryCallbackMiddleware(BaseMiddleware): - """ - Protects from user don't get update by callbackquery - """ - - async def __call__( - self, - handler: Callable[[CallbackQuery, Dict[str, Any]], Awaitable[Any]], - event: ErrorEvent[TelegramRetryAfter, Update], - data: Dict[str, Any] - ) -> Any: - time.sleep(event.exception.retry_after) - return await handler(event.update.callback_query, data) -- 2.30.2 From 348a8c7245b4700b3b2cc6546b4f811ad5d6de2e Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:51:08 +0300 Subject: [PATCH 03/13] It is still getting developed. Changelog: - Added all features of bozenka - Added features_list.py - Some refactors and starting writing code of registering all features handlers --- bozenka/features/__init__.py | 79 +-- bozenka/features/admin/__init__.py | 4 + bozenka/features/admin/invite.py | 83 +++ bozenka/features/admin/moderation.py | 74 ++- bozenka/features/admin/pins.py | 32 +- bozenka/features/admin/topics.py | 86 ++- bozenka/features/basic/__init__.py | 2 + bozenka/features/basic/setup.py | 103 ++++ bozenka/features/basic/start.py | 3 +- bozenka/features/features_list.py | 30 + bozenka/features/user/__init__.py | 3 + bozenka/features/user/image_generation.py | 157 +++++ bozenka/features/user/text_generation.py | 559 ++++++++++++++++++ bozenka/features/user/welcome.py | 82 +++ .../telegram/handlers/chat_admin/__init__.py | 2 - .../telegram/handlers/dev/image_generation.py | 12 +- .../telegram/handlers/queries/setup.py | 8 +- .../telegram/utils/callbacks_factory/setup.py | 2 +- .../utils/simpler/lists_of_content.py | 4 +- 19 files changed, 1189 insertions(+), 136 deletions(-) create mode 100644 bozenka/features/features_list.py diff --git a/bozenka/features/__init__.py b/bozenka/features/__init__.py index 401b1df..8343157 100644 --- a/bozenka/features/__init__.py +++ b/bozenka/features/__init__.py @@ -1,11 +1,3 @@ -from typing import Callable - -from aiogram import Dispatcher -from aiogram.filters import CommandObject -from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.database.tables.telegram import TelegramChatSettings class BasicFeature: @@ -13,60 +5,29 @@ class BasicFeature: A classic class of lineral (basic) feature of bozenka. IN FUTURE! """ - cmd_description: str = "Your description of command" - - ''' - Here is example of code you can add: - - async def generate_telegram_inline_keyboard(self) -> InlineKeyboardMarkup: - """ - Generates a special telegram keyboard (menu) - :return: Inline Keyboard - """ - pass - - async def telegram_command_handler(self, msg: Message, cmd: CommandObject, session_maker: async_sessionmaker) -> None: - """ - A special telegram handler for command (if exist) - It is just an example - :param msg: Telegram message object - :param cmd: Aiogram command object - :param session_maker: Async session maker object of SQLAlchemy - :return: Nothing - """ - pass - - async def telegram_callback_handler(self, call: CallbackQuery, callback_data, session_maker: async_sessionmaker) -> None: - """ - A special telegram handler for command (if exist) - It is just an example - :param call: Telegram callbackquery object - :param callback_data: A custom callback data created by callback factory - :param session_maker: Async session maker object of SQLAlchemy - :return: Nothing - """ - pass - ''' def __init__(self): """ All information about feature will be inside this function """ - self.cmd_description: str = "Your description of command" - # Telegram feature settings - self.telegram_setting = TelegramChatSettings.text_generation - self.telegram_commands: list[str | None] = ["test"] - self.telegram_cmd_avaible = True # Is a feature have a commands - self.telegram_callback_factory = None - self.telegram_message_handlers = { - """ - Format is - Handler: [Filters] - """ - } - self.telegram_callback_handlers = { - """ - Format is - Handler: [Filters] - """ + + # Telegram setting info + self.telegram_setting_in_list = False # Does feature shows in /setup list + self.telegram_setting_name = None # Setting title in /setup command + self.telegram_setting_description = None # Setting description in /setup command + self.telegram_db_name = None # Name of TelegramChatSettings column will be affected + # Telegram commands list of feature + self.telegram_commands: dict[str: str] = { + # + # Format is "CommandNameHere": "Command description is here" + # + "example": "Its an example" } + self.telegram_cmd_avaible = True # Does this feature have a telegram commands + # All handlers + self.telegram_message_handlers = ( + # Format is [Handler, [Filters]] + ) + self.telegram_callback_handlers = ( + # Format is [Handler, [Filters]] + ) \ No newline at end of file diff --git a/bozenka/features/admin/__init__.py b/bozenka/features/admin/__init__.py index e69de29..f14b364 100644 --- a/bozenka/features/admin/__init__.py +++ b/bozenka/features/admin/__init__.py @@ -0,0 +1,4 @@ +from invite import Invite +from moderation import Moderation +from pins import Pins +from topics import Threads diff --git a/bozenka/features/admin/invite.py b/bozenka/features/admin/invite.py index e69de29..b39c107 100644 --- a/bozenka/features/admin/invite.py +++ b/bozenka/features/admin/invite.py @@ -0,0 +1,83 @@ +import logging + +from aiogram.enums import ChatMemberStatus +from aiogram.filters import Command +from aiogram.types import Message, CallbackQuery + +from bozenka.database.tables.telegram import TelegramChatSettings +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import RevokeCallbackData +from bozenka.instances.telegram.utils.keyboards import invite_keyboard +from bozenka.instances.telegram.utils.simpler import ru_cmds + + +class Invite(BasicFeature): + """ + A class with information about invite feature + All codes will be here + """ + + @staticmethod + async def telegram_invite_command_handler(msg: Message) -> None: + """ + Generating invite to group by /invite command + :param msg: Message telegram object + :return: None + """ + logging.log(msg=f"Generating invite for user_id={msg.from_user.id}", + level=logging.INFO) + link = await msg.chat.create_invite_link() + + await msg.answer( + f" Держите ваше приглашение в чат, {msg.from_user.mention_html('пользователь')} 👋", + reply_markup=invite_keyboard(link=str(link.invite_link), admin_id=msg.from_user.id, + chat_name=msg.chat.full_name) + ) + + @staticmethod + async def telegram_revoke_callback_handler(call: CallbackQuery, callback_data: RevokeCallbackData) -> None: + """ + Handler of CallbackQuery, revokes link after pressing button + :param call: CallbackQuery aioram object + :param callback_data: RevokeCallbackData object + :return: Nothing + """ + user_clicked = await call.message.chat.get_member(call.from_user.id) + + if callback_data.admin_id != call.from_user.id and \ + user_clicked.status != ChatMemberStatus.ADMINISTRATOR and user_clicked.status == ChatMemberStatus.CREATOR: + return + logging.log(msg=f"Revoking link for user_id={call.from_user.id}", + level=logging.INFO) + await call.message.chat.revoke_invite_link(invite_link="https://" + str(callback_data.link)) + await call.answer("Удача ✅") + await call.message.delete() + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + """ + Telegram feature settings + """ + # Telegram setting info + self.telegram_setting_in_list = True + self.telegram_setting_name = "Приглашения в Чат ✉" + self.telegram_setting_description = "Генератор приглашения в Чат ✉\n" \ + "Разрешает использование комманды /invite в чате, для созданния приглашений.\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." + self.telegram_db_name = TelegramChatSettings.invite_generator + # Telegram commands + self.telegram_commands: dict[str: str] = {"/invite": 'Generates invite into current chat'} + self.telegram_cmd_avaible = True # Is a feature have a commands + # List of aiogram handlers + self.telegram_message_handlers = ( + # Format is [Handler, [Filters]] + [self.telegram_invite_command_handler, [Command(commands=["invite"])]] + ) + self.telegram_callback_handlers = ( + # Format is [Handler, [Filters]] + [self.telegram_revoke_callback_handler, [RevokeCallbackData.filter()]] + ) diff --git a/bozenka/features/admin/moderation.py b/bozenka/features/admin/moderation.py index 4e39e53..637b969 100644 --- a/bozenka/features/admin/moderation.py +++ b/bozenka/features/admin/moderation.py @@ -1,21 +1,18 @@ import logging from aiogram import F -from aiogram.enums import ChatType, ChatMemberStatus -from aiogram.filters import Command, CommandObject -from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, InlineKeyboardButton -from aiogram.utils.keyboard import InlineKeyboardBuilder +from aiogram.enums import ChatMemberStatus +from aiogram.filters import CommandObject, Command +from aiogram.types import Message, CallbackQuery from sqlalchemy.ext.asyncio import async_sessionmaker -from bozenka.database.tables.telegram import get_chat_config_value +from bozenka.database.tables.telegram import get_chat_config_value, TelegramChatSettings from bozenka.features import BasicFeature -from bozenka.instances.telegram.utils.callbacks_factory import HelpCategory, HelpBackCategory, HelpFeature, HelpBack, \ - UnbanData, BanData, UnmuteData, MuteData -from bozenka.instances.telegram.utils.keyboards import help_category_keyboard, help_keyboard, \ - help_feature_keyboard, gpt_categories_keyboard, ban_keyboard, delete_keyboard, mute_keyboard, unmute_keyboard, \ +from bozenka.instances.telegram.utils.callbacks_factory import UnbanData, BanData, UnmuteData, MuteData +from bozenka.instances.telegram.utils.filters import IsAdminFilter, BotHasPermissions, UserHasPermissions +from bozenka.instances.telegram.utils.keyboards import ban_keyboard, delete_keyboard, mute_keyboard, unmute_keyboard, \ unban_keyboard from bozenka.instances.telegram.utils.simpler import list_of_features, SolutionSimpler -from bozenka.instances.version import build, is_updated class Moderation(BasicFeature): @@ -23,7 +20,6 @@ class Moderation(BasicFeature): A class of moderation related feature All staff related to it will be here """ - cmd_description: str = "Basic command to show main menu" @staticmethod async def telegram_ban_callback_handler(call: CallbackQuery, callback_data: BanData, @@ -455,15 +451,49 @@ class Moderation(BasicFeature): will be inside this function """ super().__init__() - self.cmd_description: str = "Your description of command" - # Telegram feature settings - self.telegram_setting = None - self.telegram_commands: list[str | None] = ["start"] + # Telegram setting info + self.telegram_setting_in_list = True + self.telegram_setting_name = "Модерация чата 🕵️" + self.telegram_setting_description = "Модерация чата🕵️\nДанная настройка включает следущие комманды:" \ + "\n
/ban [время блокировки] [причина блокировки] - блокировка пользователя" \
+                                            "\n/unban - разблокировка пользователя\n" \
+                                            "/mute [время мута] [причина мута] - мут пользователя\n" \
+                                            "/unmute - Размут пользователя
\n" \ + "Время обозначается как:" \ + "
1h - один час, " \
+                                            "1d - один день, " \
+                                            "1m - одна минута, " \
+                                            "1s - одна секунда
\n" \ + "Для того, " \ + "чтобы выполнить одну из комманд по отношению к пользователю, " \ + "ответьте на сообщение пользователя и используйте команду\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." + self.telegram_db_name = TelegramChatSettings.moderation + # Telegram commands + self.telegram_commands: dict[str: str] = { + "ban": "Command to ban user in chat", + 'unban': 'Command to unban user in chat', + 'mute': 'Command to mute user in chat', + 'unmute': 'Command to unmute user in chat', + } self.telegram_cmd_avaible = True # Is a feature have a commands - self.telegram_callback_factory = None - self.telegram_message_handlers = { - # Your message handlers - } - self.telegram_callback_handlers = { - # Start menu - } + # All handlers + self.telegram_message_handlers = ( + # Format is [Handler, [Filters]] + [self.telegram_ban_cmd_handler, [Command(commands="ban"), + IsAdminFilter(True), F.reply_to_message.text]], + [self.telegram_unban_cmd_handler, [Command(commands="unban"), + IsAdminFilter(True), F.reply_to_message.text]], + [self.telegram_mute_cmd_handler, [Command(commands=["mute", "re"]), + UserHasPermissions(["can_restrict_members"]), + BotHasPermissions(["can_restrict_members"])]], + [self.telegram_unmute_cmd_handler, [Command(commands=["unmute"]), + UserHasPermissions(["can_restrict_members"]), + BotHasPermissions(["can_restrict_members"])]] + ) + self.telegram_callback_handlers = ( + # Format is [Handler, [Filters]] + [self.telegram_ban_callback_handler, [BanData.filter()]], + [self.telegram_unban_callback_handler, [UnbanData.filter()]], + [self.telegram_mute_callback_handler, [MuteData.filter()]], + [self.telegram_unmute_callback_handler, [UnmuteData.filter()]]) diff --git a/bozenka/features/admin/pins.py b/bozenka/features/admin/pins.py index 55b551e..10e0614 100644 --- a/bozenka/features/admin/pins.py +++ b/bozenka/features/admin/pins.py @@ -1,7 +1,11 @@ +from aiogram import F +from aiogram.filters import Command from aiogram.types import Message, CallbackQuery +from bozenka.database.tables.telegram import TelegramChatSettings from bozenka.features import BasicFeature from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg +from bozenka.instances.telegram.utils.filters import UserHasPermissions, BotHasPermissions, IsAdminFilter from bozenka.instances.telegram.utils.keyboards import unpin_msg_keyboard, delete_keyboard, pin_msg_keyboard from bozenka.instances.telegram.utils.simpler import SolutionSimpler @@ -92,13 +96,31 @@ class Pins(BasicFeature): super().__init__() self.cmd_description: str = "Your description of command" # Telegram feature settings - self.telegram_setting = None - self.telegram_commands: list[str | None] = ["start"] + self.telegram_setting_in_list = True + self.telegram_setting_name = "Закреп 📌" + self.telegram_setting_description = "Закреп📌" \ + "\nДанная функция включает команды:" \ + "
/pin - закрепляет сообщение\n" \
+                                            "/unpin - открепляет сообщение\n" \
+                                            "/unpin_all - открепляет все сообщения, которые видит бот
\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." + self.telegram_db_name = TelegramChatSettings.pins + # Telegram commands + self.telegram_commands: dict[str: str] = { + 'pin': 'Pin fast any message in chat', + 'unpin': 'Unpin fast any message in chat', + } self.telegram_cmd_avaible = True # Is a feature have a commands - self.telegram_callback_factory = None + # Telegram Handler self.telegram_message_handlers = { - + self.telegram_pin_cmd: [Command(commands="pin"), UserHasPermissions(["can_pin_messages"]), + BotHasPermissions(["can_pin_messages"]), F.reply_to_message], + self.telegram_unpin_cmd: [Command(commands="unpin"), UserHasPermissions(["can_pin_messages"]), + BotHasPermissions(["can_pin_messages"]), F.reply_to_message], + self.telegram_unpinall_cmd: [Command(commands="unpin_all"), IsAdminFilter(True), + BotHasPermissions(["can_pin_messages"]), F.reply_to_message.text], } self.telegram_callback_handlers = { - + self.telegram_pin_callback_handler: [PinMsg.filter()], + self.telegram_unpin_callback_handler: [UnpinMsg.filter()] } diff --git a/bozenka/features/admin/topics.py b/bozenka/features/admin/topics.py index b81187d..247061a 100644 --- a/bozenka/features/admin/topics.py +++ b/bozenka/features/admin/topics.py @@ -1,17 +1,13 @@ -from aiogram import F, Bot -from aiogram.enums import ChatType +from aiogram import F from aiogram.filters import Command -from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, InlineKeyboardButton -from aiogram.utils.keyboard import InlineKeyboardBuilder +from aiogram.types import Message, CallbackQuery +from bozenka.database.tables.telegram import TelegramChatSettings from bozenka.features import BasicFeature -from bozenka.instances.telegram.utils.callbacks_factory import HelpCategory, HelpBackCategory, HelpFeature, HelpBack, \ - PinMsg, UnpinMsg, CloseThread, OpenThread -from bozenka.instances.telegram.utils.keyboards import help_category_keyboard, help_keyboard, \ - help_feature_keyboard, gpt_categories_keyboard, unpin_msg_keyboard, delete_keyboard, pin_msg_keyboard, \ - close_thread_keyboard, open_thread_keyboard -from bozenka.instances.telegram.utils.simpler import list_of_features, SolutionSimpler -from bozenka.instances.version import build, is_updated +from bozenka.instances.telegram.utils.callbacks_factory import CloseThread, OpenThread +from bozenka.instances.telegram.utils.filters import UserHasPermissions, BotHasPermissions +from bozenka.instances.telegram.utils.keyboards import delete_keyboard, close_thread_keyboard, open_thread_keyboard +from bozenka.instances.telegram.utils.simpler import SolutionSimpler class Threads(BasicFeature): @@ -21,11 +17,10 @@ class Threads(BasicFeature): """ @staticmethod - async def telegram_close_topic_cmd_handler(msg: Message, bot: Bot) -> None: + async def telegram_close_topic_cmd_handler(msg: Message) -> None: """ /close command function. Closing thread :param msg: Message telegram object - :param bot: Object of telegram bot :return: Nothing """ config = await SolutionSimpler.close_topic(msg=msg) @@ -34,11 +29,10 @@ class Threads(BasicFeature): if config[1] else delete_keyboard(msg.from_user.id)) @staticmethod - async def telegram_reopen_topic_cmd_handler(msg: Message, bot: Bot) -> None: + async def telegram_reopen_topic_cmd_handler(msg: Message) -> None: """ /open command function. Opens thread :param msg: Message telegram object - :param bot: Object of telegram bot :return: Nothing """ config = await SolutionSimpler.open_topic(msg=msg) @@ -47,11 +41,10 @@ class Threads(BasicFeature): if config[1] else delete_keyboard(msg.from_user.id)) @staticmethod - async def telegram_close_general_topic_cmd_handler(msg: Message, bot: Bot) -> None: + async def telegram_close_general_topic_cmd_handler(msg: Message) -> None: """ /close_general command function. Closes general thread :param msg: Message telegram object - :param bot: Object of telegram bot :return: Nothing """ config = await SolutionSimpler.close_general_topic(msg=msg) @@ -60,11 +53,10 @@ class Threads(BasicFeature): if config[1] else delete_keyboard(msg.from_user.id)) @staticmethod - async def telegram_reopen_general_topic_cmd(msg: Message, bot: Bot) -> None: + async def telegram_reopen_general_topic_cmd(msg: Message) -> None: """ /open_general command function. Opens general thread :param msg: Message telegram object - :param bot: Object of telegram bot :return: Nothing """ config = await SolutionSimpler.open_general_topic(msg=msg) @@ -73,11 +65,10 @@ class Threads(BasicFeature): if config[1] else delete_keyboard(msg.from_user.id)) @staticmethod - async def telegram_hide_general_topic_cmd_handler(msg: Message, bot: Bot) -> None: + async def telegram_hide_general_topic_cmd_handler(msg: Message) -> None: """ /hide_general command function. Hides general thread :param msg: Message telegram object - :param bot: Object of telegram bot :return: Nothing """ config = await SolutionSimpler.hide_general_topic(msg=msg) @@ -85,11 +76,10 @@ class Threads(BasicFeature): reply_markup=delete_keyboard(msg.from_user.id)) @staticmethod - async def telegram_unhide_general_topic_cmd(msg: Message, bot: Bot) -> None: + async def telegram_unhide_general_topic_cmd(msg: Message) -> None: """ /show_general command function. Shows back general thread. :param msg: Message telegram object - :param bot: Object of telegram bot :return: Nothing """ config = await SolutionSimpler.show_general_topic(msg=msg) @@ -138,15 +128,51 @@ class Threads(BasicFeature): will be inside this function """ super().__init__() - self.cmd_description: str = "Your description of command" - # Telegram feature settings - self.telegram_setting = None - self.telegram_commands: list[str | None] = ["start"] + # Telegram setting info + self.telegram_setting_in_list = True + self.telegram_setting_name = "Работа с Форумом 💬" + self.telegram_setting_description = "Работа с Форумом💬\nДанная настройка включает следущие комманды:\n" \ + "
/open - открывают тему форума\n" \
+                                            "/close - закрывают тему форума\n" \
+                                            "/open_general - открывают основную тему форума\n" \
+                                            "/close_general - закрывает основную тему форума\n" \
+                                            "/hide_general - прячет основную тему форума\n" \
+                                            "/show_general - показывает основную тему форума
\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть" \ + "включен форум" + self.telegram_db_name = TelegramChatSettings.topics + # Telegram commands + self.telegram_commands: dict[str: str] = { + 'close': 'Close fast topic (not general) in chat', + 'open': 'Open fast topic (not general) in chat', + 'hide_general': 'Hide general topic in chat', + 'show_general': 'Show general topic in chat', + "close_general": 'Closes general topic in chat', + "open_general": 'Opens general topic in chat', + } self.telegram_cmd_avaible = True # Is a feature have a commands - self.telegram_callback_factory = None + # All handlers self.telegram_message_handlers = { - + self.telegram_close_topic_cmd_handler: [Command(commands=["close_topic", "close"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], + self.telegram_reopen_topic_cmd_handler: [Command(commands=["reopen_topic", "open_topic", "open"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], + self.telegram_close_general_topic_cmd_handler: [Command(commands=["close_general"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], + self.telegram_reopen_general_topic_cmd: [Command(commands=["reopen_general", "open_general"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], + self.telegram_hide_general_topic_cmd_handler: [Command(commands=["hide_general"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], + self.telegram_unhide_general_topic_cmd: [Command(commands=["unhide_general", "show_general"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum] } self.telegram_callback_handlers = { - + self.telegram_close_thread_callback_handler: [CloseThread.filter()], + self.telegram_reopen_topic_cmd_handler: [OpenThread.filter()] } diff --git a/bozenka/features/basic/__init__.py b/bozenka/features/basic/__init__.py index e69de29..b34966c 100644 --- a/bozenka/features/basic/__init__.py +++ b/bozenka/features/basic/__init__.py @@ -0,0 +1,2 @@ +from setup import Setup +from start import Start diff --git a/bozenka/features/basic/setup.py b/bozenka/features/basic/setup.py index e69de29..13d3398 100644 --- a/bozenka/features/basic/setup.py +++ b/bozenka/features/basic/setup.py @@ -0,0 +1,103 @@ +from aiogram import F +from aiogram.enums import ChatType +from aiogram.filters import Command +from aiogram.types import Message, CallbackQuery +from sqlalchemy import Update +from sqlalchemy.ext.asyncio import async_sessionmaker + +from bozenka.database.tables.telegram import get_chat_config_value, TelegramChatSettings +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import SetupAction, SetupFeature, SetupCategory +from bozenka.instances.telegram.utils.keyboards import setup_keyboard, setup_category_keyboard, setup_feature_keyboard +from bozenka.instances.telegram.utils.simpler import list_of_features + + +class Setup(BasicFeature): + """ + A class of /setup command + All staff related to it will be here + """ + + @staticmethod + async def telegram_setup_cmd_handler(msg: Message) -> None: + """ + /setup telegram handler + :param msg: Telegram message object + :return: Nothing + """ + await msg.answer("Привет владелец чата 👋\n" + "Чтобы меня настроить, используй меню под данным сообщением", + reply_markup=setup_keyboard()) + + @staticmethod + async def telegram_setup_categories_handler(call: CallbackQuery, callback_data: SetupCategory | SetupAction): + """ + Query, what shows list of features to enable. + :param call: + :param callback_data: + :return: + """ + await call.message.edit_text("Выберите настройку, которую хотите изменить", + reply_markup=setup_category_keyboard(category=callback_data.category_name)) + + @staticmethod + async def telegram_setup_edit_feature_handler(call: CallbackQuery, callback_data: SetupFeature, session_maker: async_sessionmaker): + """ + Query, what shows menu to enable / disable feature + :param call: + :param callback_data: + :param session_maker: + :return: + """ + is_enabled = await get_chat_config_value( + chat_id=call.message.chat.id, + session=session_maker, + setting=list_of_features[callback_data.feature_category][callback_data.feature_index] + ) + + await call.message.edit_text( + list_of_features[callback_data.feature_category][callback_data.feature_index].description, + reply_markup=await setup_feature_keyboard(category=callback_data.feature_category, + index=callback_data.feature_index, + is_enabled=is_enabled)) + + @staticmethod + async def telegram_features_edit_handler(call: CallbackQuery, callback_data: SetupAction, session_maker: async_sessionmaker): + """ + Query, what shows menu to enable / disable feature + after editing + :param call: + :param callback_data: + :param session_maker: + :return: + """ + async with session_maker() as session: + async with session.begin(): + await session.execute(Update(TelegramChatSettings) + .values( + {list_of_features[callback_data.category_name][callback_data.feature_index].settings_name: callback_data.action == "enable"}) + .where(TelegramChatSettings.chat_id == call.message.chat.id)) + await call.message.edit_text( + list_of_features[callback_data.category_name][callback_data.feature_index].description, + reply_markup=await setup_feature_keyboard(category=callback_data.category_name, + index=callback_data.afeature_index, + is_enabled=callback_data.action == "enable")) + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + # Telegram feature settings + self.telegram_setting_in_list = False + self.telegram_commands = {"setup": 'Command to setup bozenka features in chat'} + self.telegram_cmd_avaible = True + self.telegram_message_handlers = { + self.telegram_setup_cmd_handler: [Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE)] + } + self.telegram_callback_handlers = { + self.telegram_features_edit_handler: [SetupAction.filter(F.action == "disable" or F.action == "enable")], + self.telegram_setup_edit_feature_handler: [SetupFeature.filter()], + self.telegram_setup_categories_handler: [SetupAction.filter(F.action == "back")] + } diff --git a/bozenka/features/basic/start.py b/bozenka/features/basic/start.py index c7e38c6..ba20c1d 100644 --- a/bozenka/features/basic/start.py +++ b/bozenka/features/basic/start.py @@ -201,10 +201,9 @@ class Start(BasicFeature): will be inside this function """ super().__init__() - self.cmd_description: str = "Your description of command" # Telegram feature settings self.telegram_setting = None - self.telegram_commands: list[str | None] = ["start"] + self.telegram_commands: dict[str: str] = {"start": "Command to start work with bozenka the bot"} self.telegram_cmd_avaible = True # Is a feature have a commands self.telegram_callback_factory = None self.telegram_message_handlers = { diff --git a/bozenka/features/features_list.py b/bozenka/features/features_list.py new file mode 100644 index 0000000..e86bd98 --- /dev/null +++ b/bozenka/features/features_list.py @@ -0,0 +1,30 @@ +from aiogram import Dispatcher + +from bozenka.features import BasicFeature +from bozenka.features.admin import * +from bozenka.features.user import * +from bozenka.features.basic import * + +features_list = [ + # Admin related category + Moderation, + Invite, + Pins, + Threads, + # User related category + ImageGeneratrion, + TextGeneratrion, + Welcome, + # Basic Functions + Setup, + Start +] + + +def register_all_features(features_list: list[BasicFeature], dispatcher: Dispatcher) -> None: + """ + Registers all features / handlers avaible in bozenka + :param features_list: List of features + :return: None + """ + pass diff --git a/bozenka/features/user/__init__.py b/bozenka/features/user/__init__.py index e69de29..26b1d3c 100644 --- a/bozenka/features/user/__init__.py +++ b/bozenka/features/user/__init__.py @@ -0,0 +1,3 @@ +from image_generation import ImageGeneratrion +from text_generation import TextGeneratrion +from welcome import Welcome diff --git a/bozenka/features/user/image_generation.py b/bozenka/features/user/image_generation.py index e69de29..3f94c9b 100644 --- a/bozenka/features/user/image_generation.py +++ b/bozenka/features/user/image_generation.py @@ -0,0 +1,157 @@ +import logging +from typing import Callable + +from aiogram import Dispatcher +from aiogram.filters import CommandObject, Command +from aiogram.fsm.context import FSMContext +from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, FSInputFile +from sqlalchemy.ext.asyncio import async_sessionmaker + +from bozenka.database.tables.telegram import TelegramChatSettings +from bozenka.features import BasicFeature +from bozenka.generative.kadinsky import kadinsky_gen +from bozenka.instances.telegram.utils.callbacks_factory import ImageGenerationCategory, ImageGeneration +from bozenka.instances.telegram.utils.keyboards import image_resolution_keyboard, delete_keyboard, \ + image_generation_keyboard, image_response_keyboard +from bozenka.instances.telegram.utils.simpler import GeneratingImages + + +class ImageGeneratrion(BasicFeature): + """ + A classic class of lineral (basic) + feature of bozenka. IN FUTURE! + """ + cmd_description: str = "Your description of command" + + @staticmethod + async def telegram_select_image_size_handler(call: CallbackQuery, callback_data: ImageGenerationCategory, + state: FSMContext) -> None: + """ + Query, what shows menu for image size to generate in + :param call: CallbackQuery object + :param callback_data: ImageGenerationCategory + :param state: FSMContext aiogram object + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + + await state.update_data(set_category=callback_data.category) + await state.set_state(GeneratingImages.set_size) + await call.message.edit_text("Пожалуста, выберите размер изображения 🖼", + reply_markup=image_resolution_keyboard(user_id=call.from_user.id, + category=callback_data.category)) + + @staticmethod + async def telegram_end_generation_handler(call: CallbackQuery, callback_data: ImageGeneration, state: FSMContext) -> None: + """ + Query, what shows menu for image size to generate in + :param call: + :param callback_data: + :param state: + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + await state.update_data(set_size=callback_data.size) + await state.set_state(GeneratingImages.ready_to_generate) + await call.message.edit_text( + f"Вы выбрали {callback_data.category} для генерации изображений в размере {callback_data.size}.\n" + "Напишите /cancel для отмены", + reply_markup=delete_keyboard(admin_id=call.from_user.id)) + + @staticmethod + async def telegram_already_generating_handler(msg: Message, state: FSMContext) -> None: + """ + Giving response, if generating image for user right now, + but user still asks something + :param msg: Message telegram object + :param state: FSM state of bot + :return: + """ + await msg.answer( + "Подождите пожалуйста, мы уже генерируем изображение для вас, подождите, когда мы ответим на ваш передыдущий вопрос", + reply_markup=delete_keyboard(admin_id=msg.from_user.id)) + + @staticmethod + async def telegram_imagine_handler(msg: Message, state: FSMContext) -> None: + """ + /imagine command handler, start menu + :param msg: Message telegram object + :param state: FSM state of bot + :return: + """ + if await state.get_state(): + return + await msg.answer("Пожалуста, выберите сервис / модель для генерации изображений", + reply_markup=image_generation_keyboard(user_id=msg.from_user.id)) + + @staticmethod + async def telegram_kadinsky_generating_handler(msg: Message, state: FSMContext) -> None: + """ + Message handler for kandinsky to generate image by text from message + :param msg: Message telegram object + :param state: FSM state of bot + :return: + """ + await state.set_state(GeneratingImages.generating) + message = await msg.answer("Пожалуйста подождите, мы генерируем изображение ⏰\n" + "Если что-то пойдет не так, мы вам сообщим 👌") + data = await state.get_data() + + try: + + model_id = kadinsky_gen.get_model() + width, height = data["set_size"].split("x") + generating = kadinsky_gen.generate(model=model_id, + prompt=msg.text, + width=int(width), + height=int(height)) + result = kadinsky_gen.check_generation(request_id=generating) + + if result: + path = kadinsky_gen.save_image(result[0], f"telegram_{msg.from_user.id}") + photo = FSInputFile(path) + await msg.answer_photo(photo=photo, + caption=msg.text, + reply_markup=image_response_keyboard(user_id=msg.from_user.id)) + await message.delete() + else: + await message.edit_text("Простите, произошла ошибка 😔\n" + "Убедитесь, что севрера kadinsky работают и ваш промт не является неподобающим и неприемлимым\n" + "Если это продолжается, пожалуйста используйте /cancel", + reply_markup=image_response_keyboard(user_id=msg.from_user.id)) + + except Exception as ex: + logging.log(msg=f"Get an exception for generating answer={ex}", + level=logging.ERROR) + finally: + logging.log(msg=f"Generated image for user_id={msg.from_user.id} with promt", + level=logging.INFO) + await state.set_state(GeneratingImages.ready_to_generate) + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + # Telegram feature settings + self.telegram_setting = TelegramChatSettings.image_generation + self.telegram_commands: dict[str: str] = {'imagine', 'Starts conversation with image generative ai'} + self.telegram_setting_in_list = True + self.telegram_setting_name = "Генерация изображений 📸" + self.telegram_setting_description = "Генерация изображений 🤖" \ + "\nНаходится в разработке.\n" \ + "На текущий момент есть поддержка:\n" \ + "- Kadinksy\n" \ + " Следите за обновлениями 😘" + self.telegram_cmd_avaible = True # Is a feature have a commands + self.telegram_message_handlers = { + self.telegram_kadinsky_generating_handler: [GeneratingImages.ready_to_generate, ~Command(commands=["cancel"])], + self.telegram_imagine_handler: [Command(commands=["imagine"])] + } + self.telegram_callback_handlers = { + self.telegram_select_image_size_handler: [ImageGenerationCategory.filter()], + self.telegram_end_generation_handler: [ImageGeneration.filter()] + } diff --git a/bozenka/features/user/text_generation.py b/bozenka/features/user/text_generation.py index e69de29..359abca 100644 --- a/bozenka/features/user/text_generation.py +++ b/bozenka/features/user/text_generation.py @@ -0,0 +1,559 @@ +import logging + +import g4f +from aiogram import F +from aiogram.filters import Command +from aiogram.fsm.context import FSMContext +from aiogram.types import Message, CallbackQuery +from gpt4all import GPT4All + +from bozenka.database.tables.telegram import TelegramChatSettings +from bozenka.features import BasicFeature +from bozenka.generative.gpt4all import model_path, check +from bozenka.generative.gpt4free import generate_gpt4free_providers +from bozenka.instances.telegram.utils.callbacks_factory import Gpt4FreeProvsModelPage, Gpt4FreeProviderPage, \ + Gpt4AllSelect, Gpt4AllModel, GptCategory, Gpt4freeResult, \ + Gpt4FreeProvider, GptBackMenu, Gpt4FreeModel, Gpt4FreeCategory, Gpt4FreeModelPage, GptStop +from bozenka.instances.telegram.utils.keyboards import delete_keyboard, \ + text_response_keyboard, gpt_categories_keyboard, \ + gpt4free_models_by_provider_keyboard, gpt4free_providers_keyboard, gpt4all_model_menu, generate_gpt4all_page, \ + gpt4free_categories_keyboard, gpt4free_models_keyboard +from bozenka.instances.telegram.utils.simpler import AnsweringGPT4Free, AnsweringGpt4All + + +class TextGeneratrion(BasicFeature): + """ + A class, what have inside all handlers / functions + related to text generation of bozenka + """ + cmd_description: str = "Your description of command" + + @staticmethod + async def telegram_already_answering_handler(msg: Message, state: FSMContext) -> None: + """ + Giving response, if answering user now, + but he still asks something + :param msg: Message telegram object + :param state: FSM state of bot + :return: Nothing + """ + await msg.answer( + "Подождите пожалуйста, мы уже генерируем ответ для вас, подождите, когда мы ответим на ваш передыдущий вопрос", + reply_markup=delete_keyboard(admin_id=msg.from_user.id)) + + @staticmethod + async def telegram_conversation_cmd_handler(msg: Message, state: FSMContext) -> None: + """ + /conversation command handler, start + :param msg: Message telegram object + :param state: FSM state of bot + :return: + """ + if await state.get_state(): + return + await msg.answer("Пожалуста, выберите сервис для ИИ.", + reply_markup=gpt_categories_keyboard + (user_id=msg.from_user.id)) + + @staticmethod + async def telegram_cancel_cmd_handler(msg: Message, state: FSMContext) -> None: + """ + Canceling dialog with generative model + Works on command /cancel + :param msg: Message telegram object + :param state: FSM state of bot + :return: + """ + current = await state.get_state() + if current is None: + return + await state.clear() + await msg.answer("Удача ✅\n" + "Диалог отменён!", reply_markup=delete_keyboard(admin_id=msg.from_user.id)) + + # G4F telegram category + # All handlers and other stuff + # All code and comments + @staticmethod + async def telegram_g4f_generate_handler(msg: Message, state: FSMContext) -> None: + """ + Generating answer if GPT4Free model and provider has been selected + :param msg: Message telegram object + :param state: FSM state of bot + :return: + """ + await state.set_state(AnsweringGPT4Free.answering) + + info = await state.get_data() + + providers = generate_gpt4free_providers() + reply = await msg.reply("Пожалуйста подождите, мы генерируем ответ от провайдера ⏰\n" + "Если что-то пойдет не так, мы вам сообщим 👌") + + current_messages = [] + if info.get("ready_to_answer"): + for message in info["ready_to_answer"]: + current_messages.append(message) + + if not info.get("set_provider"): + info["set_provider"] = None + + current_messages.append({"role": "user", "content": msg.text}) + + response = "" + try: + response = await g4f.ChatCompletion.create_async( + model=info["set_model"], + messages=current_messages, + provider=None if info["set_provider"] is None else providers[info["set_provider"]], + stream=False + ) + + except NameError or SyntaxError: + try: + response = g4f.ChatCompletion.create( + model=info["set_model"], + messages=current_messages, + provider=None if info["set_provider"] is None else providers[info["set_provider"]], + stream=False + ) + except Exception as S: + response = "Простите, произошла ошибка 😔\nЕсли это продолжается, пожалуйста используйте /cancel" + logging.log(msg=f"Get an exception for generating answer={S}", + level=logging.ERROR) + except Exception as S: + response = "Простите, произошла ошибка 😔\nЕсли это продолжается, пожалуйста используйте /cancel" + logging.log(msg=f"Get an exception for generating answer={S}", + level=logging.ERROR) + finally: + await reply.edit_text(text=response, reply_markup=text_response_keyboard(user_id=msg.from_user.id)) + current_messages.append({"role": "assistant", "content": response}) + await state.update_data(ready_to_answer=current_messages) + await state.set_state(AnsweringGPT4Free.ready_to_answer) + + @staticmethod + async def telegram_instart_conversation_handler(call: CallbackQuery, callback_data: GptBackMenu, state: FSMContext) -> None: + """ + Query, what shows when clicking on button in /start menu + :param call: CallbackQuery class + :param state: FSMContext aiogram class + :param callback_data: GptBackMenu class + :return: Nothing + """ + if call.from_user.id != callback_data.user_id or await state.get_state(): + return + await call.message.edit_text("Пожалуста, выберите сервис для ИИ.", + reply_markup=gpt_categories_keyboard(user_id=call.from_user.id)) + + @staticmethod + async def telegram_g4f_providers_handlers(call: CallbackQuery, callback_data: Gpt4FreeCategory, + state: FSMContext) -> None: + """ + Query, what creating providers selecting menu. + :param call: CallbackQuery class + :param state: FSMContext aiogram class + :param callback_data: Gpt4FreeCategory + return: Nothing + """ + if call.from_user.id != callback_data.user_id: + return + + logging.log(msg=f"Selected gpt4free category by user_id={call.from_user.id}", + level=logging.INFO) + + await call.answer("Вы выбрали провайдеры 🤖") + + await state.set_state(AnsweringGPT4Free.set_provider) + await call.message.edit_text("Выберите пожалуйста одного из провайдеров 👨‍💻", + reply_markup=gpt4free_providers_keyboard(user_id=call.from_user.id, page=0)) + + @staticmethod + async def telegram_g4f_models_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: + """ + Query, what creating models selecting menu + :param call: CallbackQuery class + :param state: FSMContext aiogram class + :param callback_data: GptCategory + return: Nothing + """ + if call.from_user.id != callback_data.user_id: + return + + await state.set_state(AnsweringGPT4Free.set_model) + + await call.answer("Вы выбрали модели 🤖") + + await call.message.edit_text("Выберите модель, с которой будете общаться 🤖", + reply_markup=gpt4free_models_keyboard(user_id=call.from_user.id, page=0)) + + @staticmethod + async def telegram_end_g4f_model_handler(call: CallbackQuery, callback_data: Gpt4FreeModel, state: FSMContext) -> None: + """ + Query, what ending g4f model selecting + :param call: CallbackQuery class + :param callback_data: Gpt4FreeModel model + :param state: FSMContext aiogram class + :return: Nothing + """ + if call.from_user.id != callback_data.user_id: + return + + await state.update_data(set_model=callback_data.model) + await state.set_state(AnsweringGPT4Free.ready_to_answer) + + await call.answer("Вы можете начать общаться 🤖") + + await call.message.edit_text("Удача ✅\n" + "Вы теперь можете спокойно вести диалог 🤖\n" + f"Вы выбрали модель {callback_data.model}👾\n" + "Чтобы прекратить общение, используйте /cancel ", + reply_markup=delete_keyboard(admin_id=call.from_user.id)) + + @staticmethod + async def telegram_g4f_next_model_handler(call: CallbackQuery, callback_data: Gpt4FreeModelPage, + state: FSMContext) -> None: + """ + Query, what creating models selecting menu + :param state: FSMContext aiogram class + :param call: CallbackQuery class + :param callback_data: Gpt4FreeModelPage class + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + + await call.answer(f"Вы перелистнули на страницу {callback_data.page + 1}📄") + + await call.message.edit_text("Выберите модель, с которой будете общаться 🤖", + reply_markup=gpt4free_models_keyboard(user_id=call.from_user.id, + page=callback_data.page)) + + @staticmethod + async def telegram_g4f_category_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: + """ + Query, what creating providers selecting menu. + :param state: FSMContext aiogram class + :param call: CallbackQuery class + :param callback_data: GptCategory class + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + + logging.log(msg=f"Selected gpt4free category by user_id={call.from_user.id}", + level=logging.INFO) + + await state.update_data(set_category=callback_data.category) + await call.answer("Вы выбрали Gpt4Free 🤖") + await call.message.edit_text("Выберите, по какому пункту мы будем вести диалог с нейронной сети 🤖", + reply_markup=gpt4free_categories_keyboard(user_id=call.from_user.id)) + await call.answer("Выберите, по какому пункту мы будем вести диалог с нейронной сети 🤖") + + @staticmethod + async def telegram_g4f_back_provider_handler(call: CallbackQuery, callback_data: GptBackMenu, + state: FSMContext) -> None: + """ + Query, what creating providers selecting menu. + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: GptBackMenu class + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + + logging.log(msg=f"Back to providers menu by user_id={call.from_user.id}", + level=logging.INFO) + await state.set_state(AnsweringGPT4Free.set_provider) + + await call.message.edit_text("Выберите пожалуйста одного из провайдеров 👨‍💻", + reply_markup=gpt4free_providers_keyboard(page=0, user_id=callback_data.user_id)) + await call.answer("Выберите пожалуйста одного из провайдеров 👨‍💻") + + @staticmethod + async def inline_g4f_provider_models(call: CallbackQuery, callback_data: Gpt4FreeProvider, + state: FSMContext) -> None: + """ + Query, what creating models selecting menu. + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: Gpt4FreeProvider Class + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + + logging.log(msg=f"Selected gpt4free provider {callback_data.provider} by user_id={call.from_user.id}", + level=logging.INFO) + + await state.update_data(set_provider=callback_data.provider) + await state.set_state(AnsweringGPT4Free.set_model) + + await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", + reply_markup=gpt4free_models_by_provider_keyboard( + user_id=callback_data.user_id, + provider=callback_data.provider, + page=0 + )) + await call.answer("Выберите пожалуйста модель ИИ 👾") + + @staticmethod + async def telegram_g4f_ready_handler(call: CallbackQuery, callback_data: Gpt4freeResult, state: FSMContext) -> None: + """ + Query, what says about getting ready to questions for ChatGPT from Gpt4Free. + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: Gpt4freeResult + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + + logging.log(msg=f"Selected gpt4free model {callback_data.model} by user_id={call.from_user.id}", + level=logging.INFO) + + await state.update_data(set_model=callback_data.model) + await state.set_state(AnsweringGPT4Free.ready_to_answer) + + logging.log(msg=f"Loaded GPT answering status for user_id={call.from_user.id}", + level=logging.INFO) + + await call.message.edit_text("Удача ✅\n" + "Вы теперь можете спокойно вести диалог 🤖\n" + f"Вы выбрали модель {callback_data.model}👾, от провайдера {callback_data.provider}👨‍💻\n" + "Чтобы прекратить общение, используйте /cancel ", + reply_markup=delete_keyboard(admin_id=callback_data.user_id)) + await call.answer("Вы теперь можете спокойно вести диалог 🤖") + + @staticmethod + async def telegram_g4f_models_by_provider_handler(call: CallbackQuery, callback_data: Gpt4FreeProvsModelPage, + state: FSMContext) -> None: + """ + Query, what generates a next page of models for user. + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: Gpt4FreeProvsModelPage + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + logging.log(msg=f"Changed page to {str(callback_data.page + 1)} user_id={call.from_user.id}", + level=logging.INFO) + await call.message.edit_text(call.message.text, + reply_markup=gpt4free_models_by_provider_keyboard( + user_id=callback_data.user_id, + provider=callback_data.provider, + page=callback_data.page + )) + await call.answer(f"Вы перелистали на страницу {callback_data.page + 1}📄") + + @staticmethod + async def telegram_next_g4f_providers_handler(call: CallbackQuery, callback_data: Gpt4FreeProviderPage, + state: FSMContext) -> None: + """ + Query, what generates a next page of providers for user + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: Gpt4FreeProviderPage class + :return: None + """ + if call.from_user.id != callback_data.user_id: + return + logging.log(msg=f"Changed page to {str(callback_data.page + 1)} user_id={call.from_user.id}", + level=logging.INFO) + await call.message.edit_text(call.message.text, + reply_markup=gpt4free_providers_keyboard(user_id=callback_data.user_id, + page=callback_data.page)) + await call.answer(f"Вы перелистнули на страницу {callback_data.page + 1}📄") + + # G4A telegram handlers section + # All code and commentaries here + # All handlers here + + @staticmethod + async def telegram_g4a_generate_handler(msg: Message, state: FSMContext) -> None: + """ + Generating answer if Gpt4All has been selected + :param msg: Message telegram object + :param state: FSM state of bot + :return: + """ + await state.set_state(AnsweringGpt4All.answering) + + models = GPT4All.list_models() + info = await state.get_data() + answer = "" + + main_msg = await msg.answer("Пожалуйста подождите, мы генерируем вам ответ ⏰\n" + "Если что-то пойдет не так, мы вам сообщим 👌", + reply_markup=text_response_keyboard(user_id=msg.from_user.id)) + + if not check(models[info["set_model"]]["filename"]): + main_msg = await main_msg.edit_text(main_msg.text + "\nПодождите пожалуста, мы скачиваем модель...", + reply_markup=main_msg.reply_markup) + + try: + # Setting Gpt4All model + model = GPT4All(model_name=models[info['set_model']]['filename'], + model_path=model_path, + allow_download=True) + # Setting our chat session if exist + model.current_chat_session = [] if not info.get("ready_to_answer") else info["ready_to_answer"] + # Generating answer + with model.chat_session(): + answer = model.generate(msg.text) + await state.update_data(ready_to_answer=model.current_chat_session) + + except Exception as S: + answer = "Простите, произошла ошибка 😔\nЕсли это продолжается, пожалуйста используйте /cancel" + logging.log(msg=f"Get an exception for generating answer={S}", + level=logging.ERROR) + finally: + await main_msg.edit_text(answer, reply_markup=text_response_keyboard(user_id=msg.from_user.id)) + + await state.set_state(AnsweringGpt4All.ready_to_answer) + + @staticmethod + async def telegram_g4a_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: + """ + Query, what shows list for gpt4all models + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: GptCategory class + :return: None + """ + if callback_data.user_id != call.from_user.id: + return + await state.set_state(AnsweringGpt4All.set_model) + await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", + reply_markup=generate_gpt4all_page(user_id=call.from_user.id)) + + @staticmethod + async def telegram_g4a_back_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: + """ + Query, what shows list for gpt4all models back + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: GptCategory class + :return: None + """ + if callback_data.user_id != call.from_user.id: + return + await state.set_state(AnsweringGpt4All.set_model) + await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", + reply_markup=generate_gpt4all_page(user_id=call.from_user.id)) + + @staticmethod + async def telegram_g4a_infomration_handler(call: CallbackQuery, callback_data: Gpt4AllModel, state: FSMContext) -> None: + """ + Query, what show information about clicked gpt4all model from list + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: Gpt4AllModel class + :return: None + """ + if callback_data.user_id != call.from_user.id: + return + models = GPT4All.list_models() + name = models[callback_data.index]['name'] + await call.message.edit_text(f"{name}\n" + f"Обученно на основе {models[callback_data.index]['parameters']} строк 👨‍💻", + reply_markup=gpt4all_model_menu(user_id=call.from_user.id, + index=callback_data.index)) + + @staticmethod + async def telegram_g4a_end_handler(call: CallbackQuery, callback_data: Gpt4AllSelect, + state: FSMContext) -> None: + """ + Query, what says about getting ready for question for Gpt4All model + :param state: FSMContext aiogram class + :param call: CallbackQuery telegram class + :param callback_data: Gpt4AllSelect class + :return: None + """ + if callback_data.user_id != call.from_user.id: + return + await state.update_data(set_model=callback_data.index) + await state.set_state(AnsweringGpt4All.ready_to_answer) + models = GPT4All.list_models() + + await call.message.edit_text("Удача ✅\n" + "Вы теперь можете спокойно вести диалог 🤖\n" + f"Вы выбрали модель {models[callback_data.index]['name']}👾 от Gpt4All\n" + "Чтобы прекратить общение, используйте /cancel ", + reply_markup=delete_keyboard(admin_id=callback_data.user_id)) + + @staticmethod + async def telegram_pages_handler(call: CallbackQuery) -> None: + """ + Query, made for helping purposes. + Shows current page. + :param call: CallbackQuery telegram class + :return: None + """ + logging.log(msg=f"Showed helping info for user_id={call.from_user.id}", + level=logging.INFO) + await call.answer("Здесь расположается текущая странница 📃") + + @staticmethod + async def telegram_stop_dialog_handler(call: CallbackQuery, callback_data: GptStop, state: FSMContext) -> None: + """ + Query, what stops dialog + :param call: CallbackQuery telegram class + :param callback_data: GptStop class + :param state: None + """ + # Checking user_id of user + if callback_data.user_id != call.from_user.id: + return + # Clearing state + await state.clear() + # Answering something + await call.answer("Хорошо ✅") + if await state.get_state() == AnsweringGPT4Free.ready_to_answer or await state.get_state() == AnsweringGpt4All.answering: + await call.message.edit_text(text=call.message.text + "\n\nДиалог остановлен ✅\n", + reply_markup=delete_keyboard(admin_id=call.from_user.id)) + else: + await call.message.delete() + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + # Telegram feature settings + self.telegram_setting = TelegramChatSettings.text_generation + self.telegram_setting_in_list = True + self.telegram_setting_name = "ИИ ЧатБот 🤖" + self.telegram_setting_description = "ИИ ЧатБот 🤖" \ + "\nЕсть поддержка:\n" \ + "- Моделей Gpt4All\n" \ + "- Провайдеров Gpt4Free и моделей\n" \ + "Для использования:\n" \ + "
/conversations
" \ + "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘" + self.telegram_commands: dict[str: str] = { + 'conversation': 'Starts conversation with text generative ai' + } + self.telegram_cmd_avaible = True # Is a feature have a commands + self.telegram_message_handlers = { + self.telegram_conversation_cmd_handler: [Command(commands=["conversation"])], + self.telegram_g4a_generate_handler: [AnsweringGpt4All.ready_to_answer, ~Command(commands=["cancel"])], + self.telegram_g4f_generate_handler: [AnsweringGPT4Free.ready_to_answer, ~Command(commands=["cancel"])], + self.telegram_already_answering_handler: [AnsweringGPT4Free.answering, AnsweringGpt4All.answering] + } + self.telegram_callback_handlers = { + # g4a + self.telegram_g4a_handler: [GptCategory.filter(F.category == "Gpt4All")], + self.telegram_g4a_infomration_handler: [Gpt4AllModel.filter()], + self.telegram_g4a_end_handler: [Gpt4AllSelect.filter()], + # g4f + self.telegram_g4f_category_handler: [GptCategory.filter(F.category == "Gpt4Free")], + self.telegram_g4f_models_handler: [Gpt4FreeCategory.filter(F.category == "models")], + self.telegram_g4f_providers_handlers: [Gpt4FreeCategory.filter(F.category == "providers")], + self.telegram_g4f_models_by_provider_handler: [Gpt4FreeProvider.filter()], + self.telegram_next_g4f_providers_handler: [Gpt4FreeProviderPage.filter()], + # stop talking + self.telegram_stop_dialog_handler: [GptStop.filter()] + } diff --git a/bozenka/features/user/welcome.py b/bozenka/features/user/welcome.py index e69de29..3584425 100644 --- a/bozenka/features/user/welcome.py +++ b/bozenka/features/user/welcome.py @@ -0,0 +1,82 @@ +import logging + +from aiogram import Bot +from aiogram.types import Message, CallbackQuery +from sqlalchemy.ext.asyncio import async_sessionmaker + +from bozenka.database.tables.telegram import TelegramChatSettings +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg +from bozenka.instances.telegram.utils.keyboards import unpin_msg_keyboard, delete_keyboard, pin_msg_keyboard +from bozenka.instances.telegram.utils.simpler import SolutionSimpler + + +class Welcome(BasicFeature): + """ + A class of pins related commands + All staff related to it will be here + """ + + @staticmethod + async def telegram_join_handler(msg: Message, session_maker: async_sessionmaker) -> None: + """ + Message handler. + Send welcome message, after adding new member to chat. + Also works on adding bot to chat and sending welcome message. + :param msg: Message telegram object + :param session_maker: AsyncSessionmaker object + :return: None + """ + for new in msg.new_chat_members: + if new.id != msg.bot.id: + logging.log(msg=f"Saing welcome for user_id={new.id}, chat_id={msg.chat.id}", + level=logging.INFO) + await msg.answer( + f"Пользователь {new.mention_html()} переехал в конфу, благодаря {msg.from_user.mention_html()}👋", + ) + await msg.delete() + else: + logging.log(msg=f"Saing welcome to administrators for chat_id={msg.chat.id}", + level=logging.INFO) + await msg.answer("Здраствуйте администраторы чата 👋\n" + "Я - бозенька, мультифункциональный бот, разрабатываемый Bozo Developement\n" + "Выдайте мне полные права администратора для моей полной работы.\n" + "Чтобы настроить функционал, используйте /setup или кнопку под сообщением", ) + await SolutionSimpler.auto_settings(msg=msg, session=session_maker) + + @staticmethod + async def telegram_leave_handler(msg: Message, bot: Bot) -> None: + """ + Sens goodbye message, after deleting member from chat + :param msg: Message telegram object + :param bot: Aiogram bot object + :return: Nothing + """ + await msg.delete() + if msg.from_user.id == bot.id: + return + logging.log(msg=f"Saing goodbye for user_id={msg.left_chat_member.id}, chat_id={msg.chat.id}", + level=logging.INFO) + await msg.answer( + f"Пользователь {msg.left_chat_member.mention_html()} съехал с конфы, благодаря {msg.from_user.mention_html()}👋" + ) + + def __init__(self): + """ + All information about feature + will be inside this function + """ + super().__init__() + self.cmd_description: str = "Your description of command" + # Telegram feature settings + self.telegram_setting = TelegramChatSettings.welcome_messages + self.telegram_commands: dict[str: str] = {} + self.telegram_setting_in_list = True + self.telegram_setting_name = "Приветсвенные сообщения 👋" + self.telegram_setting_description = "Приветсвенные сообщения 👋" \ + "\nПриветсвенные сообщения новым и ушедшим пользователям.", + self.telegram_cmd_avaible = False # Is a feature have a commands + self.telegram_message_handlers = { + + } + self.telegram_callback_handlers = {} diff --git a/bozenka/instances/telegram/handlers/chat_admin/__init__.py b/bozenka/instances/telegram/handlers/chat_admin/__init__.py index 10651b4..06a94a9 100644 --- a/bozenka/instances/telegram/handlers/chat_admin/__init__.py +++ b/bozenka/instances/telegram/handlers/chat_admin/__init__.py @@ -23,8 +23,6 @@ def register_admin_cmd(router: Router) -> None: logging.log(msg="Registering administrator commands", level=logging.INFO) # Ban / Unban commands handler - router.message.register(ban_command, Command(commands="ban"), - IsAdminFilter(True)) router.message.register(ban_command, Command(commands="ban"), IsAdminFilter(True), F.reply_to_message.text) router.message.register(unban_command, Command(commands="unban"), diff --git a/bozenka/instances/telegram/handlers/dev/image_generation.py b/bozenka/instances/telegram/handlers/dev/image_generation.py index 5abc24c..9359bfe 100644 --- a/bozenka/instances/telegram/handlers/dev/image_generation.py +++ b/bozenka/instances/telegram/handlers/dev/image_generation.py @@ -1,18 +1,12 @@ import logging -import os -import g4f -import base64 -from gpt4all import GPT4All from aiogram.fsm.context import FSMContext from aiogram.types import Message as Message, FSInputFile from bozenka.generative.kadinsky import kadinsky_gen -from bozenka.instances.telegram.utils.keyboards import gpt_categories_keyboard, delete_keyboard, text_response_keyboard, \ - image_generation_keyboard, image_response_keyboard -from bozenka.instances.telegram.utils.simpler import AnsweringGpt4All, \ - AnsweringGPT4Free, GeneratingImages -from bozenka.generative.gpt4free import generate_gpt4free_providers +from bozenka.instances.telegram.utils.keyboards import delete_keyboard, image_generation_keyboard, \ + image_response_keyboard +from bozenka.instances.telegram.utils.simpler import GeneratingImages async def already_generating(msg: Message, state: FSMContext): diff --git a/bozenka/instances/telegram/handlers/queries/setup.py b/bozenka/instances/telegram/handlers/queries/setup.py index e56239a..715ad81 100644 --- a/bozenka/instances/telegram/handlers/queries/setup.py +++ b/bozenka/instances/telegram/handlers/queries/setup.py @@ -27,7 +27,7 @@ async def inline_setup_category_back(call: CallbackQuery, callback_data: SetupAc :return: """ await call.message.edit_text("Выберите настройку, которую хотите изменить", - reply_markup=setup_category_keyboard(category=callback_data.feature_category)) + reply_markup=setup_category_keyboard(category=callback_data.category_name)) async def inline_edit_feature(call: CallbackQuery, callback_data: SetupFeature, session_maker: async_sessionmaker): @@ -63,11 +63,11 @@ async def inline_feature_edited(call: CallbackQuery, callback_data: SetupAction, async with session_maker() as session: async with session.begin(): await session.execute(Update(TelegramChatSettings) - .values({list_of_features[callback_data.feature_category][callback_data.feature_index].settings_name: + .values({list_of_features[callback_data.category_name][callback_data.feature_index].settings_name: callback_data.action == "enable"}) .where(TelegramChatSettings.chat_id == call.message.chat.id)) await call.message.edit_text( - list_of_features[callback_data.feature_category][callback_data.feature_index].description, - reply_markup=await setup_feature_keyboard(category=callback_data.feature_category, + list_of_features[callback_data.category_name][callback_data.feature_index].description, + reply_markup=await setup_feature_keyboard(category=callback_data.category_name, index=callback_data.feature_index, is_enabled=callback_data.action == "enable")) diff --git a/bozenka/instances/telegram/utils/callbacks_factory/setup.py b/bozenka/instances/telegram/utils/callbacks_factory/setup.py index 5a41c6c..1426531 100644 --- a/bozenka/instances/telegram/utils/callbacks_factory/setup.py +++ b/bozenka/instances/telegram/utils/callbacks_factory/setup.py @@ -28,7 +28,7 @@ class SetupAction(CallbackData, prefix="sa"): Callback with information to do with a feature """ action: str - feature_category: str + category_name: str feature_index: int diff --git a/bozenka/instances/telegram/utils/simpler/lists_of_content.py b/bozenka/instances/telegram/utils/simpler/lists_of_content.py index 34327aa..69e4598 100644 --- a/bozenka/instances/telegram/utils/simpler/lists_of_content.py +++ b/bozenka/instances/telegram/utils/simpler/lists_of_content.py @@ -92,7 +92,7 @@ list_of_features = { BaseFeature( name="Приглашения в Чат ✉", description="Генератор приглашения в Чат ✉\n" - "Разрешает использование комманды /invite в чате, для созданния приглашений.\n" + "Разрешает использование комманды /invite в чате, для созданния приглашений.\n" "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота.", callback_name="invites", settings_name="invite_generator", @@ -288,7 +288,7 @@ list_of_commands = { ("open_general", 'Opens general topic in chat'), # AI related ('conversation', 'Starts conversation with text generative ai'), - ('imagine', 'Starts conversation with image generative ai'), \ + ('imagine', 'Starts conversation with image generative ai'), # Basic features ('invite', 'Generates invite into current chat'), ('about', 'Sends information about bozenka'), -- 2.30.2 From 9b2fd5d7505b4e241c1a11bc4239ce07437f6595 Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Sat, 10 Feb 2024 22:14:31 +0300 Subject: [PATCH 04/13] Before removing old code Full refactoring Errors fixed New features introducing --- bozenka/features/__init__.py | 33 ++-- bozenka/features/admin/__init__.py | 8 +- bozenka/features/admin/invite.py | 54 +++-- bozenka/features/admin/moderation.py | 184 +++++++++++------- bozenka/features/admin/pins.py | 102 ++++++---- bozenka/features/admin/topics.py | 113 ++++++----- bozenka/features/basic/__init__.py | 4 +- bozenka/features/basic/setup.py | 38 ++-- bozenka/features/basic/start.py | 145 ++++++++------ bozenka/features/features_list.py | 11 +- bozenka/features/user/__init__.py | 6 +- bozenka/features/user/image_generation.py | 55 +++--- bozenka/features/user/text_generation.py | 131 ++++++------- bozenka/features/user/welcome.py | 37 ++-- bozenka/instances/telegram/__init__.py | 38 +++- .../telegram/utils/filters/permissions.py | 81 ++++++-- .../telegram/utils/keyboards/inline.py | 8 +- 17 files changed, 580 insertions(+), 468 deletions(-) diff --git a/bozenka/features/__init__.py b/bozenka/features/__init__.py index 8343157..fad29b1 100644 --- a/bozenka/features/__init__.py +++ b/bozenka/features/__init__.py @@ -5,29 +5,22 @@ class BasicFeature: A classic class of lineral (basic) feature of bozenka. IN FUTURE! """ - def __init__(self): - """ - All information about feature - will be inside this function - """ - - # Telegram setting info - self.telegram_setting_in_list = False # Does feature shows in /setup list - self.telegram_setting_name = None # Setting title in /setup command - self.telegram_setting_description = None # Setting description in /setup command - self.telegram_db_name = None # Name of TelegramChatSettings column will be affected - # Telegram commands list of feature - self.telegram_commands: dict[str: str] = { + telegram_setting_in_list = False # Does feature shows in /setup list + telegram_setting_name = None # Setting title in /setup command + telegram_setting_description = None # Setting description in /setup command + telegram_db_name = None # Name of TelegramChatSettings column will be affected + # Telegram commands list of feature + telegram_commands: dict[str: str] = { # # Format is "CommandNameHere": "Command description is here" # "example": "Its an example" - } - self.telegram_cmd_avaible = True # Does this feature have a telegram commands - # All handlers - self.telegram_message_handlers = ( + } + telegram_cmd_avaible = True # Does this feature have a telegram commands + # All handlers + telegram_message_handlers = [ # Format is [Handler, [Filters]] - ) - self.telegram_callback_handlers = ( + ] + telegram_callback_handlers = [ # Format is [Handler, [Filters]] - ) \ No newline at end of file + ] diff --git a/bozenka/features/admin/__init__.py b/bozenka/features/admin/__init__.py index f14b364..8e7fa94 100644 --- a/bozenka/features/admin/__init__.py +++ b/bozenka/features/admin/__init__.py @@ -1,4 +1,4 @@ -from invite import Invite -from moderation import Moderation -from pins import Pins -from topics import Threads +from .invite import Invite +from .moderation import Moderation +from .pins import Pins +from .topics import Threads diff --git a/bozenka/features/admin/invite.py b/bozenka/features/admin/invite.py index b39c107..c8bc720 100644 --- a/bozenka/features/admin/invite.py +++ b/bozenka/features/admin/invite.py @@ -17,7 +17,6 @@ class Invite(BasicFeature): All codes will be here """ - @staticmethod async def telegram_invite_command_handler(msg: Message) -> None: """ Generating invite to group by /invite command @@ -34,7 +33,6 @@ class Invite(BasicFeature): chat_name=msg.chat.full_name) ) - @staticmethod async def telegram_revoke_callback_handler(call: CallbackQuery, callback_data: RevokeCallbackData) -> None: """ Handler of CallbackQuery, revokes link after pressing button @@ -48,36 +46,30 @@ class Invite(BasicFeature): user_clicked.status != ChatMemberStatus.ADMINISTRATOR and user_clicked.status == ChatMemberStatus.CREATOR: return logging.log(msg=f"Revoking link for user_id={call.from_user.id}", - level=logging.INFO) + level=logging.INFO) await call.message.chat.revoke_invite_link(invite_link="https://" + str(callback_data.link)) await call.answer("Удача ✅") await call.message.delete() - def __init__(self): - """ - All information about feature - will be inside this function - """ - super().__init__() - """ - Telegram feature settings - """ - # Telegram setting info - self.telegram_setting_in_list = True - self.telegram_setting_name = "Приглашения в Чат ✉" - self.telegram_setting_description = "Генератор приглашения в Чат ✉\n" \ - "Разрешает использование комманды /invite в чате, для созданния приглашений.\n" \ - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." - self.telegram_db_name = TelegramChatSettings.invite_generator - # Telegram commands - self.telegram_commands: dict[str: str] = {"/invite": 'Generates invite into current chat'} - self.telegram_cmd_avaible = True # Is a feature have a commands - # List of aiogram handlers - self.telegram_message_handlers = ( - # Format is [Handler, [Filters]] - [self.telegram_invite_command_handler, [Command(commands=["invite"])]] - ) - self.telegram_callback_handlers = ( - # Format is [Handler, [Filters]] - [self.telegram_revoke_callback_handler, [RevokeCallbackData.filter()]] - ) + """ + Telegram feature settings + """ + # Telegram setting info + telegram_setting_in_list = True + telegram_setting_name = "Приглашения в Чат ✉" + telegram_setting_description = "Генератор приглашения в Чат ✉\n" \ + "Разрешает использование комманды /invite в чате, для созданния приглашений.\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." + telegram_db_name = TelegramChatSettings.invite_generator + # Telegram commands + telegram_commands: dict[str: str] = {"/invite": 'Generates invite into current chat'} + telegram_cmd_avaible = True # Is a feature have a commands + # List of aiogram handlers + telegram_message_handlers = [ + # Format is [Handler, [Filters]] + [telegram_invite_command_handler, [Command(commands=["invite"])]] + ] + telegram_callback_handlers = [ + # Format is [Handler, [Filters]] + [telegram_revoke_callback_handler, [RevokeCallbackData.filter()]] + ] diff --git a/bozenka/features/admin/moderation.py b/bozenka/features/admin/moderation.py index 637b969..fa76e48 100644 --- a/bozenka/features/admin/moderation.py +++ b/bozenka/features/admin/moderation.py @@ -1,7 +1,7 @@ import logging from aiogram import F -from aiogram.enums import ChatMemberStatus +from aiogram.enums import ChatMemberStatus, ChatType from aiogram.filters import CommandObject, Command from aiogram.types import Message, CallbackQuery from sqlalchemy.ext.asyncio import async_sessionmaker @@ -21,7 +21,6 @@ class Moderation(BasicFeature): All staff related to it will be here """ - @staticmethod async def telegram_ban_callback_handler(call: CallbackQuery, callback_data: BanData, session_maker: async_sessionmaker) -> None: """ @@ -35,7 +34,7 @@ class Moderation(BasicFeature): banned_user = await call.message.chat.get_member(int(callback_data.user_id_ban)) send_notification = await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]) + setting=list_of_features["Admins"][5]) if call.from_user.id != callback_data.user_id_clicked \ and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: @@ -62,7 +61,6 @@ class Moderation(BasicFeature): logging.log(msg=f"Banned user @{banned_user.user.full_name} user_id=f{banned_user.user.id}", level=logging.INFO) - @staticmethod async def telegram_unban_callback_handler(call: CallbackQuery, callback_data: UnbanData, session_maker: async_sessionmaker) -> None: """ @@ -92,7 +90,7 @@ class Moderation(BasicFeature): ) if await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]): + setting=list_of_features["Admins"][5]): await call.message.bot.send_message( chat_id=unbanned_user.user.id, text=f"{unbanned_user.user.mention_html('Вы')} были разблокирован {call.from_user.mention_html('этим пользователем')} в чате {call.message.chat.id}.", @@ -102,7 +100,6 @@ class Moderation(BasicFeature): logging.log(msg=f"Unbanned user @{unbanned_user.user.full_name} user_id=f{unbanned_user.user.id}", level=logging.INFO) - @staticmethod async def telegram_ban_cmd_handler(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None: """ /ban command function, supports time and reasons. @@ -113,9 +110,9 @@ class Moderation(BasicFeature): """ banned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][4]) + setting=list_of_features["Admins"][4]) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]) + setting=list_of_features["Admins"][5]) where_send = { True: msg.from_user.id, @@ -183,7 +180,6 @@ class Moderation(BasicFeature): f"{msg.chat.title}.\n", reply_markup=delete_keyboard(admin_id=banned_user.user.id)) - @staticmethod async def telegram_unban_cmd_handler(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None: """ @@ -196,9 +192,9 @@ class Moderation(BasicFeature): unbanned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][4]) + setting=list_of_features["Admins"][4]) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]) + setting=list_of_features["Admins"][5]) where_send = { True: msg.from_user.id, @@ -245,7 +241,6 @@ class Moderation(BasicFeature): reply_markup=delete_keyboard(admin_id=unbanned_user.user.id) ) - @staticmethod async def telegram_mute_callback_handler(call: CallbackQuery, callback_data: MuteData, session_maker: async_sessionmaker) -> None: """ @@ -285,7 +280,6 @@ class Moderation(BasicFeature): logging.log(msg=f"Muted user @{muted_user.user.full_name} user_id=f{muted_user.user.id}", level=logging.INFO) - @staticmethod async def telegram_unmute_callback_handler(call: CallbackQuery, callback_data: UnmuteData, session_maker: async_sessionmaker) -> None: """ @@ -325,7 +319,6 @@ class Moderation(BasicFeature): logging.log(msg=f"Unbanned user @{unmuted_user.user.full_name} user_id=f{unmuted_user.user.id}", level=logging.INFO) - @staticmethod async def telegram_mute_cmd_handler(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None: """ @@ -336,12 +329,14 @@ class Moderation(BasicFeature): :param session_maker: Session maker object of SqlAlchemy :return: Nothing """ + print(msg.reply_to_message) + print("341414124") mute_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][4]) + setting=list_of_features["Admins"][4]) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]) + setting=list_of_features["Admins"][5]) where_send = { True: msg.from_user.id, @@ -411,7 +406,6 @@ class Moderation(BasicFeature): f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n", reply_markup=delete_keyboard(admin_id=mute_user.user.id)) - @staticmethod async def telegram_unmute_cmd_handler(msg: Message, session_maker: async_sessionmaker) -> None: """ Handler of command /unmute @@ -423,9 +417,9 @@ class Moderation(BasicFeature): await SolutionSimpler.unmute_user(msg, session_maker) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][4]) + setting=list_of_features["Admins"][4]) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]) + setting=list_of_features["Admins"][5]) where_send = { True: msg.from_user.id, @@ -445,55 +439,107 @@ class Moderation(BasicFeature): f"сообщения {msg.reply_to_message.from_user.mention_html('вам')}", reply_markup=delete_keyboard(admin_id=msg.reply_to_message.from_user.id)) - def __init__(self): + # Help moderation telegram + # Code part + async def telegram_help_ban_handler(msg: Message) -> None: """ - All information about feature - will be inside this function + Shows help message for /ban + :param msg: Message telegram object + :return: Nothing """ - super().__init__() - # Telegram setting info - self.telegram_setting_in_list = True - self.telegram_setting_name = "Модерация чата 🕵️" - self.telegram_setting_description = "Модерация чата🕵️\nДанная настройка включает следущие комманды:" \ - "\n
/ban [время блокировки] [причина блокировки] - блокировка пользователя" \
-                                            "\n/unban - разблокировка пользователя\n" \
-                                            "/mute [время мута] [причина мута] - мут пользователя\n" \
-                                            "/unmute - Размут пользователя
\n" \ - "Время обозначается как:" \ - "
1h - один час, " \
-                                            "1d - один день, " \
-                                            "1m - одна минута, " \
-                                            "1s - одна секунда
\n" \ - "Для того, " \ - "чтобы выполнить одну из комманд по отношению к пользователю, " \ - "ответьте на сообщение пользователя и используйте команду\n" \ - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." - self.telegram_db_name = TelegramChatSettings.moderation - # Telegram commands - self.telegram_commands: dict[str: str] = { - "ban": "Command to ban user in chat", - 'unban': 'Command to unban user in chat', - 'mute': 'Command to mute user in chat', - 'unmute': 'Command to unmute user in chat', - } - self.telegram_cmd_avaible = True # Is a feature have a commands - # All handlers - self.telegram_message_handlers = ( - # Format is [Handler, [Filters]] - [self.telegram_ban_cmd_handler, [Command(commands="ban"), - IsAdminFilter(True), F.reply_to_message.text]], - [self.telegram_unban_cmd_handler, [Command(commands="unban"), - IsAdminFilter(True), F.reply_to_message.text]], - [self.telegram_mute_cmd_handler, [Command(commands=["mute", "re"]), - UserHasPermissions(["can_restrict_members"]), - BotHasPermissions(["can_restrict_members"])]], - [self.telegram_unmute_cmd_handler, [Command(commands=["unmute"]), - UserHasPermissions(["can_restrict_members"]), - BotHasPermissions(["can_restrict_members"])]] - ) - self.telegram_callback_handlers = ( - # Format is [Handler, [Filters]] - [self.telegram_ban_callback_handler, [BanData.filter()]], - [self.telegram_unban_callback_handler, [UnbanData.filter()]], - [self.telegram_mute_callback_handler, [MuteData.filter()]], - [self.telegram_unmute_callback_handler, [UnmuteData.filter()]]) + await msg.answer("Использование:\n" + "
/ban [время блокировки] [причина блокировки]
\n" + "Ответьте на сообщение, чтобы заблокировать пользователя", + reply_markup=delete_keyboard(msg.from_user.id)) + + async def telegram_help_unban_handler(msg: Message) -> None: + """ + Shows help message for /unban + :param msg: Message telegram object + :return: Nothing + """ + await msg.answer("Использование:\n" + "
/unban
\n" + "Ответьте на сообщение, чтобы разблокировать пользователя", + reply_markup=delete_keyboard(msg.from_user.id)) + + async def telegram_help_mute_handler(msg: Message) -> None: + """ + Shows help message for /mute + :param msg: Message telegram object + :return: Nothing + """ + await msg.answer("Использование:\n" + "
/mute [время мута] [причина мута]
\n" + "Ответьте на сообщение, чтобы замутить пользователя", + reply_markup=delete_keyboard(msg.from_user.id)) + + async def telegram_help_unmute_handler(msg: Message) -> None: + """ + Shows help message for /unmute + :param msg: Message telegram object + :return: Nothing + """ + await msg.answer("Использование:\n" + "
/unmute
\n" + "Ответьте на сообщение, чтобы замутить пользователя", + reply_markup=delete_keyboard(msg.from_user.id)) + + telegram_setting_in_list = True + telegram_setting_name = "Модерация чата 🕵️" + telegram_setting_description = "Модерация чата🕵️\nДанная настройка включает следущие комманды:" \ + "\n
/ban [время блокировки] [причина блокировки] - блокировка пользователя" \
+                                   "\n/unban - разблокировка пользователя\n" \
+                                   "/mute [время мута] [причина мута] - мут пользователя\n" \
+                                   "/unmute - Размут пользователя
\n" \ + "Время обозначается как:" \ + "
1h - один час, " \
+                                   "1d - один день, " \
+                                   "1m - одна минута, " \
+                                   "1s - одна секунда
\n" \ + "Для того, " \ + "чтобы выполнить одну из комманд по отношению к пользователю, " \ + "ответьте на сообщение пользователя и используйте команду\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." + + telegram_db_name = TelegramChatSettings.moderation + # Telegram commands + telegram_commands: dict[str: str] = { + "ban": "Command to ban user in chat", + "unban": "Command to unban user in chat", + "mute": "Command to mute user in chat", + "unmute": "Command to unmute user in chat", + } + telegram_cmd_avaible = True # Is a feature have a commands + # All handlers + telegram_message_handlers = [ + # Format is [Handler, [Filters]] + [telegram_ban_cmd_handler, [Command(commands="ban"), + IsAdminFilter(True, True), F.reply_to_message.text, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_unban_cmd_handler, [Command(commands="unban"), + IsAdminFilter(True, True), F.reply_to_message.text, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_mute_cmd_handler, [Command(commands=["mute", "re"]), + UserHasPermissions(["can_restrict_members"]), + BotHasPermissions(["can_restrict_members"]), ~(F.chat.type == ChatType.PRIVATE), F.reply_to_message.text]], + [telegram_unmute_cmd_handler, [Command(commands=["unmute"]), + UserHasPermissions(["can_restrict_members"]), + BotHasPermissions(["can_restrict_members"]), + ~(F.chat.type == ChatType.PRIVATE), F.reply_to_message.text]], + [telegram_help_ban_handler, + [Command(commands="ban"), IsAdminFilter(True, True), ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_help_unban_handler, + [Command(commands="unban"), IsAdminFilter(True, True), ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_help_mute_handler, [Command(commands=["mute", "re"]), UserHasPermissions(["can_restrict_members"]), + BotHasPermissions(["can_restrict_members"]), ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_help_unmute_handler, + [Command(commands="unmute"), ~(F.chat.type == ChatType.PRIVATE), UserHasPermissions(["can_restrict_members"]), + BotHasPermissions(["can_restrict_members"])]] + ] + telegram_callback_handlers = [ + # Format is [Handler, [Filters]] + [telegram_ban_callback_handler, [BanData.filter()]], + [telegram_unban_callback_handler, [UnbanData.filter()]], + [telegram_mute_callback_handler, [MuteData.filter()]], + [telegram_unmute_callback_handler, [UnmuteData.filter()]]] diff --git a/bozenka/features/admin/pins.py b/bozenka/features/admin/pins.py index 10e0614..afa4f9c 100644 --- a/bozenka/features/admin/pins.py +++ b/bozenka/features/admin/pins.py @@ -1,4 +1,5 @@ from aiogram import F +from aiogram.enums import ChatType from aiogram.filters import Command from aiogram.types import Message, CallbackQuery @@ -16,7 +17,6 @@ class Pins(BasicFeature): All staff related to it will be here """ - @staticmethod async def telegram_pin_callback_handler(call: CallbackQuery, callback_data: PinMsg) -> None: """ Query, what pins message @@ -33,7 +33,6 @@ class Pins(BasicFeature): reply_markup=pin_msg_keyboard(user_id=call.from_user.id, msg_id=callback_data.msg_id)) - @staticmethod async def telegram_unpin_callback_handler(call: CallbackQuery, callback_data: UnpinMsg) -> None: """ Query, what unpins message @@ -50,7 +49,6 @@ class Pins(BasicFeature): reply_markup=unpin_msg_keyboard(user_id=call.from_user.id, msg_id=callback_data.msg_id)) - @staticmethod async def telegram_pin_cmd(msg: Message) -> None: """ /pin command function, pins replied command @@ -63,7 +61,6 @@ class Pins(BasicFeature): reply_markup=pin_msg_keyboard(msg_id=msg.reply_to_message.message_id, user_id=msg.from_user.id)) - @staticmethod async def telegram_unpin_cmd(msg: Message) -> None: """ /unpin command function, unpins replied command @@ -76,7 +73,6 @@ class Pins(BasicFeature): reply_markup=unpin_msg_keyboard(msg_id=msg.reply_to_message.message_id, user_id=msg.from_user.id)) - @staticmethod async def telegram_unpinall_cmd(msg: Message) -> None: """ /unpin_all command function, unpins all messages in chat @@ -88,39 +84,67 @@ class Pins(BasicFeature): "Все сообщения были откреплены 📌", reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - def __init__(self): + async def telegram_help_pin_cmd(msg: Message) -> None: """ - All information about feature - will be inside this function + Shows help message for /mute + :param msg: Message telegram object + :return: Nothing """ - super().__init__() - self.cmd_description: str = "Your description of command" - # Telegram feature settings - self.telegram_setting_in_list = True - self.telegram_setting_name = "Закреп 📌" - self.telegram_setting_description = "Закреп📌" \ - "\nДанная функция включает команды:" \ - "
/pin - закрепляет сообщение\n" \
-                                            "/unpin - открепляет сообщение\n" \
-                                            "/unpin_all - открепляет все сообщения, которые видит бот
\n" \ - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." - self.telegram_db_name = TelegramChatSettings.pins - # Telegram commands - self.telegram_commands: dict[str: str] = { - 'pin': 'Pin fast any message in chat', - 'unpin': 'Unpin fast any message in chat', - } - self.telegram_cmd_avaible = True # Is a feature have a commands - # Telegram Handler - self.telegram_message_handlers = { - self.telegram_pin_cmd: [Command(commands="pin"), UserHasPermissions(["can_pin_messages"]), - BotHasPermissions(["can_pin_messages"]), F.reply_to_message], - self.telegram_unpin_cmd: [Command(commands="unpin"), UserHasPermissions(["can_pin_messages"]), - BotHasPermissions(["can_pin_messages"]), F.reply_to_message], - self.telegram_unpinall_cmd: [Command(commands="unpin_all"), IsAdminFilter(True), - BotHasPermissions(["can_pin_messages"]), F.reply_to_message.text], - } - self.telegram_callback_handlers = { - self.telegram_pin_callback_handler: [PinMsg.filter()], - self.telegram_unpin_callback_handler: [UnpinMsg.filter()] - } + await msg.answer("Использование:\n" + "
/pin
\n" + "Ответьте на сообщение, чтобы закрепить сообщение", + reply_markup=delete_keyboard(msg.from_user.id)) + + async def telegramm_help_unpin_cmd(msg: Message) -> None: + """ + Shows help message for /mute + :param msg: Message telegram object + :return: Nothing + """ + await msg.answer("Использование:\n" + "
/unpin
\n" + "Ответьте на сообщение, чтобы открепить сообщение", + reply_markup=delete_keyboard(msg.from_user.id)) + + """ + Telegram feature settings + """ + # Telegram feature settings + telegram_setting_in_list = True + telegram_setting_name = "Закреп 📌" + telegram_setting_description = "Закреп📌" \ + "\nДанная функция включает команды:" \ + "
/pin - закрепляет сообщение\n" \
+                                   "/unpin - открепляет сообщение\n" \
+                                   "/unpin_all - открепляет все сообщения, которые видит бот
\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." + telegram_db_name = TelegramChatSettings.pins + # Telegram commands + telegram_commands: dict[str: str] = { + 'pin': 'Pin fast any message in chat', + 'unpin': 'Unpin fast any message in chat', + } + telegram_cmd_avaible = True # Is a feature have a commands + # Telegram Handler + telegram_message_handlers = [ + # Format is [Handler, [Filters]] + [telegram_pin_cmd, [Command(commands="pin"), UserHasPermissions(["can_pin_messages"]), + BotHasPermissions(["can_pin_messages"]), F.reply_to_message, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_unpin_cmd, [Command(commands="unpin"), UserHasPermissions(["can_pin_messages"]), + BotHasPermissions(["can_pin_messages"]), F.reply_to_message, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_unpinall_cmd, [Command(commands="unpin_all"), IsAdminFilter(True, False), + BotHasPermissions(["can_pin_messages"]), F.reply_to_message.text, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_help_pin_cmd, [Command(commands="pin"), UserHasPermissions(["can_pin_messages"]), + BotHasPermissions(["can_pin_messages"]), ~(F.chat.type == ChatType.PRIVATE)]], + [telegramm_help_unpin_cmd, [Command(commands="unpin"), UserHasPermissions(["can_pin_messages"]), + BotHasPermissions(["can_pin_messages"]), ~(F.chat.type == ChatType.PRIVATE)]] + + ] + telegram_callback_handlers = [ + # Format is [Handler, [Filters]] + [telegram_pin_callback_handler, [PinMsg.filter()]], + [telegram_unpin_callback_handler, [UnpinMsg.filter()]] + ] diff --git a/bozenka/features/admin/topics.py b/bozenka/features/admin/topics.py index 247061a..9b3e068 100644 --- a/bozenka/features/admin/topics.py +++ b/bozenka/features/admin/topics.py @@ -1,4 +1,5 @@ from aiogram import F +from aiogram.enums import ChatType from aiogram.filters import Command from aiogram.types import Message, CallbackQuery @@ -16,7 +17,6 @@ class Threads(BasicFeature): All staff related to it will be here """ - @staticmethod async def telegram_close_topic_cmd_handler(msg: Message) -> None: """ /close command function. Closing thread @@ -28,7 +28,6 @@ class Threads(BasicFeature): reply_markup=close_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) - @staticmethod async def telegram_reopen_topic_cmd_handler(msg: Message) -> None: """ /open command function. Opens thread @@ -40,7 +39,6 @@ class Threads(BasicFeature): reply_markup=open_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) - @staticmethod async def telegram_close_general_topic_cmd_handler(msg: Message) -> None: """ /close_general command function. Closes general thread @@ -52,7 +50,6 @@ class Threads(BasicFeature): reply_markup=close_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) - @staticmethod async def telegram_reopen_general_topic_cmd(msg: Message) -> None: """ /open_general command function. Opens general thread @@ -64,7 +61,6 @@ class Threads(BasicFeature): reply_markup=open_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) - @staticmethod async def telegram_hide_general_topic_cmd_handler(msg: Message) -> None: """ /hide_general command function. Hides general thread @@ -75,7 +71,6 @@ class Threads(BasicFeature): await msg.answer(config[0], reply_markup=delete_keyboard(msg.from_user.id)) - @staticmethod async def telegram_unhide_general_topic_cmd(msg: Message) -> None: """ /show_general command function. Shows back general thread. @@ -86,7 +81,6 @@ class Threads(BasicFeature): await msg.answer(config[0], reply_markup=delete_keyboard(msg.from_user.id)) - @staticmethod async def telegram_close_thread_callback_handler(call: CallbackQuery, callback_data: CloseThread) -> None: """ Query, what close thread @@ -104,7 +98,6 @@ class Threads(BasicFeature): delete_keyboard(admin_id=call.from_user.id) ) - @staticmethod async def inline_open_thread(call: CallbackQuery, callback_data: OpenThread) -> None: """ Query, what opens thread @@ -122,57 +115,61 @@ class Threads(BasicFeature): delete_keyboard(admin_id=call.from_user.id) ) - def __init__(self): """ - All information about feature - will be inside this function + Telegram feature settings """ - super().__init__() # Telegram setting info - self.telegram_setting_in_list = True - self.telegram_setting_name = "Работа с Форумом 💬" - self.telegram_setting_description = "Работа с Форумом💬\nДанная настройка включает следущие комманды:\n" \ - "
/open - открывают тему форума\n" \
-                                            "/close - закрывают тему форума\n" \
-                                            "/open_general - открывают основную тему форума\n" \
-                                            "/close_general - закрывает основную тему форума\n" \
-                                            "/hide_general - прячет основную тему форума\n" \
-                                            "/show_general - показывает основную тему форума
\n" \ - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть" \ - "включен форум" - self.telegram_db_name = TelegramChatSettings.topics - # Telegram commands - self.telegram_commands: dict[str: str] = { - 'close': 'Close fast topic (not general) in chat', - 'open': 'Open fast topic (not general) in chat', - 'hide_general': 'Hide general topic in chat', - 'show_general': 'Show general topic in chat', - "close_general": 'Closes general topic in chat', - "open_general": 'Opens general topic in chat', - } - self.telegram_cmd_avaible = True # Is a feature have a commands - # All handlers - self.telegram_message_handlers = { - self.telegram_close_topic_cmd_handler: [Command(commands=["close_topic", "close"]), + + telegram_setting_in_list = True + telegram_setting_name = "Работа с Форумом 💬" + telegram_setting_description = "Работа с Форумом💬\nДанная настройка включает следущие комманды:\n" \ + "
/open - открывают тему форума\n" \
+                                   "/close - закрывают тему форума\n" \
+                                   "/open_general - открывают основную тему форума\n" \
+                                   "/close_general - закрывает основную тему форума\n" \
+                                   "/hide_general - прячет основную тему форума\n" \
+                                   "/show_general - показывает основную тему форума
\n" \ + "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть" \ + "включен форум" + telegram_db_name = TelegramChatSettings.topics + # Telegram commands + telegram_commands: dict[str: str] = { + 'close': 'Close fast topic (not general) in chat', + 'open': 'Open fast topic (not general) in chat', + 'hide_general': 'Hide general topic in chat', + 'show_general': 'Show general topic in chat', + "close_general": 'Closes general topic in chat', + "open_general": 'Opens general topic in chat', + } + telegram_cmd_avaible = True # Is a feature have a commands + # All handlers + telegram_message_handlers = [ + [telegram_close_topic_cmd_handler, [Command(commands=["close_topic", "close"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_reopen_topic_cmd_handler, [Command(commands=["reopen_topic", "open_topic", "open"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_close_general_topic_cmd_handler, [Command(commands=["close_general"]), UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], - self.telegram_reopen_topic_cmd_handler: [Command(commands=["reopen_topic", "open_topic", "open"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], - self.telegram_close_general_topic_cmd_handler: [Command(commands=["close_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], - self.telegram_reopen_general_topic_cmd: [Command(commands=["reopen_general", "open_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], - self.telegram_hide_general_topic_cmd_handler: [Command(commands=["hide_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum], - self.telegram_unhide_general_topic_cmd: [Command(commands=["unhide_general", "show_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum] - } - self.telegram_callback_handlers = { - self.telegram_close_thread_callback_handler: [CloseThread.filter()], - self.telegram_reopen_topic_cmd_handler: [OpenThread.filter()] - } + BotHasPermissions(["can_manage_topics"]), + F.chat.is_forum]], + [telegram_reopen_general_topic_cmd, [Command(commands=["reopen_general", "open_general"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_hide_general_topic_cmd_handler, [Command(commands=["hide_general"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum, + ~(F.chat.type == ChatType.PRIVATE)]], + [telegram_unhide_general_topic_cmd, [Command(commands=["unhide_general", "show_general"]), + UserHasPermissions(["can_manage_topics"]), + BotHasPermissions(["can_manage_topics"]), F.chat.is_forum, + ~(F.chat.type == ChatType.PRIVATE)]] + ] + telegram_callback_handlers = [ + [telegram_close_thread_callback_handler, [CloseThread.filter()]], + [telegram_reopen_topic_cmd_handler, [OpenThread.filter()]] + ] diff --git a/bozenka/features/basic/__init__.py b/bozenka/features/basic/__init__.py index b34966c..c5a2f52 100644 --- a/bozenka/features/basic/__init__.py +++ b/bozenka/features/basic/__init__.py @@ -1,2 +1,2 @@ -from setup import Setup -from start import Start +from .setup import Setup +from .start import Start diff --git a/bozenka/features/basic/setup.py b/bozenka/features/basic/setup.py index 13d3398..2966dff 100644 --- a/bozenka/features/basic/setup.py +++ b/bozenka/features/basic/setup.py @@ -18,7 +18,6 @@ class Setup(BasicFeature): All staff related to it will be here """ - @staticmethod async def telegram_setup_cmd_handler(msg: Message) -> None: """ /setup telegram handler @@ -29,7 +28,6 @@ class Setup(BasicFeature): "Чтобы меня настроить, используй меню под данным сообщением", reply_markup=setup_keyboard()) - @staticmethod async def telegram_setup_categories_handler(call: CallbackQuery, callback_data: SetupCategory | SetupAction): """ Query, what shows list of features to enable. @@ -40,7 +38,6 @@ class Setup(BasicFeature): await call.message.edit_text("Выберите настройку, которую хотите изменить", reply_markup=setup_category_keyboard(category=callback_data.category_name)) - @staticmethod async def telegram_setup_edit_feature_handler(call: CallbackQuery, callback_data: SetupFeature, session_maker: async_sessionmaker): """ Query, what shows menu to enable / disable feature @@ -61,7 +58,6 @@ class Setup(BasicFeature): index=callback_data.feature_index, is_enabled=is_enabled)) - @staticmethod async def telegram_features_edit_handler(call: CallbackQuery, callback_data: SetupAction, session_maker: async_sessionmaker): """ Query, what shows menu to enable / disable feature @@ -83,21 +79,19 @@ class Setup(BasicFeature): index=callback_data.afeature_index, is_enabled=callback_data.action == "enable")) - def __init__(self): - """ - All information about feature - will be inside this function - """ - super().__init__() - # Telegram feature settings - self.telegram_setting_in_list = False - self.telegram_commands = {"setup": 'Command to setup bozenka features in chat'} - self.telegram_cmd_avaible = True - self.telegram_message_handlers = { - self.telegram_setup_cmd_handler: [Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE)] - } - self.telegram_callback_handlers = { - self.telegram_features_edit_handler: [SetupAction.filter(F.action == "disable" or F.action == "enable")], - self.telegram_setup_edit_feature_handler: [SetupFeature.filter()], - self.telegram_setup_categories_handler: [SetupAction.filter(F.action == "back")] - } + """ + Telegram feature settings + """ + # Telegram feature settings + telegram_setting_in_list = False + telegram_commands = {"setup": 'Command to setup bozenka features in chat'} + telegram_cmd_avaible = True + telegram_message_handlers = [ + [telegram_setup_cmd_handler, [Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE)]] + ] + telegram_callback_handlers = [ + [telegram_features_edit_handler, [SetupAction.filter(F.action == "disable")]], + [telegram_features_edit_handler, [SetupAction.filter(F.action == "enable")]], + [telegram_setup_edit_feature_handler, [SetupFeature.filter()]], + [telegram_setup_categories_handler, [SetupAction.filter(F.action == "back")]] + ] diff --git a/bozenka/features/basic/start.py b/bozenka/features/basic/start.py index ba20c1d..41e60e6 100644 --- a/bozenka/features/basic/start.py +++ b/bozenka/features/basic/start.py @@ -11,34 +11,7 @@ from bozenka.instances.telegram.utils.keyboards import help_category_keyboard, h from bozenka.instances.telegram.utils.simpler import list_of_features from bozenka.instances.version import build, is_updated - -class Start(BasicFeature): - """ - A class of /start command - All staff related to it will be here - """ - cmd_description: str = "Basic command to show main menu" - main_text = """ -Привет 👋 -Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах. - -Вот что ты можешь сделать с помощью меню: -• Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него. -• Функционал: показывает список доступных функций и команд, которые я могу выполнить. -• О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота. -• О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота. -• Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию. -• Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта - -Вот нужные ссылки обо мне: -• Канал с новостями об разработке -• Исходный код на Github - -Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже. -Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала. -Удачного использования! - """ - telegram_main_menu = InlineKeyboardMarkup( +telegram_main_menu = InlineKeyboardMarkup( inline_keyboard=[ [InlineKeyboardButton(text="Добавить в ваш групповой чат 🔌", callback_data="addtochat")], [InlineKeyboardButton(text="Информация об функционале бота 🔨", callback_data="functional")], @@ -49,9 +22,17 @@ class Start(BasicFeature): ] ) + +class Start(BasicFeature): + """ + A class of /start command + All staff related to it will be here + """ + # There starting a help category of handlers # It's related to one of menus # Showing information about features, will be remade later :D + @staticmethod async def back_help_categories_handler(call: CallbackQuery, callback_data: HelpBack) -> None: """ @@ -156,12 +137,12 @@ class Start(BasicFeature): InlineKeyboardButton(text="Вернуться 🔙", callback_data="back") ]]) await call.message.edit_text(""" - Бозенька - это мультифункциональный (в будущем кроссплатформенный) бот.\n - Он умеет работать с групповыми чатами и готовыми нейронными сетями для генерации текста и изображений. - Бозенька разрабатывается коммандой, которая состоит на данный момент из одного человека.\n - Исходный код проекта\n - Исходный код находится под лицензией GPL-3.0, исходный код проекта можно посмотреть всегда здесь - Канал с новостями разработки находится здесь +Бозенька - это мультифункциональный (в будущем кроссплатформенный) бот.\n +Он умеет работать с групповыми чатами и готовыми нейронными сетями для генерации текста и изображений. +Бозенька разрабатывается коммандой, которая состоит на данный момент из одного человека.\n +Исходный код проекта\n +Исходный код находится под лицензией GPL-3.0, исходный код проекта можно посмотреть всегда здесь +Канал с новостями разработки находится здесь """, reply_markup=kb, disable_web_page_preview=True) @staticmethod @@ -175,50 +156,86 @@ class Start(BasicFeature): reply_markup=gpt_categories_keyboard (user_id=call.from_user.id)) - async def start_callback_handler(self, call: CallbackQuery) -> None: + @staticmethod + async def start_callback_handler(call: CallbackQuery) -> None: """ /start command function handler. Just back it by clicking on button. Shows menu and basic information about bozenka :param call: Message telegram object :return: Nothing """ - await call.message.edit_text(self.main_text, - reply_markup=self.telegram_main_menu, disable_web_page_preview=True) + await call.message.edit_text(""" +Привет 👋 +Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах. - async def start_cmd_handler(self, msg: Message) -> None: +Вот что ты можешь сделать с помощью меню: +• Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него. +• Функционал: показывает список доступных функций и команд, которые я могу выполнить. +• О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота. +• О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота. +• Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию. +• Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта + +Вот нужные ссылки обо мне: +• Канал с новостями об разработке +• Исходный код на Github + +Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже. +Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала. +Удачного использования! + """, reply_markup=telegram_main_menu, disable_web_page_preview=True) + + @staticmethod + async def start_cmd_handler(msg: Message) -> None: """ /start command function handler Shows menu and basic information about bozenka :param msg: Message telegram object :return: Nothing """ - await msg.answer(self.main_text, - reply_markup=self.telegram_main_menu, disable_web_page_preview=True) + await msg.answer(""" +Привет 👋 +Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах. - def __init__(self): - """ - All information about feature - will be inside this function - """ - super().__init__() - # Telegram feature settings - self.telegram_setting = None - self.telegram_commands: dict[str: str] = {"start": "Command to start work with bozenka the bot"} - self.telegram_cmd_avaible = True # Is a feature have a commands - self.telegram_callback_factory = None - self.telegram_message_handlers = { - self.start_cmd_handler: [Command(commands=["start"]), F.chat.type == ChatType.PRIVATE], +Вот что ты можешь сделать с помощью меню: +• Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него. +• Функционал: показывает список доступных функций и команд, которые я могу выполнить. +• О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота. +• О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота. +• Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию. +• Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта - } - self.telegram_callback_handlers = { +Вот нужные ссылки обо мне: +• Канал с новостями об разработке +• Исходный код на Github + +Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже. +Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала. +Удачного использования! + """, reply_markup=telegram_main_menu, disable_web_page_preview=True) + + """ + Telegram feature settings + """ + # Telegram feature settings + telegram_setting = None + telegram_commands: dict[str: str] = {"start": "Command to start work with bozenka the bot"} + telegram_cmd_avaible = True # Is a feature have a commands + telegram_callback_factory = None + telegram_message_handlers = [ + [start_cmd_handler, [Command(commands=["start"]), F.chat.type == ChatType.PRIVATE]], + ] + telegram_callback_handlers = [ # Start menu - self.start_dialog_handler: [F.data == "dialogai"], - self.add_to_menu_handler: [F.data == "addtochat"], - self.about_developers_handler: [F.data == "aboutdevs"], - self.about_instance_callback_handler: [F.data == "aboutbot"], - self.start_callback_handler: [F.data == "back"], + [start_dialog_handler, [F.data == "dialogai"]], + [add_to_menu_handler, [F.data == "addtochat"]], + [about_developers_handler, [F.data == "aboutdevs"]], + [about_instance_callback_handler, [F.data == "aboutbot"]], + [start_callback_handler, [F.data == "back"]], # Help menu - self.feature_info_handler: [HelpFeature.filter() or HelpBackCategory.filter()], - self.help_menu_handler: [HelpCategory.filter() or HelpBack.filter(F.back_to == "category")], - - } + [help_menu_handler, [F.data == "functional"]], + [feature_info_handler, [HelpFeature.filter()]], + [help_features_handler, [HelpBackCategory.filter()]], + [help_features_handler, [HelpCategory.filter()]], + [help_menu_handler, [HelpBack.filter(F.back_to == "category")]] + ] diff --git a/bozenka/features/features_list.py b/bozenka/features/features_list.py index e86bd98..6c9ff5a 100644 --- a/bozenka/features/features_list.py +++ b/bozenka/features/features_list.py @@ -1,4 +1,5 @@ -from aiogram import Dispatcher +from aiogram import Dispatcher, Bot +from aiogram.types import BotCommand from bozenka.features import BasicFeature from bozenka.features.admin import * @@ -21,10 +22,4 @@ features_list = [ ] -def register_all_features(features_list: list[BasicFeature], dispatcher: Dispatcher) -> None: - """ - Registers all features / handlers avaible in bozenka - :param features_list: List of features - :return: None - """ - pass + diff --git a/bozenka/features/user/__init__.py b/bozenka/features/user/__init__.py index 26b1d3c..e33fcdf 100644 --- a/bozenka/features/user/__init__.py +++ b/bozenka/features/user/__init__.py @@ -1,3 +1,3 @@ -from image_generation import ImageGeneratrion -from text_generation import TextGeneratrion -from welcome import Welcome +from .image_generation import ImageGeneratrion +from .text_generation import TextGeneratrion +from .welcome import Welcome diff --git a/bozenka/features/user/image_generation.py b/bozenka/features/user/image_generation.py index 3f94c9b..8e63a1c 100644 --- a/bozenka/features/user/image_generation.py +++ b/bozenka/features/user/image_generation.py @@ -23,7 +23,6 @@ class ImageGeneratrion(BasicFeature): """ cmd_description: str = "Your description of command" - @staticmethod async def telegram_select_image_size_handler(call: CallbackQuery, callback_data: ImageGenerationCategory, state: FSMContext) -> None: """ @@ -42,8 +41,8 @@ class ImageGeneratrion(BasicFeature): reply_markup=image_resolution_keyboard(user_id=call.from_user.id, category=callback_data.category)) - @staticmethod - async def telegram_end_generation_handler(call: CallbackQuery, callback_data: ImageGeneration, state: FSMContext) -> None: + async def telegram_end_generation_handler(call: CallbackQuery, callback_data: ImageGeneration, + state: FSMContext) -> None: """ Query, what shows menu for image size to generate in :param call: @@ -60,7 +59,6 @@ class ImageGeneratrion(BasicFeature): "Напишите /cancel для отмены", reply_markup=delete_keyboard(admin_id=call.from_user.id)) - @staticmethod async def telegram_already_generating_handler(msg: Message, state: FSMContext) -> None: """ Giving response, if generating image for user right now, @@ -73,7 +71,6 @@ class ImageGeneratrion(BasicFeature): "Подождите пожалуйста, мы уже генерируем изображение для вас, подождите, когда мы ответим на ваш передыдущий вопрос", reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - @staticmethod async def telegram_imagine_handler(msg: Message, state: FSMContext) -> None: """ /imagine command handler, start menu @@ -86,7 +83,6 @@ class ImageGeneratrion(BasicFeature): await msg.answer("Пожалуста, выберите сервис / модель для генерации изображений", reply_markup=image_generation_keyboard(user_id=msg.from_user.id)) - @staticmethod async def telegram_kadinsky_generating_handler(msg: Message, state: FSMContext) -> None: """ Message handler for kandinsky to generate image by text from message @@ -130,28 +126,25 @@ class ImageGeneratrion(BasicFeature): level=logging.INFO) await state.set_state(GeneratingImages.ready_to_generate) - def __init__(self): - """ - All information about feature - will be inside this function - """ - super().__init__() - # Telegram feature settings - self.telegram_setting = TelegramChatSettings.image_generation - self.telegram_commands: dict[str: str] = {'imagine', 'Starts conversation with image generative ai'} - self.telegram_setting_in_list = True - self.telegram_setting_name = "Генерация изображений 📸" - self.telegram_setting_description = "Генерация изображений 🤖" \ - "\nНаходится в разработке.\n" \ - "На текущий момент есть поддержка:\n" \ - "- Kadinksy\n" \ - " Следите за обновлениями 😘" - self.telegram_cmd_avaible = True # Is a feature have a commands - self.telegram_message_handlers = { - self.telegram_kadinsky_generating_handler: [GeneratingImages.ready_to_generate, ~Command(commands=["cancel"])], - self.telegram_imagine_handler: [Command(commands=["imagine"])] - } - self.telegram_callback_handlers = { - self.telegram_select_image_size_handler: [ImageGenerationCategory.filter()], - self.telegram_end_generation_handler: [ImageGeneration.filter()] - } + """ + Telegram feature settings + """ + # Telegram feature settings + telegram_setting = TelegramChatSettings.image_generation + telegram_commands: dict[str: str] = {'imagine': 'Starts conversation with image generative ai'} + telegram_setting_in_list = True + telegram_setting_name = "Генерация изображений 📸" + telegram_setting_description = "Генерация изображений 🤖" \ + "\nНаходится в разработке.\n" \ + "На текущий момент есть поддержка:\n" \ + "- Kadinksy\n" \ + " Следите за обновлениями 😘" + telegram_cmd_avaible = True # Is a feature have a commands + telegram_message_handlers = [ + [telegram_kadinsky_generating_handler, [GeneratingImages.ready_to_generate, ~Command(commands=["cancel"])]], + [telegram_imagine_handler, [Command(commands=["imagine"])]] + ] + telegram_callback_handlers = [ + [telegram_select_image_size_handler, [ImageGenerationCategory.filter()]], + [telegram_end_generation_handler, [ImageGeneration.filter()]] + ] diff --git a/bozenka/features/user/text_generation.py b/bozenka/features/user/text_generation.py index 359abca..e7760e8 100644 --- a/bozenka/features/user/text_generation.py +++ b/bozenka/features/user/text_generation.py @@ -26,9 +26,7 @@ class TextGeneratrion(BasicFeature): A class, what have inside all handlers / functions related to text generation of bozenka """ - cmd_description: str = "Your description of command" - @staticmethod async def telegram_already_answering_handler(msg: Message, state: FSMContext) -> None: """ Giving response, if answering user now, @@ -41,7 +39,6 @@ class TextGeneratrion(BasicFeature): "Подождите пожалуйста, мы уже генерируем ответ для вас, подождите, когда мы ответим на ваш передыдущий вопрос", reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - @staticmethod async def telegram_conversation_cmd_handler(msg: Message, state: FSMContext) -> None: """ /conversation command handler, start @@ -55,7 +52,6 @@ class TextGeneratrion(BasicFeature): reply_markup=gpt_categories_keyboard (user_id=msg.from_user.id)) - @staticmethod async def telegram_cancel_cmd_handler(msg: Message, state: FSMContext) -> None: """ Canceling dialog with generative model @@ -74,7 +70,6 @@ class TextGeneratrion(BasicFeature): # G4F telegram category # All handlers and other stuff # All code and comments - @staticmethod async def telegram_g4f_generate_handler(msg: Message, state: FSMContext) -> None: """ Generating answer if GPT4Free model and provider has been selected @@ -131,8 +126,8 @@ class TextGeneratrion(BasicFeature): await state.update_data(ready_to_answer=current_messages) await state.set_state(AnsweringGPT4Free.ready_to_answer) - @staticmethod - async def telegram_instart_conversation_handler(call: CallbackQuery, callback_data: GptBackMenu, state: FSMContext) -> None: + async def telegram_instart_conversation_handler(call: CallbackQuery, callback_data: GptBackMenu, + state: FSMContext) -> None: """ Query, what shows when clicking on button in /start menu :param call: CallbackQuery class @@ -145,7 +140,6 @@ class TextGeneratrion(BasicFeature): await call.message.edit_text("Пожалуста, выберите сервис для ИИ.", reply_markup=gpt_categories_keyboard(user_id=call.from_user.id)) - @staticmethod async def telegram_g4f_providers_handlers(call: CallbackQuery, callback_data: Gpt4FreeCategory, state: FSMContext) -> None: """ @@ -167,7 +161,6 @@ class TextGeneratrion(BasicFeature): await call.message.edit_text("Выберите пожалуйста одного из провайдеров 👨‍💻", reply_markup=gpt4free_providers_keyboard(user_id=call.from_user.id, page=0)) - @staticmethod async def telegram_g4f_models_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: """ Query, what creating models selecting menu @@ -186,8 +179,8 @@ class TextGeneratrion(BasicFeature): await call.message.edit_text("Выберите модель, с которой будете общаться 🤖", reply_markup=gpt4free_models_keyboard(user_id=call.from_user.id, page=0)) - @staticmethod - async def telegram_end_g4f_model_handler(call: CallbackQuery, callback_data: Gpt4FreeModel, state: FSMContext) -> None: + async def telegram_g4f_model_ready_handler(call: CallbackQuery, callback_data: Gpt4FreeModel, + state: FSMContext) -> None: """ Query, what ending g4f model selecting :param call: CallbackQuery class @@ -209,7 +202,6 @@ class TextGeneratrion(BasicFeature): "Чтобы прекратить общение, используйте /cancel ", reply_markup=delete_keyboard(admin_id=call.from_user.id)) - @staticmethod async def telegram_g4f_next_model_handler(call: CallbackQuery, callback_data: Gpt4FreeModelPage, state: FSMContext) -> None: """ @@ -228,8 +220,7 @@ class TextGeneratrion(BasicFeature): reply_markup=gpt4free_models_keyboard(user_id=call.from_user.id, page=callback_data.page)) - @staticmethod - async def telegram_g4f_category_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: + async def telegram_g4f_category_handler(call: CallbackQuery, callback_data: GptCategory | GptBackMenu, state: FSMContext) -> None: """ Query, what creating providers selecting menu. :param state: FSMContext aiogram class @@ -243,13 +234,14 @@ class TextGeneratrion(BasicFeature): logging.log(msg=f"Selected gpt4free category by user_id={call.from_user.id}", level=logging.INFO) - await state.update_data(set_category=callback_data.category) + if type(callback_data) == GptCategory: + await state.update_data(set_category=callback_data.category) + await call.answer("Вы выбрали Gpt4Free 🤖") await call.message.edit_text("Выберите, по какому пункту мы будем вести диалог с нейронной сети 🤖", reply_markup=gpt4free_categories_keyboard(user_id=call.from_user.id)) await call.answer("Выберите, по какому пункту мы будем вести диалог с нейронной сети 🤖") - @staticmethod async def telegram_g4f_back_provider_handler(call: CallbackQuery, callback_data: GptBackMenu, state: FSMContext) -> None: """ @@ -270,9 +262,8 @@ class TextGeneratrion(BasicFeature): reply_markup=gpt4free_providers_keyboard(page=0, user_id=callback_data.user_id)) await call.answer("Выберите пожалуйста одного из провайдеров 👨‍💻") - @staticmethod - async def inline_g4f_provider_models(call: CallbackQuery, callback_data: Gpt4FreeProvider, - state: FSMContext) -> None: + async def telegram_g4f_by_provider_models(call: CallbackQuery, callback_data: Gpt4FreeProvider, + state: FSMContext) -> None: """ Query, what creating models selecting menu. :param state: FSMContext aiogram class @@ -297,8 +288,7 @@ class TextGeneratrion(BasicFeature): )) await call.answer("Выберите пожалуйста модель ИИ 👾") - @staticmethod - async def telegram_g4f_ready_handler(call: CallbackQuery, callback_data: Gpt4freeResult, state: FSMContext) -> None: + async def telegram_g4f_provider_ready_handler(call: CallbackQuery, callback_data: Gpt4freeResult, state: FSMContext) -> None: """ Query, what says about getting ready to questions for ChatGPT from Gpt4Free. :param state: FSMContext aiogram class @@ -325,7 +315,6 @@ class TextGeneratrion(BasicFeature): reply_markup=delete_keyboard(admin_id=callback_data.user_id)) await call.answer("Вы теперь можете спокойно вести диалог 🤖") - @staticmethod async def telegram_g4f_models_by_provider_handler(call: CallbackQuery, callback_data: Gpt4FreeProvsModelPage, state: FSMContext) -> None: """ @@ -347,7 +336,6 @@ class TextGeneratrion(BasicFeature): )) await call.answer(f"Вы перелистали на страницу {callback_data.page + 1}📄") - @staticmethod async def telegram_next_g4f_providers_handler(call: CallbackQuery, callback_data: Gpt4FreeProviderPage, state: FSMContext) -> None: """ @@ -370,7 +358,6 @@ class TextGeneratrion(BasicFeature): # All code and commentaries here # All handlers here - @staticmethod async def telegram_g4a_generate_handler(msg: Message, state: FSMContext) -> None: """ Generating answer if Gpt4All has been selected @@ -413,7 +400,6 @@ class TextGeneratrion(BasicFeature): await state.set_state(AnsweringGpt4All.ready_to_answer) - @staticmethod async def telegram_g4a_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: """ Query, what shows list for gpt4all models @@ -428,7 +414,6 @@ class TextGeneratrion(BasicFeature): await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", reply_markup=generate_gpt4all_page(user_id=call.from_user.id)) - @staticmethod async def telegram_g4a_back_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: """ Query, what shows list for gpt4all models back @@ -443,8 +428,8 @@ class TextGeneratrion(BasicFeature): await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", reply_markup=generate_gpt4all_page(user_id=call.from_user.id)) - @staticmethod - async def telegram_g4a_infomration_handler(call: CallbackQuery, callback_data: Gpt4AllModel, state: FSMContext) -> None: + async def telegram_g4a_infomration_handler(call: CallbackQuery, callback_data: Gpt4AllModel, + state: FSMContext) -> None: """ Query, what show information about clicked gpt4all model from list :param state: FSMContext aiogram class @@ -461,7 +446,6 @@ class TextGeneratrion(BasicFeature): reply_markup=gpt4all_model_menu(user_id=call.from_user.id, index=callback_data.index)) - @staticmethod async def telegram_g4a_end_handler(call: CallbackQuery, callback_data: Gpt4AllSelect, state: FSMContext) -> None: """ @@ -483,7 +467,6 @@ class TextGeneratrion(BasicFeature): "Чтобы прекратить общение, используйте /cancel ", reply_markup=delete_keyboard(admin_id=callback_data.user_id)) - @staticmethod async def telegram_pages_handler(call: CallbackQuery) -> None: """ Query, made for helping purposes. @@ -495,7 +478,6 @@ class TextGeneratrion(BasicFeature): level=logging.INFO) await call.answer("Здесь расположается текущая странница 📃") - @staticmethod async def telegram_stop_dialog_handler(call: CallbackQuery, callback_data: GptStop, state: FSMContext) -> None: """ Query, what stops dialog @@ -516,44 +498,49 @@ class TextGeneratrion(BasicFeature): else: await call.message.delete() - def __init__(self): - """ - All information about feature - will be inside this function - """ - super().__init__() - # Telegram feature settings - self.telegram_setting = TelegramChatSettings.text_generation - self.telegram_setting_in_list = True - self.telegram_setting_name = "ИИ ЧатБот 🤖" - self.telegram_setting_description = "ИИ ЧатБот 🤖" \ - "\nЕсть поддержка:\n" \ - "- Моделей Gpt4All\n" \ - "- Провайдеров Gpt4Free и моделей\n" \ - "Для использования:\n" \ - "
/conversations
" \ - "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘" - self.telegram_commands: dict[str: str] = { - 'conversation': 'Starts conversation with text generative ai' - } - self.telegram_cmd_avaible = True # Is a feature have a commands - self.telegram_message_handlers = { - self.telegram_conversation_cmd_handler: [Command(commands=["conversation"])], - self.telegram_g4a_generate_handler: [AnsweringGpt4All.ready_to_answer, ~Command(commands=["cancel"])], - self.telegram_g4f_generate_handler: [AnsweringGPT4Free.ready_to_answer, ~Command(commands=["cancel"])], - self.telegram_already_answering_handler: [AnsweringGPT4Free.answering, AnsweringGpt4All.answering] - } - self.telegram_callback_handlers = { - # g4a - self.telegram_g4a_handler: [GptCategory.filter(F.category == "Gpt4All")], - self.telegram_g4a_infomration_handler: [Gpt4AllModel.filter()], - self.telegram_g4a_end_handler: [Gpt4AllSelect.filter()], - # g4f - self.telegram_g4f_category_handler: [GptCategory.filter(F.category == "Gpt4Free")], - self.telegram_g4f_models_handler: [Gpt4FreeCategory.filter(F.category == "models")], - self.telegram_g4f_providers_handlers: [Gpt4FreeCategory.filter(F.category == "providers")], - self.telegram_g4f_models_by_provider_handler: [Gpt4FreeProvider.filter()], - self.telegram_next_g4f_providers_handler: [Gpt4FreeProviderPage.filter()], - # stop talking - self.telegram_stop_dialog_handler: [GptStop.filter()] - } + # Telegram feature settings + telegram_setting = TelegramChatSettings.text_generation + telegram_setting_in_list = True + telegram_setting_name = "ИИ ЧатБот 🤖" + telegram_setting_description = "ИИ ЧатБот 🤖" \ + "\nЕсть поддержка:\n" \ + "- Моделей Gpt4All\n" \ + "- Провайдеров Gpt4Free и моделей\n" \ + "Для использования:\n" \ + "
/conversations
" \ + "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘" + telegram_commands: dict[str: str] = { + 'conversation': 'Starts conversation with text generative ai' + } + telegram_cmd_avaible = True # Is a feature have a commands + telegram_message_handlers = ( + [telegram_conversation_cmd_handler, [Command(commands=["conversation"])]], + [telegram_g4a_generate_handler, [AnsweringGpt4All.ready_to_answer, ~Command(commands=["cancel"])]], + [telegram_g4f_generate_handler, [AnsweringGPT4Free.ready_to_answer, ~Command(commands=["cancel"])]], + [telegram_already_answering_handler, [AnsweringGPT4Free.answering, AnsweringGpt4All.answering]] + ) + telegram_callback_handlers = ( + # g4a + [telegram_g4a_handler, [GptCategory.filter(F.category == "Gpt4All")]], + [telegram_g4a_infomration_handler, [Gpt4AllModel.filter()]], + [telegram_g4a_end_handler, [Gpt4AllSelect.filter()]], + # g4f + [telegram_g4f_category_handler, [GptCategory.filter(F.category == "Gpt4Free")]], + [telegram_g4f_category_handler, [GptBackMenu.filter(F.back_to == "g4fcategory")]], + # categories + [telegram_g4f_models_handler, [Gpt4FreeCategory.filter(F.category == "models")]], + [telegram_g4f_providers_handlers, [Gpt4FreeCategory.filter(F.category == "providers")]], + # providers list + [telegram_g4f_providers_handlers, [GptBackMenu.filter(F.back_to == "providers")]], + [telegram_next_g4f_providers_handler, [Gpt4FreeProviderPage.filter()]], + # models by provider list + [telegram_g4f_models_by_provider_handler, [Gpt4FreeProvsModelPage.filter()]], + [telegram_g4f_by_provider_models, [Gpt4FreeProvider.filter()]], + # models list + [telegram_g4f_next_model_handler, [Gpt4FreeModelPage.filter()]], + # end features + [telegram_g4f_model_ready_handler, [Gpt4FreeModel.filter()]], + [telegram_g4f_provider_ready_handler, [Gpt4freeResult.filter()]], + # stop talking + [telegram_stop_dialog_handler, [GptStop.filter()]] + ) diff --git a/bozenka/features/user/welcome.py b/bozenka/features/user/welcome.py index 3584425..d94c7d6 100644 --- a/bozenka/features/user/welcome.py +++ b/bozenka/features/user/welcome.py @@ -1,6 +1,7 @@ import logging -from aiogram import Bot +from aiogram import Bot, F +from aiogram.enums import ContentType from aiogram.types import Message, CallbackQuery from sqlalchemy.ext.asyncio import async_sessionmaker @@ -17,7 +18,6 @@ class Welcome(BasicFeature): All staff related to it will be here """ - @staticmethod async def telegram_join_handler(msg: Message, session_maker: async_sessionmaker) -> None: """ Message handler. @@ -44,7 +44,6 @@ class Welcome(BasicFeature): "Чтобы настроить функционал, используйте /setup или кнопку под сообщением", ) await SolutionSimpler.auto_settings(msg=msg, session=session_maker) - @staticmethod async def telegram_leave_handler(msg: Message, bot: Bot) -> None: """ Sens goodbye message, after deleting member from chat @@ -61,22 +60,16 @@ class Welcome(BasicFeature): f"Пользователь {msg.left_chat_member.mention_html()} съехал с конфы, благодаря {msg.from_user.mention_html()}👋" ) - def __init__(self): - """ - All information about feature - will be inside this function - """ - super().__init__() - self.cmd_description: str = "Your description of command" - # Telegram feature settings - self.telegram_setting = TelegramChatSettings.welcome_messages - self.telegram_commands: dict[str: str] = {} - self.telegram_setting_in_list = True - self.telegram_setting_name = "Приветсвенные сообщения 👋" - self.telegram_setting_description = "Приветсвенные сообщения 👋" \ - "\nПриветсвенные сообщения новым и ушедшим пользователям.", - self.telegram_cmd_avaible = False # Is a feature have a commands - self.telegram_message_handlers = { - - } - self.telegram_callback_handlers = {} + # Telegram feature settings + telegram_setting = TelegramChatSettings.welcome_messages + telegram_commands: dict[str: str] = {} + telegram_setting_in_list = True + telegram_setting_name = "Приветсвенные сообщения 👋" + telegram_setting_description = "Приветсвенные сообщения 👋" \ + "\nПриветсвенные сообщения новым и ушедшим пользователям.", + telegram_cmd_avaible = False # Is a feature have a commands + telegram_message_handlers = [ + [telegram_leave_handler, [F.content_type == ContentType.LEFT_CHAT_MEMBER]], + [telegram_join_handler, [F.content_type == ContentType.NEW_CHAT_MEMBERS]] + ] + telegram_callback_handlers = [] diff --git a/bozenka/instances/telegram/__init__.py b/bozenka/instances/telegram/__init__.py index d63faf5..9576011 100644 --- a/bozenka/instances/telegram/__init__.py +++ b/bozenka/instances/telegram/__init__.py @@ -5,10 +5,39 @@ from aiogram import Dispatcher, Bot from aiogram.types import BotCommand from sqlalchemy.ext.asyncio import async_sessionmaker +from bozenka.features import BasicFeature +from bozenka.features.features_list import features_list +from bozenka.features.admin import * +from bozenka.features.basic import * +from bozenka.features.user import * from bozenka.instances.telegram.handlers import register_handlers from bozenka.instances.telegram.utils.simpler import list_of_commands +async def register_all_features(list_of_features: list[BasicFeature], dispatcher: Dispatcher, bot: Bot) -> None: + """ + Registers all features / handlers avaible in bozenka + :param list_of_features: List of features + :param dispatcher: Dispatcher aiogram class + :param bot: Bot aiogram class + :return: None + """ + cmd_list = [] + for feature in list_of_features: + + if feature.telegram_cmd_avaible: + for command, description in feature.telegram_commands.items(): + cmd_list.append(BotCommand(command=command, description=description)) + + for message_handler in feature.telegram_message_handlers: + dispatcher.message.register(message_handler[0], *message_handler[1]) + + for callback_query_handler in feature.telegram_callback_handlers: + dispatcher.callback_query.register(callback_query_handler[0], *callback_query_handler[1]) + + await bot.set_my_commands(cmd_list) + + async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: """ Launches telegram bot with token from enviroment @@ -19,10 +48,7 @@ async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: bot = Bot(token=os.getenv("tg_bot_token"), parse_mode="HTML") - cmd_of_bot = [] - for command in list_of_commands: - cmd_of_bot.append(BotCommand(command=command[0], description=command[1])) - await bot.set_my_commands(cmd_of_bot) - dp = Dispatcher() - await dp.start_polling(bot, session_maker=session_maker, on_startup=[register_handlers(dp)]) + + await register_all_features(list_of_features=features_list, dispatcher=dp, bot=bot) + await dp.start_polling(bot, session_maker=session_maker, on_startup=[]) diff --git a/bozenka/instances/telegram/utils/filters/permissions.py b/bozenka/instances/telegram/utils/filters/permissions.py index 1b2cccd..eb597e4 100644 --- a/bozenka/instances/telegram/utils/filters/permissions.py +++ b/bozenka/instances/telegram/utils/filters/permissions.py @@ -1,6 +1,7 @@ from typing import Any from aiogram.filters import Filter +from aiogram.methods import GetChatMember from aiogram.types import Message, ChatPermissions from aiogram.enums import ChatMemberStatus from bozenka.instances.telegram.utils.simpler import ru_cmds @@ -39,7 +40,8 @@ class UserHasPermissions(Filter): def __init__(self, perms: list[Any]) -> None: self.perms = perms - async def check_permissions(self, permission, msg: Message) -> bool: + @staticmethod + async def check_permissions(permission, msg: Message) -> bool: """ Checking permissions, included to user. :return: @@ -52,19 +54,29 @@ class UserHasPermissions(Filter): def generate_perms_list(self, user) -> list[Any]: """ - Generates list of permissions, included to user - :param user: - :return: + Generates list of permissions for user. + :param user: User telegram object + :return: List """ permission = [] for rule in self.perms: - if rule in permission: + if rule in self.permissions: exec(f"permission.append(user.{rule})") return permission async def __call__(self, msg: Message) -> bool: + """ + Working after catching a call from aiogram + :param msg: Message telegram object + :param self: A self object of this class + :return: None + """ user = await msg.chat.get_member(msg.from_user.id) - permission = self.generate_perms_list(user) + if user.status != ChatMemberStatus.CREATOR: + permission = self.generate_perms_list(user) + else: + permission = None + return True if user.status == ChatMemberStatus.CREATOR else self.check_permissions(permission, msg) @@ -72,20 +84,39 @@ class BotHasPermissions(UserHasPermissions): """ Check, does bot have permissions, what user need to work with bot. """ - async def __call__(self, msg: Message, *args, **kwargs): + + async def __call__(self, msg: Message, *args, **kwargs) -> bool: + """ + Working after catching a call from aiogram + :param msg: Message telegram object + :param self: A self object of this class + :return: None + """ bot = await msg.chat.get_member(msg.chat.bot.id) permission = self.generate_perms_list(bot) - return self.check_permissions(permission, msg) + return await self.check_permissions(permission, msg) class IsOwner(Filter): """ - Checks, is User are owner of chat + Checks, is memeber is owner of this chat """ + def __init__(self, is_admin: bool) -> None: + """ + Basic init class + :param is_admin: Is admin status + :return: Nothing + """ self.is_admin = is_admin async def __call__(self, msg: Message) -> bool: + """ + Working after catching a call from aiogram + :param msg: Message telegram object + :param self: A self object of this class + :return: None + """ user = await msg.chat.get_member(msg.from_user.id) if ChatMemberStatus.CREATOR != user.status: await msg.answer(ru_cmds["no-perms"]) @@ -93,12 +124,36 @@ class IsOwner(Filter): class IsAdminFilter(Filter): - def __init__(self, is_admin: bool) -> None: - self.is_admin = is_admin + """ + Checks, is member of chat is admin and + does bot have administration rights + """ + + def __init__(self, is_user_admin: bool, is_bot_admin: bool) -> None: + """ + Basic init class + + """ + self.is_user_admin = is_user_admin + self.is_bot_admin = is_bot_admin async def __call__(self, msg: Message) -> bool: + """ + Working after catching a call from aiogram + :param msg: Message telegram object + :param self: A self object of this class + :return: None + """ user = await msg.chat.get_member(msg.from_user.id) + bot = await msg.chat.get_member(msg.bot.id) + if ChatMemberStatus.ADMINISTRATOR != user.status and ChatMemberStatus.CREATOR != user.status: + if bot.status != ChatMemberStatus.ADMINISTRATOR: + await msg.reply("Ошибка ❌\n" + "У вас нет прав на использование этой комманды. У меня нет прав на использование 🚫") + else: + await msg.reply("Ошибка ❌\n" + "У вас нет прав на использование этой комманды 🚫") + return False if ChatMemberStatus.CREATOR == user.status: return True - return ChatMemberStatus.ADMINISTRATOR == user.status - + return ChatMemberStatus.ADMINISTRATOR == user.status or ChatMemberStatus.CREATOR == user.status diff --git a/bozenka/instances/telegram/utils/keyboards/inline.py b/bozenka/instances/telegram/utils/keyboards/inline.py index fa4b510..17f6274 100644 --- a/bozenka/instances/telegram/utils/keyboards/inline.py +++ b/bozenka/instances/telegram/utils/keyboards/inline.py @@ -28,10 +28,10 @@ def start_keyboard() -> InlineKeyboardMarkup: inline_keyboard=[ [InlineKeyboardButton(text="Добавить в ваш групповой чат 🔌", callback_data="addtochat")], [InlineKeyboardButton(text="Информация об функционале бота 🔨", callback_data="functional")], - [InlineKeyboardButton(text="Об данном проекте ℹ️", callback_data="aboutdevs")], + [InlineKeyboardButton(text="О данном проекте ℹ️", callback_data="aboutdevs")], [InlineKeyboardButton(text="О данном запущенном экзепляре ℹ️", callback_data="aboutbot")], [InlineKeyboardButton(text="Начать диалог с текстовым ИИ 🤖", callback_data="dialogai")], - [InlineKeyboardButton(text="Начать генерацию изображений 🖼", callback_data="dialogimage")], + [InlineKeyboardButton(text="Начать генерировать изображения 🖼", callback_data="dialogimage")], ] ) return kb @@ -82,7 +82,7 @@ def help_feature_keyboard(category: str) -> InlineKeyboardMarkup: """ kb = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="🔙 Назад к функциям", - callback_data=HelpBackCategory(back_to_category=category).pack())] + callback_data=HelpBackCategory(category_name=category).pack())] ]) return kb @@ -414,7 +414,7 @@ def generate_gpt4all_page(user_id: int) -> InlineKeyboardMarkup: callback_data=Gpt4AllModel(user_id=str(user_id), index=str(models.index(model))).pack()) ) builder.row(InlineKeyboardButton(text="🔙 Вернуться к списку", - callback_data=GptBackMenu(user_id=user_id, back_to="category").pack())) + callback_data=GptBackMenu(user_id=user_id, back_to="g4fcategory").pack())) builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", callback_data=GptStop(user_id=str(user_id)).pack())) return builder.as_markup() -- 2.30.2 From 4d3b9513f06e7683d8ea878dc52751045c73dcb8 Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Sat, 10 Feb 2024 22:24:05 +0300 Subject: [PATCH 05/13] A little bit changes too X2 --- .../telegram/handlers/queries/__init__.py | 2 +- .../telegram/handlers/queries/delete.py | 4 +- .../instances/telegram/queries/__init__.py | 0 bozenka/instances/telegram/queries/menu.py | 39 +++++++++++++++++++ .../utils/callbacks_factory/__init__.py | 7 ++-- .../{admin.py => administration.py} | 3 ++ .../{setup.py => basic_functional.py} | 30 ++++++++++++++ .../utils/callbacks_factory/delete.py | 8 ---- .../utils/callbacks_factory/menu_controler.py | 15 +++++++ .../telegram/utils/callbacks_factory/start.py | 38 ------------------ .../telegram/utils/keyboards/inline.py | 24 ++++++------ 11 files changed, 105 insertions(+), 65 deletions(-) create mode 100644 bozenka/instances/telegram/queries/__init__.py create mode 100644 bozenka/instances/telegram/queries/menu.py rename bozenka/instances/telegram/utils/callbacks_factory/{admin.py => administration.py} (91%) rename bozenka/instances/telegram/utils/callbacks_factory/{setup.py => basic_functional.py} (59%) delete mode 100644 bozenka/instances/telegram/utils/callbacks_factory/delete.py create mode 100644 bozenka/instances/telegram/utils/callbacks_factory/menu_controler.py delete mode 100644 bozenka/instances/telegram/utils/callbacks_factory/start.py diff --git a/bozenka/instances/telegram/handlers/queries/__init__.py b/bozenka/instances/telegram/handlers/queries/__init__.py index fef7601..ee5323b 100644 --- a/bozenka/instances/telegram/handlers/queries/__init__.py +++ b/bozenka/instances/telegram/handlers/queries/__init__.py @@ -33,7 +33,7 @@ def register_queries(router: Router) -> None: # Revoke telegram invite link button router.callback_query.register(inline_revoke, RevokeCallbackData.filter()) # Delete button message reaction - router.callback_query.register(inline_delete, DeleteCallbackData.filter()) + router.callback_query.register(inline_delete, DeleteMenu.filter()) # Threads (Close/Open) router.callback_query.register(inline_close_thread, CloseThread.filter()) diff --git a/bozenka/instances/telegram/handlers/queries/delete.py b/bozenka/instances/telegram/handlers/queries/delete.py index 0f05718..20f24cf 100644 --- a/bozenka/instances/telegram/handlers/queries/delete.py +++ b/bozenka/instances/telegram/handlers/queries/delete.py @@ -2,11 +2,11 @@ import logging from aiogram import types -from bozenka.instances.telegram.utils.callbacks_factory import DeleteCallbackData +from bozenka.instances.telegram.utils.callbacks_factory import DeleteMenu from aiogram.enums import ChatMemberStatus -async def inline_delete(call: types.CallbackQuery, callback_data: DeleteCallbackData) -> None: +async def inline_delete(call: types.CallbackQuery, callback_data: DeleteMenu) -> None: """ Deletes messsage, after special callback :param call: diff --git a/bozenka/instances/telegram/queries/__init__.py b/bozenka/instances/telegram/queries/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/instances/telegram/queries/menu.py b/bozenka/instances/telegram/queries/menu.py new file mode 100644 index 0000000..627b091 --- /dev/null +++ b/bozenka/instances/telegram/queries/menu.py @@ -0,0 +1,39 @@ +import logging + +from aiogram import types + +from bozenka.instances.telegram.utils.callbacks_factory import DeleteMenu +from aiogram.enums import ChatMemberStatus + +from bozenka.instances.telegram.utils.callbacks_factory.menu_controler import HideMenu + + +async def delete_callback_handler(call: types.CallbackQuery, callback_data: DeleteMenu) -> None: + """ + Deletes messsage, after special callback + :param call: CallbackQuery telegram object + :param callback_data: DeleteMenu object + :return: None + """ + user_clicked = await call.message.chat.get_member(call.from_user.id) + if call.from_user.id == callback_data.user_id_clicked or user_clicked.status == ChatMemberStatus.ADMINISTRATOR: + await call.answer("Хорошо ✅") + logging.log(msg=f"Deleted message with message_id={call.message.message_id}", + level=logging.INFO) + await call.message.delete() + + +async def hide_menu_handler(call: types.CallbackQuery, callback_data: HideMenu): + """ + Hide InlineKeyboard, after special callback + :param call: CallbackQuery telegram object + :param callback_data: HideMenu object + :return: None + """ + user_clicked = await call.message.chat.get_member(call.from_user.id) + if call.from_user.id == callback_data.user_id_clicked or user_clicked.status == ChatMemberStatus.ADMINISTRATOR: + await call.answer("Хорошо ✅") + logging.log(msg=f"Hide inline keyboard message with message_id={call.message.message_id}", + level=logging.INFO) + await call.message.edit_text(call.message.text, reply_markup=None) + diff --git a/bozenka/instances/telegram/utils/callbacks_factory/__init__.py b/bozenka/instances/telegram/utils/callbacks_factory/__init__.py index c7d0fea..cd876be 100644 --- a/bozenka/instances/telegram/utils/callbacks_factory/__init__.py +++ b/bozenka/instances/telegram/utils/callbacks_factory/__init__.py @@ -1,6 +1,5 @@ -from .admin import * -from .delete import DeleteCallbackData +from .administration import * +from .menu_controler import DeleteMenu from .text_generation import * -from .setup import * -from .start import * +from .basic_functional import * from .img_generation import * diff --git a/bozenka/instances/telegram/utils/callbacks_factory/admin.py b/bozenka/instances/telegram/utils/callbacks_factory/administration.py similarity index 91% rename from bozenka/instances/telegram/utils/callbacks_factory/admin.py rename to bozenka/instances/telegram/utils/callbacks_factory/administration.py index 5a8b83e..f1c7986 100644 --- a/bozenka/instances/telegram/utils/callbacks_factory/admin.py +++ b/bozenka/instances/telegram/utils/callbacks_factory/administration.py @@ -5,6 +5,7 @@ from aiogram.filters.callback_data import CallbackData class BanData(CallbackData, prefix="ban"): """ Callback with information to ban user + and handle clicking on button ban """ user_id_ban: int user_id_clicked: int @@ -13,6 +14,7 @@ class BanData(CallbackData, prefix="ban"): class UnbanData(CallbackData, prefix="unban"): """ Callback with information to unban user + and handle clicking on button unban """ user_id_unban: int user_id_clicked: int @@ -22,6 +24,7 @@ class UnbanData(CallbackData, prefix="unban"): class MuteData(CallbackData, prefix="mute"): """ Callback with information to mute user + and handle clicking on button unmute """ user_id_mute: int user_id_clicked: int diff --git a/bozenka/instances/telegram/utils/callbacks_factory/setup.py b/bozenka/instances/telegram/utils/callbacks_factory/basic_functional.py similarity index 59% rename from bozenka/instances/telegram/utils/callbacks_factory/setup.py rename to bozenka/instances/telegram/utils/callbacks_factory/basic_functional.py index 1426531..c8edcf3 100644 --- a/bozenka/instances/telegram/utils/callbacks_factory/setup.py +++ b/bozenka/instances/telegram/utils/callbacks_factory/basic_functional.py @@ -39,3 +39,33 @@ class SetupEditFeature(CallbackData, prefix="sef"): enable: bool feature_index: int feature_category: str + + +class HelpCategory(CallbackData, prefix="hc"): + """ + Callback data of help categories + """ + category_name: str + + +class HelpFeature(CallbackData, prefix="hf"): + """ + Callback data of features category + """ + feature_index: int + feature_category: str + + +class HelpBack(CallbackData, prefix="hb"): + """ + Callback data to back to categories in help menu + """ + back_to: str + + +class HelpBackCategory(CallbackData, prefix="hbc"): + """ + Callback data to back to list of features in one + of categories in menu + """ + category_name: str diff --git a/bozenka/instances/telegram/utils/callbacks_factory/delete.py b/bozenka/instances/telegram/utils/callbacks_factory/delete.py deleted file mode 100644 index 68845c2..0000000 --- a/bozenka/instances/telegram/utils/callbacks_factory/delete.py +++ /dev/null @@ -1,8 +0,0 @@ -from aiogram.filters.callback_data import CallbackData - - -class DeleteCallbackData(CallbackData, prefix="delete"): - """ - Callback with information to delete message - """ - user_id_clicked: int diff --git a/bozenka/instances/telegram/utils/callbacks_factory/menu_controler.py b/bozenka/instances/telegram/utils/callbacks_factory/menu_controler.py new file mode 100644 index 0000000..296b679 --- /dev/null +++ b/bozenka/instances/telegram/utils/callbacks_factory/menu_controler.py @@ -0,0 +1,15 @@ +from aiogram.filters.callback_data import CallbackData + + +class DeleteMenu(CallbackData, prefix="delete"): + """ + Callback with information to delete message + """ + user_id_clicked: int + + +class HideMenu(CallbackData, prefix="hide"): + """ + Callback with information to hide message + """ + user_id_clicked: int diff --git a/bozenka/instances/telegram/utils/callbacks_factory/start.py b/bozenka/instances/telegram/utils/callbacks_factory/start.py deleted file mode 100644 index 0c4048d..0000000 --- a/bozenka/instances/telegram/utils/callbacks_factory/start.py +++ /dev/null @@ -1,38 +0,0 @@ -from aiogram.filters.callback_data import CallbackData - - -class HelpCategory(CallbackData, prefix="hc"): - """ - Callback data of help categories - """ - category_name: str - - -class HelpFeature(CallbackData, prefix="hf"): - """ - Callback data of features category - """ - feature_index: int - feature_category: str - - -class HelpBack(CallbackData, prefix="hb"): - """ - Callback data to back to categories in help menu - """ - back_to: str - - -class HelpBackCategory(CallbackData, prefix="hbc"): - """ - Callback data to back to list of features in one - of categories in menu - """ - category_name: str - - -class BackStart(CallbackData, prefix="start"): - """ - Callback data to back to /start - """ - pass diff --git a/bozenka/instances/telegram/utils/keyboards/inline.py b/bozenka/instances/telegram/utils/keyboards/inline.py index 17f6274..e377704 100644 --- a/bozenka/instances/telegram/utils/keyboards/inline.py +++ b/bozenka/instances/telegram/utils/keyboards/inline.py @@ -156,7 +156,7 @@ def delete_keyboard(admin_id: int) -> InlineKeyboardMarkup: :return: """ kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack()) + InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) ]]) return kb @@ -445,7 +445,7 @@ def text_response_keyboard(user_id: int) -> InlineKeyboardMarkup: :return: """ kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())], + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())], [InlineKeyboardButton(text="Завершить диалог 🚫", callback_data=GptStop(user_id=str(user_id)).pack())] ]) return kb @@ -458,7 +458,7 @@ def image_response_keyboard(user_id: int) -> InlineKeyboardMarkup: :return: """ kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())], + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())], [InlineKeyboardButton(text="Хватит 🚫", callback_data=GptStop(user_id=str(user_id)).pack())] ]) return kb @@ -474,7 +474,7 @@ def ban_keyboard(admin_id: int, ban_id: int) -> InlineKeyboardMarkup: :return: """ kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack()) + InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) ], [ InlineKeyboardButton(text="Разбанить 🛠️", callback_data=UnbanData(user_id_unban=str(ban_id), user_id_clicked=str(admin_id)).pack()) @@ -491,7 +491,7 @@ def unban_keyboard(admin_id: int, ban_id: int) -> InlineKeyboardMarkup: """ print(ban_id) kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack()) + InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) ], [ InlineKeyboardButton(text="Забанить 🛠️", callback_data=BanData(user_id_ban=str(ban_id), user_id_clicked=str(admin_id)).pack()) @@ -509,7 +509,7 @@ def mute_keyboard(admin_id: int, mute_id: int) -> InlineKeyboardMarkup: """ kb = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Спасибо ✅", - callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())], + callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())], [InlineKeyboardButton(text="Размутить 🛠️", callback_data=UnmuteData(user_id_unmute=mute_id, user_id_clicked=admin_id).pack())]]) return kb @@ -524,7 +524,7 @@ def unmute_keyboard(admin_id: int, unmute_id: int) -> InlineKeyboardMarkup: """ kb = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Спасибо ✅", - callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())], + callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())], [InlineKeyboardButton(text="Замутить 🛠️", callback_data=MuteData(user_id_mute=unmute_id, user_id_clicked=admin_id).pack())]]) return kb @@ -545,7 +545,7 @@ def invite_keyboard(link: str, admin_id: int, chat_name: str) -> InlineKeyboardM [InlineKeyboardButton(text="Отозвать 🛠️", callback_data=RevokeCallbackData(admin_id=admin_id, link=link).pack())], [InlineKeyboardButton(text="Спасибо ✅", - callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())]]) + callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())]]) return kb @@ -558,7 +558,7 @@ def close_thread_keyboard(user_id: int) -> InlineKeyboardMarkup: """ kb = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Окрыть обсуждение 🛠️", callback_data=OpenThread(user_id=user_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())] + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] ]) return kb @@ -571,7 +571,7 @@ def open_thread_keyboard(user_id: int) -> InlineKeyboardMarkup: """ kb = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Закрыть обсуждение 🛠️", callback_data=CloseThread(user_id=user_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())] + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] ]) return kb @@ -587,7 +587,7 @@ def pin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup: kb = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Открепить сообщение 📌", callback_data=UnpinMsg(user_id=user_id, msg_id=msg_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())] + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] ]) return kb @@ -602,7 +602,7 @@ def unpin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup: kb = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Открепить сообщение 📌", callback_data=PinMsg(user_id=user_id, msg_id=msg_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())] + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] ]) return kb -- 2.30.2 From 347c666a78485879f0cb5021bb5daeda8d7b1dfb Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Sat, 10 Feb 2024 22:24:42 +0300 Subject: [PATCH 06/13] Removed other source code --- .../instances/telegram/handlers/__init__.py | 25 -- .../telegram/handlers/chat_admin/__init__.py | 72 ---- .../telegram/handlers/chat_admin/bans.py | 114 ------ .../telegram/handlers/chat_admin/help.py | 76 ---- .../telegram/handlers/chat_admin/mutes.py | 59 --- .../telegram/handlers/chat_admin/pins.py | 40 -- .../telegram/handlers/chat_admin/topics.py | 93 ----- .../telegram/handlers/chat_user/__init__.py | 29 -- .../telegram/handlers/chat_user/about.py | 19 - .../telegram/handlers/chat_user/info.py | 32 -- .../telegram/handlers/chat_user/invite.py | 22 -- .../telegram/handlers/chat_user/welcome.py | 50 --- .../telegram/handlers/dev/__init__.py | 31 -- .../instances/telegram/handlers/dev/hello.py | 28 -- .../telegram/handlers/dev/image_generation.py | 95 ----- .../telegram/handlers/dev/text_generation.py | 156 -------- .../telegram/handlers/main/__init__.py | 33 -- .../instances/telegram/handlers/main/setup.py | 31 -- .../instances/telegram/handlers/main/start.py | 36 -- .../telegram/handlers/queries/__init__.py | 128 ------- .../telegram/handlers/queries/ban.py | 67 ---- .../telegram/handlers/queries/delete.py | 21 - .../handlers/queries/image_generation.py | 60 --- .../telegram/handlers/queries/mute.py | 67 ---- .../telegram/handlers/queries/pins.py | 36 -- .../telegram/handlers/queries/revoke.py | 24 -- .../telegram/handlers/queries/setup.py | 73 ---- .../telegram/handlers/queries/start.py | 168 -------- .../handlers/queries/text_generation.py | 358 ------------------ .../telegram/handlers/queries/threads.py | 41 -- 30 files changed, 2084 deletions(-) delete mode 100644 bozenka/instances/telegram/handlers/__init__.py delete mode 100644 bozenka/instances/telegram/handlers/chat_admin/__init__.py delete mode 100644 bozenka/instances/telegram/handlers/chat_admin/bans.py delete mode 100644 bozenka/instances/telegram/handlers/chat_admin/help.py delete mode 100644 bozenka/instances/telegram/handlers/chat_admin/mutes.py delete mode 100644 bozenka/instances/telegram/handlers/chat_admin/pins.py delete mode 100644 bozenka/instances/telegram/handlers/chat_admin/topics.py delete mode 100644 bozenka/instances/telegram/handlers/chat_user/__init__.py delete mode 100644 bozenka/instances/telegram/handlers/chat_user/about.py delete mode 100644 bozenka/instances/telegram/handlers/chat_user/info.py delete mode 100644 bozenka/instances/telegram/handlers/chat_user/invite.py delete mode 100644 bozenka/instances/telegram/handlers/chat_user/welcome.py delete mode 100644 bozenka/instances/telegram/handlers/dev/__init__.py delete mode 100644 bozenka/instances/telegram/handlers/dev/hello.py delete mode 100644 bozenka/instances/telegram/handlers/dev/image_generation.py delete mode 100644 bozenka/instances/telegram/handlers/dev/text_generation.py delete mode 100644 bozenka/instances/telegram/handlers/main/__init__.py delete mode 100644 bozenka/instances/telegram/handlers/main/setup.py delete mode 100644 bozenka/instances/telegram/handlers/main/start.py delete mode 100644 bozenka/instances/telegram/handlers/queries/__init__.py delete mode 100644 bozenka/instances/telegram/handlers/queries/ban.py delete mode 100644 bozenka/instances/telegram/handlers/queries/delete.py delete mode 100644 bozenka/instances/telegram/handlers/queries/image_generation.py delete mode 100644 bozenka/instances/telegram/handlers/queries/mute.py delete mode 100644 bozenka/instances/telegram/handlers/queries/pins.py delete mode 100644 bozenka/instances/telegram/handlers/queries/revoke.py delete mode 100644 bozenka/instances/telegram/handlers/queries/setup.py delete mode 100644 bozenka/instances/telegram/handlers/queries/start.py delete mode 100644 bozenka/instances/telegram/handlers/queries/text_generation.py delete mode 100644 bozenka/instances/telegram/handlers/queries/threads.py diff --git a/bozenka/instances/telegram/handlers/__init__.py b/bozenka/instances/telegram/handlers/__init__.py deleted file mode 100644 index 5ff430f..0000000 --- a/bozenka/instances/telegram/handlers/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -import logging - -from aiogram import Dispatcher - -from bozenka.instances.telegram.handlers.chat_admin import register_admin_cmd -from bozenka.instances.telegram.handlers.queries import register_queries -from bozenka.instances.telegram.handlers.dev import register_dev_cmd -from bozenka.instances.telegram.handlers.main import register_main_cmd -from bozenka.instances.telegram.handlers.chat_user import register_user_cmd -from bozenka.instances.telegram.utils.middleware import register_middlewares - - -def register_handlers(dp: Dispatcher) -> None: - """ - Registers all handlers - :param dp: - :return: - """ - logging.log(msg="Starting registering all handlers", level=logging.INFO) - register_dev_cmd(dp) - register_user_cmd(dp) - register_admin_cmd(dp) - register_main_cmd(dp) - register_queries(dp) - register_middlewares(dp) diff --git a/bozenka/instances/telegram/handlers/chat_admin/__init__.py b/bozenka/instances/telegram/handlers/chat_admin/__init__.py deleted file mode 100644 index 06a94a9..0000000 --- a/bozenka/instances/telegram/handlers/chat_admin/__init__.py +++ /dev/null @@ -1,72 +0,0 @@ - - -import logging - -from aiogram import Router, F -from aiogram.filters import Command - -from bozenka.instances.telegram.handlers.chat_admin.help import * -from bozenka.instances.telegram.handlers.chat_admin.mutes import mute, unmute -from bozenka.instances.telegram.handlers.chat_admin.pins import pin, unpin, unpin_all -from bozenka.instances.telegram.handlers.chat_admin.topics import * -from bozenka.instances.telegram.handlers.chat_admin.bans import ban_command, unban_command -from bozenka.instances.telegram.utils.filters import * - - -def register_admin_cmd(router: Router) -> None: - """ - Registers all commands related to administrators in group. - All commands there require access to some group perms. - :param router: - :return: - """ - logging.log(msg="Registering administrator commands", level=logging.INFO) - - # Ban / Unban commands handler - router.message.register(ban_command, Command(commands="ban"), - IsAdminFilter(True), F.reply_to_message.text) - router.message.register(unban_command, Command(commands="unban"), - IsAdminFilter(True), F.reply_to_message.text) - - # Mute / Unmute commands handler - router.message.register(mute, Command(commands=["mute", "re"]), UserHasPermissions(["can_restrict_members"]), - BotHasPermissions(["can_restrict_members"])) - router.message.register(unmute, Command(commands=["unmute"]), UserHasPermissions(["can_restrict_members"]), - BotHasPermissions(["can_restrict_members"])) - - # Pin / Unpin / Unpinall commands handler - router.message.register(pin, Command(commands="pin"), UserHasPermissions(["can_pin_messages"]), - BotHasPermissions(["can_pin_messages"]), F.reply_to_message.text) - router.message.register(unpin, Command(commands="unpin"), UserHasPermissions(["can_pin_messages"]), - BotHasPermissions(["can_pin_messages"]), F.reply_to_message.text) - router.message.register(unpin_all, Command(commands="unpin_all"), IsAdminFilter(True), - BotHasPermissions(["can_pin_messages"]), F.reply_to_message.text) - - # Topic managment handlers - router.message.register(reopen_topic, Command(commands=["reopen_topic", "open_topic", "open"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum) - router.message.register(close_topic, Command(commands=["close_topic", "close"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum) - router.message.register(close_general_topic, Command(commands=["close_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum) - router.message.register(reopen_general_topic, Command(commands=["reopen_general", "open_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum) - router.message.register(hide_general_topic, Command(commands=["hide_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum) - router.message.register(unhide_general_topic, Command(commands=["unhide_general", "show_general"]), - UserHasPermissions(["can_manage_topics"]), - BotHasPermissions(["can_manage_topics"]), F.chat.is_forum) - - # Helpig handlers - router.message.register(help_ban, Command(commands=["ban"])) - router.message.register(help_unban, Command(commands=["unban"])) - router.message.register(help_mute, Command(commands=["mute"])) - router.message.register(help_unmute, Command(commands=["mute"])) - router.message.register(help_pin, Command(commands=["pin"])) - router.message.register(help_unpin, Command(commands=["unpin"])) - diff --git a/bozenka/instances/telegram/handlers/chat_admin/bans.py b/bozenka/instances/telegram/handlers/chat_admin/bans.py deleted file mode 100644 index fc52bd2..0000000 --- a/bozenka/instances/telegram/handlers/chat_admin/bans.py +++ /dev/null @@ -1,114 +0,0 @@ -from aiogram.filters import CommandObject -from aiogram.types import Message -from aiogram.enums import ChatMemberStatus -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.database.tables.telegram import get_chat_config_value -from bozenka.instances.telegram.utils.keyboards import ban_keyboard, delete_keyboard - -from bozenka.instances.telegram.utils.simpler import SolutionSimpler, ru_cmds, list_of_features - - -async def ban_command(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None: - """ - /ban command function, supports time and reasons. - :param msg: Message telegram object - :param command: Object of telegram command - :param session_maker: Session maker object of SqlAlchemy - :return: Nothing - """ - banned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) - send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, setting=list_of_features["Admin"][4]) - send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, setting=list_of_features["Admin"][5]) - - where_send = { - True: msg.from_user.id, - False: msg.chat.id - } - - if banned_user.status == ChatMemberStatus.KICKED: - await msg.bot.send_message(chat_id=where_send[send_to_dm], - text="Ошибка ❌\n" - "Этот пользователь уже удален из группы", - reply_markup=delete_keyboard(msg.from_user.id)) - await msg.answer() - return - - config = await SolutionSimpler.ban_user(msg, command, session_maker) - if config["reason"] and config["ban_time"]: - await msg.answer("Удача ✅\n" - f"Пользователь {msg.reply_to_message.from_user.mention_html()} был заблокирован пользователем {msg.from_user.mention_html()}.\n" - f"По причине {config['reason']}, до даты {config['ban_time']}", - reply_markup=ban_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) - elif config["reason"]: - await msg.answer( - "Удача ✅\n" - f"Пользователь {msg.reply_to_message.from_user.mention_html()} был заблокирован пользователем {msg.reply_to_message.from_user.mention_html()}.\n" - f"По причине {config['reason']}.", - reply_markup=ban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id) - ) - elif config["ban_time"]: - await msg.answer( - "Удача ✅\n" - f"Пользователь {msg.reply_to_message.from_user.mention_html()} был заблокирован пользователем {msg.from_user.mention_html()}, до даты {config['ban_time']}", - reply_markup=ban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id) - ) - else: - await msg.answer( - "Удача ✅\n" - f"Пользователь {msg.reply_to_message.from_user.mention_html()} был заблокирован пользователем {msg.from_user.mention_html()}.", - reply_markup=ban_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id) - ) - - -async def unban_command(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None: - """ - /unban command function - :param msg: Message telegram object - :param command: Object of telegram command - :param session_maker: Session maker object of SqlAlchemy - """ - await SolutionSimpler.unban_user(msg, session_maker) - unbanned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) - if unbanned_user.is_member and unbanned_user.status != ChatMemberStatus.KICKED: - await msg.answer( - "Ошибка ❌\n" - "Этот пользователь не находится в бане.", - reply_markup=delete_keyboard(admin_id=msg.from_user.id) - ) - elif not command.text: - await msg.answer( - "Удача ✅\n" - f"Пользователь {msg.reply_to_message.from_user.mention_html()} был разблокирован пользователем {msg.from_user.mention_html()}.\n", - reply_markup=ban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id) - ) - else: - await msg.answer( - "Удача ✅\n" - f"Пользователь {msg.reply_to_message.from_user.mention_html()} был разблокирован пользователем {msg.from_user.mention_html()}.\n" - f"По причине {CommandObject.text}.", - reply_markup=ban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id) - ) - - -async def status_command(msg: Message, session_maker: async_sessionmaker) -> None: - """ - /status command function - Checks is user banned and muted - :param msg: Message telegram object - :param session_maker: Session maker object of SqlAlchemy - :return: - """ - config = await SolutionSimpler.get_status(msg, session_maker) - msg_text = "" - if config["is_banned"]: - msg_text += "Находится в бане" - if config["ban_reason"]: - msg_text += f"по причине {config['ban_reason']}" - msg_text += "🔨\n" - if config["is_muted"]: - msg_text += "Находится в муте" - if config["mute_reason"]: - msg_text += f"по причине {config['mute_reason']}" - msg_text += "🤐\n" - await msg.answer(msg_text, reply_markup=delete_keyboard(msg.from_user.id)) diff --git a/bozenka/instances/telegram/handlers/chat_admin/help.py b/bozenka/instances/telegram/handlers/chat_admin/help.py deleted file mode 100644 index f2ed75b..0000000 --- a/bozenka/instances/telegram/handlers/chat_admin/help.py +++ /dev/null @@ -1,76 +0,0 @@ -from aiogram.types import Message - -from bozenka.instances.telegram.utils.keyboards import delete_keyboard - - -async def help_ban(msg: Message) -> None: - """ - Shows help message for /ban - :param msg: Message telegram object - :return: Nothing - """ - await msg.answer("Использование:\n" - "
/ban [время блокировки] [причина блокировки]
\n" - "Ответьте на сообщение, чтобы заблокировать пользователя", - reply_markup=delete_keyboard(msg.from_user.id)) - - -async def help_unban(msg: Message) -> None: - """ - Shows help message for /unban - :param msg: Message telegram object - :return: Nothing - """ - await msg.answer("Использование:\n" - "
/unban
\n" - "Ответьте на сообщение, чтобы разблокировать пользователя", - reply_markup=delete_keyboard(msg.from_user.id)) - - -async def help_mute(msg: Message) -> None: - """ - Shows help message for /mute - :param msg: Message telegram object - :return: Nothing - """ - await msg.answer("Использование:\n" - "
/mute [время мута] [причина мута]
\n" - "Ответьте на сообщение, чтобы замутить пользователя", - reply_markup=delete_keyboard(msg.from_user.id)) - - -async def help_unmute(msg: Message) -> None: - """ - Shows help message for /unmute - :param msg: Message telegram object - :return: Nothing - """ - await msg.answer("Использование:\n" - "
/unmute
\n" - "Ответьте на сообщение, чтобы замутить пользователя", - reply_markup=delete_keyboard(msg.from_user.id)) - - -async def help_pin(msg: Message) -> None: - """ - Shows help message for /mute - :param msg: Message telegram object - :return: Nothing - """ - await msg.answer("Использование:\n" - "
/pin
\n" - "Ответьте на сообщение, чтобы закрепить сообщение", - reply_markup=delete_keyboard(msg.from_user.id)) - - -async def help_unpin(msg: Message) -> None: - """ - Shows help message for /mute - :param msg: Message telegram object - :return: Nothing - """ - await msg.answer("Использование:\n" - "
/unpin
\n" - "Ответьте на сообщение, чтобы открепить сообщение", - reply_markup=delete_keyboard(msg.from_user.id)) - diff --git a/bozenka/instances/telegram/handlers/chat_admin/mutes.py b/bozenka/instances/telegram/handlers/chat_admin/mutes.py deleted file mode 100644 index 1981cb2..0000000 --- a/bozenka/instances/telegram/handlers/chat_admin/mutes.py +++ /dev/null @@ -1,59 +0,0 @@ -from aiogram.filters import CommandObject -from aiogram.types import Message as Message -from aiogram.enums import ChatMemberStatus -from sqlalchemy.ext.asyncio import async_sessionmaker -from bozenka.instances.telegram.utils.keyboards import mute_keyboard, unmute_keyboard -from bozenka.instances.telegram.utils.simpler import SolutionSimpler - - -async def mute(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None: - """ - Handler of command /mute - Restricts member from using chat - :param msg: Message telegram object - :param command: Object of telegram command - :param session_maker: Session maker object of SqlAlchemy - :return: Nothing - """ - restricting = await msg.chat.get_member(msg.reply_to_message.from_user.id) - if restricting.status == ChatMemberStatus.LEFT or restricting.status == ChatMemberStatus.KICKED: - return - config = await SolutionSimpler.mute_user(msg, command, session_maker) - if config["mute_time"] and config["reason"] != "": - await msg.answer("Удача ✅\n" - f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " - f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" - f"По причине {config['reason']}, до даты {config['mute_time']}", - reply_markup=mute_keyboard(msg.from_user.id, restricting.user.id)) - elif config["reason"] != "": - await msg.answer("Удача ✅\n" - f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " - f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" - f"По причине {config['reason']}", - reply_markup=mute_keyboard(msg.from_user.id, restricting.user.id)) - elif config["mute_time"]: - await msg.answer("Удача ✅\n" - f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " - f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" - f"До даты {config['mute_time']}", - reply_markup=mute_keyboard(msg.from_user.id, restricting.user.id)) - else: - await msg.answer("Удача ✅\n" - f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " - f"сообщения пользователю {msg.reply_to_message.from_user.mention_html()}.\n", - reply_markup=mute_keyboard(msg.from_user.id, restricting.user.id)) - - -async def unmute(msg: Message, session_maker: async_sessionmaker) -> None: - """ - Handler of command /unmute - Gives access member to send messages into chat - :param msg: Message telegram object - :param session_maker: Session maker object of SqlAlchemy - :return: Nothing - """ - await SolutionSimpler.unmute_user(msg, session_maker) - await msg.answer("Удача ✅" - f"{msg.from_user.mention_html('Этот пользователь')} разрешил писать\n" - f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}", - reply_markup=unmute_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) diff --git a/bozenka/instances/telegram/handlers/chat_admin/pins.py b/bozenka/instances/telegram/handlers/chat_admin/pins.py deleted file mode 100644 index 5ae4d0c..0000000 --- a/bozenka/instances/telegram/handlers/chat_admin/pins.py +++ /dev/null @@ -1,40 +0,0 @@ -from aiogram.types import Message as Message -from bozenka.instances.telegram.utils.keyboards import unpin_msg_keyboard, pin_msg_keyboard, delete_keyboard -from bozenka.instances.telegram.utils.simpler import SolutionSimpler - - -async def pin(msg: Message) -> None: - """ - /pin command function, pins replied command - :param msg: Message telegram object - :return: Nothing - """ - await SolutionSimpler.pin_msg(msg) - await msg.answer("Удача ✅\n" - "Сообщение было закреплено 📌", - reply_markup=pin_msg_keyboard(msg_id=msg.reply_to_message.message_id, user_id=msg.from_user.id)) - - -async def unpin(msg: Message) -> None: - """ - /unpin command function, unpins replied command - :param msg: Message telegram object - :return: Nothing - """ - await SolutionSimpler.unpin_msg(msg) - await msg.answer("Удача ✅\n" - "Сообщение было откреплено 📌", - reply_markup=unpin_msg_keyboard(msg_id=msg.reply_to_message.message_id, user_id=msg.from_user.id)) - - -async def unpin_all(msg: Message) -> None: - """ - /unpin_all command function, unpins all messages in chat - :param msg: Message telegram object - :return: Nothing - """ - await SolutionSimpler.unpin_all_messages(msg) - await msg.answer("Удача ✅\n" - "Все сообщения были откреплены 📌", - reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - diff --git a/bozenka/instances/telegram/handlers/chat_admin/topics.py b/bozenka/instances/telegram/handlers/chat_admin/topics.py deleted file mode 100644 index f211ba9..0000000 --- a/bozenka/instances/telegram/handlers/chat_admin/topics.py +++ /dev/null @@ -1,93 +0,0 @@ -from aiogram import Bot -from aiogram.filters import CommandObject -from aiogram.types import Message as Message -from bozenka.instances.telegram.utils.keyboards import delete_keyboard, close_thread_keyboard, open_thread_keyboard -from bozenka.instances.telegram.utils.simpler import SolutionSimpler - - -async def close_topic(msg: Message, bot: Bot) -> None: - """ - /close command function. Closing thread - :param msg: Message telegram object - :param bot: Object of telegram bot - :return: Nothing - """ - config = await SolutionSimpler.close_topic(msg=msg) - await msg.answer(config[0], - reply_markup=close_thread_keyboard(user_id=msg.from_user.id) - if config[1] else delete_keyboard(msg.from_user.id)) - - -async def reopen_topic(msg: Message, bot: Bot) -> None: - """ - /open command function. Opens thread - :param msg: Message telegram object - :param bot: Object of telegram bot - :return: Nothing - """ - config = await SolutionSimpler.open_topic(msg=msg) - await msg.answer(config[0], - reply_markup=open_thread_keyboard(user_id=msg.from_user.id) - if config[1] else delete_keyboard(msg.from_user.id)) - - -async def close_general_topic(msg: Message, bot: Bot) -> None: - """ - /close_general command function. Closes general thread - :param msg: Message telegram object - :param bot: Object of telegram bot - :return: Nothing - """ - config = await SolutionSimpler.close_general_topic(msg=msg) - await msg.answer(config[0], - reply_markup=close_thread_keyboard(user_id=msg.from_user.id) - if config[1] else delete_keyboard(msg.from_user.id)) - - -async def reopen_general_topic(msg: Message, bot: Bot) -> None: - """ - /open_general command function. Opens general thread - :param msg: Message telegram object - :param bot: Object of telegram bot - :return: Nothing - """ - config = await SolutionSimpler.open_general_topic(msg=msg) - await msg.answer(config[0], - reply_markup=open_thread_keyboard(user_id=msg.from_user.id) - if config[1] else delete_keyboard(msg.from_user.id)) - - -async def hide_general_topic(msg: Message, bot: Bot) -> None: - """ - /hide_general command function. Hides general thread - :param msg: Message telegram object - :param bot: Object of telegram bot - :return: Nothing - """ - config = await SolutionSimpler.hide_general_topic(msg=msg) - await msg.answer(config[0], - reply_markup=delete_keyboard(msg.from_user.id)) - - -async def unhide_general_topic(msg: Message, bot: Bot) -> None: - """ - /show_general command function. Shows back general thread. - :param msg: Message telegram object - :param bot: Object of telegram bot - :return: Nothing - """ - config = await SolutionSimpler.show_general_topic(msg=msg) - await msg.answer(config[0], - reply_markup=delete_keyboard(msg.from_user.id)) - - -async def rename_topic(msg: Message, bot: Bot, command: CommandObject) -> None: - """ - /rename command function. Rename thread to a new name - :param msg: Message telegram object - :param bot: Object of telegram bot - :param command: Object of telegram command - :return: Nothing - """ - await msg.general_forum_topic_unhidden - await bot.edit_forum_topic(name=command.text, chat_id=msg.chat.id, message_thread_id=msg.message_thread_id) diff --git a/bozenka/instances/telegram/handlers/chat_user/__init__.py b/bozenka/instances/telegram/handlers/chat_user/__init__.py deleted file mode 100644 index 35e6c06..0000000 --- a/bozenka/instances/telegram/handlers/chat_user/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ - -import logging - -from aiogram.enums import ContentType -from aiogram.filters import Command -from aiogram import Router, F - -from bozenka.instances.telegram.handlers.chat_user.about import about -from bozenka.instances.telegram.handlers.chat_user.invite import invite -from bozenka.instances.telegram.handlers.chat_user.info import chat_info -from bozenka.instances.telegram.handlers.chat_user.welcome import * - - -def register_user_cmd(router: Router) -> None: - """ - Registers all commands related to users, and can be used by them. - Some of them require access to some perms for bot. - :param router: - :return: - """ - logging.log(msg="Registering user commands", level=logging.INFO) - - router.message.register(invite, Command(commands=["invite"])) - router.message.register(about, Command(commands=["about"])) - - router.message.register(leave, F.content_type == ContentType.LEFT_CHAT_MEMBER) - router.message.register(join, F.content_type == ContentType.NEW_CHAT_MEMBERS) - - router.message.register(chat_info, Command(commands=["info"])) diff --git a/bozenka/instances/telegram/handlers/chat_user/about.py b/bozenka/instances/telegram/handlers/chat_user/about.py deleted file mode 100644 index e6f7b06..0000000 --- a/bozenka/instances/telegram/handlers/chat_user/about.py +++ /dev/null @@ -1,19 +0,0 @@ -import logging - -from aiogram.types import Message as Message -from bozenka.instances.telegram.utils.keyboards import about_keyboard - - -async def about(msg: Message): - """ - Sending information about bot by command `/about` - Will be deleted by its use - :param msg: - :return: - """ - logging.log(msg=f"Sending about information for user_id={msg.from_user.id}", - level=logging.INFO) - await msg.answer("Кто я? 👁" - "\nЯ - многозадачный бот, разрабатываемый Bozo Developement и всё ещё нахожусь в разработке" - "\n(Ссылочки на нас внизу короче)☺️", - reply_markup=about_keyboard.as_markup()) diff --git a/bozenka/instances/telegram/handlers/chat_user/info.py b/bozenka/instances/telegram/handlers/chat_user/info.py deleted file mode 100644 index 90854f1..0000000 --- a/bozenka/instances/telegram/handlers/chat_user/info.py +++ /dev/null @@ -1,32 +0,0 @@ -import logging - -from aiogram.types import Message -from bozenka.instances.telegram.utils.simpler import ru_cmds -from bozenka.instances.telegram.utils.keyboards import delete_keyboard - - -async def chat_info(msg: Message): - """ - Shows information about chat by command `/info` - :param msg: - :return: - """ - logging.log(msg=f"Sending information about chat user_id={msg.from_user.id}", - level=logging.INFO) - chat = await msg.bot.get_chat(msg.chat.id) - # Related texts - texts = { - "chat_types": {"group": "группой", "supergroup": "cупер группой"}, - "forum_type": {True: "форумом,", False: ", не является форумом,", None: ", не является форумом,"}, - "required_invite": {True: "требуется одобрение заявки на вступление", False: "заявка не требуется.", - None: "заявка не требуется."}, - "hidden_members": {True: "присуствуют", False: "отсуствуют", None: "отсуствуют"}, - "isprotected": {True: "пересылать сообщения из группы можно.", False: "пересылать сообщения из группы нельзя.", - None: "пересылать сообщения из группы можно."}, - } - - await msg.answer(f"{chat.title}\n" - f"{chat.description}\n\n" - f"Является {texts['chat_types'][chat.type]} {texts['forum_type'][chat.is_forum]} {texts['required_invite'][chat.join_by_request]}\n" - f"Скрытые пользователи {texts['hidden_members'][chat.has_hidden_members]}, {texts['isprotected'][chat.has_protected_content]}", - reply_markup=delete_keyboard(admin_id=msg.from_user.id)) \ No newline at end of file diff --git a/bozenka/instances/telegram/handlers/chat_user/invite.py b/bozenka/instances/telegram/handlers/chat_user/invite.py deleted file mode 100644 index fce300d..0000000 --- a/bozenka/instances/telegram/handlers/chat_user/invite.py +++ /dev/null @@ -1,22 +0,0 @@ -import logging - -from aiogram.types import Message -from bozenka.instances.telegram.utils.keyboards import invite_keyboard -from bozenka.instances.telegram.utils.simpler import ru_cmds - - -async def invite(msg: Message): - """ - Generating invite to group by /invite command - :param msg: - :return: - """ - logging.log(msg=f"Generating invite for user_id={msg.from_user.id}", - level=logging.INFO) - link = await msg.chat.create_invite_link() - print(link.invite_link[0]) - await msg.answer( - ru_cmds["invite_generation"].replace("user", msg.from_user.mention_html(ru_cmds["sir"])), - reply_markup=invite_keyboard(link=str(link.invite_link), admin_id=msg.from_user.id, chat_name=msg.chat.full_name) - ) - diff --git a/bozenka/instances/telegram/handlers/chat_user/welcome.py b/bozenka/instances/telegram/handlers/chat_user/welcome.py deleted file mode 100644 index 66bd64e..0000000 --- a/bozenka/instances/telegram/handlers/chat_user/welcome.py +++ /dev/null @@ -1,50 +0,0 @@ -import logging - -from aiogram import Bot -from aiogram.types import Message as Message -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.instances.telegram.utils.simpler import SolutionSimpler - - -async def join(msg: Message, session_maker: async_sessionmaker): - """ - Send welcome message, after adding new member to chat. - Also works on adding bot to chat and sending welcome message. - :param msg: - :param session_maker: - :return: - """ - for new in msg.new_chat_members: - if new.id != msg.bot.id: - logging.log(msg=f"Saing welcome for user_id={new.id}, chat_id={msg.chat.id}", - level=logging.INFO) - await msg.answer( - f"Пользователь {new.mention_html()} переехал в конфу, благодаря {msg.from_user.mention_html()}👋", - ) - await msg.delete() - else: - logging.log(msg=f"Saing welcome to administrators for chat_id={msg.chat.id}", - level=logging.INFO) - await msg.answer("Здраствуйте администраторы чата 👋\n" - "Я - бозенька, мультифункциональный бот, разрабатываемый Bozo Developement\n" - "Выдайте мне полные права администратора для моей полной работы.\n" - "Чтобы настроить функционал, используйте /setup или кнопку под сообщением", ) - await SolutionSimpler.auto_settings(msg=msg, session=session_maker) - - -async def leave(msg: Message, bot: Bot): - """ - Sens goodbye message, after deleting member from chat - :param msg: - :param bot: - :return: - """ - await msg.delete() - if msg.from_user.id == bot.id: - return - logging.log(msg=f"Saing goodbye for user_id={msg.left_chat_member.id}, chat_id={msg.chat.id}", - level=logging.INFO) - await msg.answer( - f"Пользователь {msg.left_chat_member.mention_html()} съехал с конфы, благодаря {msg.from_user.mention_html()}👋" - ) diff --git a/bozenka/instances/telegram/handlers/dev/__init__.py b/bozenka/instances/telegram/handlers/dev/__init__.py deleted file mode 100644 index 3db5fd7..0000000 --- a/bozenka/instances/telegram/handlers/dev/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -import logging - -from aiogram.filters import Command - -from bozenka.instances.telegram.handlers.dev.hello import hi, testing -from bozenka.instances.telegram.handlers.dev.text_generation import * -from bozenka.instances.telegram.handlers.dev.image_generation import * - -from bozenka.instances.telegram.utils.simpler import AnsweringGPT4Free, AnsweringGpt4All, GeneratingImages -from aiogram import Router - - -def register_dev_cmd(router: Router) -> None: - """ - Registering testing commands in development or planned in future and need much time to realise it. - Don't need any special perms in group. - :param router: - :return: - """ - logging.log(msg="Registering developer commands", level=logging.INFO) - router.message.register(hi, Command(commands=["hi", "welcome", "sup", "wassup", "hello", "priv", - "privet", "хай", "прив", "привет", "ку"])) - router.message.register(start_dialog_cmd, Command(commands=["conversation"])) - router.message.register(g4f_generate_answer, AnsweringGPT4Free.ready_to_answer, ~Command(commands=["cancel"])) - router.message.register(already_answering, AnsweringGpt4All.answering, ~Command(commands=["cancel"])) - router.message.register(already_answering, AnsweringGPT4Free.answering, ~Command(commands=["cancel"])) - router.message.register(g4a_generate_answer, AnsweringGpt4All.ready_to_answer, ~Command(commands=["cancel"])) - router.message.register(kadinsky_generating_images, GeneratingImages.ready_to_generate, ~Command(commands=["cancel"])) - router.message.register(start_imagine_cmd, Command(commands=["imagine"])) - router.message.register(cancel_answering, Command(commands=["cancel"])) - router.message.register(testing, Command(commands=["testingtest"])) diff --git a/bozenka/instances/telegram/handlers/dev/hello.py b/bozenka/instances/telegram/handlers/dev/hello.py deleted file mode 100644 index c43638b..0000000 --- a/bozenka/instances/telegram/handlers/dev/hello.py +++ /dev/null @@ -1,28 +0,0 @@ -from aiogram import Bot -from aiogram.filters import CommandObject -from aiogram.types import Message as Message, User, Chat -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.instances.telegram.utils.keyboards import delete_keyboard - - -async def hi(msg: Message): - """ - Test command, sending welcome message. - Made for testing bot working status. - :param msg: - :return: - """ - await msg.answer( - f"Привет, {msg.from_user.mention_html('')} 👋", - reply_markup=delete_keyboard(msg.from_user.id) - ) - - -async def testing(msg: Message, session_maker: async_sessionmaker, command: CommandObject, user: User, target: User, chat: Chat, bot: Bot): - print(user.full_name) - print(target.full_name) - print(msg) - print(command.args) - print(command.mention) - print(command.command) diff --git a/bozenka/instances/telegram/handlers/dev/image_generation.py b/bozenka/instances/telegram/handlers/dev/image_generation.py deleted file mode 100644 index 9359bfe..0000000 --- a/bozenka/instances/telegram/handlers/dev/image_generation.py +++ /dev/null @@ -1,95 +0,0 @@ -import logging - -from aiogram.fsm.context import FSMContext -from aiogram.types import Message as Message, FSInputFile - -from bozenka.generative.kadinsky import kadinsky_gen -from bozenka.instances.telegram.utils.keyboards import delete_keyboard, image_generation_keyboard, \ - image_response_keyboard -from bozenka.instances.telegram.utils.simpler import GeneratingImages - - -async def already_generating(msg: Message, state: FSMContext): - """ - Giving response, if generating image for user right now, - but user still asks something - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - await msg.answer( - "Подождите пожалуйста, мы уже генерируем изображение для вас, подождите, когда мы ответим на ваш передыдущий вопрос", - reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - - -async def start_imagine_cmd(msg: Message, state: FSMContext): - """ - /iamgine command handler, start menu - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - if await state.get_state(): - return - await msg.answer("Пожалуста, выберите сервис / модель для генерации изображений", - reply_markup=image_generation_keyboard(user_id=msg.from_user.id)) - - -async def kadinsky_generating_images(msg: Message, state: FSMContext): - """ - Message handler for kandinsky to generate image by text from message - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - await state.set_state(GeneratingImages.generating) - message = await msg.answer("Пожалуйста подождите, мы генерируем изображение ⏰\n" - "Если что-то пойдет не так, мы вам сообщим 👌") - data = await state.get_data() - - try: - - model_id = kadinsky_gen.get_model() - width, height = data["set_size"].split("x") - generating = kadinsky_gen.generate(model=model_id, - prompt=msg.text, - width=int(width), - height=int(height)) - result = kadinsky_gen.check_generation(request_id=generating) - - if result: - path = kadinsky_gen.save_image(result[0], f"telegram_{msg.from_user.id}") - photo = FSInputFile(path) - await msg.answer_photo(photo=photo, - caption=msg.text, - reply_markup=image_response_keyboard(user_id=msg.from_user.id)) - await message.delete() - else: - await message.edit_text("Простите, произошла ошибка 😔\n" - "Убедитесь, что севрера kadinsky работают и ваш промт не является неподобающим и неприемлимым\n" - "Если это продолжается, пожалуйста используйте /cancel", - reply_markup=image_response_keyboard(user_id=msg.from_user.id)) - - except Exception as ex: - logging.log(msg=f"Get an exception for generating answer={ex}", - level=logging.ERROR) - finally: - logging.log(msg=f"Generated image for user_id={msg.from_user.id} with promt", - level=logging.INFO) - await state.set_state(GeneratingImages.ready_to_generate) - - -async def cancefl_answering(msg: Message, state: FSMContext): - """ - Canceling generating images for user - Works on command /cancel - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - current = await state.get_state() - if current is None: - return - await state.clear() - await msg.answer("Удача ✅\n" - "Диалог отменён!", reply_markup=delete_keyboard(admin_id=msg.from_user.id)) diff --git a/bozenka/instances/telegram/handlers/dev/text_generation.py b/bozenka/instances/telegram/handlers/dev/text_generation.py deleted file mode 100644 index 738aaaa..0000000 --- a/bozenka/instances/telegram/handlers/dev/text_generation.py +++ /dev/null @@ -1,156 +0,0 @@ -import logging -import os.path - -import g4f -from gpt4all import GPT4All -from aiogram.fsm.context import FSMContext -from aiogram.types import Message as Message - -from bozenka.generative.gpt4all import check, model_path -from bozenka.instances.telegram.utils.keyboards import gpt_categories_keyboard, delete_keyboard, text_response_keyboard -from bozenka.instances.telegram.utils.simpler import AnsweringGpt4All, \ - AnsweringGPT4Free -from bozenka.generative.gpt4free import generate_gpt4free_providers - - -async def already_answering(msg: Message, state: FSMContext): - """ - Giving response, if answering user now, - but he still asks something - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - await msg.answer("Подождите пожалуйста, мы уже генерируем ответ для вас, подождите, когда мы ответим на ваш передыдущий вопрос", - reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - - -async def start_dialog_cmd(msg: Message, state: FSMContext): - """ - /conversation command handler, start - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - if await state.get_state(): - return - await msg.answer("Пожалуста, выберите сервис для ИИ.", - reply_markup=gpt_categories_keyboard - (user_id=msg.from_user.id)) - - -async def cancel_answering(msg: Message, state: FSMContext): - """ - Canceling dialog with generative model - Works on command /cancel - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - current = await state.get_state() - if current is None: - return - await state.clear() - await msg.answer("Удача ✅\n" - "Диалог отменён!", reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - - -async def g4a_generate_answer(msg: Message, state: FSMContext): - """ - Generating answer if Gpt4All has been selected - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - await state.set_state(AnsweringGpt4All.answering) - - models = GPT4All.list_models() - info = await state.get_data() - answer = "" - - main_msg = await msg.answer("Пожалуйста подождите, мы генерируем вам ответ ⏰\n" - "Если что-то пойдет не так, мы вам сообщим 👌", - reply_markup=text_response_keyboard(user_id=msg.from_user.id)) - - if not check(models[info["set_model"]]["filename"]): - main_msg = await main_msg.edit_text(main_msg.text + "\nПодождите пожалуста, мы скачиваем модель...", - reply_markup=main_msg.reply_markup) - - try: - # Setting Gpt4All model - model = GPT4All(model_name=models[info['set_model']]['filename'], - model_path=model_path, - allow_download=True) - # Setting our chat session if exist - model.current_chat_session = [] if not info.get("ready_to_answer") else info["ready_to_answer"] - # Generating answer - with model.chat_session(): - answer = model.generate(msg.text) - await state.update_data(ready_to_answer=model.current_chat_session) - - except Exception as S: - answer = "Простите, произошла ошибка 😔\nЕсли это продолжается, пожалуйста используйте /cancel" - logging.log(msg=f"Get an exception for generating answer={S}", - level=logging.ERROR) - finally: - await main_msg.edit_text(answer, reply_markup=text_response_keyboard(user_id=msg.from_user.id)) - - await state.set_state(AnsweringGpt4All.ready_to_answer) - - -async def g4f_generate_answer(msg: Message, state: FSMContext): - """ - Generating answer if GPT4Free model and provider has been selected - :param msg: Message telegram object - :param state: FSM state of bot - :return: - """ - await state.set_state(AnsweringGPT4Free.answering) - - info = await state.get_data() - - providers = generate_gpt4free_providers() - reply = await msg.reply("Пожалуйста подождите, мы генерируем ответ от провайдера ⏰\n" - "Если что-то пойдет не так, мы вам сообщим 👌") - - current_messages = [] - if info.get("ready_to_answer"): - for message in info["ready_to_answer"]: - current_messages.append(message) - - if not info.get("set_provider"): - info["set_provider"] = None - - current_messages.append({"role": "user", "content": msg.text}) - - response = "" - try: - response = await g4f.ChatCompletion.create_async( - model=info["set_model"], - messages=current_messages, - provider=None if info["set_provider"] is None else providers[info["set_provider"]], - stream=False - ) - - except NameError or SyntaxError: - try: - response = g4f.ChatCompletion.create( - model=info["set_model"], - messages=current_messages, - provider=None if info["set_provider"] is None else providers[info["set_provider"]], - stream=False - ) - except Exception as S: - response = "Простите, произошла ошибка 😔\nЕсли это продолжается, пожалуйста используйте /cancel" - logging.log(msg=f"Get an exception for generating answer={S}", - level=logging.ERROR) - except Exception as S: - response = "Простите, произошла ошибка 😔\nЕсли это продолжается, пожалуйста используйте /cancel" - logging.log(msg=f"Get an exception for generating answer={S}", - level=logging.ERROR) - finally: - await reply.edit_text(text=response, reply_markup=text_response_keyboard(user_id=msg.from_user.id)) - current_messages.append({"role": "assistant", "content": response}) - await state.update_data(ready_to_answer=current_messages) - await state.set_state(AnsweringGPT4Free.ready_to_answer) - diff --git a/bozenka/instances/telegram/handlers/main/__init__.py b/bozenka/instances/telegram/handlers/main/__init__.py deleted file mode 100644 index 43f3947..0000000 --- a/bozenka/instances/telegram/handlers/main/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ - -import logging - -from aiogram import Router, F -from aiogram.enums import ContentType -from aiogram.filters import Command, CommandStart - -from bozenka.instances.telegram.handlers.main.setup import * -from bozenka.instances.telegram.handlers.main.start import * - - -def register_main_cmd(router: Router) -> None: - """ - Registers all commands related to basic commands or main commands in bot. - Don't require any special perms for bot in group. - :param router: - :return: - """ - logging.log(msg="Registering main related commands", level=logging.INFO) - - # Start command handler - """ - router.message.register(start_cmd, Command(commands=["start"]), F.chat.type == ChatType.PRIVATE) - """ - - router.message.register(start_cmd, *[Command(commands=["start"]), F.chat.type == ChatType.PRIVATE]) - - # Registering command /setup - router.message.register(setup_cmd, Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE)) - - # After adding to chat handler - router.message.register(group_adding_handler, F.content_type == ContentType.SUPERGROUP_CHAT_CREATED) - router.message.register(group_adding_handler, F.content_type == ContentType.GROUP_CHAT_CREATED) diff --git a/bozenka/instances/telegram/handlers/main/setup.py b/bozenka/instances/telegram/handlers/main/setup.py deleted file mode 100644 index 10881b5..0000000 --- a/bozenka/instances/telegram/handlers/main/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -from aiogram.types import Message as Message -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.instances.telegram.utils.simpler import SolutionSimpler -from bozenka.instances.telegram.utils.keyboards import setup_keyboard - - -async def setup_cmd(msg: Message): - """ - /setup handler - :param msg: - :param session: - :return: - """ - await msg.answer("Привет владелец чата 👋\n" - "Чтобы меня настроить, используй меню под данным сообщением", - reply_markup=setup_keyboard()) - - -async def group_adding_handler(msg: Message, session_maker: async_sessionmaker): - """ - Send message after adding bozenka into group chat - :param msg: - :param session_maker: - :return: - """ - await SolutionSimpler.auto_settings(msg=msg, session=session_maker) - await msg.answer("Здраствуйте администраторы чата 👋\n" - "Я - бозенька, мультифункциональный бот, разрабатываемый Bozo Developement\n" - "Выдайте мне полные права администратора для моей полной работы, если не выдали." - "Чтобы настроить функционал, используйте /setup или кнопку под сообщением") diff --git a/bozenka/instances/telegram/handlers/main/start.py b/bozenka/instances/telegram/handlers/main/start.py deleted file mode 100644 index 4462a1c..0000000 --- a/bozenka/instances/telegram/handlers/main/start.py +++ /dev/null @@ -1,36 +0,0 @@ -from aiogram.enums import ChatType -from aiogram.types import Message as Message -from aiogram.utils.keyboard import InlineKeyboardBuilder - -from bozenka.instances.telegram.utils.keyboards import help_keyboard, start_keyboard - - -async def start_cmd(msg: Message) -> None: - """ - /start command function handler - Shows menu and basic information about bozenka - :param msg: Message telegram object - :return: Nothing - """ - await msg.answer( - """ - Привет 👋 -Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах. - -Вот что ты можешь сделать с помощью меню: -• Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него. -• Функционал: показывает список доступных функций и команд, которые я могу выполнить. -• О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота. -• О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота. -• Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию. -• Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта - -Вот нужные ссылки обо мне: -• Канал с новостями об разработке -• Исходный код на Github - -Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже. -Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала. -Удачного использования! - """, - reply_markup=start_keyboard(), disable_web_page_preview=True) diff --git a/bozenka/instances/telegram/handlers/queries/__init__.py b/bozenka/instances/telegram/handlers/queries/__init__.py deleted file mode 100644 index ee5323b..0000000 --- a/bozenka/instances/telegram/handlers/queries/__init__.py +++ /dev/null @@ -1,128 +0,0 @@ -from aiogram import Router, F - -from bozenka.instances.telegram.handlers.queries.image_generation import inline_image_size, inline_image_ready -from bozenka.instances.telegram.handlers.queries.mute import * -from bozenka.instances.telegram.handlers.queries.start import * -from bozenka.instances.telegram.utils.callbacks_factory import * -from bozenka.instances.telegram.handlers.queries.ban import * -from bozenka.instances.telegram.handlers.queries.pins import * -from bozenka.instances.telegram.handlers.queries.threads import * -from bozenka.instances.telegram.handlers.queries.delete import * -from bozenka.instances.telegram.handlers.queries.revoke import * -from bozenka.instances.telegram.handlers.queries.text_generation import * -from bozenka.instances.telegram.handlers.queries.setup import * - - -def register_queries(router: Router) -> None: - """ - Register all callback queries. - :param router: - :return: - """ - logging.log(msg="Registering callback queries", level=logging.INFO) - - # Moderation - # Ban / Unban buttons reactions - router.callback_query.register(inline_ban, BanData.filter()) - router.callback_query.register(inline_unban, UnbanData.filter()) - - # Mute / Un,ute buttons reactions - router.callback_query.register(inline_mute, MuteData.filter()) - router.callback_query.register(inline_unmute, UnmuteData.filter()) - - # Revoke telegram invite link button - router.callback_query.register(inline_revoke, RevokeCallbackData.filter()) - # Delete button message reaction - router.callback_query.register(inline_delete, DeleteMenu.filter()) - - # Threads (Close/Open) - router.callback_query.register(inline_close_thread, CloseThread.filter()) - router.callback_query.register(inline_open_thread, OpenThread.filter()) - - # Pins (Pin/Unpin) - router.callback_query.register(inline_pin_msg, PinMsg.filter()) - router.callback_query.register(inline_unpin_msg, UnpinMsg.filter()) - - # GPT Related queries - - # Back to gpt categories - router.callback_query.register(inline_start_gpt, GptBackMenu.filter(F.back_to == "category")) - - # Gpt4Free menus (Providers/Models) - router.callback_query.register(inline_g4f_categories, GptCategory.filter(F.category == "Gpt4Free")) - router.callback_query.register(inline_g4f_categories, GptBackMenu.filter(F.back_to == "g4fcategory")) - - router.callback_query.register(inline_g4f_provider_models, Gpt4FreeProvider.filter()) - - router.callback_query.register(inline_g4f_models, Gpt4FreeCategory.filter(F.category == "models")) - router.callback_query.register(inline_g4f_providers, Gpt4FreeCategory.filter(F.category == "providers")) - - router.callback_query.register(inline_g4f_model_select, Gpt4FreeModel.filter()) - router.callback_query.register(inline_g4f_next_models, Gpt4FreeModelPage.filter()) - - # Get back to menu state - router.callback_query.register(inline_g4f_providers_back, GptBackMenu.filter(F.back_to == "providers")) - - # Generates next pages (Providers/Models) - router.callback_query.register(inline_next_g4f_models, Gpt4FreeProvsModelPage.filter(), flags={"rate_limit": {"rate": 5}}) - router.callback_query.register(inline_next_g4f_providers, Gpt4FreeProviderPage.filter(), - flags={"rate_limit": {"rate": 5}}) - - # Help information (for page button under menu) - router.callback_query.register(inline_return_pages, F.data == "gotpages") - router.callback_query.register(inline_g4f_ready, Gpt4freeResult.filter()) - - # Image generation menu - # Size setting - router.callback_query.register(inline_image_size, ImageGenerationCategory.filter()) - - # Ready status - router.callback_query.register(inline_image_ready, ImageGeneration.filter()) - - # Gpt4All menus - # Gpt4All model menu - router.callback_query.register(inline_g4a, GptCategory.filter(F.category == "Gpt4All")) - - # Gpt4All back - router.callback_query.register(inline_g4a_back, GptBackMenu.filter(F.back_to == "g4amodels")) - - # Gpt4All selected model menu - router.callback_query.register(inline_g4a_model, Gpt4AllModel.filter()) - router.callback_query.register(inline_g4a_select_model, Gpt4AllSelect.filter()) - - # Stop dialog button under gpt message answer - router.callback_query.register(inline_stop_dialog, GptStop.filter()) - - # /setup command related queries - # List of features based on category - router.callback_query.register(inline_setup_category, SetupCategory.filter()) - - # Menu of feature to enable or disable - router.callback_query.register(inline_edit_feature, SetupFeature.filter()) - router.callback_query.register(inline_feature_edited, SetupAction.filter(F.action == "enable")) - router.callback_query.register(inline_feature_edited, SetupAction.filter(F.action == "disable")) - - # Back from feature to category - router.callback_query.register(inline_setup_category_back, SetupAction.filter(F.action == "back")) - - # /start command related queries - # Help of features based on category - router.callback_query.register(inline_help_features, HelpCategory.filter()) - router.callback_query.register(inline_back_help_categories, HelpBack.filter(F.back_to == "category")) - router.callback_query.register(inline_back_help_features, HelpBackCategory.filter()) - - # Menu to back - router.callback_query.register(inline_help_feature, HelpFeature.filter()) - - # Back to /start - router.callback_query.register(inline_start, F.data == "back") - - # Categories of menu - router.callback_query.register(inline_about_developers, F.data == "aboutdevs") - router.callback_query.register(inline_add_to_chat, F.data == "addtochat") - router.callback_query.register(inline_start_chatbot, F.data == "dialogai") - router.callback_query.register(inline_help, F.data == "functional") - router.callback_query.register(inline_about_instance, F.data == "aboutbot") - - - diff --git a/bozenka/instances/telegram/handlers/queries/ban.py b/bozenka/instances/telegram/handlers/queries/ban.py deleted file mode 100644 index 667296c..0000000 --- a/bozenka/instances/telegram/handlers/queries/ban.py +++ /dev/null @@ -1,67 +0,0 @@ -import logging - -from aiogram import types -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.instances.telegram.utils.callbacks_factory import BanData, UnbanData -from aiogram.enums import ChatMemberStatus - -from bozenka.instances.telegram.utils.keyboards import ban_keyboard, unban_keyboard -from bozenka.instances.telegram.utils.simpler import SolutionSimpler - - -async def inline_ban(call: types.CallbackQuery, callback_data: BanData, session_maker: async_sessionmaker) -> None: - """ - Query, what bannes users after callback - :param call: CallBackQuery telegram object - :param callback_data: BanData object - :param session_maker: AsyncSessionmaker object - :return: - """ - clicked_user = await call.message.chat.get_member(call.from_user.id) - banned_user = await call.message.chat.get_member(int(callback_data.user_id_ban)) - - if call.from_user.id != callback_data.user_id_clicked \ - and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: - return - await SolutionSimpler.inline_ban_user(call=call, data=callback_data, session=session_maker) - - if not banned_user.is_member and banned_user.status == ChatMemberStatus.KICKED: - await call.answer("Уже заблокирован ✅") - else: - await call.answer("Успешно заблокирован ✅") - - await call.message.edit_text( - "Удача ✅\n" - f"{banned_user.user.mention_html('Этот пользователь')} был заблокирован {call.from_user.mention_html('этим пользователем')}.", - reply_markup=ban_keyboard(admin_id=call.from_user.id, ban_id=banned_user.user.id) - ) - logging.log(msg=f"Banned user @{banned_user.user.full_name} user_id=f{banned_user.user.id}", level=logging.INFO) - - -async def inline_unban(call: types.CallbackQuery, callback_data: UnbanData, session_maker: async_sessionmaker) -> None: - """ - Query, what unbannes users after callback - :param call: CallBackQuery telegram object - :param callback_data: UnbanData object - :param session_maker: AsyncSessionmaker object - :return: - """ - clicked_user = await call.message.chat.get_member(call.from_user.id) - unbanned_user = await call.message.chat.get_member(int(callback_data.user_id_unban)) - if call.from_user.id != callback_data.user_id_clicked \ - and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: - return - - await SolutionSimpler.inline_unban_user(call=call, data=callback_data, session=session_maker) - - if unbanned_user.is_member and unbanned_user.status != ChatMemberStatus.KICKED: - await call.answer("Уже разблокирован ✅") - else: - await call.answer("Успешно разблокирован ✅") - await call.message.edit_text( - "Удача ✅\n" - f"{unbanned_user.user.mention_html('Этот пользователь')} был разблокирован {call.from_user.mention_html('этим пользователем')}.", - reply_markup=unban_keyboard(admin_id=call.from_user.id, ban_id=unbanned_user.user.id) - ) - logging.log(msg=f"Unbanned user @{unbanned_user.user.full_name} user_id=f{unbanned_user.user.id}", level=logging.INFO) diff --git a/bozenka/instances/telegram/handlers/queries/delete.py b/bozenka/instances/telegram/handlers/queries/delete.py deleted file mode 100644 index 20f24cf..0000000 --- a/bozenka/instances/telegram/handlers/queries/delete.py +++ /dev/null @@ -1,21 +0,0 @@ -import logging - -from aiogram import types - -from bozenka.instances.telegram.utils.callbacks_factory import DeleteMenu -from aiogram.enums import ChatMemberStatus - - -async def inline_delete(call: types.CallbackQuery, callback_data: DeleteMenu) -> None: - """ - Deletes messsage, after special callback - :param call: - :param callback_data: - :return: - """ - user_clicked = await call.message.chat.get_member(call.from_user.id) - if call.from_user.id == callback_data.user_id_clicked or user_clicked.status == ChatMemberStatus.ADMINISTRATOR: - await call.answer("Хорошо ✅") - logging.log(msg=f"Deleted message with message_id={call.message.message_id}", - level=logging.INFO) - await call.message.delete() diff --git a/bozenka/instances/telegram/handlers/queries/image_generation.py b/bozenka/instances/telegram/handlers/queries/image_generation.py deleted file mode 100644 index 01eb78d..0000000 --- a/bozenka/instances/telegram/handlers/queries/image_generation.py +++ /dev/null @@ -1,60 +0,0 @@ -import logging - -from aiogram import types -from aiogram.fsm.context import FSMContext -from gpt4all import GPT4All - -from bozenka.instances.telegram.utils.simpler.fsm_states import * - -# Callbacks for GPT -from bozenka.instances.telegram.utils.callbacks_factory import ( - ImageGeneration, - ImageGenerationCategory -) -# Keyboards for messages -from bozenka.instances.telegram.utils.keyboards import ( - gpt4free_models_by_provider_keyboard, - gpt4free_providers_keyboard, - delete_keyboard, gpt_categories_keyboard, generate_gpt4all_page, gpt4all_model_menu, image_resolution_keyboard -) -# Simpler utlilities -from bozenka.instances.telegram.utils.simpler import ( - AnsweringGPT4Free, - AnsweringGpt4All, -) - - -async def inline_image_size(call: types.CallbackQuery, callback_data: ImageGenerationCategory, state: FSMContext) -> None: - """ - Query, what shows menu for image size to generate in - :param call: - :param callback_data: - :param state: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - await state.update_data(set_category=callback_data.category) - await state.set_state(GeneratingImages.set_size) - await call.message.edit_text("Пожалуста, выберите размер изображения 🖼", - reply_markup=image_resolution_keyboard(user_id=call.from_user.id, - category=callback_data.category)) - - -async def inline_image_ready(call: types.CallbackQuery, callback_data: ImageGeneration, state: FSMContext) -> None: - """ - Query, what shows menu for image size to generate in - :param call: - :param callback_data: - :param state: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - await state.update_data(set_size=callback_data.size) - await state.set_state(GeneratingImages.ready_to_generate) - await call.message.edit_text(f"Вы выбрали {callback_data.category} для генерации изображений в размере {callback_data.size}.\n" - "Напишите /cancel для отмены", - reply_markup=delete_keyboard(admin_id=call.from_user.id)) - diff --git a/bozenka/instances/telegram/handlers/queries/mute.py b/bozenka/instances/telegram/handlers/queries/mute.py deleted file mode 100644 index 92c1f43..0000000 --- a/bozenka/instances/telegram/handlers/queries/mute.py +++ /dev/null @@ -1,67 +0,0 @@ -import logging - -from aiogram import types -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.instances.telegram.utils.callbacks_factory import UnmuteData, MuteData -from aiogram.enums import ChatMemberStatus - -from bozenka.instances.telegram.utils.keyboards import ban_keyboard, unban_keyboard, mute_keyboard, unmute_keyboard -from bozenka.instances.telegram.utils.simpler import SolutionSimpler - - -async def inline_mute(call: types.CallbackQuery, callback_data: MuteData, session_maker: async_sessionmaker) -> None: - """ - Query, what mutes users after callback - :param call: CallBackQuery telegram object - :param callback_data: BanData object - :param session_maker: AsyncSessionmaker object - :return: - """ - clicked_user = await call.message.chat.get_member(call.from_user.id) - muted_user = await call.message.chat.get_member(int(callback_data.user_id_mute)) - - if call.from_user.id != callback_data.user_id_clicked \ - and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: - return - await SolutionSimpler.inline_mute_user(call=call, data=callback_data, session=session_maker) - - if not muted_user.can_send_messages and muted_user.status == ChatMemberStatus.RESTRICTED: - await call.answer("Уже замучен ✅") - else: - await call.answer("Успешно замучен ✅") - - await call.message.edit_text( - "Удача ✅\n" - f"{muted_user.user.mention_html('Этот пользователь')} был замучен {call.from_user.mention_html('этим пользователем')}.", - reply_markup=mute_keyboard(admin_id=call.from_user.id, mute_id=callback_data.user_id_mute) - ) - logging.log(msg=f"Banned user @{muted_user.user.full_name} user_id=f{muted_user.user.id}", level=logging.INFO) - - -async def inline_unmute(call: types.CallbackQuery, callback_data: UnmuteData, session_maker: async_sessionmaker) -> None: - """ - Query, what unbannes users after callback - :param call: CallBackQuery telegram object - :param callback_data: UnbanData object - :param session_maker: AsyncSessionmaker object - :return: - """ - clicked_user = await call.message.chat.get_member(call.from_user.id) - unmuted_user = await call.message.chat.get_member(int(callback_data.user_id_unmute)) - if call.from_user.id != callback_data.user_id_clicked \ - and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: - return - - await SolutionSimpler.inline_unmute_user(call=call, data=callback_data, session=session_maker) - - if unmuted_user.can_send_messages or unmuted_user.status == ChatMemberStatus.RESTRICTED: - await call.answer("Уже размучен ✅") - else: - await call.answer("Успешно размучен ✅") - await call.message.edit_text( - "Удача ✅\n" - f"{unmuted_user.user.mention_html('Этот пользователь')} был размучен {call.from_user.mention_html('этим пользователем')}.", - reply_markup=unmute_keyboard(admin_id=call.from_user.id, unmute_id=unmuted_user.user.id) - ) - logging.log(msg=f"Unbanned user @{unmuted_user.user.full_name} user_id=f{unmuted_user.user.id}", level=logging.INFO) diff --git a/bozenka/instances/telegram/handlers/queries/pins.py b/bozenka/instances/telegram/handlers/queries/pins.py deleted file mode 100644 index 599a03e..0000000 --- a/bozenka/instances/telegram/handlers/queries/pins.py +++ /dev/null @@ -1,36 +0,0 @@ -from aiogram import types - -from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg -from bozenka.instances.telegram.utils.keyboards import unpin_msg_keyboard, pin_msg_keyboard - - -async def inline_pin_msg(call: types.CallbackQuery, callback_data: PinMsg) -> None: - """ - Query, what pins message - :param call: - :param callback_data: - :return: - """ - if callback_data.user_id == call.from_user.id: - return - - await call.message.chat.pin_message(message_id=callback_data.msg_id) - await call.message.edit_text("Удача ✅\n" - "Сообщение было закреплено 📌", - reply_markup=pin_msg_keyboard(user_id=call.from_user.id, msg_id=callback_data.msg_id)) - - -async def inline_unpin_msg(call: types.CallbackQuery, callback_data: UnpinMsg) -> None: - """ - Query, what unpins message - :param call: - :param callback_data: - :return: - """ - if callback_data.user_id == call.from_user.id: - return - - await call.message.chat.pin_message(message_id=callback_data.msg_id) - await call.message.edit_text("Удача ✅\n" - "Сообщение было откреплено 📌", - reply_markup=unpin_msg_keyboard(user_id=call.from_user.id, msg_id=callback_data.msg_id)) diff --git a/bozenka/instances/telegram/handlers/queries/revoke.py b/bozenka/instances/telegram/handlers/queries/revoke.py deleted file mode 100644 index 09601fc..0000000 --- a/bozenka/instances/telegram/handlers/queries/revoke.py +++ /dev/null @@ -1,24 +0,0 @@ -import logging - -from aiogram import types - -from bozenka.instances.telegram.utils.callbacks_factory import RevokeCallbackData -from aiogram.enums import ChatMemberStatus - -from bozenka.instances.telegram.utils.simpler import ru_cmds - - -async def inline_revoke(call: types.CallbackQuery, callback_data: RevokeCallbackData): - """ - Revokes invite link - :param call: - :param callback_data: - :return: - """ - user_clicked = await call.message.chat.get_member(call.from_user.id) - if callback_data.admin_id == call.from_user.id or user_clicked.status == ChatMemberStatus.ADMINISTRATOR or user_clicked.status == ChatMemberStatus.CREATOR: - logging.log(msg=f"Revoking link for user_id={call.from_user.id}", - level=logging.INFO) - await call.message.chat.revoke_invite_link(invite_link="https://" + str(callback_data.link)) - await call.answer("Удача ✅") - await call.message.delete() diff --git a/bozenka/instances/telegram/handlers/queries/setup.py b/bozenka/instances/telegram/handlers/queries/setup.py deleted file mode 100644 index 715ad81..0000000 --- a/bozenka/instances/telegram/handlers/queries/setup.py +++ /dev/null @@ -1,73 +0,0 @@ -from aiogram.types import CallbackQuery, Message -from sqlalchemy import select, Update -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.database.tables.telegram import TelegramChatSettings, get_chat_config_value -from bozenka.instances.telegram.utils.callbacks_factory import SetupCategory, SetupFeature, SetupAction -from bozenka.instances.telegram.utils.keyboards import setup_category_keyboard, setup_feature_keyboard -from bozenka.instances.telegram.utils.simpler import list_of_features - - -async def inline_setup_category(call: CallbackQuery, callback_data: SetupCategory): - """ - Query, what shows list of features to enable. - :param call: - :param callback_data: - :return: - """ - await call.message.edit_text("Выберите настройку, которую хотите изменить", - reply_markup=setup_category_keyboard(category=callback_data.category_name)) - - -async def inline_setup_category_back(call: CallbackQuery, callback_data: SetupAction): - """ - Query, what shows list of features to enable. - :param call: - :param callback_data: - :return: - """ - await call.message.edit_text("Выберите настройку, которую хотите изменить", - reply_markup=setup_category_keyboard(category=callback_data.category_name)) - - -async def inline_edit_feature(call: CallbackQuery, callback_data: SetupFeature, session_maker: async_sessionmaker): - """ - Query, what shows menu to enable / disable feature - :param call: - :param callback_data: - :param session_maker: - :return: - """ - is_enabled = await get_chat_config_value( - chat_id=call.message.chat.id, - session=session_maker, - setting=list_of_features[callback_data.feature_category][callback_data.feature_index] - ) - - await call.message.edit_text( - list_of_features[callback_data.feature_category][callback_data.feature_index].description, - reply_markup=await setup_feature_keyboard(category=callback_data.feature_category, - index=callback_data.feature_index, - is_enabled=is_enabled)) - - -async def inline_feature_edited(call: CallbackQuery, callback_data: SetupAction, session_maker: async_sessionmaker): - """ - Query, what shows menu to enable / disable feature - after editing - :param call: - :param callback_data: - :param session_maker: - :return: - """ - async with session_maker() as session: - async with session.begin(): - await session.execute(Update(TelegramChatSettings) - .values({list_of_features[callback_data.category_name][callback_data.feature_index].settings_name: - callback_data.action == "enable"}) - .where(TelegramChatSettings.chat_id == call.message.chat.id)) - await call.message.edit_text( - list_of_features[callback_data.category_name][callback_data.feature_index].description, - reply_markup=await setup_feature_keyboard(category=callback_data.category_name, - index=callback_data.feature_index, - is_enabled=callback_data.action == "enable")) diff --git a/bozenka/instances/telegram/handlers/queries/start.py b/bozenka/instances/telegram/handlers/queries/start.py deleted file mode 100644 index b114f49..0000000 --- a/bozenka/instances/telegram/handlers/queries/start.py +++ /dev/null @@ -1,168 +0,0 @@ -import git - -from aiogram.types import * - -from bozenka.instances.telegram.utils.callbacks_factory import * -from bozenka.instances.telegram.utils.keyboards import * -from bozenka.instances.telegram.utils.simpler import list_of_features -from bozenka.instances.version import is_updated, build - - -async def inline_start(call: CallbackQuery): - """ - Query, what shows back menu of /start - :param call: - :return: - """ - await call.message.edit_text( - """ - Привет 👋 -Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах. - -Вот что ты можешь сделать с помощью меню: -• Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него. -• Функционал: показывает список доступных функций и команд, которые я могу выполнить. -• О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота. -• О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота. -• Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию. -• Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта - -Вот нужные ссылки обо мне: -• Канал с новостями об разработке -• Исходный код на Github - -Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже. -Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала. -Удачного использования! - """, - reply_markup=start_keyboard(), - disable_web_page_preview=True - ) - - -async def inline_start_chatbot(call: CallbackQuery): - """ - Query, what shows list of Categories, avaible to use as chatbot - :param call: - :return: - """ - await call.message.edit_text("Пожалуста, выберите сервиc / библиотеку, через которую вы будете общаться", - reply_markup=gpt_categories_keyboard - (user_id=call.from_user.id)) - - -async def inline_help(call: CallbackQuery): - """ - Query, what shows information about bozenka and it's development - :param call: - :return: - """ - await call.message.edit_text("Выберите категорию, по которой нужна помощь:", - reply_markup=help_keyboard()) - - -async def inline_about_developers(call: CallbackQuery): - """ - Query, what shows information about bozenka and it's development - :param call: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Вернуться 🔙", callback_data="back") - ]]) - await call.message.edit_text(""" -Бозенька - это мультифункциональный (в будущем кроссплатформенный) бот.\n -Он умеет работать с групповыми чатами и готовыми нейронными сетями для генерации текста и изображений. -Бозенька разрабатывается коммандой, которая состоит на данный момент из одного человека.\n -Исходный код проекта\n -Исходный код находится под лицензией GPL-3.0, исходный код проекта можно посмотреть всегда здесь -Канал с новостями разработки находится здесь - """, reply_markup=kb, disable_web_page_preview=True) - - -async def inline_about_instance(call: CallbackQuery): - """ - Query, what shows information about runned instance - :param call: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Вернуться 🔙", callback_data="back") - ]]) - me = await call.message.bot.get_me() - update_status = {False: "требуется обновление бота 🔼", - True: "обновление не требуется, последняя версия ✅"} - await call.message.edit_text( - f"Информация об данном запущенном экземпляре бозеньки:\n" - f"Аккаунт бота: {me.mention_html()}\n" - f"Запущенная версия бота {build}\n", - f"Нужно ли обновление: {update_status[is_updated]}", - reply_markup=kb) - - -async def inline_add_to_chat(call: CallbackQuery): - """ - Query, what shows a link to add bozenka into user chat - :param call: - :return: - """ - # Getting bot - me = await call.message.bot.me() - - # Generating special keyboard - kb = InlineKeyboardBuilder() - kb.button(text="Добавить в ваш груповой чат 🔌", - url="https://t.me/" - f"{me.username}?" - "startgroup&" - "admin=promote_members+delete_messages+restrict_members+invite_users+pin_messages+manage_video_chats") - kb.row(InlineKeyboardButton(text="Вернуться 🔙", callback_data="back")) - - # Answering - await call.message.edit_text("Чтобы добавить бозеньку в ваш групповой чат, нажмите на кнопку под сообщением:", - reply_markup=kb.as_markup()) - - -async def inline_help_features(call: CallbackQuery, callback_data: HelpCategory): - """ - Query, what shows list of features to get support. - :param call: - :param callback_data: - :return: - """ - await call.message.edit_text("Выберите функцию, по которой нужна помощь", - reply_markup=help_category_keyboard(category=callback_data.category_name)) - - -async def inline_back_help_features(call: CallbackQuery, callback_data: HelpBackCategory): - """ - Query, what shows list of features to get support. - :param call: - :param callback_data: - :return: - """ - await call.message.edit_text("Выберите функцию, по которой нужна помощь", - reply_markup=help_category_keyboard(category=callback_data.back_to_category)) - - -async def inline_back_help_categories(call: CallbackQuery, callback_data: HelpBack): - """ - Query, what shows list of features to get support back. - :param call: - :param callback_data: - :return: - """ - await call.message.edit_text("Выберите категорию, по которой нужна помощь:", - reply_markup=help_keyboard()) - - -async def inline_help_feature(call: CallbackQuery, callback_data: HelpFeature): - """ - Query, what shows list of features to get support. - :param call: - :param callback_data: - :return: - """ - await call.message.edit_text( - list_of_features[callback_data.feature_category][callback_data.feature_index].description, - reply_markup=help_feature_keyboard(category=callback_data.feature_category)) diff --git a/bozenka/instances/telegram/handlers/queries/text_generation.py b/bozenka/instances/telegram/handlers/queries/text_generation.py deleted file mode 100644 index 1475141..0000000 --- a/bozenka/instances/telegram/handlers/queries/text_generation.py +++ /dev/null @@ -1,358 +0,0 @@ -import logging - -from aiogram import types -from aiogram.fsm.context import FSMContext -from gpt4all import GPT4All - -from bozenka.instances.telegram.utils.simpler.fsm_states import * - -# Callbacks for GPT -from bozenka.instances.telegram.utils.callbacks_factory import ( - GptCategory, - Gpt4FreeProvider, - Gpt4freeResult, - Gpt4FreeProviderPage, - Gpt4FreeProvsModelPage, GptStop, GptBackMenu, Gpt4AllModel, Gpt4AllSelect, Gpt4FreeCategory, Gpt4FreeModelPage, - Gpt4FreeModel -) -# Keyboards for messages -from bozenka.instances.telegram.utils.keyboards import ( - gpt4free_models_by_provider_keyboard, - gpt4free_providers_keyboard, - delete_keyboard, gpt_categories_keyboard, generate_gpt4all_page, gpt4all_model_menu, gpt4free_categories_keyboard, - gpt4free_models_keyboard -) -# Simpler utlilities -from bozenka.instances.telegram.utils.simpler import ( - AnsweringGPT4Free, - AnsweringGpt4All, -) - - -async def inline_start_gpt(call: types.CallbackQuery, callback_data: GptBackMenu, state: FSMContext) -> None: - """ - Query, what shows when clicking on button in /start menu - :param call: - :param state: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - await call.message.edit_text("Пожалуста, выберите сервис для ИИ.", - reply_markup=gpt_categories_keyboard(user_id=call.from_user.id)) - - -async def inline_g4f_providers(call: types.CallbackQuery, callback_data: Gpt4FreeCategory, state: FSMContext) -> None: - """ - Query, what creating providers selecting menu. - :param state: - :param call: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - logging.log(msg=f"Selected gpt4free category by user_id={call.from_user.id}", - level=logging.INFO) - - await call.answer("Вы выбрали провайдеры 🤖") - - await state.set_state(AnsweringGPT4Free.set_provider) - await call.message.edit_text("Выберите пожалуйста одного из провайдеров 👨‍💻", - reply_markup=gpt4free_providers_keyboard(user_id=call.from_user.id, page=0)) - - -async def inline_g4f_models(call: types.CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: - """ - Query, what creating models selecting menu - :param state: - :param call: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - await state.set_state(AnsweringGPT4Free.set_model) - - await call.answer("Вы выбрали модели 🤖") - - await call.message.edit_text("Выберите модель, с которой будете общаться 🤖", - reply_markup=gpt4free_models_keyboard(user_id=call.from_user.id, page=0)) - - -async def inline_g4f_model_select(call: types.CallbackQuery, callback_data: Gpt4FreeModel, state: FSMContext): - """ - Query, what ending model selecting - :param call: - :param callback_data: - :param state: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - await state.update_data(set_model=callback_data.model) - await state.set_state(AnsweringGPT4Free.ready_to_answer) - - await call.answer("Вы можете начать общаться 🤖") - - await call.message.edit_text("Удача ✅\n" - "Вы теперь можете спокойно вести диалог 🤖\n" - f"Вы выбрали модель {callback_data.model}👾\n" - "Чтобы прекратить общение, используйте /cancel ", reply_markup=delete_keyboard(admin_id=call.from_user.id)) - - -async def inline_g4f_next_models(call: types.CallbackQuery, callback_data: Gpt4FreeModelPage, state: FSMContext) -> None: - """ - Query, what creating models selecting menu - :param state: - :param call: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - await call.answer(f"Вы перелистнули на страницу {callback_data.page + 1}📄") - - await call.message.edit_text("Выберите модель, с которой будете общаться 🤖", - reply_markup=gpt4free_models_keyboard(user_id=call.from_user.id, page=callback_data.page)) - - -async def inline_g4f_categories(call: types.CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: - """ - Query, what creating providers selecting menu. - :param state: - :param call: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - logging.log(msg=f"Selected gpt4free category by user_id={call.from_user.id}", - level=logging.INFO) - - await state.update_data(set_category=callback_data.category) - await call.answer("Вы выбрали Gpt4Free 🤖") - await call.message.edit_text("Выберите, по какому пункту мы будем вести диалог с нейронной сети 🤖", - reply_markup=gpt4free_categories_keyboard(user_id=call.from_user.id)) - await call.answer("Выберите, по какому пункту мы будем вести диалог с нейронной сети 🤖") - - -async def inline_g4f_providers_back(call: types.CallbackQuery, callback_data: GptBackMenu, state: FSMContext) -> None: - """ - Query, what creating providers selecting menu. - :param state: - :param call: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - logging.log(msg=f"Back to providers menu by user_id={call.from_user.id}", - level=logging.INFO) - await state.set_state(AnsweringGPT4Free.set_provider) - - await call.message.edit_text("Выберите пожалуйста одного из провайдеров 👨‍💻", - reply_markup=gpt4free_providers_keyboard(page=0, user_id=callback_data.user_id)) - await call.answer("Выберите пожалуйста одного из провайдеров 👨‍💻") - - -async def inline_g4f_provider_models(call: types.CallbackQuery, callback_data: Gpt4FreeProvider, state: FSMContext) -> None: - """ - Query, what creating models selecting menu. - :param state: - :param call: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - logging.log(msg=f"Selected gpt4free provider {callback_data.provider} by user_id={call.from_user.id}", - level=logging.INFO) - - await state.update_data(set_provider=callback_data.provider) - await state.set_state(AnsweringGPT4Free.set_model) - - await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", reply_markup=gpt4free_models_by_provider_keyboard( - user_id=callback_data.user_id, - provider=callback_data.provider, - page=0 - )) - await call.answer("Выберите пожалуйста модель ИИ 👾") - - -async def inline_g4f_ready(call: types.CallbackQuery, callback_data: Gpt4freeResult, state: FSMContext) -> None: - """ - Query, what says about getting ready to questions for ChatGPT from Gpt4Free. - :param state: - :param call: - :param callback_data: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - - logging.log(msg=f"Selected gpt4free model {callback_data.model} by user_id={call.from_user.id}", - level=logging.INFO) - - await state.update_data(set_model=callback_data.model) - await state.set_state(AnsweringGPT4Free.ready_to_answer) - - logging.log(msg=f"Loaded GPT answering status for user_id={call.from_user.id}", - level=logging.INFO) - - await call.message.edit_text("Удача ✅\n" - "Вы теперь можете спокойно вести диалог 🤖\n" - f"Вы выбрали модель {callback_data.model}👾, от провайдера {callback_data.provider}👨‍💻\n" - "Чтобы прекратить общение, используйте /cancel ", - reply_markup=delete_keyboard(admin_id=callback_data.user_id)) - await call.answer("Вы теперь можете спокойно вести диалог 🤖") - - -async def inline_g4a(call: types.CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: - """ - Query, what shows list for gpt4all models - :param call: - :param callback_data: - :param state: - :return: - """ - if callback_data.user_id != call.from_user.id: - return - await state.set_state(AnsweringGpt4All.set_model) - await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", - reply_markup=generate_gpt4all_page(user_id=call.from_user.id)) - - -async def inline_g4a_back(call: types.CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: - """ - Query, what shows list for gpt4all models back - :param call: - :param callback_data: - :param state: - :return: - """ - if callback_data.user_id != call.from_user.id: - return - await state.set_state(AnsweringGpt4All.set_model) - await call.message.edit_text("Выберите пожалуйста модель ИИ 👾", - reply_markup=generate_gpt4all_page(user_id=call.from_user.id)) - - -async def inline_g4a_model(call: types.CallbackQuery, callback_data: Gpt4AllModel, state: FSMContext) -> None: - """ - Query, what show information about clicked gpt4all model from list - :param call: - :param callback_data: - :param state: - :return: - """ - if callback_data.user_id != call.from_user.id: - return - models = GPT4All.list_models() - name = models[callback_data.index]['name'] - await call.message.edit_text(f"{name}\n" - f"Обученно на основе {models[callback_data.index]['parameters']} строк 👨‍💻", - reply_markup=gpt4all_model_menu(user_id=call.from_user.id, index=callback_data.index)) - - -async def inline_g4a_select_model(call: types.CallbackQuery, callback_data: Gpt4AllSelect, state: FSMContext) -> None: - """ - Query, what says about getting ready for question for Gpt4All model - :param call: - :param callback_data: - :param state: - :return: - """ - if callback_data.user_id != call.from_user.id: - return - await state.update_data(set_model=callback_data.index) - await state.set_state(AnsweringGpt4All.ready_to_answer) - models = GPT4All.list_models() - - await call.message.edit_text("Удача ✅\n" - "Вы теперь можете спокойно вести диалог 🤖\n" - f"Вы выбрали модель {models[callback_data.index]['name']}👾 от Gpt4All\n" - "Чтобы прекратить общение, используйте /cancel ", - reply_markup=delete_keyboard(admin_id=callback_data.user_id)) - - -async def inline_next_g4f_providers(call: types.CallbackQuery, callback_data: Gpt4FreeProviderPage, - state: FSMContext) -> None: - """ - Query, what generates a next page of providers for user - :param call: - :param callback_data: - :param state: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - logging.log(msg=f"Changed page to {str(callback_data.page + 1)} user_id={call.from_user.id}", - level=logging.INFO) - await call.message.edit_text(call.message.text, - reply_markup=gpt4free_providers_keyboard(user_id=callback_data.user_id, - page=callback_data.page)) - await call.answer(f"Вы перелистнули на страницу {callback_data.page + 1}📄") - - -async def inline_next_g4f_models(call: types.CallbackQuery, callback_data: Gpt4FreeProvsModelPage, - state: FSMContext) -> None: - """ - Query, what generates a next page of models for user. - :param call: - :param callback_data: - :param state: - :return: - """ - if call.from_user.id != callback_data.user_id: - return - logging.log(msg=f"Changed page to {str(callback_data.page + 1)} user_id={call.from_user.id}", - level=logging.INFO) - await call.message.edit_text(call.message.text, - reply_markup=gpt4free_models_by_provider_keyboard( - user_id=callback_data.user_id, - provider=callback_data.provider, - page=callback_data.page - )) - await call.answer(f"Вы перелистали на страницу {callback_data.page + 1}📄") - - -async def inline_return_pages(call: types.CallbackQuery) -> None: - """ - Query, made for helping purposes. - Shows current page. - :param call: - :return: - """ - logging.log(msg=f"Showed helping info for user_id={call.from_user.id}", - level=logging.INFO) - await call.answer("Здесь расположается текущая странница 📃") - - -async def inline_stop_dialog(call: types.CallbackQuery, callback_data: GptStop, state: FSMContext) -> None: - """ - Query, what stops dialog - :param call: - :param callback_data: - :param state: - """ - # Checking user_id of user - if callback_data.user_id != call.from_user.id: - return - # Clearing state - await state.clear() - # Answering something - await call.answer("Хорошо ✅") - if await state.get_state() == AnsweringGPT4Free.ready_to_answer or await state.get_state() == AnsweringGpt4All.answering: - await call.message.edit_text(text=call.message.text + "\n\nДиалог остановлен ✅\n", - reply_markup=delete_keyboard(admin_id=call.from_user.id)) - else: - await call.message.delete() diff --git a/bozenka/instances/telegram/handlers/queries/threads.py b/bozenka/instances/telegram/handlers/queries/threads.py deleted file mode 100644 index 4ca6993..0000000 --- a/bozenka/instances/telegram/handlers/queries/threads.py +++ /dev/null @@ -1,41 +0,0 @@ -from aiogram import types - -from bozenka.instances.telegram.utils.callbacks_factory import CloseThread, OpenThread -from bozenka.instances.telegram.utils.keyboards import open_thread_keyboard, close_thread_keyboard, delete_keyboard -from bozenka.instances.telegram.utils.simpler import SolutionSimpler - - -async def inline_close_thread(call: types.CallbackQuery, callback_data: CloseThread) -> None: - """ - Query, what close thread - :param call: - :param callback_data: - :return: - """ - - if callback_data.user_id != call.from_user.id or not call.message.chat.is_forum: - return - config = await SolutionSimpler.close_topic(msg=call.message, call=call) - await call.message.edit_text( - config[0], - reply_markup=close_thread_keyboard(user_id=call.from_user.id) if config[1] else - delete_keyboard(admin_id=call.from_user.id) - ) - - -async def inline_open_thread(call: types.CallbackQuery, callback_data: OpenThread) -> None: - """ - Query, what opens thread - :param call: - :param callback_data: - :return: - """ - - if callback_data.user_id != call.from_user.id or not call.message.chat.is_forum: - return - config = await SolutionSimpler.open_topic(msg=call.message, call=call) - await call.message.edit_text( - config[0], - reply_markup=open_thread_keyboard(user_id=call.from_user.id) if config[1] else - delete_keyboard(admin_id=call.from_user.id) - ) -- 2.30.2 From 405c5f3cc1cb0aabd96b843a0c49ec12ab026f89 Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Sun, 11 Feb 2024 16:18:01 +0300 Subject: [PATCH 07/13] Final recode of project --- bozenka/features/__init__.py | 16 ++++-- bozenka/features/admin/__init__.py | 5 +- bozenka/features/admin/information.py | 51 +++++++++++++++++++ .../admin/{invite.py => invite_generation.py} | 1 + bozenka/features/admin/moderation.py | 2 +- .../features/admin/{pins.py => msg_pins.py} | 1 + bozenka/features/admin/topics.py | 1 + bozenka/features/basic/setup.py | 15 +++--- bozenka/features/basic/start.py | 4 +- bozenka/features/features_list.py | 25 --------- bozenka/features/user/image_generation.py | 3 +- bozenka/features/user/text_generation.py | 3 +- bozenka/features/user/welcome.py | 1 + bozenka/generative/__init__.py | 13 ++++- bozenka/instances/features_list.py | 26 ++++++++++ bozenka/instances/telegram/__init__.py | 29 ++++++----- .../instances/telegram/queries/__init__.py | 1 + bozenka/instances/telegram/utils/__init__.py | 0 .../telegram/utils/filters/permissions.py | 11 ++-- .../telegram/utils/keyboards/inline.py | 22 ++++---- 20 files changed, 159 insertions(+), 71 deletions(-) create mode 100644 bozenka/features/admin/information.py rename bozenka/features/admin/{invite.py => invite_generation.py} (99%) rename bozenka/features/admin/{pins.py => msg_pins.py} (99%) delete mode 100644 bozenka/features/features_list.py create mode 100644 bozenka/instances/features_list.py delete mode 100644 bozenka/instances/telegram/utils/__init__.py diff --git a/bozenka/features/__init__.py b/bozenka/features/__init__.py index fad29b1..3459743 100644 --- a/bozenka/features/__init__.py +++ b/bozenka/features/__init__.py @@ -1,14 +1,19 @@ +from bozenka.features.admin import * +from bozenka.features.user import * +from bozenka.features.basic import * class BasicFeature: """ A classic class of lineral (basic) feature of bozenka. IN FUTURE! + :param telegram_setting_in_list: Does feature shows in /setup list """ - telegram_setting_in_list = False # Does feature shows in /setup list - telegram_setting_name = None # Setting title in /setup command - telegram_setting_description = None # Setting description in /setup command - telegram_db_name = None # Name of TelegramChatSettings column will be affected + telegram_setting_in_list: bool = False # Does feature shows in /setup list + telegram_setting_name: str | None = None # Setting title in /setup command + telegram_setting_description: str | None = None # Setting description in /setup command + telegram_db_name = None # Name of TelegramChatSettings column will be affected + telegram_category: str | None = None # Telegram category name, current # Telegram commands list of feature telegram_commands: dict[str: str] = { # @@ -17,7 +22,8 @@ class BasicFeature: "example": "Its an example" } telegram_cmd_avaible = True # Does this feature have a telegram commands - # All handlers + + # All handlers to register automaticly by bozenka telegram_message_handlers = [ # Format is [Handler, [Filters]] ] diff --git a/bozenka/features/admin/__init__.py b/bozenka/features/admin/__init__.py index 8e7fa94..227b147 100644 --- a/bozenka/features/admin/__init__.py +++ b/bozenka/features/admin/__init__.py @@ -1,4 +1,5 @@ -from .invite import Invite +from .invite_generation import Invite from .moderation import Moderation -from .pins import Pins +from .msg_pins import Pins from .topics import Threads +from .information import ChatInformation diff --git a/bozenka/features/admin/information.py b/bozenka/features/admin/information.py new file mode 100644 index 0000000..2a2fa6f --- /dev/null +++ b/bozenka/features/admin/information.py @@ -0,0 +1,51 @@ +import logging + +from aiogram.filters import Command +from aiogram.types import Message + +from bozenka.features import BasicFeature +from bozenka.instances.telegram.utils.keyboards import delete_keyboard + + +class ChatInformation(BasicFeature): + """ + Shows information about chat by sending one command. + (Private, public, etc) + """ + + async def telegram_basic_chat_info_handler(msg: Message) -> None: + """ + Shows information about chat by command `/info` + :param msg: Message telegram object + :return: None + """ + logging.log(msg=f"Sending information about chat user_id={msg.from_user.id}", + level=logging.INFO) + chat = await msg.bot.get_chat(msg.chat.id) + # Related texts + texts = { + "chat_types": {"group": "группой", "supergroup": "cупер группой"}, + "forum_type": {True: "форумом,", False: ", не является форумом,", None: ", не является форумом,"}, + "required_invite": {True: "требуется одобрение заявки на вступление", False: "заявка не требуется.", + None: "заявка не требуется."}, + "hidden_members": {True: "присуствуют", False: "отсуствуют", None: "отсуствуют"}, + "isprotected": {True: "пересылать сообщения из группы можно.", + False: "пересылать сообщения из группы нельзя.", + None: "пересылать сообщения из группы можно."}, + } + + await msg.answer(f"{chat.title}, {chat.get_member_count()} пользователей\n" + f"{chat.description}\n\n" + f"Является {texts['chat_types'][chat.type]} {texts['forum_type'][chat.is_forum]} {texts['required_invite'][chat.join_by_request]}\n" + f"Скрытые пользователи {texts['hidden_members'][chat.has_hidden_members]}, {texts['isprotected'][chat.has_protected_content]}", + reply_markup=delete_keyboard(admin_id=msg.from_user.id)) + + telegram_commands: dict[str: str] = { + 'info': 'Get information about chat' + } + telegram_cmd_avaible = True + + # All handlers to register automaticly by bozenka + telegram_message_handlers = [ + [telegram_basic_chat_info_handler, [Command(commands="info")]] + ] diff --git a/bozenka/features/admin/invite.py b/bozenka/features/admin/invite_generation.py similarity index 99% rename from bozenka/features/admin/invite.py rename to bozenka/features/admin/invite_generation.py index c8bc720..6bd835d 100644 --- a/bozenka/features/admin/invite.py +++ b/bozenka/features/admin/invite_generation.py @@ -61,6 +61,7 @@ class Invite(BasicFeature): "Разрешает использование комманды /invite в чате, для созданния приглашений.\n" \ "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." telegram_db_name = TelegramChatSettings.invite_generator + telegram_category = "admin" # Telegram commands telegram_commands: dict[str: str] = {"/invite": 'Generates invite into current chat'} telegram_cmd_avaible = True # Is a feature have a commands diff --git a/bozenka/features/admin/moderation.py b/bozenka/features/admin/moderation.py index fa76e48..4930ab1 100644 --- a/bozenka/features/admin/moderation.py +++ b/bozenka/features/admin/moderation.py @@ -501,8 +501,8 @@ class Moderation(BasicFeature): "чтобы выполнить одну из комманд по отношению к пользователю, " \ "ответьте на сообщение пользователя и используйте команду\n" \ "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." - telegram_db_name = TelegramChatSettings.moderation + telegram_category = "admin" # Telegram commands telegram_commands: dict[str: str] = { "ban": "Command to ban user in chat", diff --git a/bozenka/features/admin/pins.py b/bozenka/features/admin/msg_pins.py similarity index 99% rename from bozenka/features/admin/pins.py rename to bozenka/features/admin/msg_pins.py index afa4f9c..0a16fee 100644 --- a/bozenka/features/admin/pins.py +++ b/bozenka/features/admin/msg_pins.py @@ -119,6 +119,7 @@ class Pins(BasicFeature): "/unpin_all - открепляет все сообщения, которые видит бот\n" \ "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота." telegram_db_name = TelegramChatSettings.pins + telegram_category = "admin" # Telegram commands telegram_commands: dict[str: str] = { 'pin': 'Pin fast any message in chat', diff --git a/bozenka/features/admin/topics.py b/bozenka/features/admin/topics.py index 9b3e068..f07e1d0 100644 --- a/bozenka/features/admin/topics.py +++ b/bozenka/features/admin/topics.py @@ -132,6 +132,7 @@ class Threads(BasicFeature): "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть" \ "включен форум" telegram_db_name = TelegramChatSettings.topics + telegram_category = "admin" # Telegram commands telegram_commands: dict[str: str] = { 'close': 'Close fast topic (not general) in chat', diff --git a/bozenka/features/basic/setup.py b/bozenka/features/basic/setup.py index 2966dff..43ac28d 100644 --- a/bozenka/features/basic/setup.py +++ b/bozenka/features/basic/setup.py @@ -8,6 +8,7 @@ from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import get_chat_config_value, TelegramChatSettings from bozenka.features import BasicFeature from bozenka.instances.telegram.utils.callbacks_factory import SetupAction, SetupFeature, SetupCategory +from bozenka.instances.telegram.utils.filters import IsOwner from bozenka.instances.telegram.utils.keyboards import setup_keyboard, setup_category_keyboard, setup_feature_keyboard from bozenka.instances.telegram.utils.simpler import list_of_features @@ -25,7 +26,8 @@ class Setup(BasicFeature): :return: Nothing """ await msg.answer("Привет владелец чата 👋\n" - "Чтобы меня настроить, используй меню под данным сообщением", + "Настрой меня - бота так, как тебе удобно, и я буду помогать тебе в чате с определенными функциями.\n" + "Используй меню настроек ниже, чтобы указать, какие функции, которые я умею, должен выполнять.", reply_markup=setup_keyboard()) async def telegram_setup_categories_handler(call: CallbackQuery, callback_data: SetupCategory | SetupAction): @@ -86,12 +88,13 @@ class Setup(BasicFeature): telegram_setting_in_list = False telegram_commands = {"setup": 'Command to setup bozenka features in chat'} telegram_cmd_avaible = True + telegram_category = None telegram_message_handlers = [ - [telegram_setup_cmd_handler, [Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE)]] + [telegram_setup_cmd_handler, [Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE), IsOwner(True)]] ] telegram_callback_handlers = [ - [telegram_features_edit_handler, [SetupAction.filter(F.action == "disable")]], - [telegram_features_edit_handler, [SetupAction.filter(F.action == "enable")]], - [telegram_setup_edit_feature_handler, [SetupFeature.filter()]], - [telegram_setup_categories_handler, [SetupAction.filter(F.action == "back")]] + [telegram_features_edit_handler, [SetupAction.filter(F.action == "disable"), IsOwner(True)]], + [telegram_features_edit_handler, [SetupAction.filter(F.action == "enable"), IsOwner(True)]], + [telegram_setup_edit_feature_handler, [SetupFeature.filter(), IsOwner(True)]], + [telegram_setup_categories_handler, [SetupAction.filter(F.action == "back"), IsOwner(True)]] ] diff --git a/bozenka/features/basic/start.py b/bozenka/features/basic/start.py index 41e60e6..3194b91 100644 --- a/bozenka/features/basic/start.py +++ b/bozenka/features/basic/start.py @@ -218,10 +218,10 @@ class Start(BasicFeature): Telegram feature settings """ # Telegram feature settings - telegram_setting = None + telegram_setting_in_list = False + telegram_category = None telegram_commands: dict[str: str] = {"start": "Command to start work with bozenka the bot"} telegram_cmd_avaible = True # Is a feature have a commands - telegram_callback_factory = None telegram_message_handlers = [ [start_cmd_handler, [Command(commands=["start"]), F.chat.type == ChatType.PRIVATE]], ] diff --git a/bozenka/features/features_list.py b/bozenka/features/features_list.py deleted file mode 100644 index 6c9ff5a..0000000 --- a/bozenka/features/features_list.py +++ /dev/null @@ -1,25 +0,0 @@ -from aiogram import Dispatcher, Bot -from aiogram.types import BotCommand - -from bozenka.features import BasicFeature -from bozenka.features.admin import * -from bozenka.features.user import * -from bozenka.features.basic import * - -features_list = [ - # Admin related category - Moderation, - Invite, - Pins, - Threads, - # User related category - ImageGeneratrion, - TextGeneratrion, - Welcome, - # Basic Functions - Setup, - Start -] - - - diff --git a/bozenka/features/user/image_generation.py b/bozenka/features/user/image_generation.py index 8e63a1c..a93f70e 100644 --- a/bozenka/features/user/image_generation.py +++ b/bozenka/features/user/image_generation.py @@ -130,7 +130,8 @@ class ImageGeneratrion(BasicFeature): Telegram feature settings """ # Telegram feature settings - telegram_setting = TelegramChatSettings.image_generation + telegram_category = "user" + telegram_db_name = TelegramChatSettings.image_generation telegram_commands: dict[str: str] = {'imagine': 'Starts conversation with image generative ai'} telegram_setting_in_list = True telegram_setting_name = "Генерация изображений 📸" diff --git a/bozenka/features/user/text_generation.py b/bozenka/features/user/text_generation.py index e7760e8..332c8c1 100644 --- a/bozenka/features/user/text_generation.py +++ b/bozenka/features/user/text_generation.py @@ -499,7 +499,8 @@ class TextGeneratrion(BasicFeature): await call.message.delete() # Telegram feature settings - telegram_setting = TelegramChatSettings.text_generation + telegram_category = "user" + telegram_db_name = TelegramChatSettings.text_generation telegram_setting_in_list = True telegram_setting_name = "ИИ ЧатБот 🤖" telegram_setting_description = "ИИ ЧатБот 🤖" \ diff --git a/bozenka/features/user/welcome.py b/bozenka/features/user/welcome.py index d94c7d6..9dbcfbe 100644 --- a/bozenka/features/user/welcome.py +++ b/bozenka/features/user/welcome.py @@ -62,6 +62,7 @@ class Welcome(BasicFeature): # Telegram feature settings telegram_setting = TelegramChatSettings.welcome_messages + telegram_category = "user" telegram_commands: dict[str: str] = {} telegram_setting_in_list = True telegram_setting_name = "Приветсвенные сообщения 👋" diff --git a/bozenka/generative/__init__.py b/bozenka/generative/__init__.py index 9435300..f69fa20 100644 --- a/bozenka/generative/__init__.py +++ b/bozenka/generative/__init__.py @@ -1,3 +1,14 @@ +import dataclasses + + +@dataclasses +class QueryPosition: + """ + Class of Query to generate something + with models + """ + data: dict + instance: str # List of text generative categories, what we support text_generative_categories = [ @@ -17,4 +28,4 @@ image_generative_size = [ "576x1024", "1024x680", "680x1024" -] \ No newline at end of file +] diff --git a/bozenka/instances/features_list.py b/bozenka/instances/features_list.py new file mode 100644 index 0000000..57b66e0 --- /dev/null +++ b/bozenka/instances/features_list.py @@ -0,0 +1,26 @@ +from bozenka.features import * + +features_list = [ + # Admin related category + Moderation, + Invite, + Pins, + Threads, + ChatInformation, + # User related category + ImageGeneratrion, + TextGeneratrion, + Welcome, + # Basic Functions + Setup, + Start +] + +customizable_features = {} + +for feature in features_list: + if feature.telegram_setting_in_list: + if feature.telegram_category in customizable_features.keys(): + customizable_features[feature.telegram_category].append(feature) + else: + customizable_features[feature.telegram_category] = [feature] diff --git a/bozenka/instances/telegram/__init__.py b/bozenka/instances/telegram/__init__.py index 9576011..56b5c84 100644 --- a/bozenka/instances/telegram/__init__.py +++ b/bozenka/instances/telegram/__init__.py @@ -1,17 +1,14 @@ -import os import logging -import g4f +import os + from aiogram import Dispatcher, Bot from aiogram.types import BotCommand from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.features import BasicFeature -from bozenka.features.features_list import features_list -from bozenka.features.admin import * -from bozenka.features.basic import * -from bozenka.features.user import * -from bozenka.instances.telegram.handlers import register_handlers +from bozenka.instances.features_list import features_list from bozenka.instances.telegram.utils.simpler import list_of_commands +from bozenka.instances.telegram.queries import * async def register_all_features(list_of_features: list[BasicFeature], dispatcher: Dispatcher, bot: Bot) -> None: @@ -37,18 +34,24 @@ async def register_all_features(list_of_features: list[BasicFeature], dispatcher await bot.set_my_commands(cmd_list) + # Registering other handlers + await dispatcher.callback_query.register(delete_callback_handler, DeleteMenu.filter()) + await dispatcher.callback_query.register(hide_menu_handler, HideMenu.filter()) + async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: """ - Launches telegram bot with token from enviroment - :param session_maker: - :return: + Launch bozenka telegram instance with token from enviroment + :param session_maker: AsyncSessionMaker SqlAlchemy object + :return: None """ - logging.log(msg="-" * 50 + "TELEGRAM INSTANCE LAUNCH" + "-" * 50, level=logging.INFO) + logging.log(msg="-" * 50 + "TELEGRAM BOZENKA INSTANCE LAUNCH" + "-" * 50, level=logging.INFO) bot = Bot(token=os.getenv("tg_bot_token"), parse_mode="HTML") dp = Dispatcher() - await register_all_features(list_of_features=features_list, dispatcher=dp, bot=bot) - await dp.start_polling(bot, session_maker=session_maker, on_startup=[]) + await dp.start_polling(bot, + session_maker=session_maker, # Pass your async_sessionmaker here, you can do dependency injection + on_startup=[await register_all_features(list_of_features=features_list, dispatcher=dp, bot=bot)] + ) diff --git a/bozenka/instances/telegram/queries/__init__.py b/bozenka/instances/telegram/queries/__init__.py index e69de29..f2a417c 100644 --- a/bozenka/instances/telegram/queries/__init__.py +++ b/bozenka/instances/telegram/queries/__init__.py @@ -0,0 +1 @@ +from .menu import * \ No newline at end of file diff --git a/bozenka/instances/telegram/utils/__init__.py b/bozenka/instances/telegram/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/bozenka/instances/telegram/utils/filters/permissions.py b/bozenka/instances/telegram/utils/filters/permissions.py index eb597e4..100a196 100644 --- a/bozenka/instances/telegram/utils/filters/permissions.py +++ b/bozenka/instances/telegram/utils/filters/permissions.py @@ -2,7 +2,7 @@ from typing import Any from aiogram.filters import Filter from aiogram.methods import GetChatMember -from aiogram.types import Message, ChatPermissions +from aiogram.types import Message, ChatPermissions, CallbackQuery from aiogram.enums import ChatMemberStatus from bozenka.instances.telegram.utils.simpler import ru_cmds @@ -110,16 +110,19 @@ class IsOwner(Filter): """ self.is_admin = is_admin - async def __call__(self, msg: Message) -> bool: + async def __call__(self, msg: Message | CallbackQuery) -> bool: """ Working after catching a call from aiogram - :param msg: Message telegram object + :param msg: Message or CallbackQuery telegram object :param self: A self object of this class :return: None """ + if type(msg) is CallbackQuery: + msg = msg.message user = await msg.chat.get_member(msg.from_user.id) if ChatMemberStatus.CREATOR != user.status: - await msg.answer(ru_cmds["no-perms"]) + await msg.answer("Ошибка ❌\n" + "У вас нет прав на использование этой комманды 🚫") return ChatMemberStatus.CREATOR == user.status diff --git a/bozenka/instances/telegram/utils/keyboards/inline.py b/bozenka/instances/telegram/utils/keyboards/inline.py index e377704..336ef1a 100644 --- a/bozenka/instances/telegram/utils/keyboards/inline.py +++ b/bozenka/instances/telegram/utils/keyboards/inline.py @@ -9,6 +9,7 @@ from gpt4all import GPT4All from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import get_chat_config_value +from bozenka.instances.features_list import customizable_features from bozenka.instances.telegram.utils.callbacks_factory import * from bozenka.instances.telegram.utils.simpler.lists_of_content import generate_list_of_features from bozenka.generative.gpt4free import generate_gpt4free_models, generate_gpt4free_providers @@ -69,7 +70,7 @@ def help_category_keyboard(category: str) -> InlineKeyboardMarkup: feature_index=list_of_features.index(setting), feature_category=category ).pack())) - kb.row(InlineKeyboardButton(text="🔙 Назад к категориям", + kb.row(InlineKeyboardButton(text="🔙 Назад к списку категорий", callback_data=HelpBack(back_to="category").pack())) return kb.as_markup() @@ -81,7 +82,7 @@ def help_feature_keyboard(category: str) -> InlineKeyboardMarkup: :return: """ kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="🔙 Назад к функциям", + [InlineKeyboardButton(text="🔙 Назад к списку функций", callback_data=HelpBackCategory(category_name=category).pack())] ]) return kb @@ -94,15 +95,16 @@ def setup_keyboard() -> InlineKeyboardMarkup: :return: """ kb = InlineKeyboardBuilder() + translations = { + "admin": "Администраторы 👮‍♂", + "user": "Пользователи 👤" + } - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Администраторы 👮‍♂", - callback_data=SetupCategory(category_name="Admins").pack())], - [InlineKeyboardButton(text="Пользователи 👤", - callback_data=SetupCategory(category_name="Members").pack())], - [InlineKeyboardButton(text="В разработке 👨‍💻", - callback_data=SetupCategory(category_name="Devs").pack())]]) - return kb + for category in customizable_features: + kb.row(InlineKeyboardButton(text=translations[category], + callback_data=SetupCategory(category_name=category).pack())) + + return kb.as_markup() def setup_category_keyboard(category: str) -> InlineKeyboardMarkup: -- 2.30.2 From 01322df060a94640a2607e49148f7b547b318f0c Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:04:19 +0300 Subject: [PATCH 08/13] Refactoring a little bit --- bozenka/database/tables/telegram.py | 2 +- bozenka/features/__init__.py | 29 - bozenka/features/admin/information.py | 2 +- bozenka/features/admin/invite_generation.py | 32 +- bozenka/features/admin/moderation.py | 136 ++-- bozenka/features/admin/msg_pins.py | 57 +- bozenka/features/admin/topics.py | 49 +- bozenka/features/basic/setup.py | 109 +++- bozenka/features/basic/start.py | 60 +- bozenka/features/main.py | 27 + bozenka/features/user/image_generation.py | 67 +- bozenka/features/user/text_generation.py | 272 +++++++- bozenka/features/user/welcome.py | 4 +- bozenka/generative/__init__.py | 8 - bozenka/instances/__init__.py | 0 bozenka/instances/basic_features_list.py | 6 + .../{version.py => current_version.py} | 0 .../instances/customizable_features_list.py | 30 + bozenka/instances/features_list.py | 26 - bozenka/instances/telegram/__init__.py | 21 +- .../telegram/{utils => }/filters/__init__.py | 0 .../{utils => }/filters/chat_setting.py | 18 +- .../{utils => }/filters/permissions.py | 24 +- .../{utils => }/middleware/__init__.py | 5 +- .../{utils => }/middleware/antiflood.py | 0 .../telegram/{utils => }/middleware/retry.py | 0 bozenka/instances/telegram/utils/__init__.py | 0 bozenka/instances/telegram/utils/delete.py | 16 + .../telegram/utils/keyboards/__init__.py | 1 - .../telegram/utils/keyboards/inline.py | 615 ------------------ .../utils/simpler/lists_of_content.py | 301 --------- 31 files changed, 787 insertions(+), 1130 deletions(-) create mode 100644 bozenka/features/main.py create mode 100644 bozenka/instances/__init__.py create mode 100644 bozenka/instances/basic_features_list.py rename bozenka/instances/{version.py => current_version.py} (100%) create mode 100644 bozenka/instances/customizable_features_list.py delete mode 100644 bozenka/instances/features_list.py rename bozenka/instances/telegram/{utils => }/filters/__init__.py (100%) rename bozenka/instances/telegram/{utils => }/filters/chat_setting.py (53%) rename bozenka/instances/telegram/{utils => }/filters/permissions.py (85%) rename bozenka/instances/telegram/{utils => }/middleware/__init__.py (74%) rename bozenka/instances/telegram/{utils => }/middleware/antiflood.py (100%) rename bozenka/instances/telegram/{utils => }/middleware/retry.py (100%) create mode 100644 bozenka/instances/telegram/utils/__init__.py create mode 100644 bozenka/instances/telegram/utils/delete.py delete mode 100644 bozenka/instances/telegram/utils/keyboards/__init__.py delete mode 100644 bozenka/instances/telegram/utils/keyboards/inline.py delete mode 100644 bozenka/instances/telegram/utils/simpler/lists_of_content.py diff --git a/bozenka/database/tables/telegram.py b/bozenka/database/tables/telegram.py index f83b208..958b4ed 100644 --- a/bozenka/database/tables/telegram.py +++ b/bozenka/database/tables/telegram.py @@ -83,7 +83,7 @@ async def get_chat_config_value(chat_id: int, session: async_sessionmaker, setti """ async with session() as session: async with session.begin(): - rows = (await session.execute(select(setting.db_name).where(TelegramChatSettings.chat_id == chat_id))).one() + rows = (await session.execute(select(setting).where(TelegramChatSettings.chat_id == chat_id))).one() return rows[0] diff --git a/bozenka/features/__init__.py b/bozenka/features/__init__.py index 3459743..21e1a8e 100644 --- a/bozenka/features/__init__.py +++ b/bozenka/features/__init__.py @@ -1,32 +1,3 @@ from bozenka.features.admin import * from bozenka.features.user import * from bozenka.features.basic import * - - -class BasicFeature: - """ - A classic class of lineral (basic) - feature of bozenka. IN FUTURE! - :param telegram_setting_in_list: Does feature shows in /setup list - """ - telegram_setting_in_list: bool = False # Does feature shows in /setup list - telegram_setting_name: str | None = None # Setting title in /setup command - telegram_setting_description: str | None = None # Setting description in /setup command - telegram_db_name = None # Name of TelegramChatSettings column will be affected - telegram_category: str | None = None # Telegram category name, current - # Telegram commands list of feature - telegram_commands: dict[str: str] = { - # - # Format is "CommandNameHere": "Command description is here" - # - "example": "Its an example" - } - telegram_cmd_avaible = True # Does this feature have a telegram commands - - # All handlers to register automaticly by bozenka - telegram_message_handlers = [ - # Format is [Handler, [Filters]] - ] - telegram_callback_handlers = [ - # Format is [Handler, [Filters]] - ] diff --git a/bozenka/features/admin/information.py b/bozenka/features/admin/information.py index 2a2fa6f..059fe9a 100644 --- a/bozenka/features/admin/information.py +++ b/bozenka/features/admin/information.py @@ -3,7 +3,7 @@ import logging from aiogram.filters import Command from aiogram.types import Message -from bozenka.features import BasicFeature +from bozenka.features.main import BasicFeature from bozenka.instances.telegram.utils.keyboards import delete_keyboard diff --git a/bozenka/features/admin/invite_generation.py b/bozenka/features/admin/invite_generation.py index 6bd835d..53c6989 100644 --- a/bozenka/features/admin/invite_generation.py +++ b/bozenka/features/admin/invite_generation.py @@ -2,13 +2,31 @@ import logging from aiogram.enums import ChatMemberStatus from aiogram.filters import Command -from aiogram.types import Message, CallbackQuery +from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton from bozenka.database.tables.telegram import TelegramChatSettings -from bozenka.features import BasicFeature -from bozenka.instances.telegram.utils.callbacks_factory import RevokeCallbackData -from bozenka.instances.telegram.utils.keyboards import invite_keyboard -from bozenka.instances.telegram.utils.simpler import ru_cmds +from bozenka.features.main import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import RevokeCallbackData, DeleteMenu + + +# Invite keyboard +def invite_telegram_keyboard(invite_link: str, admin_id: int, chat_name: str) -> InlineKeyboardMarkup: + """ + Generating menu for /invite command. Should be reworked. + :param invite_link: Invite link to chat + :param admin_id: User_id of telegram administrator + :param chat_name: Name of group chat + :return: Nothing + """ + invite_revoke_link = invite_link.replace("https://", "") + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text=chat_name, url=invite_link)], + [InlineKeyboardButton(text="Отозвать 🛠️", + callback_data=RevokeCallbackData(admin_id=admin_id, link=invite_revoke_link).pack())], + [InlineKeyboardButton(text="Спасибо ✅", + callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())]]) + return kb + class Invite(BasicFeature): @@ -29,8 +47,8 @@ class Invite(BasicFeature): await msg.answer( f" Держите ваше приглашение в чат, {msg.from_user.mention_html('пользователь')} 👋", - reply_markup=invite_keyboard(link=str(link.invite_link), admin_id=msg.from_user.id, - chat_name=msg.chat.full_name) + reply_markup=invite_telegram_keyboard(invite_link=str(link.invite_link), admin_id=msg.from_user.id, + chat_name=msg.chat.full_name) ) async def telegram_revoke_callback_handler(call: CallbackQuery, callback_data: RevokeCallbackData) -> None: diff --git a/bozenka/features/admin/moderation.py b/bozenka/features/admin/moderation.py index 4930ab1..5b11c90 100644 --- a/bozenka/features/admin/moderation.py +++ b/bozenka/features/admin/moderation.py @@ -3,16 +3,80 @@ import logging from aiogram import F from aiogram.enums import ChatMemberStatus, ChatType from aiogram.filters import CommandObject, Command -from aiogram.types import Message, CallbackQuery +from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import get_chat_config_value, TelegramChatSettings -from bozenka.features import BasicFeature -from bozenka.instances.telegram.utils.callbacks_factory import UnbanData, BanData, UnmuteData, MuteData -from bozenka.instances.telegram.utils.filters import IsAdminFilter, BotHasPermissions, UserHasPermissions -from bozenka.instances.telegram.utils.keyboards import ban_keyboard, delete_keyboard, mute_keyboard, unmute_keyboard, \ - unban_keyboard -from bozenka.instances.telegram.utils.simpler import list_of_features, SolutionSimpler +from bozenka.features.main import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import UnbanData, BanData, UnmuteData, MuteData, DeleteMenu +from bozenka.instances.telegram.filters import IsAdminFilter, BotHasPermissions, UserHasPermissions +from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.simpler import SolutionSimpler + + +# Ban / Unban keyboards +def telegram_ban_user_keyboard(admin_id: int, ban_id: int) -> InlineKeyboardMarkup: + """ + Generating menu for /ban command. + :param admin_id: User_id of administrator in group chat + :param ban_id: User_id of banned member + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) + ], [ + InlineKeyboardButton(text="Разбанить 🛠️", callback_data=UnbanData(user_id_unban=str(ban_id), + user_id_clicked=str(admin_id)).pack()) + ]]) + return kb + + +def telegram_unban_user_keyboard(admin_id: int, unban_id: int) -> InlineKeyboardMarkup: + """ + Generating menu for /unban command. + :param admin_id: User_id of administrator in group chat + :param unban_id: User_id of unbanned member + :return: InlineKeyboardMarkup + """ + print(unban_id) + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) + ], [ + InlineKeyboardButton(text="Забанить 🛠️", callback_data=BanData(user_id_ban=str(unban_id), + user_id_clicked=str(admin_id)).pack()) + ]]) + return kb + + +# Mute / Unmute keyboards +def telegram_mute_user_keyboard(admin_id: int, mute_id: int) -> InlineKeyboardMarkup: + """ + Generating menu for /mute command. + :param admin_id: User_id of administrator in group chat + :param mute_id: User_id of restricted member + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Спасибо ✅", + callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())], + [InlineKeyboardButton(text="Размутить 🛠️", + callback_data=UnmuteData(user_id_unmute=mute_id, user_id_clicked=admin_id).pack())]]) + return kb + + +def telegram_unmute_user_keyboard(admin_id: int, unmute_id: int) -> InlineKeyboardMarkup: + """ + Generating menu for /unmute command. + :param admin_id: User_id of administrator in group chat + :param unmute_id: User_id of unrestricted member + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Спасибо ✅", + callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())], + [InlineKeyboardButton(text="Замутить 🛠️", + callback_data=MuteData(user_id_mute=unmute_id, user_id_clicked=admin_id).pack())]]) + return kb class Moderation(BasicFeature): @@ -34,7 +98,7 @@ class Moderation(BasicFeature): banned_user = await call.message.chat.get_member(int(callback_data.user_id_ban)) send_notification = await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, - setting=list_of_features["Admins"][5]) + setting=TelegramChatSettings.restrict_notification) if call.from_user.id != callback_data.user_id_clicked \ and clicked_user.status not in [ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.CREATOR]: @@ -49,7 +113,7 @@ class Moderation(BasicFeature): await call.message.edit_text( "Удача ✅\n" f"{banned_user.user.mention_html('Этот пользователь')} был заблокирован {call.from_user.mention_html('этим пользователем')}.", - reply_markup=ban_keyboard(admin_id=call.from_user.id, ban_id=banned_user.user.id) + reply_markup=telegram_ban_user_keyboard(admin_id=call.from_user.id, ban_id=banned_user.user.id) ) if send_notification: @@ -86,11 +150,11 @@ class Moderation(BasicFeature): await call.message.edit_text( "Удача ✅\n" f"{unbanned_user.user.mention_html('Этот пользователь')} был разблокирован {call.from_user.mention_html('этим пользователем')}.", - reply_markup=unban_keyboard(admin_id=call.from_user.id, ban_id=unbanned_user.user.id) + reply_markup=telegram_unban_user_keyboard(admin_id=call.from_user.id, unban_id=unbanned_user.user.id) ) if await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, - setting=list_of_features["Admins"][5]): + setting=TelegramChatSettings.restrict_notification): await call.message.bot.send_message( chat_id=unbanned_user.user.id, text=f"{unbanned_user.user.mention_html('Вы')} были разблокирован {call.from_user.mention_html('этим пользователем')} в чате {call.message.chat.id}.", @@ -110,9 +174,9 @@ class Moderation(BasicFeature): """ banned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][4]) + setting=TelegramChatSettings.results_in_dm) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][5]) + setting=TelegramChatSettings.restrict_notification) where_send = { True: msg.from_user.id, @@ -133,7 +197,7 @@ class Moderation(BasicFeature): f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} " f"был заблокирован {msg.from_user.mention_html('этим пользователем')}.\n" f"По причине {config['reason']}, до даты {config['ban_time']}", - reply_markup=ban_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) + reply_markup=telegram_ban_user_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) if send_notification: await msg.bot.send_message(chat_id=banned_user.user.id, text="Вы " @@ -146,8 +210,8 @@ class Moderation(BasicFeature): f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} " f"был заблокирован {msg.reply_to_message.from_user.mention_html('этим пользователем')}.\n" f"По причине {config['reason']}.", - reply_markup=ban_keyboard(admin_id=msg.from_user.id, - ban_id=msg.reply_to_message.from_user.id)) + reply_markup=telegram_ban_user_keyboard(admin_id=msg.from_user.id, + ban_id=msg.reply_to_message.from_user.id)) if send_notification: await msg.bot.send_message(chat_id=banned_user.user.id, text=f"Вы " @@ -159,8 +223,8 @@ class Moderation(BasicFeature): text="Удача ✅\n" f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} " f"был заблокирован {msg.from_user.mention_html('этим пользователем')}, до даты {config['ban_time']}", - reply_markup=ban_keyboard(admin_id=msg.from_user.id, - ban_id=msg.reply_to_message.from_user.id)) + reply_markup=telegram_ban_user_keyboard(admin_id=msg.from_user.id, + ban_id=msg.reply_to_message.from_user.id)) if send_notification: await msg.bot.send_message(chat_id=banned_user.user.id, text=f"Вы " @@ -172,7 +236,7 @@ class Moderation(BasicFeature): text="Удача ✅\n" f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')}" f" был заблокирован {msg.from_user.mention_html('этим пользователем')}.", - reply_markup=ban_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) + reply_markup=telegram_ban_user_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) if send_notification: await msg.bot.send_message(chat_id=banned_user.user.id, text=f"Вы " @@ -192,9 +256,9 @@ class Moderation(BasicFeature): unbanned_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][4]) + setting=TelegramChatSettings.results_in_dm) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][5]) + setting=TelegramChatSettings.restrict_notification) where_send = { True: msg.from_user.id, @@ -215,7 +279,7 @@ class Moderation(BasicFeature): text="Удача ✅\n" f"{msg.reply_to_message.from_user.mention_html('Этот пользователь')} был разблокирован " f"{msg.from_user.mention_html('этим пользователем')}.\n", - reply_markup=unban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id) + reply_markup=telegram_unban_user_keyboard(admin_id=msg.from_user.id, unban_id=msg.reply_to_message.from_user.id) ) if send_notification: await msg.bot.send_message( @@ -266,11 +330,11 @@ class Moderation(BasicFeature): await call.message.edit_text( "Удача ✅\n" f"{muted_user.user.mention_html('Этот пользователь')} был замучен {call.from_user.mention_html('этим пользователем')}.", - reply_markup=mute_keyboard(admin_id=call.from_user.id, mute_id=callback_data.user_id_mute) + reply_markup=telegram_mute_user_keyboard(admin_id=call.from_user.id, mute_id=callback_data.user_id_mute) ) send_notification = await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]) + setting=TelegramChatSettings.restrict_notification) if send_notification: await call.message.bot.send_message( chat_id=muted_user.user.id, @@ -304,11 +368,11 @@ class Moderation(BasicFeature): await call.message.edit_text( "Удача ✅\n" f"{unmuted_user.user.mention_html('Этот пользователь')} был размучен {call.from_user.mention_html('этим пользователем')}.", - reply_markup=unmute_keyboard(admin_id=call.from_user.id, unmute_id=unmuted_user.user.id) + reply_markup=telegram_unmute_user_keyboard(admin_id=call.from_user.id, unmute_id=unmuted_user.user.id) ) send_notification = await get_chat_config_value(chat_id=call.message.chat.id, session=session_maker, - setting=list_of_features["Admin"][5]) + setting=TelegramChatSettings.restrict_notification) if send_notification: await call.message.bot.send_message( chat_id=unmuted_user.user.id, @@ -329,14 +393,12 @@ class Moderation(BasicFeature): :param session_maker: Session maker object of SqlAlchemy :return: Nothing """ - print(msg.reply_to_message) - print("341414124") mute_user = await msg.chat.get_member(msg.reply_to_message.from_user.id) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][4]) + setting=TelegramChatSettings.results_in_dm) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][5]) + setting=TelegramChatSettings.restrict_notification) where_send = { True: msg.from_user.id, @@ -353,7 +415,7 @@ class Moderation(BasicFeature): f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" f"По причине {config['reason']}, до даты {config['mute_time']}", - reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + reply_markup=telegram_mute_user_keyboard(msg.from_user.id, mute_user.user.id)) if send_notification: await msg.bot.send_message( chat_id=mute_user.user.id, @@ -369,7 +431,7 @@ class Moderation(BasicFeature): f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" f"По причине {config['reason']}.", - reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + reply_markup=telegram_mute_user_keyboard(msg.from_user.id, mute_user.user.id)) if send_notification: await msg.bot.send_message( chat_id=mute_user.user.id, @@ -384,7 +446,7 @@ class Moderation(BasicFeature): f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n" f"До даты {config['mute_time']}", - reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + reply_markup=telegram_mute_user_keyboard(msg.from_user.id, mute_user.user.id)) if send_notification: await msg.bot.send_message( chat_id=mute_user.user.id, @@ -398,7 +460,7 @@ class Moderation(BasicFeature): text="Удача ✅\n" f"{msg.from_user.mention_html('Этот пользователь')} запретил писать " f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}.\n", - reply_markup=mute_keyboard(msg.from_user.id, mute_user.user.id)) + reply_markup=telegram_mute_user_keyboard(msg.from_user.id, mute_user.user.id)) if send_notification: await msg.bot.send_message( chat_id=mute_user.user.id, @@ -417,9 +479,9 @@ class Moderation(BasicFeature): await SolutionSimpler.unmute_user(msg, session_maker) send_to_dm = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][4]) + setting=TelegramChatSettings.results_in_dm) send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, - setting=list_of_features["Admins"][5]) + setting=TelegramChatSettings.restrict_notification) where_send = { True: msg.from_user.id, @@ -431,7 +493,7 @@ class Moderation(BasicFeature): text="Удача ✅" f"{msg.from_user.mention_html('Этот пользователь')} разрешил писать\n" f"сообщения {msg.reply_to_message.from_user.mention_html('этому пользователю')}", - reply_markup=unmute_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) + reply_markup=telegram_unmute_user_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id)) if send_notification: await msg.bot.send_message( user_id=msg.reply_to_message.from_user.id, diff --git a/bozenka/features/admin/msg_pins.py b/bozenka/features/admin/msg_pins.py index 0a16fee..a2b8ace 100644 --- a/bozenka/features/admin/msg_pins.py +++ b/bozenka/features/admin/msg_pins.py @@ -1,16 +1,47 @@ from aiogram import F from aiogram.enums import ChatType from aiogram.filters import Command -from aiogram.types import Message, CallbackQuery +from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup from bozenka.database.tables.telegram import TelegramChatSettings -from bozenka.features import BasicFeature -from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg -from bozenka.instances.telegram.utils.filters import UserHasPermissions, BotHasPermissions, IsAdminFilter -from bozenka.instances.telegram.utils.keyboards import unpin_msg_keyboard, delete_keyboard, pin_msg_keyboard +from bozenka.features.main import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg, DeleteMenu +from bozenka.instances.telegram.filters import UserHasPermissions, BotHasPermissions, IsAdminFilter +from bozenka.instances.telegram.utils.keyboards import delete_keyboard from bozenka.instances.telegram.utils.simpler import SolutionSimpler +# Pin / Unpin command +def telegram_pin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup: + """ + Generate menu for /pin command + :param user_id: User_id of user pinned the message + :param msg_id: Message_id of pinned message + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Открепить сообщение 📌", + callback_data=UnpinMsg(user_id=user_id, msg_id=msg_id).pack())], + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] + ]) + return kb + + +def telegram_unpin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup: + """ + Generate menu for /unpin command + :param user_id: User_id of user unpinned the message + :param msg_id: Message_id of unpinned message + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Открепить сообщение 📌", + callback_data=PinMsg(user_id=user_id, msg_id=msg_id).pack())], + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] + ]) + return kb + + class Pins(BasicFeature): """ A class of pins related commands @@ -30,8 +61,8 @@ class Pins(BasicFeature): await call.message.chat.pin_message(message_id=callback_data.msg_id) await call.message.edit_text("Удача ✅\n" "Сообщение было закреплено 📌", - reply_markup=pin_msg_keyboard(user_id=call.from_user.id, - msg_id=callback_data.msg_id)) + reply_markup=telegram_pin_msg_keyboard(user_id=call.from_user.id, + msg_id=callback_data.msg_id)) async def telegram_unpin_callback_handler(call: CallbackQuery, callback_data: UnpinMsg) -> None: """ @@ -46,8 +77,8 @@ class Pins(BasicFeature): await call.message.chat.pin_message(message_id=callback_data.msg_id) await call.message.edit_text("Удача ✅\n" "Сообщение было откреплено 📌", - reply_markup=unpin_msg_keyboard(user_id=call.from_user.id, - msg_id=callback_data.msg_id)) + reply_markup=telegram_unpin_msg_keyboard(user_id=call.from_user.id, + msg_id=callback_data.msg_id)) async def telegram_pin_cmd(msg: Message) -> None: """ @@ -58,8 +89,8 @@ class Pins(BasicFeature): await SolutionSimpler.pin_msg(msg) await msg.answer("Удача ✅\n" "Сообщение было закреплено 📌", - reply_markup=pin_msg_keyboard(msg_id=msg.reply_to_message.message_id, - user_id=msg.from_user.id)) + reply_markup=telegram_pin_msg_keyboard(msg_id=msg.reply_to_message.message_id, + user_id=msg.from_user.id)) async def telegram_unpin_cmd(msg: Message) -> None: """ @@ -70,8 +101,8 @@ class Pins(BasicFeature): await SolutionSimpler.unpin_msg(msg) await msg.answer("Удача ✅\n" "Сообщение было откреплено 📌", - reply_markup=unpin_msg_keyboard(msg_id=msg.reply_to_message.message_id, - user_id=msg.from_user.id)) + reply_markup=telegram_unpin_msg_keyboard(msg_id=msg.reply_to_message.message_id, + user_id=msg.from_user.id)) async def telegram_unpinall_cmd(msg: Message) -> None: """ diff --git a/bozenka/features/admin/topics.py b/bozenka/features/admin/topics.py index f07e1d0..e1311ef 100644 --- a/bozenka/features/admin/topics.py +++ b/bozenka/features/admin/topics.py @@ -1,16 +1,43 @@ from aiogram import F from aiogram.enums import ChatType from aiogram.filters import Command -from aiogram.types import Message, CallbackQuery +from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup from bozenka.database.tables.telegram import TelegramChatSettings -from bozenka.features import BasicFeature -from bozenka.instances.telegram.utils.callbacks_factory import CloseThread, OpenThread -from bozenka.instances.telegram.utils.filters import UserHasPermissions, BotHasPermissions -from bozenka.instances.telegram.utils.keyboards import delete_keyboard, close_thread_keyboard, open_thread_keyboard +from bozenka.features.main import BasicFeature +from bozenka.instances.telegram.utils.callbacks_factory import CloseThread, OpenThread, DeleteMenu +from bozenka.instances.telegram.filters import UserHasPermissions, BotHasPermissions +from bozenka.instances.telegram.utils.keyboards import delete_keyboard from bozenka.instances.telegram.utils.simpler import SolutionSimpler +# Close / Open thread commands related keyboards +def telegram_close_thread_keyboard(user_id: int) -> InlineKeyboardMarkup: + """ + Generate menu for /close command + :param user_id: User_if of member, who closed thread + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Окрыть обсуждение 🛠️", callback_data=OpenThread(user_id=user_id).pack())], + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] + ]) + return kb + + +def telegram_open_thread_keyboard(user_id: int) -> InlineKeyboardMarkup: + """ + Generate menu for /open command + :param user_id: User_if of member, who opened thread + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Закрыть обсуждение 🛠️", callback_data=CloseThread(user_id=user_id).pack())], + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] + ]) + return kb + + class Threads(BasicFeature): """ A class of topics / threads related commands @@ -25,7 +52,7 @@ class Threads(BasicFeature): """ config = await SolutionSimpler.close_topic(msg=msg) await msg.answer(config[0], - reply_markup=close_thread_keyboard(user_id=msg.from_user.id) + reply_markup=telegram_close_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) async def telegram_reopen_topic_cmd_handler(msg: Message) -> None: @@ -36,7 +63,7 @@ class Threads(BasicFeature): """ config = await SolutionSimpler.open_topic(msg=msg) await msg.answer(config[0], - reply_markup=open_thread_keyboard(user_id=msg.from_user.id) + reply_markup=telegram_open_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) async def telegram_close_general_topic_cmd_handler(msg: Message) -> None: @@ -47,7 +74,7 @@ class Threads(BasicFeature): """ config = await SolutionSimpler.close_general_topic(msg=msg) await msg.answer(config[0], - reply_markup=close_thread_keyboard(user_id=msg.from_user.id) + reply_markup=telegram_close_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) async def telegram_reopen_general_topic_cmd(msg: Message) -> None: @@ -58,7 +85,7 @@ class Threads(BasicFeature): """ config = await SolutionSimpler.open_general_topic(msg=msg) await msg.answer(config[0], - reply_markup=open_thread_keyboard(user_id=msg.from_user.id) + reply_markup=telegram_open_thread_keyboard(user_id=msg.from_user.id) if config[1] else delete_keyboard(msg.from_user.id)) async def telegram_hide_general_topic_cmd_handler(msg: Message) -> None: @@ -94,7 +121,7 @@ class Threads(BasicFeature): config = await SolutionSimpler.close_topic(msg=call.message, call=call) await call.message.edit_text( config[0], - reply_markup=close_thread_keyboard(user_id=call.from_user.id) if config[1] else + reply_markup=telegram_close_thread_keyboard(user_id=call.from_user.id) if config[1] else delete_keyboard(admin_id=call.from_user.id) ) @@ -111,7 +138,7 @@ class Threads(BasicFeature): config = await SolutionSimpler.open_topic(msg=call.message, call=call) await call.message.edit_text( config[0], - reply_markup=open_thread_keyboard(user_id=call.from_user.id) if config[1] else + reply_markup=telegram_open_thread_keyboard(user_id=call.from_user.id) if config[1] else delete_keyboard(admin_id=call.from_user.id) ) diff --git a/bozenka/features/basic/setup.py b/bozenka/features/basic/setup.py index 43ac28d..0da0696 100644 --- a/bozenka/features/basic/setup.py +++ b/bozenka/features/basic/setup.py @@ -1,16 +1,74 @@ from aiogram import F from aiogram.enums import ChatType from aiogram.filters import Command -from aiogram.types import Message, CallbackQuery +from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton +from aiogram.utils.keyboard import InlineKeyboardBuilder from sqlalchemy import Update from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import get_chat_config_value, TelegramChatSettings -from bozenka.features import BasicFeature +from bozenka.features.main import BasicFeature +from bozenka.instances.customizable_features_list import categorized_customizable_features, text_transcription from bozenka.instances.telegram.utils.callbacks_factory import SetupAction, SetupFeature, SetupCategory -from bozenka.instances.telegram.utils.filters import IsOwner -from bozenka.instances.telegram.utils.keyboards import setup_keyboard, setup_category_keyboard, setup_feature_keyboard -from bozenka.instances.telegram.utils.simpler import list_of_features +from bozenka.instances.telegram.filters import IsOwner + + +# Setup related keyboards +def setup_keyboard() -> InlineKeyboardMarkup: + """ + Generate keyboard for /setup command + :return: + """ + kb = InlineKeyboardBuilder() + + for category in categorized_customizable_features: + kb.row(InlineKeyboardButton(text=text_transcription[category], + callback_data=SetupCategory(category_name=category).pack())) + + return kb.as_markup() + + +def setup_category_keyboard(category: str) -> InlineKeyboardMarkup: + """ + Generate keyboard for one of categories + :param category: + :return: + """ + kb = InlineKeyboardBuilder() + for setting in categorized_customizable_features[category]: + kb.row(InlineKeyboardButton(text=setting.name, + callback_data=SetupFeature( + feature_index=categorized_customizable_features[category].index(setting), + feature_category=category + ).pack())) + return kb.as_markup() + + +async def setup_feature_keyboard(category: str, index: int, is_enabled: bool) -> InlineKeyboardMarkup: + """ + Generate keyboard for enabling or disabling + on of features + :param is_enabled: + :param category: + :param index: + + :return: + """ + + from aiogram.types import InlineKeyboardButton + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text="Выключить ❌", callback_data=SetupAction(action="disable", + feature_category=category, + feature_index=index).pack()) + if is_enabled else + InlineKeyboardButton(text="Включить ✅", callback_data=SetupAction(action="enable", + feature_category=category, + feature_index=index).pack()) + ], [ + InlineKeyboardButton(text="Вернуться 🔙", callback_data=SetupAction(action="back", + feature_category=category, + feature_index=index).pack())]]) + return kb class Setup(BasicFeature): @@ -25,58 +83,59 @@ class Setup(BasicFeature): :param msg: Telegram message object :return: Nothing """ - await msg.answer("Привет владелец чата 👋\n" + await msg.answer("Привет владелец чата 👋\n\n" "Настрой меня - бота так, как тебе удобно, и я буду помогать тебе в чате с определенными функциями.\n" "Используй меню настроек ниже, чтобы указать, какие функции, которые я умею, должен выполнять.", reply_markup=setup_keyboard()) - async def telegram_setup_categories_handler(call: CallbackQuery, callback_data: SetupCategory | SetupAction): + async def telegram_setup_categories_handler(call: CallbackQuery, callback_data: SetupCategory | SetupAction) -> None: """ Query, what shows list of features to enable. - :param call: - :param callback_data: - :return: + :param call: CallbackQuery class + :param callback_data: SetupCategory or SetupAction + :return: None """ - await call.message.edit_text("Выберите настройку, которую хотите изменить", + await call.message.edit_text(f"{text_transcription[callback_data.category_name]}\n\n" + f"Выберите функцию, которые вы хотите настроить в данной категории у бота.", reply_markup=setup_category_keyboard(category=callback_data.category_name)) - async def telegram_setup_edit_feature_handler(call: CallbackQuery, callback_data: SetupFeature, session_maker: async_sessionmaker): + async def telegram_setup_edit_feature_handler(call: CallbackQuery, callback_data: SetupFeature, session_maker: async_sessionmaker) -> None: """ Query, what shows menu to enable / disable feature - :param call: - :param callback_data: - :param session_maker: - :return: + :param call: CallbackQuery class + :param callback_data: SetupFeature class + :param session_maker: AsyncSessionMaker SqlAlchemy object + :return: None """ is_enabled = await get_chat_config_value( chat_id=call.message.chat.id, session=session_maker, - setting=list_of_features[callback_data.feature_category][callback_data.feature_index] + setting=categorized_customizable_features[callback_data.feature_category][callback_data.feature_index] ) await call.message.edit_text( - list_of_features[callback_data.feature_category][callback_data.feature_index].description, + categorized_customizable_features[callback_data.feature_category][callback_data.feature_index].telegram_setting_description, reply_markup=await setup_feature_keyboard(category=callback_data.feature_category, index=callback_data.feature_index, is_enabled=is_enabled)) - async def telegram_features_edit_handler(call: CallbackQuery, callback_data: SetupAction, session_maker: async_sessionmaker): + async def telegram_features_edit_handler(call: CallbackQuery, callback_data: SetupAction, session_maker: async_sessionmaker) -> None: """ Query, what shows menu to enable / disable feature after editing - :param call: - :param callback_data: - :param session_maker: - :return: + :param call: CallbackQuery class + :param callback_data: SetupAction class + :param session_maker: AsyncSessionMaker SqlAlchemy object + :return: None """ async with session_maker() as session: async with session.begin(): await session.execute(Update(TelegramChatSettings) .values( - {list_of_features[callback_data.category_name][callback_data.feature_index].settings_name: callback_data.action == "enable"}) + {categorized_customizable_features[callback_data.category_name][callback_data.feature_index].telegram_setting_description: callback_data.action == "enable"}) .where(TelegramChatSettings.chat_id == call.message.chat.id)) await call.message.edit_text( - list_of_features[callback_data.category_name][callback_data.feature_index].description, + categorized_customizable_features[callback_data.feature_category][callback_data.feature_index].telegram_setting_description, reply_markup=await setup_feature_keyboard(category=callback_data.category_name, index=callback_data.afeature_index, is_enabled=callback_data.action == "enable")) diff --git a/bozenka/features/basic/start.py b/bozenka/features/basic/start.py index 3194b91..8404995 100644 --- a/bozenka/features/basic/start.py +++ b/bozenka/features/basic/start.py @@ -4,12 +4,11 @@ from aiogram.filters import Command from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, InlineKeyboardButton from aiogram.utils.keyboard import InlineKeyboardBuilder -from bozenka.features import BasicFeature +from bozenka.features.main import BasicFeature +from bozenka.instances.customizable_features_list import categorized_customizable_features, text_transcription from bozenka.instances.telegram.utils.callbacks_factory import HelpCategory, HelpBackCategory, HelpFeature, HelpBack -from bozenka.instances.telegram.utils.keyboards import help_category_keyboard, help_keyboard, \ - help_feature_keyboard, gpt_categories_keyboard -from bozenka.instances.telegram.utils.simpler import list_of_features -from bozenka.instances.version import build, is_updated +from bozenka.features.user.text_generation import gpt_categories_keyboard +from bozenka.instances.current_version import build, is_updated telegram_main_menu = InlineKeyboardMarkup( inline_keyboard=[ @@ -23,6 +22,51 @@ telegram_main_menu = InlineKeyboardMarkup( ) +# Help related keyboards +def main_help_keyboard() -> InlineKeyboardMarkup: + """ + Generate keyboard for /help command + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardBuilder() + for category in categorized_customizable_features: + kb.row(InlineKeyboardButton(text=text_transcription[category], + callback_data=HelpCategory(category_name=category).pack())) + + return kb.as_markup() + + +def help_category_keyboard(category: str) -> InlineKeyboardMarkup: + """ + Generate keyboard for one of categories + :param category: Category name + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardBuilder() + for setting in categorized_customizable_features[category]: + kb.row(InlineKeyboardButton(text=setting.telegram_setting_name, + callback_data=HelpFeature( + feature_index=categorized_customizable_features[category].index(setting), + feature_category=category + ).pack())) + kb.row(InlineKeyboardButton(text="🔙 Назад к списку категорий", + callback_data=HelpBack(back_to="category").pack())) + return kb.as_markup() + + +def help_feature_keyboard(category: str) -> InlineKeyboardMarkup: + """ + Just button for function of /help + :param category: Category name + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="🔙 Назад к списку функций", + callback_data=HelpBackCategory(category_name=category).pack())] + ]) + return kb + + class Start(BasicFeature): """ A class of /start command @@ -42,7 +86,7 @@ class Start(BasicFeature): :return: None """ await call.message.edit_text("Выберите категорию, по которой нужна помощь:", - reply_markup=help_keyboard()) + reply_markup=main_help_keyboard()) await call.answer() @staticmethod @@ -66,7 +110,7 @@ class Start(BasicFeature): :return: None """ await call.message.edit_text( - list_of_features[callback_data.feature_category][callback_data.feature_index].description, + categorized_customizable_features[callback_data.feature_category][callback_data.feature_index]. telegram_setting_description, reply_markup=help_feature_keyboard(category=callback_data.feature_category)) await call.answer() @@ -78,7 +122,7 @@ class Start(BasicFeature): :return: None """ await call.message.edit_text("Выберите категорию функций, по которой вам нужна помощь 🤖", - reply_markup=help_keyboard()) + reply_markup=main_help_keyboard()) await call.answer() @staticmethod diff --git a/bozenka/features/main.py b/bozenka/features/main.py new file mode 100644 index 0000000..0729daa --- /dev/null +++ b/bozenka/features/main.py @@ -0,0 +1,27 @@ +class BasicFeature: + """ + A classic class of lineral (basic) + feature of bozenka. IN FUTURE! + :param telegram_setting_in_list: Does feature shows in /setup list + """ + telegram_setting_in_list: bool = False # Does feature shows in /setup list + telegram_setting_name: str | None = None # Setting title in /setup command + telegram_setting_description: str | None = None # Setting description in /setup command + telegram_db_name = None # Name of TelegramChatSettings column will be affected + telegram_category: str | None = None # Telegram category name, current + # Telegram commands list of feature + telegram_commands: dict[str: str] = { + # + # Format is "CommandNameHere": "Command description is here" + # + "example": "Its an example" + } + telegram_cmd_avaible = True # Does this feature have a telegram commands + + # All handlers to register automaticly by bozenka + telegram_message_handlers = [ + # Format is [Handler, [Filters]] + ] + telegram_callback_handlers = [ + # Format is [Handler, [Filters]] + ] diff --git a/bozenka/features/user/image_generation.py b/bozenka/features/user/image_generation.py index a93f70e..ecc5007 100644 --- a/bozenka/features/user/image_generation.py +++ b/bozenka/features/user/image_generation.py @@ -4,18 +4,65 @@ from typing import Callable from aiogram import Dispatcher from aiogram.filters import CommandObject, Command from aiogram.fsm.context import FSMContext -from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, FSInputFile +from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, FSInputFile, InlineKeyboardButton +from aiogram.utils.keyboard import InlineKeyboardBuilder from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import TelegramChatSettings -from bozenka.features import BasicFeature +from bozenka.features.main import BasicFeature +from bozenka.generative import image_generative_size, image_generative_categories from bozenka.generative.kadinsky import kadinsky_gen -from bozenka.instances.telegram.utils.callbacks_factory import ImageGenerationCategory, ImageGeneration -from bozenka.instances.telegram.utils.keyboards import image_resolution_keyboard, delete_keyboard, \ - image_generation_keyboard, image_response_keyboard +from bozenka.instances.telegram.utils.callbacks_factory import ImageGenerationCategory, ImageGeneration, DeleteMenu, \ + GptStop +from bozenka.instances.telegram.utils.keyboards import delete_keyboard from bozenka.instances.telegram.utils.simpler import GeneratingImages +def telegram_image_response_keyboard(user_id: int) -> InlineKeyboardMarkup: + """ + Generating menu for image + :param user_id: User_id of called user + :return: InlineKeyboardMarkup + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())], + [InlineKeyboardButton(text="Хватит 🚫", callback_data=GptStop(user_id=str(user_id)).pack())] + ]) + return kb + + +def telegram_image_resolution_keyboard(user_id: int, category: str) -> InlineKeyboardMarkup: + """ + Create keyboard with list of resolution to generate image + :param category: Category name + :param user_id: User_id of called user + :return: InlineKeyboardMarkup + """ + builder = InlineKeyboardBuilder() + for size in image_generative_size: + builder.row(InlineKeyboardButton(text=size, + callback_data=ImageGeneration( + user_id=user_id, + category=category, + size=size + ).pack())) + return builder.as_markup() + + +def telegram_image_generation_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: + """ + Create keyboard with list of image generation librarioes avaible in the bozenka + :param user_id: User_id of called user + :return: InlineKeyboardMarkup + """ + builder = InlineKeyboardBuilder() + for category in image_generative_categories: + builder.row(InlineKeyboardButton(text=category, + callback_data=ImageGenerationCategory(user_id=user_id, + category=category).pack())) + return builder.as_markup() + + class ImageGeneratrion(BasicFeature): """ A classic class of lineral (basic) @@ -38,8 +85,8 @@ class ImageGeneratrion(BasicFeature): await state.update_data(set_category=callback_data.category) await state.set_state(GeneratingImages.set_size) await call.message.edit_text("Пожалуста, выберите размер изображения 🖼", - reply_markup=image_resolution_keyboard(user_id=call.from_user.id, - category=callback_data.category)) + reply_markup=telegram_image_resolution_keyboard(user_id=call.from_user.id, + category=callback_data.category)) async def telegram_end_generation_handler(call: CallbackQuery, callback_data: ImageGeneration, state: FSMContext) -> None: @@ -81,7 +128,7 @@ class ImageGeneratrion(BasicFeature): if await state.get_state(): return await msg.answer("Пожалуста, выберите сервис / модель для генерации изображений", - reply_markup=image_generation_keyboard(user_id=msg.from_user.id)) + reply_markup=telegram_image_generation_categories_keyboard(user_id=msg.from_user.id)) async def telegram_kadinsky_generating_handler(msg: Message, state: FSMContext) -> None: """ @@ -110,13 +157,13 @@ class ImageGeneratrion(BasicFeature): photo = FSInputFile(path) await msg.answer_photo(photo=photo, caption=msg.text, - reply_markup=image_response_keyboard(user_id=msg.from_user.id)) + reply_markup=telegram_image_response_keyboard(user_id=msg.from_user.id)) await message.delete() else: await message.edit_text("Простите, произошла ошибка 😔\n" "Убедитесь, что севрера kadinsky работают и ваш промт не является неподобающим и неприемлимым\n" "Если это продолжается, пожалуйста используйте /cancel", - reply_markup=image_response_keyboard(user_id=msg.from_user.id)) + reply_markup=telegram_image_response_keyboard(user_id=msg.from_user.id)) except Exception as ex: logging.log(msg=f"Get an exception for generating answer={ex}", diff --git a/bozenka/features/user/text_generation.py b/bozenka/features/user/text_generation.py index 332c8c1..ee41015 100644 --- a/bozenka/features/user/text_generation.py +++ b/bozenka/features/user/text_generation.py @@ -1,26 +1,284 @@ import logging +from typing import Any import g4f from aiogram import F from aiogram.filters import Command from aiogram.fsm.context import FSMContext -from aiogram.types import Message, CallbackQuery +from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup +from aiogram.utils.keyboard import InlineKeyboardBuilder from gpt4all import GPT4All from bozenka.database.tables.telegram import TelegramChatSettings -from bozenka.features import BasicFeature +from bozenka.features.main import BasicFeature +from bozenka.generative import text_generative_categories from bozenka.generative.gpt4all import model_path, check -from bozenka.generative.gpt4free import generate_gpt4free_providers +from bozenka.generative.gpt4free import generate_gpt4free_providers, generate_gpt4free_models from bozenka.instances.telegram.utils.callbacks_factory import Gpt4FreeProvsModelPage, Gpt4FreeProviderPage, \ Gpt4AllSelect, Gpt4AllModel, GptCategory, Gpt4freeResult, \ Gpt4FreeProvider, GptBackMenu, Gpt4FreeModel, Gpt4FreeCategory, Gpt4FreeModelPage, GptStop -from bozenka.instances.telegram.utils.keyboards import delete_keyboard, \ - text_response_keyboard, gpt_categories_keyboard, \ - gpt4free_models_by_provider_keyboard, gpt4free_providers_keyboard, gpt4all_model_menu, generate_gpt4all_page, \ - gpt4free_categories_keyboard, gpt4free_models_keyboard +from bozenka.instances.telegram.utils.keyboards import delete_keyboard from bozenka.instances.telegram.utils.simpler import AnsweringGPT4Free, AnsweringGpt4All + +def gpt_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: + """ + Create list keyboard list of gpt libraries, available in the bot + :param user_id: + :return: InlineKeyboardMarkup + """ + builder = InlineKeyboardBuilder() + for category in text_generative_categories: + builder.row(InlineKeyboardButton(text=category, + callback_data=GptCategory(user_id=str(user_id), category=category).pack())) + return builder.as_markup() + + +# Helper +def items_list_generator(page: int, list_of_items, count_of_items: int) -> list[Any]: + """ + Generate page, made for backend + :param page: + :param list_of_items: + :param count_of_items: + """ + items = [] + required_items = [item + page * count_of_items for item in range(count_of_items)] + for item, count in zip(list_of_items, range(0, len(list_of_items))): + if count not in required_items: + continue + items.append(item) + return items + + +def text_response_keyboard(user_id: int) -> InlineKeyboardMarkup: + """ + Generating menu for response from GPT + :param user_id: + :return: + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())], + [InlineKeyboardButton(text="Завершить диалог 🚫", callback_data=GptStop(user_id=str(user_id)).pack())] + ]) + return kb + + +def gpt4free_providers_keyboard(user_id: int, page: int) -> InlineKeyboardMarkup: + """ + Generate page of gpt providers, can be used by user. + :param user_id: + :param page: + :return: + """ + providers = generate_gpt4free_providers() + names = items_list_generator(page, providers, 4) + pages = [len(providers) // 4 - 1 if page - 1 == -1 else page - 1, + 0 if page + 1 >= len(providers) // 4 else page + 1] + generated_page = InlineKeyboardMarkup(inline_keyboard=[ + # First one provider + [InlineKeyboardButton(text=names[0], + callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[0], page="0").pack())], + # Second one provider + [InlineKeyboardButton(text=names[1], + callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[1], page="0").pack())], + # Third one provider + [InlineKeyboardButton(text=names[2], + callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[2], page="0").pack())], + # Fourh one provider (if exist) + [InlineKeyboardButton(text=names[3], + callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[3], + page="0").pack())] if len( + names) == 4 else [], + # Page right + [InlineKeyboardButton(text=str(len(providers) // 4 if page == 0 else "1"), + callback_data=Gpt4FreeProviderPage( + page=str(len(providers) // 4 - 1 if page == 0 else "0"), + user_id=user_id).pack()), + + InlineKeyboardButton(text="⬅️", callback_data=Gpt4FreeProviderPage(page=pages[0], user_id=user_id).pack()), + InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"), + # Page left + InlineKeyboardButton(text="➡️", callback_data=Gpt4FreeProviderPage(page=pages[1], user_id=user_id).pack()), + InlineKeyboardButton(text=str(len(providers) // 4 if page != len(providers) // 4 - 1 else "1"), + callback_data=Gpt4FreeProviderPage( + page=str(len(providers) // 4 - 1 if page != len(providers) // 4 - 1 else "0"), + user_id=user_id).pack()) + ], + # Under list buttons + [InlineKeyboardButton(text="🔙 Вернуться к категориям", + callback_data=GptBackMenu(user_id=user_id, back_to="g4fcategory").pack())], + [InlineKeyboardButton(text="Спасибо, не надо ❌", + callback_data=GptStop(user_id=str(user_id)).pack())]]) + return generated_page + + +def gpt4free_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: + """ + Menu of categories in Gpt4Free (Providers / Models) + :param user_id: + :return: + """ + print("!231234") + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text="По моделям 🤖", + callback_data=Gpt4FreeCategory(category="models", user_id=user_id).pack()) + ], [ + InlineKeyboardButton(text="По провайдерам 🤖", + callback_data=Gpt4FreeCategory(category="providers", user_id=user_id).pack()) + ]]) + return kb + + +def gpt4free_models_keyboard(user_id: int, page: int) -> InlineKeyboardMarkup: + """ + Generating list of GPT4FREE models, can be used to generate text. + :param user_id: + :param page: + :return: + """ + builder = InlineKeyboardBuilder() + full_list = g4f.ModelUtils.convert.keys() + models = items_list_generator(page=page, list_of_items=full_list, count_of_items=4) + pages = [len(full_list) // 4 - 1 if page - 1 == -1 else page - 1, + 0 if page + 1 >= len(full_list) // 4 else page + 1] + + for model in models: + builder.row(InlineKeyboardButton(text=model, + callback_data=Gpt4FreeModel(user_id=user_id, model=model).pack())) + builder.row( + # First page button + InlineKeyboardButton(text=str(len(full_list) // 4 if page == 0 else "1"), + callback_data=Gpt4FreeModelPage( + page=str(len(full_list) // 4 - 1 if page == 0 else "1"), + user_id=user_id).pack(), + ), + # Page back button + InlineKeyboardButton(text="⬅️", + callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[0], ).pack()), + # Count of page button + InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"), + # Next page button + InlineKeyboardButton(text="➡️", + callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[1]).pack()), + # Last page button + InlineKeyboardButton(text=str(len(full_list) // 4 if page != 0 else "1"), + callback_data=Gpt4FreeModelPage( + page=str(len(full_list) // 4 - 1) if page != 0 else "1", + user_id=user_id).pack(), )) + builder.row(InlineKeyboardButton(text="🔙 Вернуться", + callback_data=GptBackMenu(user_id=user_id, back_to="g4fcategory").pack())) + builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", + callback_data=GptStop(user_id=str(user_id)).pack())) + return builder.as_markup() + + +def gpt4free_models_by_provider_keyboard(user_id: int, provider: str, page: int) -> InlineKeyboardMarkup: + """ + Generating list of GPT4Free provider's models, can be used to generate text. + Will be also reworked. + :param user_id: + :param provider: + :param page: + :return: + """ + builder = InlineKeyboardBuilder() + models = generate_gpt4free_models() + providers = generate_gpt4free_providers() + if provider in models: + if providers[provider].supports_gpt_4: + models[provider].append("") + names = items_list_generator(page, models[provider], 4) + for name in names: + builder.row(InlineKeyboardButton(text=name.replace('-', ' '), + callback_data=Gpt4freeResult(user_id=str(user_id), provider=provider, + model=name).pack())) + pages = [len(models[provider]) // 4 - 1 if page - 1 == -1 else page - 1, + 0 if page + 1 >= len(models[provider]) // 4 else page + 1] + if len(models[provider]) > 4: + builder.row( + # First page button + InlineKeyboardButton(text=str(len(models[provider]) // 4 if page == 0 else "1"), + callback_data=Gpt4FreeProvsModelPage( + page=str(len(models[provider]) // 4 - 1 if page == 0 else "1"), + user_id=user_id, + provider=provider).pack(), + ), + # Page back button + InlineKeyboardButton(text="⬅️", + callback_data=Gpt4FreeProvsModelPage(user_id=str(user_id), page=pages[0], + provider=provider).pack()), + # Count of page button + InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"), + # Next page button + InlineKeyboardButton(text="➡️", + callback_data=Gpt4FreeProvsModelPage(user_id=str(user_id), page=pages[1], + provider=provider).pack()), + # Last page button + InlineKeyboardButton(text=str(len(models[provider]) // 4 if page != 0 else "1"), + callback_data=Gpt4FreeProvsModelPage( + page=str(len(models[provider]) // 4 - 1) if page != 0 else "1", + user_id=user_id, + provider=provider).pack(), )) + else: + if providers[provider].supports_gpt_4: + builder.row(InlineKeyboardButton(text="gpt 4", + callback_data=Gpt4freeResult(user_id=str(user_id), + provider=provider, + model="gpt-4").pack())) + if providers[provider].supports_gpt_35_turbo: + builder.row(InlineKeyboardButton(text="gpt 3.5 turbo", + callback_data=Gpt4freeResult + (user_id=str(user_id), provider=provider, model="gpt-3.5-turbo").pack())) + builder.row(InlineKeyboardButton(text="🔙 Вернуться к провайдерам", + callback_data=GptBackMenu(user_id=user_id, back_to="providers").pack())) + builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", callback_data=GptStop(user_id=str(user_id)).pack())) + return builder.as_markup() + + +# Gpt4All related keyboards +def generate_gpt4all_page(user_id: int) -> InlineKeyboardMarkup: + """ + Generating list of GPT4All models. + :param user_id: + :return: + """ + models = GPT4All.list_models() + + builder = InlineKeyboardBuilder() + + for model in models: + builder.row(InlineKeyboardButton( + text=model["name"], + callback_data=Gpt4AllModel(user_id=str(user_id), index=str(models.index(model))).pack()) + ) + builder.row(InlineKeyboardButton(text="🔙 Вернуться к списку", + callback_data=GptBackMenu(user_id=user_id, back_to="g4fcategory").pack())) + builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", + callback_data=GptStop(user_id=str(user_id)).pack())) + return builder.as_markup() + + +def gpt4all_model_menu(user_id: int, index: int) -> InlineKeyboardMarkup: + """ + Generating menu for selection on of GPT4ALL models + :param user_id: + :param index: + """ + kb = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Выбрать ✅", + callback_data=Gpt4AllSelect(user_id=user_id, index=str(index)).pack())], + [InlineKeyboardButton(text="🔙 Вернуться к списку", + callback_data=GptBackMenu(user_id=user_id, back_to="g4amodels").pack())], + [InlineKeyboardButton(text="Спасибо, не надо ❌", + callback_data=GptStop(user_id=str(user_id)).pack())] + ]) + return kb + + + + class TextGeneratrion(BasicFeature): """ A class, what have inside all handlers / functions diff --git a/bozenka/features/user/welcome.py b/bozenka/features/user/welcome.py index 9dbcfbe..facfa60 100644 --- a/bozenka/features/user/welcome.py +++ b/bozenka/features/user/welcome.py @@ -6,9 +6,7 @@ from aiogram.types import Message, CallbackQuery from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import TelegramChatSettings -from bozenka.features import BasicFeature -from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg -from bozenka.instances.telegram.utils.keyboards import unpin_msg_keyboard, delete_keyboard, pin_msg_keyboard +from bozenka.features.main import BasicFeature from bozenka.instances.telegram.utils.simpler import SolutionSimpler diff --git a/bozenka/generative/__init__.py b/bozenka/generative/__init__.py index f69fa20..4bd1f7d 100644 --- a/bozenka/generative/__init__.py +++ b/bozenka/generative/__init__.py @@ -1,14 +1,6 @@ import dataclasses -@dataclasses -class QueryPosition: - """ - Class of Query to generate something - with models - """ - data: dict - instance: str # List of text generative categories, what we support text_generative_categories = [ diff --git a/bozenka/instances/__init__.py b/bozenka/instances/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/instances/basic_features_list.py b/bozenka/instances/basic_features_list.py new file mode 100644 index 0000000..e70b04a --- /dev/null +++ b/bozenka/instances/basic_features_list.py @@ -0,0 +1,6 @@ +from bozenka.features import Setup, Start + +basic_features = [ + Setup, + Start +] diff --git a/bozenka/instances/version.py b/bozenka/instances/current_version.py similarity index 100% rename from bozenka/instances/version.py rename to bozenka/instances/current_version.py diff --git a/bozenka/instances/customizable_features_list.py b/bozenka/instances/customizable_features_list.py new file mode 100644 index 0000000..d83d7f5 --- /dev/null +++ b/bozenka/instances/customizable_features_list.py @@ -0,0 +1,30 @@ +import bozenka.features.admin +from bozenka.features import * +from bozenka.features.admin import * + +customizable_features = [ + # Admin related category + Moderation, + Invite, + Pins, + Threads, + ChatInformation, + # User related category + ImageGeneratrion, + TextGeneratrion, + Welcome, +] + +text_transcription = { + "user": "Пользователи 👤", + "admin": "Администраторы 👮‍♂" +} + +categorized_customizable_features = {} + +for feature in customizable_features: + if feature.telegram_setting_in_list: + if feature.telegram_category in categorized_customizable_features.keys(): + categorized_customizable_features[feature.telegram_category].append(feature) + else: + categorized_customizable_features[feature.telegram_category] = [feature] diff --git a/bozenka/instances/features_list.py b/bozenka/instances/features_list.py deleted file mode 100644 index 57b66e0..0000000 --- a/bozenka/instances/features_list.py +++ /dev/null @@ -1,26 +0,0 @@ -from bozenka.features import * - -features_list = [ - # Admin related category - Moderation, - Invite, - Pins, - Threads, - ChatInformation, - # User related category - ImageGeneratrion, - TextGeneratrion, - Welcome, - # Basic Functions - Setup, - Start -] - -customizable_features = {} - -for feature in features_list: - if feature.telegram_setting_in_list: - if feature.telegram_category in customizable_features.keys(): - customizable_features[feature.telegram_category].append(feature) - else: - customizable_features[feature.telegram_category] = [feature] diff --git a/bozenka/instances/telegram/__init__.py b/bozenka/instances/telegram/__init__.py index 56b5c84..e510a49 100644 --- a/bozenka/instances/telegram/__init__.py +++ b/bozenka/instances/telegram/__init__.py @@ -5,13 +5,12 @@ from aiogram import Dispatcher, Bot from aiogram.types import BotCommand from sqlalchemy.ext.asyncio import async_sessionmaker -from bozenka.features import BasicFeature -from bozenka.instances.features_list import features_list -from bozenka.instances.telegram.utils.simpler import list_of_commands +from bozenka.instances.basic_features_list import basic_features +from bozenka.instances.customizable_features_list import customizable_features from bozenka.instances.telegram.queries import * -async def register_all_features(list_of_features: list[BasicFeature], dispatcher: Dispatcher, bot: Bot) -> None: +async def register_all_features(list_of_features: list, dispatcher: Dispatcher, bot: Bot) -> None: """ Registers all features / handlers avaible in bozenka :param list_of_features: List of features @@ -34,10 +33,6 @@ async def register_all_features(list_of_features: list[BasicFeature], dispatcher await bot.set_my_commands(cmd_list) - # Registering other handlers - await dispatcher.callback_query.register(delete_callback_handler, DeleteMenu.filter()) - await dispatcher.callback_query.register(hide_menu_handler, HideMenu.filter()) - async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: """ @@ -51,7 +46,15 @@ async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: dp = Dispatcher() + # Registering other handlers + dp.callback_query.register(delete_callback_handler, DeleteMenu.filter()) + dp.callback_query.register(hide_menu_handler, HideMenu.filter()) + await dp.start_polling(bot, session_maker=session_maker, # Pass your async_sessionmaker here, you can do dependency injection - on_startup=[await register_all_features(list_of_features=features_list, dispatcher=dp, bot=bot)] + on_startup=[ + await register_all_features(list_of_features=customizable_features, dispatcher=dp, bot=bot), + await register_all_features(list_of_features=basic_features, dispatcher=dp, bot=bot) + + ] ) diff --git a/bozenka/instances/telegram/utils/filters/__init__.py b/bozenka/instances/telegram/filters/__init__.py similarity index 100% rename from bozenka/instances/telegram/utils/filters/__init__.py rename to bozenka/instances/telegram/filters/__init__.py diff --git a/bozenka/instances/telegram/utils/filters/chat_setting.py b/bozenka/instances/telegram/filters/chat_setting.py similarity index 53% rename from bozenka/instances/telegram/utils/filters/chat_setting.py rename to bozenka/instances/telegram/filters/chat_setting.py index 3bd0dba..eb44b3b 100644 --- a/bozenka/instances/telegram/utils/filters/chat_setting.py +++ b/bozenka/instances/telegram/filters/chat_setting.py @@ -3,7 +3,6 @@ from aiogram.types import Message from sqlalchemy.ext.asyncio import async_sessionmaker from bozenka.database.tables.telegram import get_chat_configuration, get_chat_config_value -from bozenka.instances.telegram.utils.simpler import list_of_features class IsSettingEnabled(Filter): @@ -11,17 +10,16 @@ class IsSettingEnabled(Filter): Check, does chat have enabled required feature """ - def __init__(self, setting: str) -> None: + def __init__(self, setting) -> None: self.setting = setting async def __call__(self, msg: Message, session_maker: async_sessionmaker) -> bool: - setting_object = None - for key in list_of_features.items(): - for feature in list_of_features[key]: - if feature.setting_name == self.setting: - setting_object = feature - else: - continue + """ + Working after calling this filter + :param msg: Message telegram boject + :param session_maker: AsyncSessionMaker SqlAlchemy object + :return: Is config enabled + """ - return await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, setting=setting_object) + return await get_chat_config_value(chat_id=msg.chat.id, session=session_maker, setting=self.setting) diff --git a/bozenka/instances/telegram/utils/filters/permissions.py b/bozenka/instances/telegram/filters/permissions.py similarity index 85% rename from bozenka/instances/telegram/utils/filters/permissions.py rename to bozenka/instances/telegram/filters/permissions.py index 100a196..1261ae5 100644 --- a/bozenka/instances/telegram/utils/filters/permissions.py +++ b/bozenka/instances/telegram/filters/permissions.py @@ -3,8 +3,9 @@ from typing import Any from aiogram.filters import Filter from aiogram.methods import GetChatMember from aiogram.types import Message, ChatPermissions, CallbackQuery -from aiogram.enums import ChatMemberStatus -from bozenka.instances.telegram.utils.simpler import ru_cmds +from aiogram.enums import ChatMemberStatus, ChatType + +from bozenka.instances.telegram.utils.keyboards import delete_keyboard class UserHasPermissions(Filter): @@ -149,14 +150,29 @@ class IsAdminFilter(Filter): """ user = await msg.chat.get_member(msg.from_user.id) bot = await msg.chat.get_member(msg.bot.id) + + if msg.chat.type == ChatType.PRIVATE: + return False + if ChatMemberStatus.ADMINISTRATOR != user.status and ChatMemberStatus.CREATOR != user.status: if bot.status != ChatMemberStatus.ADMINISTRATOR: await msg.reply("Ошибка ❌\n" - "У вас нет прав на использование этой комманды. У меня нет прав на использование 🚫") + "У вас нет прав на использование этой комманды. \n" + "У меня нет прав для осуществления этой комманды 🚫", + reply_markup=delete_keyboard()) + return False else: await msg.reply("Ошибка ❌\n" - "У вас нет прав на использование этой комманды 🚫") + "У вас нет прав на использование этой комманды 🚫", + reply_markup=delete_keyboard()) + return False + + if bot.status != ChatMemberStatus.ADMINISTRATOR: + await msg.reply("Ошибка ❌\n" + "У меня нет прав для осуществления этой комманды 🚫", + reply_markup=delete_keyboard()) return False + if ChatMemberStatus.CREATOR == user.status: return True return ChatMemberStatus.ADMINISTRATOR == user.status or ChatMemberStatus.CREATOR == user.status diff --git a/bozenka/instances/telegram/utils/middleware/__init__.py b/bozenka/instances/telegram/middleware/__init__.py similarity index 74% rename from bozenka/instances/telegram/utils/middleware/__init__.py rename to bozenka/instances/telegram/middleware/__init__.py index 4b6f273..8341dac 100644 --- a/bozenka/instances/telegram/utils/middleware/__init__.py +++ b/bozenka/instances/telegram/middleware/__init__.py @@ -1,9 +1,6 @@ import logging -from aiogram import Router, Dispatcher - -from bozenka.instances.telegram.utils.middleware.antiflood import MessageThrottlingMiddleware, \ - CallbackThrottlingMiddleware, CounterMiddleware +from aiogram import Dispatcher def register_middlewares(dp: Dispatcher) -> None: diff --git a/bozenka/instances/telegram/utils/middleware/antiflood.py b/bozenka/instances/telegram/middleware/antiflood.py similarity index 100% rename from bozenka/instances/telegram/utils/middleware/antiflood.py rename to bozenka/instances/telegram/middleware/antiflood.py diff --git a/bozenka/instances/telegram/utils/middleware/retry.py b/bozenka/instances/telegram/middleware/retry.py similarity index 100% rename from bozenka/instances/telegram/utils/middleware/retry.py rename to bozenka/instances/telegram/middleware/retry.py diff --git a/bozenka/instances/telegram/utils/__init__.py b/bozenka/instances/telegram/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bozenka/instances/telegram/utils/delete.py b/bozenka/instances/telegram/utils/delete.py new file mode 100644 index 0000000..74658f9 --- /dev/null +++ b/bozenka/instances/telegram/utils/delete.py @@ -0,0 +1,16 @@ +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + +from bozenka.instances.telegram.utils.callbacks_factory import * + + +def delete_keyboard(admin_id: int) -> InlineKeyboardMarkup: + """ + Basic keyboard for all messages from bot. + By pressing this button, message from bot will get deleted. + :param admin_id: User_id of user to work with this + :return: None + """ + kb = InlineKeyboardMarkup(inline_keyboard=[[ + InlineKeyboardButton(text="Спасибо, удали сообщение ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) + ]]) + return kb diff --git a/bozenka/instances/telegram/utils/keyboards/__init__.py b/bozenka/instances/telegram/utils/keyboards/__init__.py deleted file mode 100644 index 2453fe9..0000000 --- a/bozenka/instances/telegram/utils/keyboards/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .inline import * diff --git a/bozenka/instances/telegram/utils/keyboards/inline.py b/bozenka/instances/telegram/utils/keyboards/inline.py deleted file mode 100644 index 336ef1a..0000000 --- a/bozenka/instances/telegram/utils/keyboards/inline.py +++ /dev/null @@ -1,615 +0,0 @@ -import g4f -import gpt4all - -from typing import Any - -from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message -from aiogram.utils.keyboard import InlineKeyboardBuilder -from gpt4all import GPT4All -from sqlalchemy.ext.asyncio import async_sessionmaker - -from bozenka.database.tables.telegram import get_chat_config_value -from bozenka.instances.features_list import customizable_features -from bozenka.instances.telegram.utils.callbacks_factory import * -from bozenka.instances.telegram.utils.simpler.lists_of_content import generate_list_of_features -from bozenka.generative.gpt4free import generate_gpt4free_models, generate_gpt4free_providers -from bozenka.generative import text_generative_categories, image_generative_categories, image_generative_size - -""" -File, contains inline keyboard & menus and their work. -Right now only on Russian language, multi-language planning soon. -""" - - -def start_keyboard() -> InlineKeyboardMarkup: - """ - Generate keyboard for /start command - """ - kb = InlineKeyboardMarkup( - inline_keyboard=[ - [InlineKeyboardButton(text="Добавить в ваш групповой чат 🔌", callback_data="addtochat")], - [InlineKeyboardButton(text="Информация об функционале бота 🔨", callback_data="functional")], - [InlineKeyboardButton(text="О данном проекте ℹ️", callback_data="aboutdevs")], - [InlineKeyboardButton(text="О данном запущенном экзепляре ℹ️", callback_data="aboutbot")], - [InlineKeyboardButton(text="Начать диалог с текстовым ИИ 🤖", callback_data="dialogai")], - [InlineKeyboardButton(text="Начать генерировать изображения 🖼", callback_data="dialogimage")], - ] - ) - return kb - - -# Help related keyboards -def help_keyboard() -> InlineKeyboardMarkup: - """ - Generate keyboard for /help command - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Администраторы 👮‍♂", - callback_data=HelpCategory(category_name="Admins").pack())], - [InlineKeyboardButton(text="Пользователи 👤", - callback_data=HelpCategory(category_name="Members").pack())], - [InlineKeyboardButton(text="В разработке 👨‍💻", - callback_data=HelpCategory(category_name="Devs").pack())], - [InlineKeyboardButton(text="Вернуться 🔙", callback_data="back")] - ]) - return kb - - -def help_category_keyboard(category: str) -> InlineKeyboardMarkup: - """ - Generate keyboard for one of categories - :param category: - :return: - """ - kb = InlineKeyboardBuilder() - list_of_features = generate_list_of_features(category) - for setting in list_of_features: - kb.row(InlineKeyboardButton(text=setting.name, - callback_data=HelpFeature( - feature_index=list_of_features.index(setting), - feature_category=category - ).pack())) - kb.row(InlineKeyboardButton(text="🔙 Назад к списку категорий", - callback_data=HelpBack(back_to="category").pack())) - return kb.as_markup() - - -def help_feature_keyboard(category: str) -> InlineKeyboardMarkup: - """ - Just button for function of /help - :param category: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="🔙 Назад к списку функций", - callback_data=HelpBackCategory(category_name=category).pack())] - ]) - return kb - - -# Setup related keyboards -def setup_keyboard() -> InlineKeyboardMarkup: - """ - Generate keyboard for /setup command - :return: - """ - kb = InlineKeyboardBuilder() - translations = { - "admin": "Администраторы 👮‍♂", - "user": "Пользователи 👤" - } - - for category in customizable_features: - kb.row(InlineKeyboardButton(text=translations[category], - callback_data=SetupCategory(category_name=category).pack())) - - return kb.as_markup() - - -def setup_category_keyboard(category: str) -> InlineKeyboardMarkup: - """ - Generate keyboard for one of categories - :param category: - :return: - """ - kb = InlineKeyboardBuilder() - list_of_features = generate_list_of_features(category) - for setting in list_of_features: - kb.row(InlineKeyboardButton(text=setting.name, - callback_data=SetupFeature( - feature_index=list_of_features.index(setting), - feature_category=category - ).pack())) - return kb.as_markup() - - -async def setup_feature_keyboard(category: str, index: int, is_enabled: bool) -> InlineKeyboardMarkup: - """ - Generate keyboard for enabling or disabling - on of features - :param is_enabled: - :param category: - :param index: - - :return: - """ - - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Выключить ❌", callback_data=SetupAction(action="disable", - feature_category=category, - feature_index=index).pack()) - if is_enabled else - InlineKeyboardButton(text="Включить ✅", callback_data=SetupAction(action="enable", - feature_category=category, - feature_index=index).pack()) - ], [ - InlineKeyboardButton(text="Вернуться 🔙", callback_data=SetupAction(action="back", - feature_category=category, - feature_index=index).pack())]]) - return kb - - -def delete_keyboard(admin_id: int) -> InlineKeyboardMarkup: - """ - Basic keyboard for all messages from bot. - By pressing this button, message from bot will get deleted. - :param admin_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) - ]]) - return kb - - -def image_resolution_keyboard(user_id: int, category: str) -> InlineKeyboardMarkup: - """ - Create keyboard with list of resolution to generate image - :param user_id: - :param category: - :return: - """ - builder = InlineKeyboardBuilder() - for size in image_generative_size: - builder.row(InlineKeyboardButton(text=size, - callback_data=ImageGeneration( - user_id=user_id, - category=category, - size=size - ).pack())) - return builder.as_markup() - - -def image_generation_keyboard(user_id: int) -> InlineKeyboardMarkup: - """ - Create keyboard with list of image generation librarioes avaible in the bot - :param user_id: - :return: - """ - builder = InlineKeyboardBuilder() - for category in image_generative_categories: - builder.row(InlineKeyboardButton(text=category, - callback_data=ImageGenerationCategory(user_id=user_id, - category=category).pack())) - return builder.as_markup() - - -# LLM / GPT related keyboards -# GPT CATEGORIES -def gpt_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: - """ - Create list keyboard list of gpt libraries, available in the bot - :param user_id: - :return: InlineKeyboardMarkup - """ - builder = InlineKeyboardBuilder() - for category in text_generative_categories: - builder.row(InlineKeyboardButton(text=category, - callback_data=GptCategory(user_id=str(user_id), category=category).pack())) - return builder.as_markup() - - -# Helper -def items_list_generator(page: int, list_of_items, count_of_items: int) -> list[Any]: - """ - Generate page, made for backend - :param page: - :param list_of_items: - :param count_of_items: - """ - items = [] - required_items = [item + page * count_of_items for item in range(count_of_items)] - for item, count in zip(list_of_items, range(0, len(list_of_items))): - if count not in required_items: - continue - items.append(item) - return items - - -def gpt4free_providers_keyboard(user_id: int, page: int) -> InlineKeyboardMarkup: - """ - Generate page of gpt providers, can be used by user. - :param user_id: - :param page: - :return: - """ - providers = generate_gpt4free_providers() - names = items_list_generator(page, providers, 4) - pages = [len(providers) // 4 - 1 if page - 1 == -1 else page - 1, - 0 if page + 1 >= len(providers) // 4 else page + 1] - generated_page = InlineKeyboardMarkup(inline_keyboard=[ - # First one provider - [InlineKeyboardButton(text=names[0], - callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[0], page="0").pack())], - # Second one provider - [InlineKeyboardButton(text=names[1], - callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[1], page="0").pack())], - # Third one provider - [InlineKeyboardButton(text=names[2], - callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[2], page="0").pack())], - # Fourh one provider (if exist) - [InlineKeyboardButton(text=names[3], - callback_data=Gpt4FreeProvider(user_id=user_id, provider=names[3], - page="0").pack())] if len( - names) == 4 else [], - # Page right - [InlineKeyboardButton(text=str(len(providers) // 4 if page == 0 else "1"), - callback_data=Gpt4FreeProviderPage( - page=str(len(providers) // 4 - 1 if page == 0 else "0"), - user_id=user_id).pack()), - - InlineKeyboardButton(text="⬅️", callback_data=Gpt4FreeProviderPage(page=pages[0], user_id=user_id).pack()), - InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"), - # Page left - InlineKeyboardButton(text="➡️", callback_data=Gpt4FreeProviderPage(page=pages[1], user_id=user_id).pack()), - InlineKeyboardButton(text=str(len(providers) // 4 if page != len(providers) // 4 - 1 else "1"), - callback_data=Gpt4FreeProviderPage( - page=str(len(providers) // 4 - 1 if page != len(providers) // 4 - 1 else "0"), - user_id=user_id).pack()) - ], - # Under list buttons - [InlineKeyboardButton(text="🔙 Вернуться к категориям", - callback_data=GptBackMenu(user_id=user_id, back_to="g4fcategory").pack())], - [InlineKeyboardButton(text="Спасибо, не надо ❌", - callback_data=GptStop(user_id=str(user_id)).pack())]]) - return generated_page - - -def gpt4free_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: - """ - Menu of categories in Gpt4Free (Providers / Models) - :param user_id: - :return: - """ - print("!231234") - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="По моделям 🤖", - callback_data=Gpt4FreeCategory(category="models", user_id=user_id).pack()) - ], [ - InlineKeyboardButton(text="По провайдерам 🤖", - callback_data=Gpt4FreeCategory(category="providers", user_id=user_id).pack()) - ]]) - return kb - - -def gpt4free_models_keyboard(user_id: int, page: int) -> InlineKeyboardMarkup: - """ - Generating list of GPT4FREE models, can be used to generate text. - :param user_id: - :param page: - :return: - """ - builder = InlineKeyboardBuilder() - full_list = g4f.ModelUtils.convert.keys() - models = items_list_generator(page=page, list_of_items=full_list, count_of_items=4) - pages = [len(full_list) // 4 - 1 if page - 1 == -1 else page - 1, - 0 if page + 1 >= len(full_list) // 4 else page + 1] - - for model in models: - builder.row(InlineKeyboardButton(text=model, - callback_data=Gpt4FreeModel(user_id=user_id, model=model).pack())) - builder.row( - # First page button - InlineKeyboardButton(text=str(len(full_list) // 4 if page == 0 else "1"), - callback_data=Gpt4FreeModelPage( - page=str(len(full_list) // 4 - 1 if page == 0 else "1"), - user_id=user_id).pack(), - ), - # Page back button - InlineKeyboardButton(text="⬅️", - callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[0], ).pack()), - # Count of page button - InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"), - # Next page button - InlineKeyboardButton(text="➡️", - callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[1]).pack()), - # Last page button - InlineKeyboardButton(text=str(len(full_list) // 4 if page != 0 else "1"), - callback_data=Gpt4FreeModelPage( - page=str(len(full_list) // 4 - 1) if page != 0 else "1", - user_id=user_id).pack(), )) - builder.row(InlineKeyboardButton(text="🔙 Вернуться", - callback_data=GptBackMenu(user_id=user_id, back_to="g4fcategory").pack())) - builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", - callback_data=GptStop(user_id=str(user_id)).pack())) - return builder.as_markup() - - -def gpt4free_models_by_provider_keyboard(user_id: int, provider: str, page: int) -> InlineKeyboardMarkup: - """ - Generating list of GPT4Free provider's models, can be used to generate text. - Will be also reworked. - :param user_id: - :param provider: - :param page: - :return: - """ - builder = InlineKeyboardBuilder() - models = generate_gpt4free_models() - providers = generate_gpt4free_providers() - if provider in models: - if providers[provider].supports_gpt_4: - models[provider].append("") - names = items_list_generator(page, models[provider], 4) - for name in names: - builder.row(InlineKeyboardButton(text=name.replace('-', ' '), - callback_data=Gpt4freeResult(user_id=str(user_id), provider=provider, - model=name).pack())) - pages = [len(models[provider]) // 4 - 1 if page - 1 == -1 else page - 1, - 0 if page + 1 >= len(models[provider]) // 4 else page + 1] - if len(models[provider]) > 4: - builder.row( - # First page button - InlineKeyboardButton(text=str(len(models[provider]) // 4 if page == 0 else "1"), - callback_data=Gpt4FreeProvsModelPage( - page=str(len(models[provider]) // 4 - 1 if page == 0 else "1"), - user_id=user_id, - provider=provider).pack(), - ), - # Page back button - InlineKeyboardButton(text="⬅️", - callback_data=Gpt4FreeProvsModelPage(user_id=str(user_id), page=pages[0], - provider=provider).pack()), - # Count of page button - InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"), - # Next page button - InlineKeyboardButton(text="➡️", - callback_data=Gpt4FreeProvsModelPage(user_id=str(user_id), page=pages[1], - provider=provider).pack()), - # Last page button - InlineKeyboardButton(text=str(len(models[provider]) // 4 if page != 0 else "1"), - callback_data=Gpt4FreeProvsModelPage( - page=str(len(models[provider]) // 4 - 1) if page != 0 else "1", - user_id=user_id, - provider=provider).pack(), )) - else: - if providers[provider].supports_gpt_4: - builder.row(InlineKeyboardButton(text="gpt 4", - callback_data=Gpt4freeResult(user_id=str(user_id), - provider=provider, - model="gpt-4").pack())) - if providers[provider].supports_gpt_35_turbo: - builder.row(InlineKeyboardButton(text="gpt 3.5 turbo", - callback_data=Gpt4freeResult - (user_id=str(user_id), provider=provider, model="gpt-3.5-turbo").pack())) - builder.row(InlineKeyboardButton(text="🔙 Вернуться к провайдерам", - callback_data=GptBackMenu(user_id=user_id, back_to="providers").pack())) - builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", callback_data=GptStop(user_id=str(user_id)).pack())) - return builder.as_markup() - - -# Gpt4All related keyboards -def generate_gpt4all_page(user_id: int) -> InlineKeyboardMarkup: - """ - Generating list of GPT4All models. - :param user_id: - :return: - """ - models = GPT4All.list_models() - - builder = InlineKeyboardBuilder() - - for model in models: - builder.row(InlineKeyboardButton( - text=model["name"], - callback_data=Gpt4AllModel(user_id=str(user_id), index=str(models.index(model))).pack()) - ) - builder.row(InlineKeyboardButton(text="🔙 Вернуться к списку", - callback_data=GptBackMenu(user_id=user_id, back_to="g4fcategory").pack())) - builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", - callback_data=GptStop(user_id=str(user_id)).pack())) - return builder.as_markup() - - -def gpt4all_model_menu(user_id: int, index: int) -> InlineKeyboardMarkup: - """ - Generating menu for selection on of GPT4ALL models - :param user_id: - :param index: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Выбрать ✅", - callback_data=Gpt4AllSelect(user_id=user_id, index=str(index)).pack())], - [InlineKeyboardButton(text="🔙 Вернуться к списку", - callback_data=GptBackMenu(user_id=user_id, back_to="g4amodels").pack())], - [InlineKeyboardButton(text="Спасибо, не надо ❌", - callback_data=GptStop(user_id=str(user_id)).pack())] - ]) - return kb - - -# Universal response from GPT / LLM keyboard -def text_response_keyboard(user_id: int) -> InlineKeyboardMarkup: - """ - Generating menu for response from GPT - :param user_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())], - [InlineKeyboardButton(text="Завершить диалог 🚫", callback_data=GptStop(user_id=str(user_id)).pack())] - ]) - return kb - - -def image_response_keyboard(user_id: int) -> InlineKeyboardMarkup: - """ - Generating menu for image - :param user_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())], - [InlineKeyboardButton(text="Хватит 🚫", callback_data=GptStop(user_id=str(user_id)).pack())] - ]) - return kb - - -# Admin related keyboards -# Ban / Unban keyboards -def ban_keyboard(admin_id: int, ban_id: int) -> InlineKeyboardMarkup: - """ - Generating menu for /ban command. - :param admin_id: - :param ban_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) - ], [ - InlineKeyboardButton(text="Разбанить 🛠️", callback_data=UnbanData(user_id_unban=str(ban_id), - user_id_clicked=str(admin_id)).pack()) - ]]) - return kb - - -def unban_keyboard(admin_id: int, ban_id: int) -> InlineKeyboardMarkup: - """ - Generating menu for /unban command. - :param admin_id: - :param ban_id: - :return: - """ - print(ban_id) - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack()) - ], [ - InlineKeyboardButton(text="Забанить 🛠️", callback_data=BanData(user_id_ban=str(ban_id), - user_id_clicked=str(admin_id)).pack()) - ]]) - return kb - - -# Mute / Unmute keyboards -def mute_keyboard(admin_id: int, mute_id: int) -> InlineKeyboardMarkup: - """ - Generating menu for /mute command. - :param admin_id: - :param mute_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Спасибо ✅", - callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())], - [InlineKeyboardButton(text="Размутить 🛠️", - callback_data=UnmuteData(user_id_unmute=mute_id, user_id_clicked=admin_id).pack())]]) - return kb - - -def unmute_keyboard(admin_id: int, unmute_id: int) -> InlineKeyboardMarkup: - """ - Generating menu for /unmute command. - :param admin_id: - :param unmute_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Спасибо ✅", - callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())], - [InlineKeyboardButton(text="Замутить 🛠️", - callback_data=MuteData(user_id_mute=unmute_id, user_id_clicked=admin_id).pack())]]) - return kb - - -# Invite keyboard -def invite_keyboard(link: str, admin_id: int, chat_name: str) -> InlineKeyboardMarkup: - """ - Generating menu for /invite command. Should be reworked. - :param link: - :param admin_id: - :param chat_name: - :return: - """ - link = link.replace("https://", "") - kb = InlineKeyboardMarkup(inline_keyboard=[[ - InlineKeyboardButton(text=chat_name, url=link)], - [InlineKeyboardButton(text="Отозвать 🛠️", - callback_data=RevokeCallbackData(admin_id=admin_id, link=link).pack())], - [InlineKeyboardButton(text="Спасибо ✅", - callback_data=DeleteMenu(user_id_clicked=str(admin_id)).pack())]]) - return kb - - -# Close / Open thread commands related keyboards -def close_thread_keyboard(user_id: int) -> InlineKeyboardMarkup: - """ - Generate menu for /close command - :param user_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Окрыть обсуждение 🛠️", callback_data=OpenThread(user_id=user_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] - ]) - return kb - - -def open_thread_keyboard(user_id: int) -> InlineKeyboardMarkup: - """ - Generate menu for /open command - :param user_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Закрыть обсуждение 🛠️", callback_data=CloseThread(user_id=user_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] - ]) - return kb - - -# Pin / Unpin command -def pin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup: - """ - Generate menu for /pin command - :param user_id: - :param msg_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Открепить сообщение 📌", - callback_data=UnpinMsg(user_id=user_id, msg_id=msg_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] - ]) - return kb - - -def unpin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup: - """ - Generate menu for /unpin command - :param user_id: - :param msg_id: - :return: - """ - kb = InlineKeyboardMarkup(inline_keyboard=[ - [InlineKeyboardButton(text="Открепить сообщение 📌", - callback_data=PinMsg(user_id=user_id, msg_id=msg_id).pack())], - [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteMenu(user_id_clicked=str(user_id)).pack())] - ]) - return kb - - -about_keyboard = InlineKeyboardBuilder() -about_keyboard.button( - text="Bozo Development", url="https://t.me/BozoDevelopment" -) diff --git a/bozenka/instances/telegram/utils/simpler/lists_of_content.py b/bozenka/instances/telegram/utils/simpler/lists_of_content.py deleted file mode 100644 index 69e4598..0000000 --- a/bozenka/instances/telegram/utils/simpler/lists_of_content.py +++ /dev/null @@ -1,301 +0,0 @@ -from dataclasses import dataclass -from typing import List, Any - -import g4f -from g4f import Provider -from g4f.Provider import RetryProvider -from varname import nameof - -from bozenka.database.tables.telegram import TelegramChatSettings - - -@dataclass -class BaseFeature: - """ - Basic class of Feature. - Have inside desription, name, callback name, - """ - name: str - description: str - callback_name: str - settings_name: str - db_name: Any - - -@dataclass -class BaseCategory: - """ - Basic class of Feature category - Have inside category name, callbackname - """ - name: str - callback_name: str - - -# List of categories, avaible in bot -list_of_categories = [ - BaseCategory(name="Администраторы 👮‍♂", callback_name="Admins"), - BaseCategory(name="Пользователи 👤", callback_name="Members"), - BaseCategory(name="В разработке 👨‍💻", callback_name="Devs") -] - -# List of features, avaible in bot -list_of_features = { - "Admins": [ - BaseFeature( - name="Закреп 📌", - description="Закреп📌" - "\nДанная функция включает команды:" - "
/pin - закрепляет сообщение\n"
-                        "/unpin - открепляет сообщение\n"
-                        "/unpin_all - открепляет все сообщения, которые видит бот
\n" - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота.", - callback_name="pins", - settings_name="pins", - db_name=TelegramChatSettings.pins - ), - BaseFeature( - name="Модерация чата 🕵️", - description="Модерация чата🕵️\nДанная настройка включает следущие комманды:" - "\n
/ban [время блокировки] [причина блокировки] - блокировка пользователя"
-                        "\n/unban - разблокировка пользователя\n"
-                        "/mute [время мута] [причина мута] - мут пользователя\n"
-                        "/unmute - Размут пользователя
\n" - "Время обозначается как:" - "
1h - один час, "
-                        "1d - один день, "
-                        "1m - одна минута, "
-                        "1s - одна секунда
\n" - "Для того, " - "чтобы выполнить одну из комманд по отношению к пользователю, " - "ответьте на сообщение пользователя и используйте команду\n" - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота.", - callback_name="moderation", - settings_name="moderation", - db_name=TelegramChatSettings.moderation - ), - BaseFeature( - name="Работа с Форумом 💬", - description="Работа с Форумом💬\nДанная настройка включает следущие комманды:\n" - "
/open - открывают тему форума\n"
-                        "/close - закрывают тему форума\n"
-                        "/open_general - открывают основную тему форума\n"
-                        "/close_general - закрывает основную тему форума\n"
-                        "/hide_general - прячет основную тему форума\n"
-                        "/show_general - показывает основную тему форума
\n" - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть" - "включен форум", - callback_name="topics", - settings_name="topics", - db_name=TelegramChatSettings.topics - ), - BaseFeature( - name="Приглашения в Чат ✉", - description="Генератор приглашения в Чат ✉\n" - "Разрешает использование комманды /invite в чате, для созданния приглашений.\n" - "Для исполнения требует соответсвующих прав от пользователя и их наличие у бота.", - callback_name="invites", - settings_name="invite_generator", - db_name=TelegramChatSettings.invite_generator - ), - BaseFeature( - name="Результаты в лс ✉", - description="Результаты в личных сообщениях ✉\n" - "Отправляет все результаты команд модерации в личные сообщения пользователя\n" - "Никаких особых прав у бота не требует.", - callback_name="results_in_dm", - settings_name="results_in_dm", - db_name=TelegramChatSettings.results_in_dm - ), - BaseFeature( - name="Оповещение об ограничении 🗯", - description="Оповещение об ограничении 🗯\n" - "Отправляет оповещение пользователю об его муте, бане\n" - "Никаких особых прав у бота не требует.", - callback_name="restrict_notification", - settings_name="restrict_notification", - db_name=TelegramChatSettings.restrict_notification - ) - ], - "Members": [ - BaseFeature( - name="Приветсвенные сообщения 👋", - description="Приветсвенные сообщения 👋" - "\nПриветсвенные сообщения новым и ушедшим пользователям.", - callback_name="welcome", - settings_name="welcome_messages", - db_name=TelegramChatSettings.welcome_messages - ), - BaseFeature( - name="Оповещение о муте 📬", - description="Оповещение о муте 📬" - "\nОповещает пользователя в личных сообщениях, что тот был: замучен, размучен, забанен, разбанен", - callback_name="notify", - settings_name="restrict_notification", - db_name=TelegramChatSettings.restrict_notification - ) - ], - "Devs": [ - BaseFeature( - name="Функция Привет 👋", - description="Функция `Привет` 👋" - "\nБот будет отвечать на комманды " - "/hi, /hello, /privet и т.п., отвечая приветсвием на сообщение пользователя.", - callback_name="hi", - settings_name="hi_command", - db_name=TelegramChatSettings.hi_command - ), - BaseFeature( - name="ИИ ЧатБот 🤖", - description="ИИ ЧатБот 🤖" - "\nЕсть поддержка:\n" - "- Моделей Gpt4All\n" - "- Провайдеров Gpt4Free и моделей\n" - "Для использования:\n" - "
/conversations
" - "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘", - callback_name="gtm", - settings_name="gpt_conversations", - db_name=TelegramChatSettings.text_generation - ), - BaseFeature( - name="Генерация изображений 📸", - description="Генерация изображений 🤖" - "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘", - callback_name="gpm", - settings_name="123", - db_name=TelegramChatSettings.image_generation - ) - ] - -} - - -def generate_list_of_features(category: str) -> list[BaseFeature]: - """ - Generates list of features avaible at some category - made for future auto translate - :param category: - :return: - """ - return list_of_features[category] - - -ru_cmds = { - # /info command translation - "info": "Информация об чате с названием nameofchathere" - "descr\n" - "Является chattype isforum requiredinvite\n" - "Скрытые участники ishiddenmembers, isprotected", - "chat_types": {"group": "группой", "supergroup": "cупер группой"}, - "forum_type": {True: "и форумом,", False: ", не является форумом,", None: ", не является форумом,"}, - "required_invite": {True: "требуется одобрение заявки на вступление", False: "заявка не требуется.", - None: "заявка не требуется."}, - "hidden_members": {True: "присуствуют", False: "отсуствуют", None: "отсуствуют"}, - "isprotected": {True: "пересылать сообщения из группы можно.", False: "пересылать сообщения из группы нельзя.", - None: "пересылать сообщения из группы можно."}, - # /hi command translation - "hi": "Привет, user 👋", - "user": "пользователь", - # /invite command translation - "invite_generation": " Держите ваше приглашение в чат, user 👋", - "sir": "сэр", - # Ban cases - "ban_1": "Удача ✅\n" - "Пользователь banned был заблокирован пользователем admin.\n" - "По причине ban_reason, до даты ban_time", - "ban_2": "Удача ✅\n" - "Пользователь banned был заблокирован пользователем admin.\n" - "По причине ban_reason.", - "ban_3": "Удача ✅\n" - "Пользователь banned был заблокирован пользователем admin.", - "ban_4": "Удача ✅\n" - "Пользователь banned был заблокирован пользователем admin, до даты ban_time.\n", - "ban_success": "Успешно заблокирован ✅", - # Unban cases - "unban_1": "Удача ✅\n" - "Пользователь unbanned был разблокирован пользователем admin.\n" - "По причине reason.", - "unban_2": "Удача ✅\n" - "Пользователь unbanned был разблокирован пользователем admin.", - "unban_3": "Ошибка ❌\n" - "Этот пользователь не находится в бане.", - "unban_success": "Успешно разблокирован ✅", - # Work with topic - "topic_closed": "Удача ✅\n" - "Пользователь user закрыл данное обсуждение.", - "open_topic": "Удача ✅\n" - "Пользователь user открыл данное обсуждение.", - "close_general": "Удача ✅\n" - "Пользователь user закрыл основное обсуждение", - "open_general": "Удача ✅\n" - "Пользователь user открыл основное обсуждение", - "hide_general": "Удача ✅\n" - "Пользователь user скрыл основное обсуждение", - "show_general": "Удача ✅\n" - f"Пользователь user раскрыл основное обсуждение", - "topic_renamed": "Удача ✅\n" - f"Пользователь user переименовал обсуждение
originalthreadname
", - # GPT cases - "generate_answer": "Пожалуйста подождите, ответ генерируется ⏰", - "select_provider": "Выберите пожалуйста одного из провайдеров 👨‍💻", - "select_provider_message": "Выберите пожалуйста одного из провайдеров 👨‍💻", - "help_notification": "Это текущая странница 📃", - "select_provider_page": "Пожалуйста, выберите одного из провайдеров 👨‍💻\n" - "Ваша текущая страница это pagecount📄", - "moved_page": "Перенесли на страницу pagecount📄", - "finish_gpt4all_message": "Удача ✅\n" - "Вы теперь можете спокойно вести диалог 🤖\n" - "Чтобы прекратить общение, используйте /cancel", - "finish_gptfree_message": "Удача ✅\n" - "Вы теперь можете спокойно вести диалог 🤖\n" - "Вы выбрали модель
modelname
👾, от провайдера
providername
👨‍💻\n" - "Чтобы прекратить общение, используйте /cancel ", - "finish_gpt": "Вы теперь можете спокойно вести диалог 🤖", - "select_model_message": "Выберите пожалуйста модель ИИ 👾", - "select_model": "Выберите пожалуйста модель ИИ 👾", - # No Permission translation - "no_perms": "Ошибка ❌" - "У вас нет прав на использование этой комманды 🚫", - # After adding bot into group message text - "after_adding": "Здраствуйте администраторы чата 👋\n" - "Я - бозенька, мультифункциональный бот, разрабатываемый Bozo Developement\n" - "Выдайте мне полные права администратора для моей полной работы." - "Чтобы настроить функционал, используйте /setup или кнопку под сообщением", - # Success - "success": "Удача ✅" - -} - -list_of_commands = { - # Main commands - ("start", "Command to start work with bozenka the bot"), - ('setup', 'Command to setup bozenka features in chat'), - # Moderation commands - ("ban", "Command to ban user in chat"), - ('unban', 'Command to unban user in chat'), - ('mute', 'Command to mute user in chat'), - ('unmute', 'Command to unmute user in chat'), - # Work with pins - ('pin', 'Pin fast any message in chat'), - ('unpin', 'Unpin fast any message in chat'), - # Close / open topics - ('close', 'Close fast topic (not general) in chat'), - ('open', 'Open fast topic (not general) in chat'), - ('hide_general', 'Hide general topic in chat'), - ('show_general', 'Show general topic in chat'), - ("close_general", 'Closes general topic in chat'), - ("open_general", 'Opens general topic in chat'), - # AI related - ('conversation', 'Starts conversation with text generative ai'), - ('imagine', 'Starts conversation with image generative ai'), - # Basic features - ('invite', 'Generates invite into current chat'), - ('about', 'Sends information about bozenka'), - ('hi', 'Sends test welcome message'), - ('info', 'Get information about chat') -} - -translations = { - "ru": ru_cmds, -} -- 2.30.2 From 402c4c9c18efa0b8672ea8dfddc627a6cb2bdc7a Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:12:54 +0300 Subject: [PATCH 09/13] Workflow is back --- .github/workflows/start.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/start.yml diff --git a/.github/workflows/start.yml b/.github/workflows/start.yml new file mode 100644 index 0000000..488fb44 --- /dev/null +++ b/.github/workflows/start.yml @@ -0,0 +1,24 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + push: + branches: [ "telegram", "main", "discord", "matrix" ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + telegram_notification: + runs-on: ubuntu-latest + steps: + - name: Github Telegram Notifier + uses: EverythingSuckz/github-telegram-notify@v1.1.2 + with: + bot_token: '${{ secrets.BOT_TOKEN }}' + chat_id: '${{ secrets.CHAT_ID }}' + + + -- 2.30.2 From 71b33ef6660fc79215b495759f977e1750a0731f Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:56:17 +0300 Subject: [PATCH 10/13] Fixing source code --- bozenka/features/admin/information.py | 2 +- bozenka/features/admin/invite_generation.py | 1 - bozenka/features/admin/moderation.py | 2 +- bozenka/features/admin/msg_pins.py | 2 +- bozenka/features/admin/topics.py | 2 +- bozenka/features/user/image_generation.py | 2 +- bozenka/features/user/text_generation.py | 2 +- bozenka/instances/telegram/__init__.py | 12 +++++++++--- bozenka/instances/telegram/filters/permissions.py | 2 +- bozenka/instances/telegram/utils/simpler/__init__.py | 4 ---- 10 files changed, 16 insertions(+), 15 deletions(-) diff --git a/bozenka/features/admin/information.py b/bozenka/features/admin/information.py index 059fe9a..ffc5e5e 100644 --- a/bozenka/features/admin/information.py +++ b/bozenka/features/admin/information.py @@ -4,7 +4,7 @@ from aiogram.filters import Command from aiogram.types import Message from bozenka.features.main import BasicFeature -from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.delete import delete_keyboard class ChatInformation(BasicFeature): diff --git a/bozenka/features/admin/invite_generation.py b/bozenka/features/admin/invite_generation.py index 53c6989..b72f61f 100644 --- a/bozenka/features/admin/invite_generation.py +++ b/bozenka/features/admin/invite_generation.py @@ -28,7 +28,6 @@ def invite_telegram_keyboard(invite_link: str, admin_id: int, chat_name: str) -> return kb - class Invite(BasicFeature): """ A class with information about invite feature diff --git a/bozenka/features/admin/moderation.py b/bozenka/features/admin/moderation.py index 5b11c90..b3ca93f 100644 --- a/bozenka/features/admin/moderation.py +++ b/bozenka/features/admin/moderation.py @@ -10,7 +10,7 @@ from bozenka.database.tables.telegram import get_chat_config_value, TelegramChat from bozenka.features.main import BasicFeature from bozenka.instances.telegram.utils.callbacks_factory import UnbanData, BanData, UnmuteData, MuteData, DeleteMenu from bozenka.instances.telegram.filters import IsAdminFilter, BotHasPermissions, UserHasPermissions -from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.delete import delete_keyboard from bozenka.instances.telegram.utils.simpler import SolutionSimpler diff --git a/bozenka/features/admin/msg_pins.py b/bozenka/features/admin/msg_pins.py index a2b8ace..25d345f 100644 --- a/bozenka/features/admin/msg_pins.py +++ b/bozenka/features/admin/msg_pins.py @@ -7,7 +7,7 @@ from bozenka.database.tables.telegram import TelegramChatSettings from bozenka.features.main import BasicFeature from bozenka.instances.telegram.utils.callbacks_factory import PinMsg, UnpinMsg, DeleteMenu from bozenka.instances.telegram.filters import UserHasPermissions, BotHasPermissions, IsAdminFilter -from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.delete import delete_keyboard from bozenka.instances.telegram.utils.simpler import SolutionSimpler diff --git a/bozenka/features/admin/topics.py b/bozenka/features/admin/topics.py index e1311ef..0ada18e 100644 --- a/bozenka/features/admin/topics.py +++ b/bozenka/features/admin/topics.py @@ -7,7 +7,7 @@ from bozenka.database.tables.telegram import TelegramChatSettings from bozenka.features.main import BasicFeature from bozenka.instances.telegram.utils.callbacks_factory import CloseThread, OpenThread, DeleteMenu from bozenka.instances.telegram.filters import UserHasPermissions, BotHasPermissions -from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.delete import delete_keyboard from bozenka.instances.telegram.utils.simpler import SolutionSimpler diff --git a/bozenka/features/user/image_generation.py b/bozenka/features/user/image_generation.py index ecc5007..5dff3b9 100644 --- a/bozenka/features/user/image_generation.py +++ b/bozenka/features/user/image_generation.py @@ -14,7 +14,7 @@ from bozenka.generative import image_generative_size, image_generative_categorie from bozenka.generative.kadinsky import kadinsky_gen from bozenka.instances.telegram.utils.callbacks_factory import ImageGenerationCategory, ImageGeneration, DeleteMenu, \ GptStop -from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.delete import delete_keyboard from bozenka.instances.telegram.utils.simpler import GeneratingImages diff --git a/bozenka/features/user/text_generation.py b/bozenka/features/user/text_generation.py index ee41015..44019ab 100644 --- a/bozenka/features/user/text_generation.py +++ b/bozenka/features/user/text_generation.py @@ -17,7 +17,7 @@ from bozenka.generative.gpt4free import generate_gpt4free_providers, generate_gp from bozenka.instances.telegram.utils.callbacks_factory import Gpt4FreeProvsModelPage, Gpt4FreeProviderPage, \ Gpt4AllSelect, Gpt4AllModel, GptCategory, Gpt4freeResult, \ Gpt4FreeProvider, GptBackMenu, Gpt4FreeModel, Gpt4FreeCategory, Gpt4FreeModelPage, GptStop -from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.delete import delete_keyboard from bozenka.instances.telegram.utils.simpler import AnsweringGPT4Free, AnsweringGpt4All diff --git a/bozenka/instances/telegram/__init__.py b/bozenka/instances/telegram/__init__.py index e510a49..c0aa434 100644 --- a/bozenka/instances/telegram/__init__.py +++ b/bozenka/instances/telegram/__init__.py @@ -31,7 +31,12 @@ async def register_all_features(list_of_features: list, dispatcher: Dispatcher, for callback_query_handler in feature.telegram_callback_handlers: dispatcher.callback_query.register(callback_query_handler[0], *callback_query_handler[1]) - await bot.set_my_commands(cmd_list) + if not (commands := await bot.get_my_commands()): + await bot.set_my_commands(cmd_list) + else: + for cmd in cmd_list: + commands.append(cmd) + await bot.set_my_commands(commands) async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: @@ -46,6 +51,8 @@ async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: dp = Dispatcher() + await bot.delete_my_commands() + # Registering other handlers dp.callback_query.register(delete_callback_handler, DeleteMenu.filter()) dp.callback_query.register(hide_menu_handler, HideMenu.filter()) @@ -56,5 +63,4 @@ async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: await register_all_features(list_of_features=customizable_features, dispatcher=dp, bot=bot), await register_all_features(list_of_features=basic_features, dispatcher=dp, bot=bot) - ] - ) + ]) diff --git a/bozenka/instances/telegram/filters/permissions.py b/bozenka/instances/telegram/filters/permissions.py index 1261ae5..edb9767 100644 --- a/bozenka/instances/telegram/filters/permissions.py +++ b/bozenka/instances/telegram/filters/permissions.py @@ -5,7 +5,7 @@ from aiogram.methods import GetChatMember from aiogram.types import Message, ChatPermissions, CallbackQuery from aiogram.enums import ChatMemberStatus, ChatType -from bozenka.instances.telegram.utils.keyboards import delete_keyboard +from bozenka.instances.telegram.utils.delete import delete_keyboard class UserHasPermissions(Filter): diff --git a/bozenka/instances/telegram/utils/simpler/__init__.py b/bozenka/instances/telegram/utils/simpler/__init__.py index 0b5517c..4ce3ddc 100644 --- a/bozenka/instances/telegram/utils/simpler/__init__.py +++ b/bozenka/instances/telegram/utils/simpler/__init__.py @@ -1,6 +1,2 @@ from .solution_simpler import SolutionSimpler -from .lists_of_content import * from .fsm_states import * - - - -- 2.30.2 From 3bc579d6122292054396aa6e6835f12f5a2526f7 Mon Sep 17 00:00:00 2001 From: kittyneverdies <85691197+KittyNeverDies@users.noreply.github.com> Date: Wed, 14 Feb 2024 21:24:13 +0300 Subject: [PATCH 11/13] Fixed all code --- bozenka/features/basic/start.py | 7 +++--- bozenka/features/user/image_generation.py | 13 +++++++----- bozenka/features/user/text_generation.py | 26 +++++++++++------------ bozenka/generative/gpt4all/__init__.py | 3 +-- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/bozenka/features/basic/start.py b/bozenka/features/basic/start.py index 8404995..85485c0 100644 --- a/bozenka/features/basic/start.py +++ b/bozenka/features/basic/start.py @@ -7,7 +7,7 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder from bozenka.features.main import BasicFeature from bozenka.instances.customizable_features_list import categorized_customizable_features, text_transcription from bozenka.instances.telegram.utils.callbacks_factory import HelpCategory, HelpBackCategory, HelpFeature, HelpBack -from bozenka.features.user.text_generation import gpt_categories_keyboard +from bozenka.features.user.text_generation import telegram_text_categories_keyboard from bozenka.instances.current_version import build, is_updated telegram_main_menu = InlineKeyboardMarkup( @@ -197,7 +197,7 @@ class Start(BasicFeature): :return: Nothing """ await call.message.edit_text("Пожалуста, выберите сервиc / библиотеку, через которую вы будете общаться", - reply_markup=gpt_categories_keyboard + reply_markup=telegram_text_categories_keyboard (user_id=call.from_user.id)) @staticmethod @@ -239,7 +239,7 @@ class Start(BasicFeature): """ await msg.answer(""" Привет 👋 -Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах. +Я - групповой чат-бот с открытым исходным кодом, который поможет тебе в различных задачах. Вот что ты можешь сделать с помощью меню: • Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него. @@ -250,7 +250,6 @@ class Start(BasicFeature): • Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта Вот нужные ссылки обо мне: -• Канал с новостями об разработкеИсходный код на Github Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже. diff --git a/bozenka/features/user/image_generation.py b/bozenka/features/user/image_generation.py index 5dff3b9..0272853 100644 --- a/bozenka/features/user/image_generation.py +++ b/bozenka/features/user/image_generation.py @@ -1,7 +1,7 @@ import logging from typing import Callable -from aiogram import Dispatcher +from aiogram import Dispatcher, F from aiogram.filters import CommandObject, Command from aiogram.fsm.context import FSMContext from aiogram.types import InlineKeyboardMarkup, Message, CallbackQuery, FSInputFile, InlineKeyboardButton @@ -68,8 +68,6 @@ class ImageGeneratrion(BasicFeature): A classic class of lineral (basic) feature of bozenka. IN FUTURE! """ - cmd_description: str = "Your description of command" - async def telegram_select_image_size_handler(call: CallbackQuery, callback_data: ImageGenerationCategory, state: FSMContext) -> None: """ @@ -118,7 +116,7 @@ class ImageGeneratrion(BasicFeature): "Подождите пожалуйста, мы уже генерируем изображение для вас, подождите, когда мы ответим на ваш передыдущий вопрос", reply_markup=delete_keyboard(admin_id=msg.from_user.id)) - async def telegram_imagine_handler(msg: Message, state: FSMContext) -> None: + async def telegram_imagine_handler(msg: Message | CallbackQuery, state: FSMContext) -> None: """ /imagine command handler, start menu :param msg: Message telegram object @@ -127,6 +125,10 @@ class ImageGeneratrion(BasicFeature): """ if await state.get_state(): return + + if type(msg) == CallbackQuery: + msg = msg.message + await msg.answer("Пожалуста, выберите сервис / модель для генерации изображений", reply_markup=telegram_image_generation_categories_keyboard(user_id=msg.from_user.id)) @@ -194,5 +196,6 @@ class ImageGeneratrion(BasicFeature): ] telegram_callback_handlers = [ [telegram_select_image_size_handler, [ImageGenerationCategory.filter()]], - [telegram_end_generation_handler, [ImageGeneration.filter()]] + [telegram_end_generation_handler, [ImageGeneration.filter()]], + [telegram_imagine_handler, [F.data == "dialogimage"]] ] diff --git a/bozenka/features/user/text_generation.py b/bozenka/features/user/text_generation.py index 44019ab..e17618a 100644 --- a/bozenka/features/user/text_generation.py +++ b/bozenka/features/user/text_generation.py @@ -11,9 +11,10 @@ from gpt4all import GPT4All from bozenka.database.tables.telegram import TelegramChatSettings from bozenka.features.main import BasicFeature -from bozenka.generative import text_generative_categories +from bozenka.generative import text2text_generatiove_libraries from bozenka.generative.gpt4all import model_path, check from bozenka.generative.gpt4free import generate_gpt4free_providers, generate_gpt4free_models +from bozenka.instances.telegram.utils.callbacks_factory import DeleteMenu from bozenka.instances.telegram.utils.callbacks_factory import Gpt4FreeProvsModelPage, Gpt4FreeProviderPage, \ Gpt4AllSelect, Gpt4AllModel, GptCategory, Gpt4freeResult, \ Gpt4FreeProvider, GptBackMenu, Gpt4FreeModel, Gpt4FreeCategory, Gpt4FreeModelPage, GptStop @@ -21,15 +22,14 @@ from bozenka.instances.telegram.utils.delete import delete_keyboard from bozenka.instances.telegram.utils.simpler import AnsweringGPT4Free, AnsweringGpt4All - -def gpt_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: +def telegram_text_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: """ Create list keyboard list of gpt libraries, available in the bot - :param user_id: + :param user_id: User_id of user :return: InlineKeyboardMarkup """ builder = InlineKeyboardBuilder() - for category in text_generative_categories: + for category in text2text_generatiove_libraries: builder.row(InlineKeyboardButton(text=category, callback_data=GptCategory(user_id=str(user_id), category=category).pack())) return builder.as_markup() @@ -39,7 +39,7 @@ def gpt_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: def items_list_generator(page: int, list_of_items, count_of_items: int) -> list[Any]: """ Generate page, made for backend - :param page: + :param page: Number of page :param list_of_items: :param count_of_items: """ @@ -65,7 +65,7 @@ def text_response_keyboard(user_id: int) -> InlineKeyboardMarkup: return kb -def gpt4free_providers_keyboard(user_id: int, page: int) -> InlineKeyboardMarkup: +def telegram_gpt4free_providers_keyboard(user_id: int, page: int) -> InlineKeyboardMarkup: """ Generate page of gpt providers, can be used by user. :param user_id: @@ -307,7 +307,7 @@ class TextGeneratrion(BasicFeature): if await state.get_state(): return await msg.answer("Пожалуста, выберите сервис для ИИ.", - reply_markup=gpt_categories_keyboard + reply_markup=telegram_text_categories_keyboard (user_id=msg.from_user.id)) async def telegram_cancel_cmd_handler(msg: Message, state: FSMContext) -> None: @@ -396,7 +396,7 @@ class TextGeneratrion(BasicFeature): if call.from_user.id != callback_data.user_id or await state.get_state(): return await call.message.edit_text("Пожалуста, выберите сервис для ИИ.", - reply_markup=gpt_categories_keyboard(user_id=call.from_user.id)) + reply_markup=telegram_text_categories_keyboard(user_id=call.from_user.id)) async def telegram_g4f_providers_handlers(call: CallbackQuery, callback_data: Gpt4FreeCategory, state: FSMContext) -> None: @@ -417,7 +417,7 @@ class TextGeneratrion(BasicFeature): await state.set_state(AnsweringGPT4Free.set_provider) await call.message.edit_text("Выберите пожалуйста одного из провайдеров 👨‍💻", - reply_markup=gpt4free_providers_keyboard(user_id=call.from_user.id, page=0)) + reply_markup=telegram_gpt4free_providers_keyboard(user_id=call.from_user.id, page=0)) async def telegram_g4f_models_handler(call: CallbackQuery, callback_data: GptCategory, state: FSMContext) -> None: """ @@ -517,7 +517,7 @@ class TextGeneratrion(BasicFeature): await state.set_state(AnsweringGPT4Free.set_provider) await call.message.edit_text("Выберите пожалуйста одного из провайдеров 👨‍💻", - reply_markup=gpt4free_providers_keyboard(page=0, user_id=callback_data.user_id)) + reply_markup=telegram_gpt4free_providers_keyboard(page=0, user_id=callback_data.user_id)) await call.answer("Выберите пожалуйста одного из провайдеров 👨‍💻") async def telegram_g4f_by_provider_models(call: CallbackQuery, callback_data: Gpt4FreeProvider, @@ -608,8 +608,8 @@ class TextGeneratrion(BasicFeature): logging.log(msg=f"Changed page to {str(callback_data.page + 1)} user_id={call.from_user.id}", level=logging.INFO) await call.message.edit_text(call.message.text, - reply_markup=gpt4free_providers_keyboard(user_id=callback_data.user_id, - page=callback_data.page)) + reply_markup=telegram_gpt4free_providers_keyboard(user_id=callback_data.user_id, + page=callback_data.page)) await call.answer(f"Вы перелистнули на страницу {callback_data.page + 1}📄") # G4A telegram handlers section diff --git a/bozenka/generative/gpt4all/__init__.py b/bozenka/generative/gpt4all/__init__.py index 0aa5da9..4420033 100644 --- a/bozenka/generative/gpt4all/__init__.py +++ b/bozenka/generative/gpt4all/__init__.py @@ -4,14 +4,13 @@ import pathlib model_path = os.getcwd() + "\\model\\" - def check(model_filename: str) -> bool: """ Checking & downloading our gpt4all models Returns True if it's already downloaded Returns False if it's not downloaded :param model_filename: File name of gpt4all model - :return: + :return: Does it exist """ print(os.path.exists("models\\" + model_filename)) return os.path.exists("models\\" + model_filename) -- 2.30.2 From d784c57df419d51ee3816498c6f15ffe3aeb14c5 Mon Sep 17 00:00:00 2001 From: kittyneverdies catofeyev Date: Wed, 14 Feb 2024 18:39:56 +0000 Subject: [PATCH 12/13] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 61 ------------------------------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index 6e0f2af..0000000 --- a/README.md +++ /dev/null @@ -1,61 +0,0 @@ -
- - - -[![CodeFactor](https://www.codefactor.io/repository/github/kittyneverdies/bozenka/badge)](https://www.codefactor.io/repository/github/kittyneverdies/bozenka) - -[Telegram Channel](https://t.me/bozodevelopment/) - - -
- -

Telegram Instance

- -### Features of Telegram instance - -- [ ] Group - - [ ] Administration - - [x] Ban & Unban commands - - [x] Mute & Unmute commands - - [x] Pin & Unpin & Unpin all commands - - [ ] Bad words & Spam filter - - [ ] Setup command (Going to release) - - [x] Welcome message to administrators after adding bot to chat. - - [x] Work with inline keyboard - - [x] Work with telegram topics - - [x] Close & Open Topics - - [x] Hide general topic - - [x] Rename topics - - [x] Work with inline keyboard - - [x] Users - - [x] Show information about chat (/info) - - [x] Welcome messages - - [x] Generating invites - - [x] Start command menu (/start) -- [ ] Fun - - [ ] GPT based text generation - - [x] Gpt4All - - [x] Gpt4Free - - [ ] RWKV - - [ ] H20 - - [x] Work with inline keyboard - - [ ] Using tutorial. - - [x] Threads and Topic of dialog support (Already by new aiogram) - - [ ] Image generation - - [ ] Using tutorial - - [ ] Inline generation - - [x] Imagine command + inline keyboard support -- [x] Code - - [x] Logging support - - [x] Features descriptions - - [x] Custom Filters - - [x] Middlewares - - [x] Database - - -### This part of project made with - -- [Aiogram python library](https://github.com/aiogram/aiogram) and with their community support. -- [GPT4Free](https://github.com/xtekky/gpt4free), [Gpt4All](https://github.com/nomic-ai/gpt4all), [SqlAlchemy](https://github.com/sqlalchemy/sqlalchemy/) python libraries -- With our love & your support <3 -
-- 2.30.2 From a6e6d1617eac599f011fb77700865583f11b0d76 Mon Sep 17 00:00:00 2001 From: kittyneverdies catofeyev Date: Wed, 14 Feb 2024 18:55:52 +0000 Subject: [PATCH 13/13] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20.github/workflows/start.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/start.yml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .github/workflows/start.yml diff --git a/.github/workflows/start.yml b/.github/workflows/start.yml deleted file mode 100644 index 488fb44..0000000 --- a/.github/workflows/start.yml +++ /dev/null @@ -1,24 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: CI - -# Controls when the workflow will run -on: - # Triggers the workflow on push or pull request events but only for the "main" branch - push: - branches: [ "telegram", "main", "discord", "matrix" ] - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - telegram_notification: - runs-on: ubuntu-latest - steps: - - name: Github Telegram Notifier - uses: EverythingSuckz/github-telegram-notify@v1.1.2 - with: - bot_token: '${{ secrets.BOT_TOKEN }}' - chat_id: '${{ secrets.CHAT_ID }}' - - - -- 2.30.2