-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from groundmax/feature/telegram_bot
added bot commands regarding team info
- Loading branch information
Showing
16 changed files
with
731 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,21 @@ | ||
import asyncio | ||
|
||
from requestor.bot import dp, config, register_handlers, bot, BotCommands | ||
from requestor.services import make_db_service | ||
from requestor.log import setup_logging | ||
|
||
async def main(): | ||
db_service = make_db_service(config) | ||
register_handlers(dp, db_service, config) | ||
setup_logging(config) | ||
|
||
await bot.set_my_commands(commands=BotCommands.get_bot_commands()) | ||
await db_service.setup() | ||
try: | ||
await dp.start_polling() | ||
finally: | ||
await db_service.cleanup() | ||
|
||
|
||
if __name__ == "__main__": | ||
pass | ||
asyncio.run(main()) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from .commands import BotCommands | ||
from .create_bot import bot, config, dp | ||
from .handlers import register_handlers | ||
|
||
__all__ = ( | ||
"dp", | ||
"bot", | ||
"config", | ||
"register_handlers", | ||
"BotCommands", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import typing as tp | ||
|
||
from aiogram import types | ||
from aiogram.utils.markdown import bold, escape_md, text | ||
|
||
from requestor.models import Model, TeamInfo | ||
|
||
from .constants import DATETIME_FORMAT | ||
|
||
|
||
# TODO: somehow try generalize this func to reduce duplicate code | ||
def parse_msg_with_team_info( | ||
message: types.Message, | ||
) -> tp.Tuple[tp.Optional[str], tp.Optional[TeamInfo]]: | ||
args = message.get_args().split() | ||
n_args = len(args) | ||
if n_args == 4: | ||
token, title, api_base_url, api_key = args | ||
elif n_args == 3: | ||
token, title, api_base_url = args | ||
api_key = None | ||
|
||
try: | ||
return token, TeamInfo( | ||
title=title, chat_id=message.chat.id, api_base_url=api_base_url, api_key=api_key | ||
) | ||
except NameError: | ||
return None, None | ||
|
||
|
||
def parse_msg_with_model_info( | ||
message: types.Message, | ||
) -> tp.Tuple[tp.Optional[str], tp.Optional[str]]: | ||
args = message.get_args().split(maxsplit=1) | ||
n_args = len(args) | ||
if n_args == 2: | ||
name, description = args | ||
elif n_args == 1: | ||
name = args[0] | ||
description = None | ||
|
||
try: | ||
return name, description | ||
except NameError: | ||
return None, None | ||
|
||
|
||
def generate_model_description(model: Model, model_num: int) -> str: | ||
description = model.description or "Отсутствует" | ||
created_at = model.created_at.strftime(DATETIME_FORMAT) | ||
return text( | ||
bold(model_num), | ||
f"{bold('Название')}: {escape_md(model.name)}", | ||
f"{bold('Описание')}: {escape_md(description)}", | ||
f"{bold('Дата добавления (UTC)')}: {escape_md(created_at)}", | ||
sep="\n", | ||
) | ||
|
||
|
||
def generate_models_description(models: tp.List[Model]) -> str: | ||
model_descriptions = [] | ||
for model_num, model in enumerate(models, 1): | ||
model_description = generate_model_description(model, model_num) | ||
model_descriptions.append(model_description) | ||
|
||
reply = "\n\n".join(model_descriptions) | ||
return reply |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import typing as tp | ||
from dataclasses import dataclass | ||
from enum import Enum | ||
|
||
from aiogram.types import BotCommand | ||
from aiogram.utils.markdown import text | ||
|
||
from .constants import TEAM_MODELS_DISPLAY_LIMIT | ||
|
||
|
||
@dataclass | ||
class CommandDescription: | ||
command_name: str | ||
short_description: str | ||
long_description: tp.Optional[str] = None | ||
|
||
|
||
commands_description = ( | ||
( | ||
"start", | ||
"Начало работы с ботом", | ||
), | ||
( | ||
"help", | ||
"Список доступных команд", | ||
), | ||
( | ||
"register_team", | ||
"Регистрация команды", | ||
text( | ||
"С помощью этой команды можно зарегистрировать свою команду", | ||
"Принимает на вход аргументы через пробел:", | ||
"token - токен, который генерируется индивидуально для каждой команды.", | ||
"title - название команды, без пробелов и кавычек.", | ||
"api_base_url - хост, по которому будет находиться API команды.", | ||
"api_key - опционально, токен для запрашивания API.", | ||
"Пример использования:", | ||
"/register_team MyToken MyTeamName http://myapi.ru/api/v1 MyApiKey", | ||
sep="\n", | ||
), | ||
), | ||
( | ||
"update_team", | ||
"Обновление информации команды", | ||
text( | ||
"С помощью этой команды можно обновить хост или токен API.", | ||
"Для этого используются соответствующие аргументы через пробел.", | ||
"api_base_url - хост, по которому будет находиться API команды.", | ||
"api_key - токен для запрашивания API.", | ||
"Пример использования для обновления хоста:", | ||
"/update_team api_base_url http://myapi.ru/api/v2", | ||
sep="\n", | ||
), | ||
), | ||
( | ||
"show_team", | ||
"Вывод информации по текущей команде", | ||
"Выводит название команды, хост и API токен", | ||
), | ||
( | ||
"add_model", | ||
"Добавление новой модели", | ||
text( | ||
"С помощью этой команды можно добавить модель для проверки.", | ||
"Для этого используются следующие аргументы:", | ||
"name - название модели, без пробелов и кавычек.", | ||
"description - опционально, более подробное описание модели", | ||
"Пример использования для добавления модели:", | ||
"/add_model lightfm_64", | ||
"Далее модели будут запрашиваться по адресу: {api_base_url}/{name}/{user_id}", | ||
( | ||
"То есть адрес для запроса выглядит, например, так: " | ||
"http://myapi.ru/api/v1/lightfm_64/178" | ||
), | ||
"Пример использования для добавления модели с описанием:", | ||
"/add_model lightfm_64 Добавили фичи по юзерам и айтемам", | ||
sep="\n", | ||
), | ||
), | ||
( | ||
"show_models", | ||
"Вывод информации по добавленным моделям", | ||
text( | ||
"С помощью этой команды можно вывести следующую информацию:", | ||
( | ||
"Название, описание (если присутствует) и дату добавления модели по UTC. " | ||
f"Если было добавлено более {TEAM_MODELS_DISPLAY_LIMIT} моделей, " | ||
f"то выведутся последние {TEAM_MODELS_DISPLAY_LIMIT} по дате добавления " | ||
"в обратном хронологическом порядке." | ||
), | ||
sep="\n", | ||
), | ||
), | ||
# TODO: create request command | ||
("request", "Запрос рекомендаций по модели", "Какое-то описание"), | ||
) | ||
|
||
cmd2cls_desc = {args[0]: CommandDescription(*args) for args in commands_description} | ||
|
||
|
||
# it can be initialized via Enum("BotCommands", cmd2cls_desc) | ||
# but IDE doesn't provide you with helper annotations | ||
# and you can not add class methods without "hacks" | ||
# TODO: think of simple way instantiate a frozen class | ||
# with typehinting from IDE | ||
class BotCommands(Enum): | ||
start: CommandDescription = cmd2cls_desc["start"] | ||
help: CommandDescription = cmd2cls_desc["help"] | ||
register_team: CommandDescription = cmd2cls_desc["register_team"] | ||
update_team: CommandDescription = cmd2cls_desc["update_team"] | ||
show_team: CommandDescription = cmd2cls_desc["show_team"] | ||
add_model: CommandDescription = cmd2cls_desc["add_model"] | ||
show_models: CommandDescription = cmd2cls_desc["show_models"] | ||
|
||
@classmethod | ||
def get_bot_commands(cls) -> tp.List[BotCommand]: | ||
return [ | ||
BotCommand(command=command.name, description=command.value.short_description) | ||
for command in BotCommands | ||
] | ||
|
||
@classmethod | ||
def get_description_for_available_commands(cls) -> str: | ||
descriptions = [] | ||
for command in BotCommands: | ||
if command not in (BotCommands.start, BotCommands.help): | ||
descriptions.append(f"/{command.name}\n{command.value.long_description}") | ||
|
||
return "\n\n".join(descriptions) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import typing as tp | ||
|
||
AVAILABLE_FOR_UPDATE: tp.Final = { | ||
"api_base_url", | ||
"api_key", | ||
} | ||
|
||
INCORRECT_DATA_IN_MSG: tp.Final = ( | ||
"Пожалуйста, введите данные в корректном формате. Используйте команду /help для справки." | ||
) | ||
|
||
TEAM_NOT_FOUND_MSG: tp.Final = ( | ||
"Команда от вашего чата не найдена. Скорее всего, вы еще не регистрировались." | ||
) | ||
|
||
TEAM_MODELS_DISPLAY_LIMIT: tp.Final = 10 | ||
|
||
DATETIME_FORMAT: tp.Final = "%Y-%m-%d %H:%M:%S" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from aiogram import Bot | ||
from aiogram.dispatcher import Dispatcher | ||
|
||
from requestor.settings import get_config | ||
|
||
config = get_config() | ||
|
||
bot = Bot(token=config.telegram_config.bot_token) | ||
|
||
dp = Dispatcher(bot) |
Oops, something went wrong.