Changelog:

- /start finished
- started codding /setup database
- too much refactors
- started codding image generation
- reverted changes for /ban recode
This commit is contained in:
kittyneverdies 2023-12-30 14:52:36 +03:00
parent 3ee2844ffc
commit 3fc4432e42
30 changed files with 580 additions and 289 deletions

View File

@ -2,7 +2,7 @@
[alembic] [alembic]
# path to migration scripts # path to migration scripts
script_location = bozenka/db/migrate script_location = bozenka/database/migrate
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time # Uncomment the line below if you want the files to be prepended with date and time

View File

@ -13,6 +13,8 @@ def launch_instances() -> None:
:return: :return:
""" """
logging.log(msg="Setting up g4f logging!", level=logging.INFO) logging.log(msg="Setting up g4f logging!", level=logging.INFO)
logging.basicConfig(level=logging.INFO)
logging.log(msg="Setting up logging!", level=logging.INFO)
g4f.logging = True g4f.logging = True
db_url = generate_url() db_url = generate_url()

View File

@ -22,7 +22,7 @@ if config.config_file_name is not None:
# for 'autogenerate' support # for 'autogenerate' support
# from myapp import mymodel # from myapp import mymodel
# target_metadata = mymodel.Base.metadata # target_metadata = mymodel.Base.metadata
target_metadata = bozenka.db.main.MainModel.metadata target_metadata = bozenka.database.main.MainModel.metadata
# other values from the config, defined by the needs of env.py, # other values from the config, defined by the needs of env.py,
# can be acquired: # can be acquired:

View File

@ -1,6 +1,7 @@
import asyncio
from typing import Tuple, Any from typing import Tuple, Any
from sqlalchemy import Column, Integer, VARCHAR, Boolean, Text, select, BigInteger, Row from sqlalchemy import Column, Integer, VARCHAR, Boolean, Text, select, BigInteger, Row, inspect
from sqlalchemy.ext.asyncio import async_sessionmaker from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from bozenka.database.main import MainModel from bozenka.database.main import MainModel
@ -65,9 +66,32 @@ async def get_settings(chat_id: int, session: async_sessionmaker):
""" """
async with session() as session: async with session() as session:
async with session.begin(): 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() return (await session.execute(select(ChatSettings).where(ChatSettings.chat_id == chat_id))).one_or_none()
async def get_setting(chat_id: int, session: async_sessionmaker, setting: str) -> bool:
"""
Return setting by sessionmaker and chat_id
:param chat_id: id of telegram chat
:param session: sessionmaker from dispatcher
:param setting: string setting what we need to get
:return:
"""
async with session() as session:
async with session.begin():
rows = (await session.execute(select(ChatSettings).where(ChatSettings.chat_id == chat_id))).one().__dict__
for r in rows:
print(r.__dict__)
print("!@#1221312321312312313")
print(rows)
for i in rows:
print("+")
print(i)
async def get_user(user_id: int, chat_id: int, session: async_sessionmaker) -> Row[tuple[Any, ...] | Any] | None: async def get_user(user_id: int, chat_id: int, session: async_sessionmaker) -> Row[tuple[Any, ...] | Any] | None:
""" """
Return user with sessionmaker by user_id and chat_id. Return user with sessionmaker by user_id and chat_id.

View File

@ -1,6 +1,19 @@
# List of generative categories, what we support # List of text generative categories, what we support
text_generative_categories = [ text_generative_categories = [
"Gpt4Free", "Gpt4Free",
"Gpt4All", "Gpt4All",
]
# List of image generative categories, what we support
image_generative_categories = [
"Kadinsky"
]
image_generative_size = [
"1024x1024",
"1024x576",
"576x1024",
"1024x680",
"680x1024"
] ]

View File

@ -6,7 +6,16 @@ def check(model_filename: str) -> bool:
Checking & downloading our gpt4all models Checking & downloading our gpt4all models
Returns True if it's already downloaded Returns True if it's already downloaded
Returns False if it's not downloaded Returns False if it's not downloaded
:param model_filename: :param model_filename: File name of gpt4all model
:return: :return:
""" """
return os.path.exists("models\\" + model_filename) return os.path.exists("models\\" + model_filename)
def get_model_path(model_filename: str) -> str:
"""
Just returning path of our gpt4all models.
:param model_filename: File name of gpt4all model
:return:
"""
return os.curdir + "models\\" + model_filename

View File

@ -1,4 +1,5 @@
import g4f import g4f
import g4f.Provider
from g4f.Provider import RetryProvider from g4f.Provider import RetryProvider
from varname import nameof from varname import nameof
@ -8,15 +9,9 @@ def generate_gpt4free_providers():
Generates list of g4f providers Generates list of g4f providers
:return: :return:
""" """
provider = {} return {prov: g4f.Provider.ProviderUtils.convert[prov] for prov in g4f.Provider.__all__
for prov in g4f.Provider.__all__: if prov != "BaseProvider" and prov != "AsyncProvider" and prov != "RetryProvider" and
if prov != "BaseProvider" and prov != "AsyncProvider" and prov != "RetryProvider": g4f.Provider.ProviderUtils.convert[prov].working}
exec(f"provider['{prov}']=g4f.Provider.{prov}")
result = {}
for check in provider:
if provider[check].working:
result[check] = provider[check]
return result
def generate_gpt4free_models(): def generate_gpt4free_models():
@ -25,16 +20,17 @@ def generate_gpt4free_models():
:return: :return:
""" """
models = {} models = {}
for model, model_name in g4f.models.ModelUtils.convert.items(), g4f.models.ModelUtils.convert.keys(): for model_name, model in g4f.models.ModelUtils.convert.items():
if type(model.best_provider) is RetryProvider: if type(model.best_provider) is RetryProvider:
for pr in model.best_provider.providers: for pr in model.best_provider.providers:
if pr in models: if pr.__name__ in models:
models[nameof(pr)].append(model_name) models[pr.__name__].append(model_name)
else: else:
models[nameof(pr)] = [model_name] models[pr.__name__] = [model_name]
else: else:
if nameof(model.best_provider) in models: if model.best_provider.__name__ in models:
models[nameof(model.best_provider)].append(model_name) models[model.best_provider.__name__].append(model_name)
else: else:
models[nameof(model.best_provider)] = [model_name] models[model.best_provider.__name__] = [model_name]
print(models)
return models return models

View File

@ -0,0 +1,50 @@
import json
import time
import requests
class Kadinsky:
"""
Kadinsky class from their documentation.
"""
def __init__(self, url, api_key, secret_key):
self.URL = url
self.AUTH_HEADERS = {
'X-Key': f'Key {api_key}',
'X-Secret': f'Secret {secret_key}',
}
def get_model(self):
response = requests.get(self.URL + 'key/api/v1/models', headers=self.AUTH_HEADERS)
data = response.json()
return data[0]['id']
def generate(self, prompt, model, images=1, width=1024, height=1024):
params = {
"type": "GENERATE",
"numImages": images,
"width": width,
"height": height,
"generateParams": {
"query": f"{prompt}"
}
}
data = {
'model_id': (None, model),
'params': (None, json.dumps(params), 'application/json')
}
response = requests.post(self.URL + 'key/api/v1/text2image/run', headers=self.AUTH_HEADERS, files=data)
data = response.json()
return data['uuid']
def check_generation(self, request_id, attempts=10, delay=10):
while attempts > 0:
response = requests.get(self.URL + 'key/api/v1/text2image/status/' + request_id, headers=self.AUTH_HEADERS)
data = response.json()
if data['status'] == 'DONE':
return data['images']
attempts -= 1
time.sleep(delay)

View File

@ -12,11 +12,10 @@ from bozenka.instances.telegram.utils.simpler import list_of_commands
async def launch_telegram_instance(session_maker: async_sessionmaker) -> None: async def launch_telegram_instance(session_maker: async_sessionmaker) -> None:
""" """
Launches telegram bot with token from enviroment Launches telegram bot with token from enviroment
:param session_maker:
:return: :return:
""" """
logging.basicConfig(level=logging.INFO) logging.log(msg="-" * 50 + "TELEGRAM INSTANCE LAUNCH" + "-" * 50, level=logging.INFO)
logging.log(msg="Setting up logging!", level=logging.INFO)
g4f.logging = True
bot = Bot(token=os.getenv("tg_bot_token"), parse_mode="HTML") bot = Bot(token=os.getenv("tg_bot_token"), parse_mode="HTML")

View File

@ -9,7 +9,7 @@ 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.mutes import mute, unmute
from bozenka.instances.telegram.handlers.chat_admin.pins import pin, unpin, unpin_all 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.topics import *
from bozenka.instances.telegram.handlers.chat_admin.bans import ban, unban from bozenka.instances.telegram.handlers.chat_admin.bans import ban_command, unban_command
from bozenka.instances.telegram.utils.filters import * from bozenka.instances.telegram.utils.filters import *
@ -29,11 +29,11 @@ def register_admin_cmd(router: Router) -> None:
router.message.register(help_pin, Command(commands=["pin"])) router.message.register(help_pin, Command(commands=["pin"]))
router.message.register(help_unpin, Command(commands=["unpin"])) router.message.register(help_unpin, Command(commands=["unpin"]))
# Ban / Unban commands handler # Ban / Unban commands handler
router.message.register(ban, Command(commands="ban"), router.message.register(ban_command, Command(commands="ban"),
IsAdminFilter(True)) IsAdminFilter(True))
router.message.register(ban, Command(commands="ban"), router.message.register(ban_command, Command(commands="ban"),
IsAdminFilter(True), F.reply_to_message.text) IsAdminFilter(True), F.reply_to_message.text)
router.message.register(unban, Command(commands="unban"), router.message.register(unban_command, Command(commands="unban"),
IsAdminFilter(True), F.reply_to_message.text) IsAdminFilter(True), F.reply_to_message.text)
# Mute / Unmute commands handler # Mute / Unmute commands handler
router.message.register(mute, Command(commands=["mute", "re"]), UserHasPermissions(["can_restrict_members"]), router.message.register(mute, Command(commands=["mute", "re"]), UserHasPermissions(["can_restrict_members"]),

View File

@ -8,7 +8,7 @@ from bozenka.instances.telegram.utils.keyboards import ban_keyboard, delete_keyb
from bozenka.instances.telegram.utils.simpler import SolutionSimpler, ru_cmds from bozenka.instances.telegram.utils.simpler import SolutionSimpler, ru_cmds
async def ban(msg: Message, command: CommandObject, session_maker: async_sessionmaker): async def ban_command(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None:
""" """
/ban command function, supports time and reasons. /ban command function, supports time and reasons.
:param msg: Message telegram object :param msg: Message telegram object
@ -25,68 +25,23 @@ async def ban(msg: Message, command: CommandObject, session_maker: async_session
config = await SolutionSimpler.ban_user(msg, command, session_maker) config = await SolutionSimpler.ban_user(msg, command, session_maker)
if config["reason"] and config["ban_time"]: if config["reason"] and config["ban_time"]:
if mentions := [entity for entity in msg.entities if entity.type == 'mention']: await msg.answer("Удача ✅\n"
mentions_list = "" f"Пользователь {msg.reply_to_message.from_user.mention_html()} был заблокирован пользователем {msg.from_user.mention_html()}.\n"
f"По причине {config['reason']}, до даты {config['ban_time']}",
for mention in mentions: reply_markup=ban_keyboard(msg.from_user.id, msg.reply_to_message.from_user.id))
mentions_list += f"{mention.user.mention_html()} "
if msg.reply_to_message.from_user:
mentions_list += f"{msg.reply_to_message.from_user.mention_html()} "
await msg.answer("Удача ✅\n"
f"Пользователи {mentions_list}были заблокирован пользователем {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))
else:
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"]: elif config["reason"]:
if mentions := [entity for entity in msg.entities if entity.type == 'mention']: await msg.answer(
mentions_list = "" "Удача ✅\n"
f"Пользователь {msg.reply_to_message.from_user.mention_html()} был заблокирован пользователем {msg.reply_to_message.from_user.mention_html()}.\n"
for mention in mentions: f"По причине {config['reason']}.",
mentions_list += f"{mention.user.mention_html()} " reply_markup=ban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id)
)
if msg.reply_to_message.from_user:
mentions_list += f"{msg.reply_to_message.from_user.mention_html()} "
await msg.answer(
"Удача ✅\n"
f"Пользователи {mentions_list}были заблокирован пользователем {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)
)
else:
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"]: elif config["ban_time"]:
if mentions := [entity for entity in msg.entities if entity.type == 'mention']: await msg.answer(
mentions_list = "" "Удача ✅\n"
for mention in mentions: f"Пользователь {msg.reply_to_message.from_user.mention_html()} был заблокирован пользователем {msg.from_user.mention_html()}, до даты {config['ban_time']}",
mentions_list += f"{mention.user.mention_html()} " reply_markup=ban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id)
)
if msg.reply_to_message.from_user:
mentions_list += f"{msg.reply_to_message.from_user.mention_html()} "
await msg.answer(
"Удача ✅\n"
f"Пользователи {msg.reply_to_message.from_user.mention_html()}были заблокирован пользователем {msg.from_user.mention_html()}\n"
f"До даты {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()}, до даты {config['ban_time']}",
reply_markup=ban_keyboard(admin_id=msg.from_user.id, ban_id=msg.reply_to_message.from_user.id)
)
else: else:
await msg.answer( await msg.answer(
"Удача ✅\n" "Удача ✅\n"
@ -95,7 +50,7 @@ async def ban(msg: Message, command: CommandObject, session_maker: async_session
) )
async def unban(msg: Message, command: CommandObject, session_maker: async_sessionmaker): async def unban_command(msg: Message, command: CommandObject, session_maker: async_sessionmaker) -> None:
""" """
/unban command function /unban command function
:param msg: Message telegram object :param msg: Message telegram object
@ -125,13 +80,12 @@ async def unban(msg: Message, command: CommandObject, session_maker: async_sessi
) )
async def status(msg: Message, session_maker: async_sessionmaker): async def status_command(msg: Message, session_maker: async_sessionmaker) -> None:
""" """
/status command function /status command function
Checks is user banned and muted Checks is user banned and muted
:param msg: :param msg: Message telegram object
:param command: :param session_maker: Session maker object of SqlAlchemy
:param session_maker:
:return: :return:
""" """
config = await SolutionSimpler.get_status(msg, session_maker) config = await SolutionSimpler.get_status(msg, session_maker)

View File

@ -2,14 +2,17 @@ import logging
from aiogram import Bot from aiogram import Bot
from aiogram.types import Message as Message from aiogram.types import Message as Message
from bozenka.instances.telegram.utils.simpler import ru_cmds from sqlalchemy.ext.asyncio import async_sessionmaker
from bozenka.instances.telegram.utils.simpler import SolutionSimpler
async def join(msg: Message): async def join(msg: Message, session_maker: async_sessionmaker):
""" """
Send welcome message, after adding new member to chat. Send welcome message, after adding new member to chat.
Also works on adding bot to chat and sending welcome message. Also works on adding bot to chat and sending welcome message.
:param msg: :param msg:
:param session_maker:
:return: :return:
""" """
for new in msg.new_chat_members: for new in msg.new_chat_members:
@ -17,13 +20,17 @@ async def join(msg: Message):
logging.log(msg=f"Saing welcome for user_id={new.id}, chat_id={msg.chat.id}", logging.log(msg=f"Saing welcome for user_id={new.id}, chat_id={msg.chat.id}",
level=logging.INFO) level=logging.INFO)
await msg.answer( await msg.answer(
f"Пользователь {new.mention_html()} переехал в конфу, благодаря {msg.from_user.mention_html()}👋", f"Пользователь {new.mention_html()} переехал в конфу, благодаря {msg.from_user.mention_html()}👋",
) )
await msg.delete()
else: else:
logging.log(msg=f"Saing welcome to administrators for chat_id={msg.chat.id}", logging.log(msg=f"Saing welcome to administrators for chat_id={msg.chat.id}",
level=logging.INFO) level=logging.INFO)
await msg.answer(ru_cmds["after_adding"]) await msg.answer("Здраствуйте администраторы чата 👋\n"
await msg.delete() "Я - <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): async def leave(msg: Message, bot: Bot):
@ -41,4 +48,3 @@ async def leave(msg: Message, bot: Bot):
await msg.answer( await msg.answer(
f"Пользователь {msg.left_chat_member.mention_html()} съехал с конфы, благодаря {msg.from_user.mention_html()}👋" f"Пользователь {msg.left_chat_member.mention_html()} съехал с конфы, благодаря {msg.from_user.mention_html()}👋"
) )

View File

@ -8,16 +8,17 @@ from aiogram.types import Message as Message
from bozenka.generative.gpt4all import check from bozenka.generative.gpt4all import check
from bozenka.instances.telegram.utils.keyboards import gpt_categories_keyboard, delete_keyboard, response_keyboard from bozenka.instances.telegram.utils.keyboards import gpt_categories_keyboard, delete_keyboard, response_keyboard
from bozenka.instances.telegram.utils.simpler import generate_gpt4free_providers, ru_cmds, AnsweringGpt4All, \ from bozenka.instances.telegram.utils.simpler import AnsweringGpt4All, \
AnsweringGPT4Free AnsweringGPT4Free
from bozenka.generative.gpt4free import generate_gpt4free_providers
async def already_answering(msg: Message, state: FSMContext): async def already_answering(msg: Message, state: FSMContext):
""" """
Giving response, if answering user now, Giving response, if answering user now,
but he still asks something but he still asks something
:param msg: :param msg: Message telegram object
:param state: :param state: FSM state of bot
:return: :return:
""" """
await msg.answer("Подождите пожалуйста, мы уже генерируем ответ для вас, подождите, когда мы ответим на ваш передыдущий вопрос", await msg.answer("Подождите пожалуйста, мы уже генерируем ответ для вас, подождите, когда мы ответим на ваш передыдущий вопрос",
@ -27,8 +28,8 @@ async def already_answering(msg: Message, state: FSMContext):
async def start_dialog_cmd(msg: Message, state: FSMContext): async def start_dialog_cmd(msg: Message, state: FSMContext):
""" """
/conversation command handler, start /conversation command handler, start
:param msg: :param msg: Message telegram object
:param state: :param state: FSM state of bot
:return: :return:
""" """
if await state.get_state(): if await state.get_state():
@ -42,8 +43,8 @@ async def cancel_answering(msg: Message, state: FSMContext):
""" """
Canceling dialog with generative model Canceling dialog with generative model
Works on command /cancel Works on command /cancel
:param msg: :param msg: Message telegram object
:param state: :param state: FSM state of bot
:return: :return:
""" """
current = await state.get_state() current = await state.get_state()
@ -57,8 +58,8 @@ async def cancel_answering(msg: Message, state: FSMContext):
async def g4a_generate_answer(msg: Message, state: FSMContext): async def g4a_generate_answer(msg: Message, state: FSMContext):
""" """
Generating answer if Gpt4All has been selected Generating answer if Gpt4All has been selected
:param msg: :param msg: Message telegram object
:param state: :param state: FSM state of bot
:return: :return:
""" """
await state.set_state(AnsweringGpt4All.answering) await state.set_state(AnsweringGpt4All.answering)
@ -100,8 +101,8 @@ async def g4a_generate_answer(msg: Message, state: FSMContext):
async def g4f_generate_answer(msg: Message, state: FSMContext): async def g4f_generate_answer(msg: Message, state: FSMContext):
""" """
Generating answer if GPT4Free model and provider has been selected Generating answer if GPT4Free model and provider has been selected
:param msg: :param msg: Message telegram object
:param state: :param state: FSM state of bot
:return: :return:
""" """
await state.set_state(AnsweringGPT4Free.answering) await state.set_state(AnsweringGPT4Free.answering)
@ -126,7 +127,8 @@ async def g4f_generate_answer(msg: Message, state: FSMContext):
provider=providers[info["set_provider"]], provider=providers[info["set_provider"]],
stream=False stream=False
) )
except NameError:
except NameError or SyntaxError:
try: try:
response = g4f.ChatCompletion.create( response = g4f.ChatCompletion.create(
model=info["set_model"], model=info["set_model"],
@ -152,6 +154,6 @@ async def g4f_generate_answer(msg: Message, state: FSMContext):
async def generate_image(msg: Message): async def generate_image(msg: Message):
""" """
Image generation, planned in future Image generation, planned in future
:param msg: :param msg: Message telegram object
""" """
pass pass

View File

@ -18,13 +18,13 @@ def register_main_cmd(router: Router) -> None:
:return: :return:
""" """
logging.log(msg="Registering main related commands", level=logging.INFO) logging.log(msg="Registering main related commands", level=logging.INFO)
# Start command handler # Start command handler
router.message.register(start_cmd, Command(commands=["start"]), F.chat.type == ChatType.PRIVATE) router.message.register(start_cmd, Command(commands=["start"]), F.chat.type == ChatType.PRIVATE)
# Routes handler
router.message.register(add_to_chat, F.text == "Добавить в чат 🔌", F.chat.type == ChatType.PRIVATE) # Registering command /setup
router.message.register(features_list, F.text == "Функционал 🔨", F.chat.type == ChatType.PRIVATE) router.message.register(setup_cmd, Command(commands=["setup"]), ~(F.chat.type == ChatType.PRIVATE))
# router.message.register(start_cmd, CommandStart)
router.message.register(setup_cmd, Command(commands=["setup"]))
# After adding to chat handler # After adding to chat handler
router.message.register(after_adding, F.content_type == ContentType.SUPERGROUP_CHAT_CREATED) router.message.register(group_adding_handler, F.content_type == ContentType.SUPERGROUP_CHAT_CREATED)
router.message.register(after_adding, F.content_type == ContentType.GROUP_CHAT_CREATED) router.message.register(group_adding_handler, F.content_type == ContentType.GROUP_CHAT_CREATED)

View File

@ -1,4 +1,6 @@
from aiogram.types import Message as Message 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.simpler import SolutionSimpler
from bozenka.instances.telegram.utils.keyboards import setup_keyboard from bozenka.instances.telegram.utils.keyboards import setup_keyboard
@ -7,6 +9,7 @@ async def setup_cmd(msg: Message):
""" """
/setup handler /setup handler
:param msg: :param msg:
:param session:
:return: :return:
""" """
await msg.answer("Привет владелец чата 👋\n" await msg.answer("Привет владелец чата 👋\n"
@ -14,12 +17,14 @@ async def setup_cmd(msg: Message):
reply_markup=setup_keyboard()) reply_markup=setup_keyboard())
async def after_adding(msg: Message): async def group_adding_handler(msg: Message, session_maker: async_sessionmaker):
""" """
Send message after adding bozenka into group chat Send message after adding bozenka into group chat
:param msg: :param msg:
:param session_maker:
:return: :return:
""" """
await SolutionSimpler.auto_settings(msg=msg, session=session_maker)
await msg.answer("Здраствуйте администраторы чата 👋\n" await msg.answer("Здраствуйте администраторы чата 👋\n"
"Я - <b>бозенька</b>, мультифункциональный бот, разрабатываемый Bozo Developement\n" "Я - <b>бозенька</b>, мультифункциональный бот, разрабатываемый Bozo Developement\n"
"Выдайте мне <b>полные права администратора</b> для моей полной работы, если не выдали." "Выдайте мне <b>полные права администратора</b> для моей полной работы, если не выдали."

View File

@ -2,7 +2,7 @@ from aiogram.enums import ChatType
from aiogram.types import Message as Message from aiogram.types import Message as Message
from aiogram.utils.keyboard import InlineKeyboardBuilder from aiogram.utils.keyboard import InlineKeyboardBuilder
from bozenka.instances.telegram.utils.keyboards import start_keyboard_builder, help_keyboard from bozenka.instances.telegram.utils.keyboards import start_keyboard_builder, help_keyboard, start_keyboard
async def start_cmd(msg: Message): async def start_cmd(msg: Message):
@ -15,47 +15,5 @@ async def start_cmd(msg: Message):
'Привет, пользователь, я - Бозенька 👋\n' 'Привет, пользователь, я - Бозенька 👋\n'
'Я мультизадачный телеграм (в будущем кросс-платформенный) бот с открытым исходным кодом, разрабатываемый <b>Bozo Developement</b>\n' 'Я мультизадачный телеграм (в будущем кросс-платформенный) бот с открытым исходным кодом, разрабатываемый <b>Bozo Developement</b>\n'
f'Выберите, что будете делать, {msg.from_user.mention_html(name="пользователь")}.', f'Выберите, что будете делать, {msg.from_user.mention_html(name="пользователь")}.',
reply_markup=start_keyboard_builder.as_markup(one_time_keyboard=True, resize_keyboard=True) reply_markup=start_keyboard()
) )
async def features_list(msg: Message):
"""
Shows features list from reply keyboard
:param msg:
:return:
"""
await msg.answer("Выберите категорию, по которой нужна помощь:",
reply_markup=help_keyboard())
async def about_devs(msg: Message):
"""
Shows info about devs from reply keyboard
:param msg:
:return:
"""
await msg.answer("Бозеьнка разработавается коммандой, состаящей из одного человека.\n"
"Исходный код находится под лицензией <b>GPL-3.0</b>. Исходный код проекта всегда будет открыт и доступен.\n"
"Исходный код проекта всегда можно найти тут: https://github.com/kittyneverdies/bozenka/")
await msg.delete()
async def add_to_chat(msg: Message):
"""
Sends link for adding bot into chat
:param msg:
:return:
"""
# Getting bot
me = await msg.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")
# Answering
await msg.answer("Чтобы добавить бозеньку в чат, нажмите на кнопку под сообщением:",
reply_markup=kb.as_markup())
await msg.delete()

View File

@ -1,16 +1,13 @@
__all__ = ["ban", "delete", "gpt"]
from aiogram import Router, F from aiogram import Router, F
from bozenka.instances.telegram.handlers.queries.start import inline_help_features, inline_help_feature, \ from bozenka.instances.telegram.handlers.queries.start import *
inline_back_help_categories, inline_back_help_features
from bozenka.instances.telegram.utils.callbacks_factory import * from bozenka.instances.telegram.utils.callbacks_factory import *
from bozenka.instances.telegram.handlers.queries.ban import * from bozenka.instances.telegram.handlers.queries.ban import *
from bozenka.instances.telegram.handlers.queries.pins import * from bozenka.instances.telegram.handlers.queries.pins import *
from bozenka.instances.telegram.handlers.queries.threads import * from bozenka.instances.telegram.handlers.queries.threads import *
from bozenka.instances.telegram.handlers.queries.delete import * from bozenka.instances.telegram.handlers.queries.delete import *
from bozenka.instances.telegram.handlers.queries.revoke import * from bozenka.instances.telegram.handlers.queries.revoke import *
from bozenka.instances.telegram.handlers.queries.gpt import * from bozenka.instances.telegram.handlers.queries.text_generation import *
from bozenka.instances.telegram.handlers.queries.setup import * from bozenka.instances.telegram.handlers.queries.setup import *
@ -77,16 +74,34 @@ def register_queries(router: Router) -> None:
# /setup command related queries # /setup command related queries
# List of features based on category # List of features based on category
router.callback_query.register(inline_setup_features, SetupCategory.filter()) router.callback_query.register(inline_setup_category, SetupCategory.filter())
# Menu of feature to enable or disable # Menu of feature to enable or disable
router.callback_query.register(inline_feature, SetupFeature.filter()) 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 # /start command related queries
# Help of features based on category # Help of features based on category
router.callback_query.register(inline_help_features, HelpCategory.filter()) 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_categories, HelpBack.filter(F.back_to == "category"))
router.callback_query.register(inline_back_help_features, HelpBackCategory.filter()) router.callback_query.register(inline_back_help_features, HelpBackCategory.filter())
# Menu to back # Menu to back
router.callback_query.register(inline_help_feature, HelpFeature.filter()) 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")

View File

@ -0,0 +1,27 @@
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,
Gpt4FreeModelPage, GptStop, GptBackMenu, Gpt4AllModel, Gpt4AllSelect
)
# Keyboards for messages
from bozenka.instances.telegram.utils.keyboards import (
gpt4free_models_keyboard,
gpt4free_providers_keyboard,
delete_keyboard, gpt_categories_keyboard, generate_gpt4all_page, gpt4all_model_menu
)
# Simpler utlilities
from bozenka.instances.telegram.utils.simpler import (
AnsweringGPT4Free,
AnsweringGpt4All,
)

View File

@ -1,11 +1,14 @@
from aiogram.types import * from aiogram.types import CallbackQuery, Message
from sqlalchemy import select, Update
from sqlalchemy.ext.asyncio import async_sessionmaker
from bozenka.instances.telegram.utils.callbacks_factory import SetupCategory, SetupFeature from bozenka.database.tables.telegram import ChatSettings
from bozenka.instances.telegram.utils.keyboards import setup_category_keyboard 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 from bozenka.instances.telegram.utils.simpler import list_of_features
async def inline_setup_features(call: CallbackQuery, callback_data: SetupCategory): async def inline_setup_category(call: CallbackQuery, callback_data: SetupCategory):
""" """
Query, what shows list of features to enable. Query, what shows list of features to enable.
:param call: :param call:
@ -16,7 +19,7 @@ async def inline_setup_features(call: CallbackQuery, callback_data: SetupCategor
reply_markup=setup_category_keyboard(category=callback_data.category_name)) reply_markup=setup_category_keyboard(category=callback_data.category_name))
async def inline_setup_features_back(call: CallbackQuery, callback_data: SetupCategory): async def inline_setup_category_back(call: CallbackQuery, callback_data: SetupAction):
""" """
Query, what shows list of features to enable. Query, what shows list of features to enable.
:param call: :param call:
@ -24,16 +27,40 @@ async def inline_setup_features_back(call: CallbackQuery, callback_data: SetupCa
:return: :return:
""" """
await call.message.edit_text("Выберите настройку, которую хотите изменить", await call.message.edit_text("Выберите настройку, которую хотите изменить",
reply_markup=setup_category_keyboard(category=callback_data.category_name)) reply_markup=setup_category_keyboard(category=callback_data.feature_category))
async def inline_edit_feature(call: CallbackQuery, callback_data: SetupFeature, session_maker: async_sessionmaker):
async def inline_feature(call: CallbackQuery, callback_data: SetupFeature):
""" """
Query, what shows menu to enable / disable feature Query, what shows menu to enable / disable feature
:param call: :param call:
:param callback_data: :param callback_data:
:param session_maker:
:return: :return:
""" """
await call.message.edit_text(list_of_features[callback_data.feature_category][callback_data.feature_index].description) 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,
session=session_maker, msg=call.message))
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,
session=session, msg=call.message))

View File

@ -5,6 +5,82 @@ from bozenka.instances.telegram.utils.keyboards import *
from bozenka.instances.telegram.utils.simpler import list_of_features from bozenka.instances.telegram.utils.simpler import list_of_features
async def inline_start(call: CallbackQuery):
"""
Query, what shows back menu of /start
:param call:
:return:
"""
await call.message.edit_text(
'Привет, пользователь, я - Бозенька 👋\n'
'Я мультизадачный телеграм (в будущем кросс-платформенный) бот с открытым исходным кодом, разрабатываемый <b>Bozo Developement</b>\n'
f'Выберите, что будете делать, {call.from_user.mention_html(name="пользователь")}.',
reply_markup=start_keyboard()
)
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:
"""
kb = InlineKeyboardMarkup(inline_keyboard=[[
]])
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"
"Бозеьнка разработавается коммандой, состаящей из одного человека, сам проект был изначально для развития моих навыков в Python\n"
"Исходный код находится под лицензией <b>GPL-3.0</b>. Исходный код проекта всегда будет открыт и доступен.\n"
"Исходный код проекта всегда можно найти по этой ссылке: https://github.com/kittyneverdies/bozenka/\n"
"Исходный код бота для телеграма можно найти по этой ссылке: https://github.com/kittyneverdies/bozenka/branch/telegram",
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): async def inline_help_features(call: CallbackQuery, callback_data: HelpCategory):
""" """
Query, what shows list of features to get support. Query, what shows list of features to get support.
@ -45,5 +121,6 @@ async def inline_help_feature(call: CallbackQuery, callback_data: HelpFeature):
:param callback_data: :param callback_data:
:return: :return:
""" """
await call.message.edit_text(list_of_features[callback_data.feature_category][callback_data.feature_index].description, await call.message.edit_text(
reply_markup=help_feature_keyboard(category=callback_data.feature_category)) list_of_features[callback_data.feature_category][callback_data.feature_index].description,
reply_markup=help_feature_keyboard(category=callback_data.feature_category))

View File

@ -4,7 +4,7 @@ from aiogram import types
from aiogram.fsm.context import FSMContext from aiogram.fsm.context import FSMContext
from gpt4all import GPT4All from gpt4all import GPT4All
from bozenka.instances.telegram.utils.simpler.states import * from bozenka.instances.telegram.utils.simpler.fsm_states import *
# Callbacks for GPT # Callbacks for GPT
from bozenka.instances.telegram.utils.callbacks_factory import ( from bozenka.instances.telegram.utils.callbacks_factory import (
@ -170,10 +170,10 @@ async def inline_g4a_model(call: types.CallbackQuery, callback_data: Gpt4AllMode
if callback_data.user_id != call.from_user.id: if callback_data.user_id != call.from_user.id:
return return
models = GPT4All.list_models() models = GPT4All.list_models()
name = models[callback_data.model_index]['name'] name = models[callback_data.index]['name']
await call.message.edit_text(f"{name}\n" await call.message.edit_text(f"{name}\n"
f"Обученно на основе {models[callback_data.model_index]['parameters']} строк 👨‍💻", f"Обученно на основе {models[callback_data.index]['parameters']} строк 👨‍💻",
reply_markup=gpt4all_model_menu(user_id=call.from_user.id, index=callback_data.model_index)) 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: async def inline_g4a_select_model(call: types.CallbackQuery, callback_data: Gpt4AllSelect, state: FSMContext) -> None:
@ -186,13 +186,13 @@ async def inline_g4a_select_model(call: types.CallbackQuery, callback_data: Gpt4
""" """
if callback_data.user_id != call.from_user.id: if callback_data.user_id != call.from_user.id:
return return
await state.update_data(set_model=callback_data.model_index) await state.update_data(set_model=callback_data.index)
await state.set_state(AnsweringGpt4All.ready_to_answer) await state.set_state(AnsweringGpt4All.ready_to_answer)
models = GPT4All.list_models() models = GPT4All.list_models()
await call.message.edit_text("Удача ✅\n" await call.message.edit_text("Удача ✅\n"
"Вы теперь можете спокойно вести диалог 🤖\n" "Вы теперь можете спокойно вести диалог 🤖\n"
f"Вы выбрали модель <b>{models[callback_data.model_index]['name']}</b>👾 от Gpt4All\n" f"Вы выбрали модель <b>{models[callback_data.index]['name']}</b>👾 от Gpt4All\n"
"Чтобы прекратить общение, используйте /cancel ", "Чтобы прекратить общение, используйте /cancel ",
reply_markup=delete_keyboard(admin_id=callback_data.user_id)) reply_markup=delete_keyboard(admin_id=callback_data.user_id))

View File

@ -1,7 +1,24 @@
from aiogram.filters.callback_data import CallbackData from aiogram.filters.callback_data import CallbackData
class Gpt4FreeProvider(CallbackData, prefix="provider"): class ImageGenerationCategory(CallbackData, prefix="igc"):
"""
Callback with information related to image
"""
user_id: int
category: str
class ImageGeneration(CallbackData, prefix="igc"):
"""
Callback with information related to image
"""
user_id: int
category: str
size: str
class Gpt4FreeProvider(CallbackData, prefix="g4fp"):
""" """
Callback with information related to selected provider Callback with information related to selected provider
""" """
@ -48,7 +65,7 @@ class Gpt4AllModel(CallbackData, prefix="g4a"):
Callback with information to show GPT4All content Callback with information to show GPT4All content
""" """
user_id: int user_id: int
model_index: int index: int
class GptBackMenu(CallbackData, prefix="gbm"): class GptBackMenu(CallbackData, prefix="gbm"):
@ -64,7 +81,7 @@ class Gpt4AllSelect(CallbackData, prefix="g4s"):
Callback with information about selecting model Callback with information about selecting model
""" """
user_id: int user_id: int
model_index: int index: int
class GptStop(CallbackData, prefix="gs"): class GptStop(CallbackData, prefix="gs"):

View File

@ -23,6 +23,15 @@ class SetupBack(CallbackData, prefix="sb"):
back_to: str back_to: str
class SetupAction(CallbackData, prefix="sa"):
"""
Callback with information to do with a feature
"""
action: str
feature_category: str
feature_index: int
class SetupEditFeature(CallbackData, prefix="sef"): class SetupEditFeature(CallbackData, prefix="sef"):
""" """
Callback data with information to edit status of bozenka enabled feature Callback data with information to edit status of bozenka enabled feature

View File

@ -1,2 +1,2 @@
from .permissions import * from .permissions import *
from .message_entities import * from .chat_setting import *

View File

@ -0,0 +1,21 @@
from aiogram.filters import Filter
from aiogram.types import Message
from sqlalchemy.ext.asyncio import async_sessionmaker
from varname.helpers import exec_code
from bozenka.database.tables.telegram import get_settings
class ChatSettingFilter(Filter):
"""
Check, does chat have enabled features
"""
def __init__(self, settings: str) -> None:
self.settings = settings
async def __call__(self, msg: Message, session: async_sessionmaker) -> bool:
chat_setting = await get_settings(chat_id=msg.chat.id, session=session)
exec_code(f'return chat_setting.{self.settings}')
return True

View File

@ -2,13 +2,16 @@ import gpt4all
from typing import Any from typing import Any
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
from aiogram.utils.keyboard import InlineKeyboardBuilder from aiogram.utils.keyboard import InlineKeyboardBuilder
from gpt4all import GPT4All from gpt4all import GPT4All
from sqlalchemy.ext.asyncio import async_sessionmaker
from bozenka.database.tables.telegram import get_setting
from bozenka.instances.telegram.utils.callbacks_factory import * from bozenka.instances.telegram.utils.callbacks_factory import *
from bozenka.instances.telegram.utils.simpler import gpt_categories, generate_gpt4free_models, generate_gpt4free_providers, \ from bozenka.instances.telegram.utils.simpler import generate_list_of_features
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. File, contains inline keyboard & menus and their work.
@ -16,6 +19,22 @@ 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="dialogai")],
[InlineKeyboardButton(text="Генерация Изображений 🖼", callback_data="dialogimage")],
]
)
return kb
# Help related keyboards # Help related keyboards
def help_keyboard() -> InlineKeyboardMarkup: def help_keyboard() -> InlineKeyboardMarkup:
""" """
@ -28,7 +47,9 @@ def help_keyboard() -> InlineKeyboardMarkup:
[InlineKeyboardButton(text="Пользователи 👤", [InlineKeyboardButton(text="Пользователи 👤",
callback_data=HelpCategory(category_name="Members").pack())], callback_data=HelpCategory(category_name="Members").pack())],
[InlineKeyboardButton(text="В разработке 👨‍💻", [InlineKeyboardButton(text="В разработке 👨‍💻",
callback_data=HelpCategory(category_name="Devs").pack())]]) callback_data=HelpCategory(category_name="Devs").pack())],
[InlineKeyboardButton(text="Вернуться 🔙", callback_data="back")]
])
return kb return kb
@ -72,6 +93,8 @@ def setup_keyboard() -> InlineKeyboardMarkup:
Generate keyboard for /setup command Generate keyboard for /setup command
:return: :return:
""" """
kb = InlineKeyboardBuilder()
kb = InlineKeyboardMarkup(inline_keyboard=[[ kb = InlineKeyboardMarkup(inline_keyboard=[[
InlineKeyboardButton(text="Администраторы 👮‍♂", InlineKeyboardButton(text="Администраторы 👮‍♂",
callback_data=SetupCategory(category_name="Admins").pack())], callback_data=SetupCategory(category_name="Admins").pack())],
@ -99,8 +122,37 @@ def setup_category_keyboard(category: str) -> InlineKeyboardMarkup:
return kb.as_markup() return kb.as_markup()
def setup_feature_keyboard() -> InlineKeyboardMarkup: async def setup_feature_keyboard(category: str, index: int, session: async_sessionmaker,
pass msg: Message) -> InlineKeyboardMarkup:
"""
Generate keyboard for enabling or disabling
on of features
:param category:
:param index:
:param session:
:param msg:
:return:
"""
list_of_features = generate_list_of_features(category)
is_enabled = await get_setting(
chat_id=msg.chat.id,
session=session,
setting=list_of_features[index].settings_name)
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: def delete_keyboard(admin_id: int) -> InlineKeyboardMarkup:
@ -116,6 +168,37 @@ def delete_keyboard(admin_id: int) -> InlineKeyboardMarkup:
return kb 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 # LLM / GPT related keyboards
# GPT CATEGORIES # GPT CATEGORIES
def gpt_categories_keyboard(user_id: int) -> InlineKeyboardMarkup: def gpt_categories_keyboard(user_id: int) -> InlineKeyboardMarkup:
@ -125,8 +208,9 @@ def gpt_categories_keyboard(user_id: int) -> InlineKeyboardMarkup:
:return: InlineKeyboardMarkup :return: InlineKeyboardMarkup
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
for category in gpt_categories: for category in text_generative_categories:
builder.row(InlineKeyboardButton(text=category, callback_data=GptCategory(user_id=str(user_id), category=category).pack())) builder.row(InlineKeyboardButton(text=category,
callback_data=GptCategory(user_id=str(user_id), category=category).pack()))
return builder.as_markup() return builder.as_markup()
@ -212,30 +296,35 @@ def gpt4free_models_keyboard(user_id: int, provider, page: int) -> InlineKeyboar
models[provider].append("") models[provider].append("")
names = items_list_generator(page, models[provider], 4) names = items_list_generator(page, models[provider], 4)
for name in names: for name in names:
builder.row(InlineKeyboardButton(text=name.replace('-', ' '), callback_data=Gpt4freeResult(user_id=str(user_id), provider=provider, model=name).pack())) 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, pages = [len(models[provider]) // 4 - 1 if page - 1 == -1 else page - 1,
0 if page + 1 >= len(models[provider]) // 4 else page + 1] 0 if page + 1 >= len(models[provider]) // 4 else page + 1]
if len(models[provider]) > 4: if len(models[provider]) > 4:
builder.row( builder.row(
# First page button # First page button
InlineKeyboardButton(text=str(len(models[provider]) // 4 if page == 0 else "1"), InlineKeyboardButton(text=str(len(models[provider]) // 4 if page == 0 else "1"),
callback_data=Gpt4FreeModelPage( callback_data=Gpt4FreeModelPage(
page=str(len(models[provider]) // 4 - 1 if page == 0 else "1"), page=str(len(models[provider]) // 4 - 1 if page == 0 else "1"),
user_id=user_id,).pack(), user_id=user_id,
), provider=provider).pack(),
# Page back button ),
InlineKeyboardButton(text="⬅️", # Page back button
callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[0], provider=provider).pack()), InlineKeyboardButton(text="⬅️",
# Count of page button callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[0],
InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"), provider=provider).pack()),
# Next page button # Count of page button
InlineKeyboardButton(text="➡️", callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[1], provider=provider).pack()), InlineKeyboardButton(text=str(page + 1), callback_data="gotpages"),
# Last page button # Next page button
InlineKeyboardButton(text=str(len(models[provider]) // 4 if page != 0 else "1"), InlineKeyboardButton(text="➡️", callback_data=Gpt4FreeModelPage(user_id=str(user_id), page=pages[1],
callback_data=Gpt4FreeModelPage( provider=provider).pack()),
page=str(len(models[provider]) // 4 - 1) if page != 0 else "1", # Last page button
user_id=user_id, InlineKeyboardButton(text=str(len(models[provider]) // 4 if page != 0 else "1"),
provider=provider).pack(),)) callback_data=Gpt4FreeModelPage(
page=str(len(models[provider]) // 4 - 1) if page != 0 else "1",
user_id=user_id,
provider=provider).pack(), ))
else: else:
if providers[provider].supports_gpt_4: if providers[provider].supports_gpt_4:
builder.row(InlineKeyboardButton(text="gpt 4", builder.row(InlineKeyboardButton(text="gpt 4",
@ -246,7 +335,8 @@ def gpt4free_models_keyboard(user_id: int, provider, page: int) -> InlineKeyboar
builder.row(InlineKeyboardButton(text="gpt 3.5 turbo", builder.row(InlineKeyboardButton(text="gpt 3.5 turbo",
callback_data=Gpt4freeResult callback_data=Gpt4freeResult
(user_id=str(user_id), provider=provider, model="gpt-3.5-turbo").pack())) (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=GptBackMenu(user_id=user_id, back_to="providers").pack()))
builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", callback_data=GptStop(user_id=str(user_id)).pack())) builder.row(InlineKeyboardButton(text="Спасибо, не надо ❌", callback_data=GptStop(user_id=str(user_id)).pack()))
return builder.as_markup() return builder.as_markup()
@ -348,7 +438,8 @@ def mute_keyboard(admin_id: int, ban_id: int) -> InlineKeyboardMarkup:
:return: :return:
""" """
kb = InlineKeyboardMarkup(inline_keyboard=[ kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())], [InlineKeyboardButton(text="Спасибо ✅",
callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())],
[InlineKeyboardButton(text="Размутить 🛠️", [InlineKeyboardButton(text="Размутить 🛠️",
callback_data=UnmuteData(user_id_unmute=ban_id, user_id_clicked=admin_id).pack())]]) callback_data=UnmuteData(user_id_unmute=ban_id, user_id_clicked=admin_id).pack())]])
return kb return kb
@ -362,8 +453,10 @@ def unmute_keyboard(admin_id: int, ban_id: int) -> InlineKeyboardMarkup:
:return: :return:
""" """
kb = InlineKeyboardMarkup(inline_keyboard=[ kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())], [InlineKeyboardButton(text="Спасибо ✅",
[InlineKeyboardButton(text="Замутить 🛠️", callback_data=MuteData(user_id_mute=ban_id, user_id_clicked=admin_id).pack())]]) callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())],
[InlineKeyboardButton(text="Замутить 🛠️",
callback_data=MuteData(user_id_mute=ban_id, user_id_clicked=admin_id).pack())]])
return kb return kb
@ -379,7 +472,8 @@ def invite_keyboard(link: str, admin_id: int, chat_name: str) -> InlineKeyboardM
link = link.replace("https://", "") link = link.replace("https://", "")
kb = InlineKeyboardMarkup(inline_keyboard=[[ kb = InlineKeyboardMarkup(inline_keyboard=[[
InlineKeyboardButton(text=chat_name, url=link)], InlineKeyboardButton(text=chat_name, url=link)],
[InlineKeyboardButton(text="Отозвать 🛠️", callback_data=RevokeCallbackData(admin_id=admin_id, link=link).pack())], [InlineKeyboardButton(text="Отозвать 🛠️",
callback_data=RevokeCallbackData(admin_id=admin_id, link=link).pack())],
[InlineKeyboardButton(text="Спасибо ✅", [InlineKeyboardButton(text="Спасибо ✅",
callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())]]) callback_data=DeleteCallbackData(user_id_clicked=str(admin_id)).pack())]])
return kb return kb
@ -421,7 +515,8 @@ def pin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup:
:return: :return:
""" """
kb = InlineKeyboardMarkup(inline_keyboard=[ kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Открепить сообщение 📌", callback_data=UnpinMsg(user_id=user_id, msg_id=msg_id).pack())], [InlineKeyboardButton(text="Открепить сообщение 📌",
callback_data=UnpinMsg(user_id=user_id, msg_id=msg_id).pack())],
[InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())] [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())]
]) ])
return kb return kb
@ -435,7 +530,8 @@ def unpin_msg_keyboard(user_id: int, msg_id: int) -> InlineKeyboardMarkup:
:return: :return:
""" """
kb = InlineKeyboardMarkup(inline_keyboard=[ kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Открепить сообщение 📌", callback_data=PinMsg(user_id=user_id, msg_id=msg_id).pack())], [InlineKeyboardButton(text="Открепить сообщение 📌",
callback_data=PinMsg(user_id=user_id, msg_id=msg_id).pack())],
[InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())] [InlineKeyboardButton(text="Спасибо ✅", callback_data=DeleteCallbackData(user_id_clicked=str(user_id)).pack())]
]) ])
return kb return kb

View File

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

View File

@ -1,3 +1,4 @@
from dataclasses import dataclass
from typing import List from typing import List
import g4f import g4f
@ -6,18 +7,36 @@ from g4f.Provider import RetryProvider
from varname import nameof from varname import nameof
@dataclass
class BaseFeature: class BaseFeature:
""" """
Basic class of Feature. Basic class of Feature.
Have inside desription, name, callback name, Have inside desription, name, callback name,
""" """
def __init__(self, name: str, description: str, callback_name: str): name: str
self.name = name description: str
self.description = description callback_name: str
self.callback_name = callback_name settings_name: str
# List of features, avaible in bozenka @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 = { list_of_features = {
"Admins": [ "Admins": [
BaseFeature( BaseFeature(
@ -28,7 +47,8 @@ list_of_features = {
"/unpin - открепляет сообщение" "/unpin - открепляет сообщение"
"/unpin_all - открепляет все сообщения, которые видит бот" "/unpin_all - открепляет все сообщения, которые видит бот"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>", "Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>",
callback_name="pins" callback_name="pins",
settings_name="pins"
), ),
BaseFeature( BaseFeature(
name="Модерация чата 🕵️", name="Модерация чата 🕵️",
@ -46,7 +66,8 @@ list_of_features = {
"чтобы выполнить одну из комманд по отношению к пользователю, " "чтобы выполнить одну из комманд по отношению к пользователю, "
"ответьте на сообщение пользователя и используйте команду\n" "ответьте на сообщение пользователя и используйте команду\n"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>", "Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>",
callback_name="moderation" callback_name="moderation",
settings_name="moderation"
), ),
BaseFeature( BaseFeature(
name="Работа с Форумом 💬", name="Работа с Форумом 💬",
@ -59,14 +80,16 @@ list_of_features = {
"/show_general - показывает основную тему форума</pre>\n" "/show_general - показывает основную тему форума</pre>\n"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть" "Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота. Также должен быть"
"включен форум</b>", "включен форум</b>",
callback_name="topics" callback_name="topics",
settings_name="topics"
), ),
BaseFeature( BaseFeature(
name="Приглашения в Чат ✉", name="Приглашения в Чат ✉",
description="<b>Генератор приглашения в Чат ✉</b>\n" description="<b>Генератор приглашения в Чат ✉</b>\n"
"Разрешает использование комманды /invite в чате, для созданния приглашений.\n" "Разрешает использование комманды /invite в чате, для созданния приглашений.\n"
"Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>", "Для исполнения <b>требует соответсвующих прав от пользователя и их наличие у бота.</b>",
callback_name="invites" callback_name="invites",
settings_name="invite_generator"
) )
], ],
"Members": [ "Members": [
@ -74,13 +97,15 @@ list_of_features = {
name="Приветсвенные сообщения 👋", name="Приветсвенные сообщения 👋",
description="<b>Приветсвенные сообщения 👋</b>" description="<b>Приветсвенные сообщения 👋</b>"
"\nПриветсвенные сообщения новым и ушедшим пользователям.", "\nПриветсвенные сообщения новым и ушедшим пользователям.",
callback_name="welcome" callback_name="welcome",
settings_name="welcome_messages"
), ),
BaseFeature( BaseFeature(
name="Оповещение о муте 📬", name="Оповещение о муте 📬",
description="<b>Оповещение о муте 📬</b>" description="<b>Оповещение о муте 📬</b>"
"\nОповещает пользователя в личных сообщениях, что тот был: замучен, размучен, забанен, разбанен", "\nОповещает пользователя в личных сообщениях, что тот был: замучен, размучен, забанен, разбанен",
callback_name="notify", callback_name="notify",
settings_name="restrict_notification"
) )
], ],
"Devs": [ "Devs": [
@ -89,7 +114,8 @@ list_of_features = {
description="<b>Функция `Привет` </b>👋" description="<b>Функция `Привет` </b>👋"
"\nБот будет отвечать на комманды " "\nБот будет отвечать на комманды "
"/hi, /hello, /privet и т.п., отвечая приветсвием на сообщение пользователя.", "/hi, /hello, /privet и т.п., отвечая приветсвием на сообщение пользователя.",
callback_name="hi" callback_name="hi",
settings_name="hi_command"
), ),
BaseFeature( BaseFeature(
name="ИИ ЧатБот 🤖", name="ИИ ЧатБот 🤖",
@ -100,24 +126,20 @@ list_of_features = {
"Для использования:\n" "Для использования:\n"
"<pre>/conversations</pre>" "<pre>/conversations</pre>"
"\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘", "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘",
callback_name="gtm" callback_name="gtm",
settings_name="gpt_conversations"
), ),
BaseFeature( BaseFeature(
name="Генерация изображений 📸", name="Генерация изображений 📸",
description="<b>Генерация изображений </b>🤖" description="<b>Генерация изображений </b>🤖"
"\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘", "\nНаходится в разработке, планируется в будущем. Следите за обновлениями 😘",
callback_name="gpm" callback_name="gpm",
settings_name="123"
) )
] ]
} }
# List of gpt categories, avaible in bozenka now
gpt_categories = [
"Gpt4Free",
"Gpt4All",
]
def generate_list_of_features(category: str) -> list[BaseFeature]: def generate_list_of_features(category: str) -> list[BaseFeature]:
@ -130,45 +152,6 @@ def generate_list_of_features(category: str) -> list[BaseFeature]:
return list_of_features[category] return list_of_features[category]
def generate_gpt4free_providers():
"""
Generates list of g4f providers
:return:
"""
provider = {}
for prov in g4f.Provider.__all__:
if prov != "BaseProvider" and prov != "AsyncProvider" and prov != "RetryProvider":
exec(f"provider['{prov}']=g4f.Provider.{prov}")
result = {}
for check in provider:
if provider[check].working:
result[check] = provider[check]
return result
def generate_gpt4free_models():
"""
Generates list of g4f models
:return:
"""
models = {}
for model, model_name in g4f.models.ModelUtils.convert.items(), g4f.models.ModelUtils.convert.keys():
if type(model.best_provider) is RetryProvider:
for pr in model.best_provider.providers:
if pr in models:
models[nameof(pr)].append(model_name)
else:
models[nameof(pr)] = [model_name]
else:
if nameof(model.best_provider) in models:
models[nameof(model.best_provider)].append(model_name)
else:
models[nameof(model.best_provider)] = [model_name]
return models
en_cmds = {}
ru_cmds = { ru_cmds = {
# /info command translation # /info command translation
"info": "Информация об чате с названием nameofchathere" "info": "Информация об чате с названием nameofchathere"
@ -278,5 +261,4 @@ list_of_commands = {
translations = { translations = {
"ru": ru_cmds, "ru": ru_cmds,
"en": en_cmds
} }

View File

@ -205,6 +205,7 @@ class SolutionSimpler:
msg=f"Muted user @{msg.reply_to_message.from_user.full_name} id={msg.reply_to_message.from_user.id}", msg=f"Muted user @{msg.reply_to_message.from_user.full_name} id={msg.reply_to_message.from_user.id}",
level=logging.INFO) level=logging.INFO)
user = await get_user(user_id=msg.from_user.id, chat_id=msg.chat.id, session=session) user = await get_user(user_id=msg.from_user.id, chat_id=msg.chat.id, session=session)
user
if not user: if not user:
new_user = Users( new_user = Users(
user_id=msg.from_user.id, user_id=msg.from_user.id,
@ -311,8 +312,9 @@ class SolutionSimpler:
:param msg: Message telegram object :param msg: Message telegram object
:param session: Object of telegram command :param session: Object of telegram command
""" """
print("123")
chat_data = await get_settings(msg.chat.id, session) chat_data = await get_settings(msg.chat.id, session)
print(chat_data)
if not chat_data: if not chat_data:
new_chat_data = ChatSettings(chat_id=msg.chat.id) new_chat_data = ChatSettings(chat_id=msg.chat.id)
async with session() as session: async with session() as session: