merging telegram to main #1

Merged
kittyneverdies merged 14 commits from telegram into main 2024-02-14 19:56:18 +01:00
76 changed files with 3148 additions and 3262 deletions

View file

@ -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

View file

@ -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"<User:{self.user_id}:{self.chat_id}>"
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).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()

View file

@ -0,0 +1,3 @@
from bozenka.features.admin import *
from bozenka.features.user import *
from bozenka.features.basic import *

View file

@ -0,0 +1,5 @@
from .invite_generation import Invite
from .moderation import Moderation
from .msg_pins import Pins
from .topics import Threads
from .information import ChatInformation

View file

@ -0,0 +1,51 @@
import logging
from aiogram.filters import Command
from aiogram.types import Message
from bozenka.features.main import BasicFeature
from bozenka.instances.telegram.utils.delete 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")]]
]

View file

@ -0,0 +1,93 @@
import logging
from aiogram.enums import ChatMemberStatus
from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
from bozenka.database.tables.telegram import TelegramChatSettings
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):
"""
A class with information about invite feature
All codes will be here
"""
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"<em> Держите ваше приглашение в чат, {msg.from_user.mention_html('пользователь')} 👋</em>",
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:
"""
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()
"""
Telegram feature settings
"""
# Telegram setting info
telegram_setting_in_list = True
telegram_setting_name = "Приглашения в Чат ✉"
telegram_setting_description = "<b>Генератор приглашения в Чат ✉</b>\n" \
"Разрешает использование комманды <code>/invite</code> в чате, для созданния приглашений.\n" \
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>"
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
# 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()]]
]

View file

@ -0,0 +1,607 @@
import logging
from aiogram import F
from aiogram.enums import ChatMemberStatus, ChatType
from aiogram.filters import CommandObject, Command
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.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.delete 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):
"""
A class of moderation related feature
All staff related to it will be here
"""
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=TelegramChatSettings.restrict_notification)
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=telegram_ban_user_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('этим пользователем')} в чате <code>{call.message.chat.id}</code>.",
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)
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=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=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('этим пользователем')} в чате <code>{call.message.chat.id}</code>.",
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)
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=TelegramChatSettings.results_in_dm)
send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker,
setting=TelegramChatSettings.restrict_notification)
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"По причине <code>{config['reason']}</code>, до даты <code>{config['ban_time']}</code>",
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"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате <code>{msg.chat.title}</code>.\n"
f"По причине <code>{config['reason']}, до даты <code>{config['ban_time']}</code>",
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"По причине <code>{config['reason']}</code>.",
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"Вы "
f"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате <code>{msg.chat.title}</code>.\n"
f"По причине <code>{config['reason']}</code>.",
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('этим пользователем')}, до даты <code>{config['ban_time']}</code>",
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"Вы "
f"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате <code>{msg.chat.title}</code>.\n"
f"До даты <code>{config['ban_time']}</code>.",
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=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"Вы "
f"были заблокированы {msg.from_user.mention_html('этим пользователем')} в чате "
f"<code>{msg.chat.title}</code>.\n",
reply_markup=delete_keyboard(admin_id=banned_user.user.id))
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=TelegramChatSettings.results_in_dm)
send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker,
setting=TelegramChatSettings.restrict_notification)
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=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(
chat_id=unbanned_user.user.id,
text=f"{msg.reply_to_message.from_user.mention_html('Вы')} "
f"был разблокированы {msg.from_user.mention_html('этим пользователем')} в чате <code>{msg.chat.title}</code>.\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('этим пользователем')} в чате <code>{msg.chat.title}</code>.\n"
f"По причине <code>{CommandObject.text}</code>",
reply_markup=delete_keyboard(admin_id=unbanned_user.user.id)
)
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=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=TelegramChatSettings.restrict_notification)
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('этим пользователем')} в чате <code>{call.message.chat.id}</code>.",
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)
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=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=TelegramChatSettings.restrict_notification)
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('этим пользователем')} в чате <code>{call.message.chat.id}</code>.",
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)
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=TelegramChatSettings.results_in_dm)
send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker,
setting=TelegramChatSettings.restrict_notification)
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"По причине <code>{config['reason']}</code>, до даты <code>{config['mute_time']}</code>",
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,
text=f"{msg.from_user.mention_html('Этот пользователь')} запретил писать "
f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n"
f"По причине <code>{config['reason']}</code>, до даты <code>{config['mute_time']}</code>",
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"По причине <code>{config['reason']}</code>.",
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,
text=f"{msg.from_user.mention_html('Этот пользователь')} запретил писать "
f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n"
f"По причине <code>{config['reason']}</code>.",
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"До даты <code>{config['mute_time']}</code>",
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,
text=f"{msg.from_user.mention_html('Этот пользователь')} запретил писать "
f"сообщения {msg.reply_to_message.from_user.mention_html('вам')} в чате {msg.chat.title}.\n"
f"До даты <code>{config['mute_time']}</code>",
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=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,
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))
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=TelegramChatSettings.results_in_dm)
send_notification = await get_chat_config_value(chat_id=msg.chat.id, session=session_maker,
setting=TelegramChatSettings.restrict_notification)
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=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,
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))
# Help moderation telegram
# Code part
async def telegram_help_ban_handler(msg: Message) -> None:
"""
Shows help message for /ban
:param msg: Message telegram object
:return: Nothing
"""
await msg.answer("Использование:\n"
"<pre>/ban [время блокировки] [причина блокировки]</pre>\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"
"<pre>/unban</pre>\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"
"<pre>/mute [время мута] [причина мута]</pre>\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"
"<pre>/unmute</pre>\n"
"Ответьте на сообщение, чтобы замутить пользователя",
reply_markup=delete_keyboard(msg.from_user.id))
telegram_setting_in_list = True
telegram_setting_name = "Модерация чата 🕵️"
telegram_setting_description = "<b>Модерация чата</b>🕵️\nДанная настройка включает следущие комманды:" \
"\n<pre>/ban [время блокировки] [причина блокировки] - блокировка пользователя" \
"\n/unban - разблокировка пользователя\n" \
"/mute [время мута] [причина мута] - мут пользователя\n" \
"/unmute - Размут пользователя</pre>\n" \
"Время обозначается как:" \
"<pre>1h - один час, " \
"1d - один день, " \
"1m - одна минута, " \
"1s - одна секунда</pre>\n" \
"Для того, " \
"чтобы выполнить одну из комманд по отношению к пользователю, " \
"ответьте на сообщение пользователя и используйте команду\n" \
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>"
telegram_db_name = TelegramChatSettings.moderation
telegram_category = "admin"
# 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()]]]

View file

@ -0,0 +1,182 @@
from aiogram import F
from aiogram.enums import ChatType
from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup
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.delete 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
All staff related to it will be here
"""
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=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:
"""
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=telegram_unpin_msg_keyboard(user_id=call.from_user.id,
msg_id=callback_data.msg_id))
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=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:
"""
/unpin command function, unpins replied command
:param msg: Message telegram object
:return: Nothing
"""
await SolutionSimpler.unpin_msg(msg)
await msg.answer("Удача ✅\n"
"Сообщение было откреплено 📌",
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:
"""
/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))
async def telegram_help_pin_cmd(msg: Message) -> None:
"""
Shows help message for /mute
:param msg: Message telegram object
:return: Nothing
"""
await msg.answer("Использование:\n"
"<pre>/pin</pre>\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"
"<pre>/unpin</pre>\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 = "<b>Закреп</b>📌" \
"\nДанная функция включает команды:" \
"<pre>/pin - закрепляет сообщение\n" \
"/unpin - открепляет сообщение\n" \
"/unpin_all - открепляет все сообщения, которые видит бот</pre>\n" \
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>"
telegram_db_name = TelegramChatSettings.pins
telegram_category = "admin"
# 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()]]
]

View file

@ -0,0 +1,203 @@
from aiogram import F
from aiogram.enums import ChatType
from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup
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.delete 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
All staff related to it will be here
"""
async def telegram_close_topic_cmd_handler(msg: Message) -> None:
"""
/close command function. Closing thread
:param msg: Message telegram object
:return: Nothing
"""
config = await SolutionSimpler.close_topic(msg=msg)
await msg.answer(config[0],
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:
"""
/open command function. Opens thread
:param msg: Message telegram object
:return: Nothing
"""
config = await SolutionSimpler.open_topic(msg=msg)
await msg.answer(config[0],
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:
"""
/close_general command function. Closes general thread
:param msg: Message telegram object
:return: Nothing
"""
config = await SolutionSimpler.close_general_topic(msg=msg)
await msg.answer(config[0],
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:
"""
/open_general command function. Opens general thread
:param msg: Message telegram object
:return: Nothing
"""
config = await SolutionSimpler.open_general_topic(msg=msg)
await msg.answer(config[0],
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:
"""
/hide_general command function. Hides general thread
:param msg: Message telegram object
: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 telegram_unhide_general_topic_cmd(msg: Message) -> None:
"""
/show_general command function. Shows back general thread.
:param msg: Message telegram object
: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 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=telegram_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: 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=telegram_open_thread_keyboard(user_id=call.from_user.id) if config[1] else
delete_keyboard(admin_id=call.from_user.id)
)
"""
Telegram feature settings
"""
# Telegram setting info
telegram_setting_in_list = True
telegram_setting_name = "Работа с Форумом 💬"
telegram_setting_description = "<b>Работа с Форумом</b>💬\nДанная настройка включает следущие комманды:\n" \
"<pre>/open - открывают тему форума\n" \
"/close - закрывают тему форума\n" \
"/open_general - открывают основную тему форума\n" \
"/close_general - закрывает основную тему форума\n" \
"/hide_general - прячет основную тему форума\n" \
"/show_general - показывает основную тему форума</pre>\n" \
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть" \
"включен форум</b>"
telegram_db_name = TelegramChatSettings.topics
telegram_category = "admin"
# 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]],
[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()]]
]

View file

@ -0,0 +1,2 @@
from .setup import Setup
from .start import Start

View file

@ -0,0 +1,159 @@
from aiogram import F
from aiogram.enums import ChatType
from aiogram.filters import Command
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.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.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):
"""
A class of /setup command
All staff related to it will be here
"""
async def telegram_setup_cmd_handler(msg: Message) -> None:
"""
/setup telegram handler
:param msg: Telegram message object
:return: Nothing
"""
await msg.answer("Привет владелец чата 👋\n\n"
"Настрой меня - бота так, как тебе удобно, и я буду помогать тебе в чате с определенными функциями.\n"
"Используй меню настроек ниже, чтобы указать, какие функции, которые я умею, должен выполнять.",
reply_markup=setup_keyboard())
async def telegram_setup_categories_handler(call: CallbackQuery, callback_data: SetupCategory | SetupAction) -> None:
"""
Query, what shows list of features to enable.
:param call: CallbackQuery class
:param callback_data: SetupCategory or SetupAction
:return: None
"""
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) -> None:
"""
Query, what shows menu to enable / disable feature
: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=categorized_customizable_features[callback_data.feature_category][callback_data.feature_index]
)
await call.message.edit_text(
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) -> None:
"""
Query, what shows menu to enable / disable feature
after editing
: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(
{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(
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"))
"""
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_category = None
telegram_message_handlers = [
[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"), 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)]]
]

View file

@ -0,0 +1,284 @@
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.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 telegram_text_categories_keyboard
from bozenka.instances.current_version import build, is_updated
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")],
]
)
# 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
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:
"""
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=main_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(
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()
@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=main_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"Запущенная версия бота <code>{build}</code>\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, исходный код проекта можно посмотреть всегда <a href="https://github.com/kittyneverdies/bozenka/">здесь</a>
Канал с новостями разработки находится <a href="https://t.me/bozodevelopment">здесь</a>
""", 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=telegram_text_categories_keyboard
(user_id=call.from_user.id))
@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("""
Привет 👋
Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах.
Вот что ты можешь сделать с помощью меню:
Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него.
Функционал: показывает список доступных функций и команд, которые я могу выполнить.
О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота.
О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота.
Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию.
Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта
Вот нужные ссылки обо мне:
<a href='https://t.me/bozodevelopment'>Канал с новостями об разработке</a>
<a href='https://github.com/kittyneverdies/bozenka/'>Исходный код на Github</a>
Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже.
Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала.
Удачного использования!
""", 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("""
Привет 👋
Я - групповой чат-бот с открытым исходным кодом, который поможет тебе в различных задачах.
Вот что ты можешь сделать с помощью меню:
Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него.
Функционал: показывает список доступных функций и команд, которые я могу выполнить.
О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота.
О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота.
Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию.
Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта
Вот нужные ссылки обо мне:
<a href='https://github.com/kittyneverdies/bozenka/'>Исходный код на Github</a>
Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже.
Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала.
Удачного использования!
""", reply_markup=telegram_main_menu, disable_web_page_preview=True)
"""
Telegram feature settings
"""
# Telegram feature settings
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_message_handlers = [
[start_cmd_handler, [Command(commands=["start"]), F.chat.type == ChatType.PRIVATE]],
]
telegram_callback_handlers = [
# Start menu
[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
[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")]]
]

27
bozenka/features/main.py Normal file
View file

@ -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]]
]

View file

@ -0,0 +1,3 @@
from .image_generation import ImageGeneratrion
from .text_generation import TextGeneratrion
from .welcome import Welcome

View file

@ -0,0 +1,201 @@
import logging
from typing import Callable
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
from aiogram.utils.keyboard import InlineKeyboardBuilder
from sqlalchemy.ext.asyncio import async_sessionmaker
from bozenka.database.tables.telegram import TelegramChatSettings
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, DeleteMenu, \
GptStop
from bozenka.instances.telegram.utils.delete 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)
feature of bozenka. IN FUTURE!
"""
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=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:
"""
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))
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))
async def telegram_imagine_handler(msg: Message | CallbackQuery, 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
if type(msg) == CallbackQuery:
msg = msg.message
await msg.answer("Пожалуста, выберите сервис / модель для генерации изображений",
reply_markup=telegram_image_generation_categories_keyboard(user_id=msg.from_user.id))
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=telegram_image_response_keyboard(user_id=msg.from_user.id))
await message.delete()
else:
await message.edit_text("Простите, произошла ошибка 😔\n"
"Убедитесь, что севрера kadinsky работают и ваш промт не является неподобающим и неприемлимым\n"
"Если это продолжается, пожалуйста используйте /cancel",
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}",
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)
"""
Telegram feature settings
"""
# Telegram feature settings
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 = "Генерация изображений 📸"
telegram_setting_description = "<b>Генерация изображений </b>🤖" \
"\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()]],
[telegram_imagine_handler, [F.data == "dialogimage"]]
]

View file

@ -0,0 +1,805 @@
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, InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
from gpt4all import GPT4All
from bozenka.database.tables.telegram import TelegramChatSettings
from bozenka.features.main import BasicFeature
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
from bozenka.instances.telegram.utils.delete import delete_keyboard
from bozenka.instances.telegram.utils.simpler import AnsweringGPT4Free, AnsweringGpt4All
def telegram_text_categories_keyboard(user_id: int) -> InlineKeyboardMarkup:
"""
Create list keyboard list of gpt libraries, available in the bot
:param user_id: User_id of user
:return: InlineKeyboardMarkup
"""
builder = InlineKeyboardBuilder()
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()
# Helper
def items_list_generator(page: int, list_of_items, count_of_items: int) -> list[Any]:
"""
Generate page, made for backend
:param page: Number of 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 telegram_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
related to text generation of bozenka
"""
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))
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=telegram_text_categories_keyboard
(user_id=msg.from_user.id))
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
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)
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=telegram_text_categories_keyboard(user_id=call.from_user.id))
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=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:
"""
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))
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
: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"Вы выбрали модель <b>{callback_data.model}</b>👾\n"
"Чтобы прекратить общение, используйте /cancel ",
reply_markup=delete_keyboard(admin_id=call.from_user.id))
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))
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
: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)
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("Выберите, по какому пункту мы будем вести диалог с нейронной сети 🤖")
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=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,
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("Выберите пожалуйста модель ИИ 👾")
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
: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"Вы выбрали модель <b>{callback_data.model}</b>👾, от провайдера <b>{callback_data.provider}</b>👨‍💻\n"
"Чтобы прекратить общение, используйте /cancel ",
reply_markup=delete_keyboard(admin_id=callback_data.user_id))
await call.answer("Вы теперь можете спокойно вести диалог 🤖")
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}📄")
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=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
# All code and commentaries here
# All handlers here
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)
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))
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))
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))
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"Вы выбрали модель <b>{models[callback_data.index]['name']}</b>👾 от Gpt4All\n"
"Чтобы прекратить общение, используйте /cancel ",
reply_markup=delete_keyboard(admin_id=callback_data.user_id))
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("Здесь расположается текущая странница 📃")
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()
# Telegram feature settings
telegram_category = "user"
telegram_db_name = TelegramChatSettings.text_generation
telegram_setting_in_list = True
telegram_setting_name = "ИИ ЧатБот 🤖"
telegram_setting_description = "<b>ИИ ЧатБот </b>🤖" \
"\nЕсть поддержка:\n" \
"- Моделей Gpt4All\n" \
"- Провайдеров Gpt4Free и моделей\n" \
"Для использования:\n" \
"<pre>/conversations</pre>" \
"\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()]]
)

View file

@ -0,0 +1,74 @@
import logging
from aiogram import Bot, F
from aiogram.enums import ContentType
from aiogram.types import Message, CallbackQuery
from sqlalchemy.ext.asyncio import async_sessionmaker
from bozenka.database.tables.telegram import TelegramChatSettings
from bozenka.features.main import BasicFeature
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
"""
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"
"Я - <b>бозенька</b>, мультифункциональный бот, разрабатываемый Bozo Developement\n"
"Выдайте мне <b>полные права администратора</b> для моей полной работы.\n"
"Чтобы настроить функционал, используйте /setup или кнопку под сообщением", )
await SolutionSimpler.auto_settings(msg=msg, session=session_maker)
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()}👋"
)
# Telegram feature settings
telegram_setting = TelegramChatSettings.welcome_messages
telegram_category = "user"
telegram_commands: dict[str: str] = {}
telegram_setting_in_list = True
telegram_setting_name = "Приветсвенные сообщения 👋"
telegram_setting_description = "<b>Приветсвенные сообщения 👋</b>" \
"\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 = []

View file

@ -1,3 +1,6 @@
import dataclasses
# List of text generative categories, what we support
text_generative_categories = [
@ -17,4 +20,4 @@ image_generative_size = [
"576x1024",
"1024x680",
"680x1024"
]
]

View file

@ -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)

View file

View file

@ -0,0 +1,6 @@
from bozenka.features import Setup, Start
basic_features = [
Setup,
Start
]

View file

@ -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]

View file

@ -1,28 +1,66 @@
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.instances.telegram.handlers import register_handlers
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, 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])
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:
"""
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")
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 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())
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=customizable_features, dispatcher=dp, bot=bot),
await register_all_features(list_of_features=basic_features, dispatcher=dp, bot=bot)
])

View file

@ -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)

View file

@ -0,0 +1,178 @@
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, ChatType
from bozenka.instances.telegram.utils.delete import delete_keyboard
class UserHasPermissions(Filter):
"""
Check, does user have permissions, what user need to work with bot.
"""
# List of permissions avaible to users.
# Basic permissions for administration and user
permissions = [
"can_manage_chat",
"can_delete_messages",
"can_manage_video_chats",
"can_restrict_members",
"can_promote_members",
"can_change_info",
"can_invite_users",
"can_post_messages",
"can_edit_messages",
"can_pin_messages",
"can_manage_topics",
"can_send_messages",
"can_send_audios",
"can_send_documents",
"can_send_photos",
"can_send_videos",
"can_send_video_notes",
"can_send_voice_notes",
"can_send_polls",
"can_send_other_messages",
"can_add_web_page_previews",
]
def __init__(self, perms: list[Any]) -> None:
self.perms = perms
@staticmethod
async def check_permissions(permission, msg: Message) -> bool:
"""
Checking permissions, included to user.
:return:
"""
if permission.count(False) > 0 or permission.count(None) > 0:
await msg.answer("Ошибка ❌\n"
"У вас нет прав на использование этой комманды 🚫")
return False
return True
def generate_perms_list(self, user) -> list[Any]:
"""
Generates list of permissions for user.
:param user: User telegram object
:return: List
"""
permission = []
for rule in self.perms:
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)
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)
class BotHasPermissions(UserHasPermissions):
"""
Check, does bot have permissions, what user need to work with bot.
"""
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 await self.check_permissions(permission, msg)
class IsOwner(Filter):
"""
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 | CallbackQuery) -> bool:
"""
Working after catching a call from aiogram
: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("Ошибка ❌\n"
"У вас нет прав на использование этой комманды 🚫")
return ChatMemberStatus.CREATOR == user.status
class IsAdminFilter(Filter):
"""
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 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

View file

@ -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)

View file

@ -1,74 +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))
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"]))

View file

@ -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"по причине <code>{config['ban_reason']}</code>"
msg_text += "🔨\n"
if config["is_muted"]:
msg_text += "Находится в муте"
if config["mute_reason"]:
msg_text += f"по причине <code>{config['mute_reason']}</code>"
msg_text += "🤐\n"
await msg.answer(msg_text, reply_markup=delete_keyboard(msg.from_user.id))

View file

@ -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"
"<pre>/ban [время блокировки] [причина блокировки]</pre>\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"
"<pre>/unban</pre>\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"
"<pre>/mute [время мута] [причина мута]</pre>\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"
"<pre>/unmute</pre>\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"
"<pre>/pin</pre>\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"
"<pre>/unpin</pre>\n"
"Ответьте на сообщение, чтобы открепить сообщение",
reply_markup=delete_keyboard(msg.from_user.id))

View file

@ -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))

View file

@ -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))

View file

@ -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)

View file

@ -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"]))

View file

@ -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())

View file

@ -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))

View file

@ -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)
)

View file

@ -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"
"Я - <b>бозенька</b>, мультифункциональный бот, разрабатываемый Bozo Developement\n"
"Выдайте мне <b>полные права администратора</b> для моей полной работы.\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()}👋"
)

View file

@ -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"]))

View file

@ -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)

View file

@ -1,101 +0,0 @@
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
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))

View file

@ -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)

View file

@ -1,29 +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)
# 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)

View file

@ -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"
"Я - <b>бозенька</b>, мультифункциональный бот, разрабатываемый Bozo Developement\n"
"Выдайте мне <b>полные права администратора</b> для моей полной работы, если не выдали."
"Чтобы настроить функционал, используйте /setup или кнопку под сообщением")

View file

@ -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(
"""
Привет 👋
Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах.
Вот что ты можешь сделать с помощью меню:
Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него.
Функционал: показывает список доступных функций и команд, которые я могу выполнить.
О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота.
О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота.
Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию.
Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта
Вот нужные ссылки обо мне:
<a href='https://t.me/bozodevelopment'>Канал с новостями об разработке</a>
<a href='https://github.com/kittyneverdies/bozenka/'>Исходный код на Github</a>
Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже.
Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала.
Удачного использования!
""",
reply_markup=start_keyboard(), disable_web_page_preview=True)

View file

@ -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, DeleteCallbackData.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")

View file

@ -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)

View file

@ -1,21 +0,0 @@
import logging
from aiogram import types
from bozenka.instances.telegram.utils.callbacks_factory import DeleteCallbackData
from aiogram.enums import ChatMemberStatus
async def inline_delete(call: types.CallbackQuery, callback_data: DeleteCallbackData) -> 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()

View file

@ -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))

View file

@ -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)

View file

@ -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))

View file

@ -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()

View file

@ -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 ChatSettings, 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.feature_category))
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(ChatSettings)
.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))
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=callback_data.action == "enable"))

View file

@ -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(
"""
Привет 👋
Я - бозенька, бот с открытым исходным кодом, который поможет тебе в различных задачах.
Вот что ты можешь сделать с помощью меню:
Добавить в чат: добавляет меня в групповой чат, чтобы я мог выполнять свои функции внутри него.
Функционал: показывает список доступных функций и команд, которые я могу выполнить.
О разработчиках: предоставляет информацию о команде разработчиков, которые создали и поддерживают этого бота.
О запущенном экземпляре: выводит информацию о текущей версии и состоянии запущенного экземпляра бота.
Начать диалог с ИИ: позволяет начать диалог с искусственным интеллектом, который может отвечать на вопросы и предоставлять информацию.
Генерация изображений: позволяет сгенерировать изображения на основе заданных параметров и промта
Вот нужные ссылки обо мне:
<a href='https://t.me/bozodevelopment'>Канал с новостями об разработке</a>
<a href='https://github.com/kittyneverdies/bozenka/'>Исходный код на Github</a>
Чтобы воспользоваться какой-либо функцией, просто нажми на соответствующую кнопку ниже.
Если у тебя возникнут вопросы или проблемы, не стесняйся обратиться к команде разработчиков или написать в обсуждении телеграм канала.
Удачного использования!
""",
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, исходный код проекта можно посмотреть всегда <a href="https://github.com/kittyneverdies/bozenka/">здесь</a>
Канал с новостями разработки находится <a href="https://t.me/bozodevelopment">здесь</a>
""", 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"Запущенная версия бота <code>{build}</code>\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))

View file

@ -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"Вы выбрали модель <b>{callback_data.model}</b>👾\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"Вы выбрали модель <b>{callback_data.model}</b>👾, от провайдера <b>{callback_data.provider}</b>👨‍💻\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"Вы выбрали модель <b>{models[callback_data.index]['name']}</b>👾 от 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()

View file

@ -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)
)

View file

@ -1,10 +1,6 @@
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
from aiogram import Dispatcher
def register_middlewares(dp: Dispatcher) -> None:
@ -16,8 +12,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)
"""

View file

@ -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

View file

@ -0,0 +1,8 @@
import time
from typing import Callable, Dict, Awaitable, Any
from aiogram import BaseMiddleware
from aiogram.exceptions import TelegramRetryAfter
from aiogram.types import Message, ErrorEvent, Update, CallbackQuery

View file

@ -0,0 +1 @@
from .menu import *

View file

@ -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)

View file

@ -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 *

View file

@ -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

View file

@ -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
@ -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

View file

@ -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

View file

@ -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

View file

@ -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
"""
back_to_category: str
class BackStart(CallbackData, prefix="start"):
"""
Callback data to back to /start
"""
pass

View file

@ -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

View file

@ -1,104 +0,0 @@
from typing import Any
from aiogram.filters import Filter
from aiogram.types import Message, ChatPermissions
from aiogram.enums import ChatMemberStatus
from bozenka.instances.telegram.utils.simpler import ru_cmds
class UserHasPermissions(Filter):
"""
Check, does user have permissions, what user need to work with bot.
"""
# List of permissions avaible to users.
# Basic permissions for administration and user
permissions = [
"can_manage_chat",
"can_delete_messages",
"can_manage_video_chats",
"can_restrict_members",
"can_promote_members",
"can_change_info",
"can_invite_users",
"can_post_messages",
"can_edit_messages",
"can_pin_messages",
"can_manage_topics",
"can_send_messages",
"can_send_audios",
"can_send_documents",
"can_send_photos",
"can_send_videos",
"can_send_video_notes",
"can_send_voice_notes",
"can_send_polls",
"can_send_other_messages",
"can_add_web_page_previews",
]
def __init__(self, perms: list[Any]) -> None:
self.perms = perms
async def check_permissions(self, permission, msg: Message) -> bool:
"""
Checking permissions, included to user.
:return:
"""
if permission.count(False) > 0 or permission.count(None) > 0:
await msg.answer("Ошибка ❌\n"
"У вас нет прав на использование этой комманды 🚫")
return False
return True
def generate_perms_list(self, user) -> list[Any]:
"""
Generates list of permissions, included to user
:param user:
:return:
"""
permission = []
for rule in self.perms:
if rule in permission:
exec(f"permission.append(user.{rule})")
return permission
async def __call__(self, msg: Message) -> bool:
user = await msg.chat.get_member(msg.from_user.id)
permission = self.generate_perms_list(user)
return True if user.status == ChatMemberStatus.CREATOR else self.check_permissions(permission, msg)
class BotHasPermissions(UserHasPermissions):
"""
Check, does bot have permissions, what user need to work with bot.
"""
async def __call__(self, msg: Message, *args, **kwargs):
bot = await msg.chat.get_member(msg.chat.bot.id)
permission = self.generate_perms_list(bot)
return self.check_permissions(permission, msg)
class IsOwner(Filter):
"""
Checks, is User are owner of chat
"""
def __init__(self, is_admin: bool) -> None:
self.is_admin = is_admin
async def __call__(self, msg: Message) -> bool:
user = await msg.chat.get_member(msg.from_user.id)
if ChatMemberStatus.CREATOR != user.status:
await msg.answer(ru_cmds["no-perms"])
return ChatMemberStatus.CREATOR == user.status
class IsAdminFilter(Filter):
def __init__(self, is_admin: bool) -> None:
self.is_admin = is_admin
async def __call__(self, msg: Message) -> bool:
user = await msg.chat.get_member(msg.from_user.id)
if ChatMemberStatus.CREATOR == user.status:
return True
return ChatMemberStatus.ADMINISTRATOR == user.status

View file

@ -1 +0,0 @@
from .inline import *

View file

@ -1,613 +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.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(back_to_category=category).pack())]
])
return kb
# Setup related keyboards
def setup_keyboard() -> InlineKeyboardMarkup:
"""
Generate keyboard for /setup command
:return:
"""
kb = InlineKeyboardBuilder()
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
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=DeleteCallbackData(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="category").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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(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=DeleteCallbackData(user_id_clicked=str(user_id)).pack())]
])
return kb
about_keyboard = InlineKeyboardBuilder()
about_keyboard.button(
text="Bozo Development", url="https://t.me/BozoDevelopment"
)

View file

@ -1,36 +0,0 @@
import time
from typing import Callable, Dict, Awaitable, Any
from aiogram import BaseMiddleware
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)

View file

@ -1,6 +1,2 @@
from .solution_simpler import SolutionSimpler
from .lists_of_content import *
from .fsm_states import *

View file

@ -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 ChatSettings
@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="<b>Закреп</b>📌"
"\nДанная функция включает команды:"
"<pre>/pin - закрепляет сообщение\n"
"/unpin - открепляет сообщение\n"
"/unpin_all - открепляет все сообщения, которые видит бот</pre>\n"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>",
callback_name="pins",
settings_name="pins",
db_name=ChatSettings.pins
),
BaseFeature(
name="Модерация чата 🕵️",
description="<b>Модерация чата</b>🕵️\nДанная настройка включает следущие комманды:"
"\n<pre>/ban [время блокировки] [причина блокировки] - блокировка пользователя"
"\n/unban - разблокировка пользователя\n"
"/mute [время мута] [причина мута] - мут пользователя\n"
"/unmute - Размут пользователя</pre>\n"
"Время обозначается как:"
"<pre>1h - один час, "
"1d - один день, "
"1m - одна минута, "
"1s - одна секунда</pre>\n"
"Для того, "
"чтобы выполнить одну из комманд по отношению к пользователю, "
"ответьте на сообщение пользователя и используйте команду\n"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>",
callback_name="moderation",
settings_name="moderation",
db_name=ChatSettings.moderation
),
BaseFeature(
name="Работа с Форумом 💬",
description="<b>Работа с Форумом</b>💬\nДанная настройка включает следущие комманды:\n"
"<pre>/open - открывают тему форума\n"
"/close - закрывают тему форума\n"
"/open_general - открывают основную тему форума\n"
"/close_general - закрывает основную тему форума\n"
"/hide_general - прячет основную тему форума\n"
"/show_general - показывает основную тему форума</pre>\n"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть"
"включен форум</b>",
callback_name="topics",
settings_name="topics",
db_name=ChatSettings.topics
),
BaseFeature(
name="Приглашения в Чат ✉",
description="<b>Генератор приглашения в Чат ✉</b>\n"
"Разрешает использование комманды /invite в чате, для созданния приглашений.\n"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>",
callback_name="invites",
settings_name="invite_generator",
db_name=ChatSettings.invite_generator
),
BaseFeature(
name="Результаты в лс ✉",
description="<b>Результаты в личных сообщениях ✉</b>\n"
"Отправляет все результаты команд модерации в личные сообщения пользователя\n"
"Никаких особых прав у бота не требует.",
callback_name="results_in_dm",
settings_name="results_in_dm",
db_name=ChatSettings.results_in_dm
),
BaseFeature(
name="Оповещение об ограничении 🗯",
description="<b>Оповещение об ограничении 🗯</b>\n"
"Отправляет оповещение пользователю об его муте, бане\n"
"Никаких особых прав у бота не требует.",
callback_name="restrict_notification",
settings_name="restrict_notification",
db_name=ChatSettings.restrict_notification
)
],
"Members": [
BaseFeature(
name="Приветсвенные сообщения 👋",
description="<b>Приветсвенные сообщения 👋</b>"
"\nПриветсвенные сообщения новым и ушедшим пользователям.",
callback_name="welcome",
settings_name="welcome_messages",
db_name=ChatSettings.welcome_messages
),
BaseFeature(
name="Оповещение о муте 📬",
description="<b>Оповещение о муте 📬</b>"
"\nОповещает пользователя в личных сообщениях, что тот был: замучен, размучен, забанен, разбанен",
callback_name="notify",
settings_name="restrict_notification",
db_name=ChatSettings.restrict_notification
)
],
"Devs": [
BaseFeature(
name="Функция Привет 👋",
description="<b>Функция `Привет` </b>👋"
"\nБот будет отвечать на комманды "
"/hi, /hello, /privet и т.п., отвечая приветсвием на сообщение пользователя.",
callback_name="hi",
settings_name="hi_command",
db_name=ChatSettings.hi_command
),
BaseFeature(
name="ИИ ЧатБот 🤖",
description="<b>ИИ ЧатБот </b>🤖"
"\nЕсть поддержка:\n"
"- Моделей Gpt4All\n"
"- Провайдеров Gpt4Free и моделей\n"
"Для использования:\n"
"<pre>/conversations</pre>"
"\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘",
callback_name="gtm",
settings_name="gpt_conversations",
db_name=ChatSettings.text_generation
),
BaseFeature(
name="Генерация изображений 📸",
description="<b>Генерация изображений </b>🤖"
"\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘",
callback_name="gpm",
settings_name="123",
db_name=ChatSettings.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": "<em> Держите ваше приглашение в чат, user 👋</em>",
"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 переименовал обсуждение <pre>originalthreadname</pre>",
# 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"
"Вы выбрали модель <pre>modelname</pre>👾, от провайдера <pre>providername</pre>👨‍💻\n"
"Чтобы прекратить общение, используйте /cancel ",
"finish_gpt": "Вы теперь можете спокойно вести диалог 🤖",
"select_model_message": "Выберите пожалуйста модель ИИ 👾",
"select_model": "Выберите пожалуйста модель ИИ 👾",
# No Permission translation
"no_perms": "Ошибка ❌"
"У вас нет прав на использование этой комманды 🚫",
# After adding bot into group message text
"after_adding": "Здраствуйте администраторы чата 👋\n"
"Я - <b>бозенька</b>, мультифункциональный бот, разрабатываемый Bozo Developement\n"
"Выдайте мне <b>полные права администратора</b> для моей полной работы."
"Чтобы настроить функционал, используйте /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,
}

View file

@ -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)