mirror of
https://github.com/ijaric/voice_assistant.git
synced 2025-05-24 14:33:26 +00:00
feat: [#49] tg_bot
This commit is contained in:
parent
8486d2e0bf
commit
0410c0d341
10
src/bot_aiogram/.env
Normal file
10
src/bot_aiogram/.env
Normal file
|
@ -0,0 +1,10 @@
|
|||
BOT_CONTAINER_NAME=bot_container_name
|
||||
BOT_IMAGE_NAME=botimage_name
|
||||
BOT_NAME=mybotname
|
||||
BOT_TOKEN=1094627178:AAHdYs50tuFiRCts3zYke9GG7feCqtbzHIE
|
||||
BOT_ADMINS=436307416
|
||||
|
||||
|
||||
API_PROTOCOL=http
|
||||
API_URL=127.0.0.1
|
||||
API_PORT=8000
|
9
src/bot_aiogram/.env.example
Normal file
9
src/bot_aiogram/.env.example
Normal file
|
@ -0,0 +1,9 @@
|
|||
BOT_CONTAINER_NAME=bot_container_name
|
||||
BOT_IMAGE_NAME=botimage_name
|
||||
BOT_NAME=mybotname
|
||||
BOT_TOKEN=123456:Your-TokEn_ExaMple
|
||||
BOT_ADMINS=123456,654321
|
||||
|
||||
API_PROTOCOL=http
|
||||
API_URL=127.0.0.1
|
||||
API_PORT=8000
|
63
src/bot_aiogram/.gitignore
vendored
Executable file
63
src/bot_aiogram/.gitignore
vendored
Executable file
|
@ -0,0 +1,63 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Environments
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
.idea/*
|
||||
.env
|
8
src/bot_aiogram/Dockerfile
Executable file
8
src/bot_aiogram/Dockerfile
Executable file
|
@ -0,0 +1,8 @@
|
|||
FROM python:3.9-buster
|
||||
ENV BOT_NAME=$BOT_NAME
|
||||
|
||||
WORKDIR /usr/src/app/"${BOT_NAME:-tg_bot}"
|
||||
|
||||
COPY requirements.txt /usr/src/app/"${BOT_NAME:-tg_bot}"
|
||||
RUN pip install -r /usr/src/app/"${BOT_NAME:-tg_bot}"/requirements.txt
|
||||
COPY . /usr/src/app/"${BOT_NAME:-tg_bot}"
|
212
src/bot_aiogram/README.md
Normal file
212
src/bot_aiogram/README.md
Normal file
|
@ -0,0 +1,212 @@
|
|||
# tgbot_template (aiogram v2.0)
|
||||
|
||||
> ⚠️ **Note**: This template is for aiogram version 2.0. If you're interested in using the latest features and functionalities, consider using the updated [tgbot_template_v3](https://github.com/Latand/tgbot_template_v3) which is compatible with aiogram 3.0.
|
||||
|
||||
<img height="30em" src="https://raw.githubusercontent.com/anki-geo/ultimate-geography/a44a569a922e1d241517113e2917736af808eed7/src/media/flags/ug-flag-united_kingdom.svg" alt="english" align = "center"/>
|
||||
This template is recommended to use in your Telegram bots written on <a href='https://github.com/aiogram/aiogram'>AIOgram</a>.
|
||||
You can see tutorials on how to create, and use it on <a href='https://botfather.dev?utm_source=github_template'>Website with course on Telegram Bots Development</a>.
|
||||
<br/><br/><br/>
|
||||
|
||||
<img height="30em" src="https://raw.githubusercontent.com/anki-geo/ultimate-geography/a44a569a922e1d241517113e2917736af808eed7/src/media/flags/ug-flag-ukraine.svg" alt="ukrainian" align = "center"/>
|
||||
Цей шаблон рекомендовано використовувати для створення ваших Telegram-ботів, написаних на <a href='https://github.com/aiogram/aiogram'>AIOgram</a>.
|
||||
Ви можете переглянути навчальні матеріали щодо створення та використання шаблону на <a href='https://botfather.dev?utm_source=github_template'>веб-сайті з курсом із розробки ботів Telegram</a>
|
||||
<br/><br/><br/>
|
||||
|
||||
<img height="30em" src="https://raw.githubusercontent.com/anki-geo/ultimate-geography/a44a569a922e1d241517113e2917736af808eed7/src/media/flags/ug-flag-russia.svg" alt="russian" align = "center"/>
|
||||
Этот шаблон рекомендуется использовать для создания ваших Telegram-ботов, написанных на <a href='https://github.com/aiogram/aiogram'>AIOgram</a>.
|
||||
Учебные материалы по созданию и использованию шаблона можно найти на <a href='https://botfather.dev?utm_source=github_template'>веб-сайте с курсом по разработке ботов Telegram</a>
|
||||
|
||||
## About the template
|
||||
|
||||
**Structure:**
|
||||
|
||||
```
|
||||
tgbot_template/
|
||||
├── bot.py
|
||||
├── tgbot/
|
||||
│ ├── __init__.py
|
||||
│ ├── config.py
|
||||
│ ├── filters/
|
||||
│ ├── handlers/
|
||||
│ └── middlewares/
|
||||
```
|
||||
|
||||
- The `tgbot` package is the root package for the bot, and it contains sub-packages for **filters**, **handlers**,
|
||||
and **middlewares**.
|
||||
|
||||
- The `filters` package contains classes that define **custom filters** for the bot's message handlers.
|
||||
|
||||
- The `handlers` package contains classes that define the bot's **message handlers**, which specify the actions to take
|
||||
in response to incoming messages.
|
||||
|
||||
- The `middlewares` package contains classes that define **custom middlewares** for the bot's dispatcher, which can be
|
||||
used to perform additional processing on incoming messages.
|
||||
|
||||
## Detailed description
|
||||
|
||||
### `bot.py`
|
||||
|
||||
The bot.py script is the entry point for the template Telegram bot. It performs the following steps to start and run the
|
||||
bot:
|
||||
|
||||
1. Set up logging: The `logging` module is imported and configured to log messages to the console.
|
||||
2. Load the configuration: The `load_config()` function from the `tgbot.config` module is called to read the configuration
|
||||
from the environment.
|
||||
3. Set up the storage: Depending on the `use_redis` flag in the configuration, either a `MemoryStorage` or a `RedisStorage2`
|
||||
instance is created to store the bot's state.
|
||||
4. Create the bot and the dispatcher: A `Bot` instance is created using the bot token from the configuration, and a
|
||||
`Dispatcher` instance is created using the `Bot` instance and the storage.
|
||||
5. Register middlewares, filters, and handlers: The `register_all_middlewares()`, `register_all_filters()`, and
|
||||
`register_all_handlers()` functions are called to register all the middlewares, filters, and handlers that are used by
|
||||
the bot.
|
||||
6. Start the polling loop: The `start_polling()` method of the Dispatcher instance is called to start the main event loop
|
||||
for the bot. This method listens for incoming messages and routes them to the appropriate handler.
|
||||
|
||||
### `tgbot/config.py`
|
||||
|
||||
The `config.py` script defines a data structure for storing configuration options for the bot, such as the Telegram bot
|
||||
token, database credentials, and other parameters.
|
||||
|
||||
The config.py script also includes a `load_config` function for loading the configuration from a file using
|
||||
the `environs` library.
|
||||
|
||||
The config.py file defines a `Config` class, which is used to store configuration settings for the bot.
|
||||
|
||||
The Config class has three nested classes, `TgBot`, `DbConfig`, and `Miscellaneous`, which are used to store
|
||||
configuration settings for the Telegram bot, the database, and miscellaneous settings, respectively.
|
||||
|
||||
The `load_config` function is used to load the configuration settings from an environment file and create a `Config`
|
||||
object.
|
||||
|
||||
### `tgbot/filters/admin.py`
|
||||
|
||||
The `admin.py` file defines an `AdminFilter` class, which is used to filter messages so that only messages from
|
||||
authorized users **(i.e., users who are listed in the ADMINS configuration setting)** are processed by the bot.
|
||||
|
||||
The `AdminFilter` class is a subclass of `BoundFilter` from the **aiogram** library, and it defines a key property that
|
||||
specifies the name of the filter. The `AdminFilter` class also defines an `__init__` method that takes a `is_admin`
|
||||
parameter, which specifies whether the user who sent the message is an authorized user.
|
||||
|
||||
The `AdminFilter` class also defines a `check` method that checks whether the user who sent the message is an admin
|
||||
user, and if so, it returns `True`, indicating that the message should be processed by the bot. Otherwise, it returns
|
||||
`False`, indicating that the message should be ignored by the bot. The `check` method is called by the bot's dispatcher
|
||||
when a message is received.
|
||||
|
||||
### `tgbot/handlers/admin.py`
|
||||
|
||||
The `admin.py` file defines a `register_admin` function, which is used to register event handlers for messages that are
|
||||
sent by authorized users (**i.e., users who are listed in the ADMINS configuration setting**).
|
||||
|
||||
The `register_admin` function takes a `Dispatcher` object as its parameter, and it uses this object to register event
|
||||
handlers that respond to different types of messages.
|
||||
|
||||
For example, it might register an event handler that responds to commands that are sent by authorized users, such as
|
||||
the `/echo` command, which causes the bot to repeat the text of the message back to the user.
|
||||
|
||||
### `tgbot/handlers/echo.py`
|
||||
|
||||
The `echo.py` file defines a `register_echo` function, which is used to register an event handler for the `/echo`
|
||||
command.
|
||||
This event handler is responsible for repeating the text of the message back to the user. The `register_echo` function
|
||||
takes a `Dispatcher` object as its parameter, and it uses this object to register the `/echo` command handler.
|
||||
|
||||
### `tgbot/handlers/user.py`
|
||||
|
||||
The `user.py` file defines a `register_user` function, which is used to register event handlers for messages that are
|
||||
sent
|
||||
by non-authorized users (i.e., users who are not listed in the ADMINS configuration setting).
|
||||
|
||||
The `register_user` function takes a `Dispatcher` object as its parameter, and it uses this object to register event
|
||||
handlers that respond to different types of messages. For example, it might register an event handler that responds to
|
||||
commands that are sent by non-authorized users, such as the `/help` command, which causes the bot to send a message with
|
||||
a list of available commands.
|
||||
|
||||
### `tgbot/middlewares/environment.py`
|
||||
|
||||
`environment.py` is a file that contains the `EnvironmentMiddleware` class, which is a middleware used in the Telegram
|
||||
bot.
|
||||
|
||||
A middleware is a piece of code that sits between the incoming request and the handler function. In this case, the
|
||||
`EnvironmentMiddleware` class allows the bot to access the configuration data that was loaded by the `load_config`
|
||||
function
|
||||
in the `config.py` file. This configuration data can then be accessed by other parts of the bot, such as the handlers,
|
||||
to
|
||||
customize its behavior.
|
||||
|
||||
### `tgbot/keyboards/(inline|reply).py`
|
||||
|
||||
The `inline.py` and `reply.py` files define classes that are used to create inline and reply keyboards, respectively.
|
||||
|
||||
The `InlineKeyboard` class is a subclass of `InlineKeyboardMarkup` from the **aiogram** library, and it defines a
|
||||
`__init__` method that takes a `inline_keyboard` parameter, which specifies the buttons that should be included in the
|
||||
keyboard.
|
||||
|
||||
The `ReplyKeyboard` class is a subclass of `ReplyKeyboardMarkup` from the **aiogram** library, and it defines a
|
||||
`__init__` method that takes a `keyboard` parameter, which specifies the buttons that should be included in the
|
||||
keyboard.
|
||||
|
||||
### `tgbot/misc`
|
||||
|
||||
In general, a package called "misc" might be used to store miscellaneous code that doesn't fit into any of the other
|
||||
packages or modules in a project. This could include utility functions, helper classes, or other types of code that are
|
||||
used by multiple parts of the project.
|
||||
|
||||
In this case, the `misc` package contains a `states.py` file, which defines a `StateGroup` class that is used to define
|
||||
the states that are used by the bot.
|
||||
|
||||
### `tgbot/models`
|
||||
|
||||
The `models` package can contain `users.py` file, which defines a `User` class that is used to represent a user in the
|
||||
database. This can be used with combination of some ORM (Object Relational Mapper) to store and retrieve data from the
|
||||
database.
|
||||
|
||||
### `tgbot/services`
|
||||
|
||||
This package can also be named `infrastructure`. It contains the code that is used to interact with external services.
|
||||
|
||||
A package called "services" could contain code that defines services that are used by an application. In software
|
||||
development, a service is a self-contained piece of functionality that performs a specific task or provides a specific
|
||||
capability. A service is typically defined as a class or a set of functions that implement the desired functionality.
|
||||
|
||||
Examples of services that might be included in a services package could include a **database access service, a caching
|
||||
service, a messaging service**, or any other type of functionality that is used by the application. The exact contents
|
||||
of
|
||||
a services package would depend on the specific needs of the application and the services that it requires.
|
||||
|
||||
The `services` package can contain a `database.py` file, which defines a `Database` class that is used to connect to the
|
||||
database and perform database operations.
|
||||
|
||||
## docker-compose.yml
|
||||
|
||||
The `docker-compose.yml` file defines the services that are used by the application, as well as the networks and volumes
|
||||
that are needed by the application. The file begins by specifying the version of the Docker Compose file format that is
|
||||
being used.
|
||||
|
||||
The `services` section of the file defines the containers that should be run as part of the application. In this example,
|
||||
there is only one service, called `bot`, which is based on the `tg_bot-image` Docker image. The `container_name` specifies the
|
||||
name that should be used for the container, and the `build` section specifies the location of the Dockerfile that should
|
||||
be used to build the image.
|
||||
|
||||
The `working_dir` specifies the working directory that should be used by the container, and the `volumes` section specifies
|
||||
the files and directories that should be mounted into the container. In this case, the entire project directory is
|
||||
mounted into the container, which allows the application to access the files on the host machine.
|
||||
|
||||
The `command` specifies the command that should be run when the container is started, and the `restart` setting specifies
|
||||
that the container should be automatically restarted if it exits.
|
||||
|
||||
The `env_file` setting specifies the location of the `.env` file, which contains the configuration settings for the application.
|
||||
|
||||
The `networks` section defines the networks that the container should be connected to. In this example, there is only one
|
||||
network, called `tg_bot`, which is based on the bridge driver. This network allows the containers in the application to
|
||||
communicate with each other.
|
||||
|
||||
## Dockerfile
|
||||
|
||||
The `Dockerfile` defines the instructions for building the Docker image that is used by the bot service. The file begins
|
||||
by specifying the base image that should be used for the image, which in this case is `python:3.9-buster`. The `ENV`
|
||||
instruction sets the value of the `BOT_NAME` environment variable, which is used by the `WORKDIR` instruction to specify the
|
||||
working directory for the container.
|
||||
|
||||
The `COPY` instructions are used to copy the `requirements.txt` file and the entire project directory into the image. The
|
||||
`RUN` instruction is used to install the Python dependencies from the `requirements.txt` file. This allows the application
|
||||
to run in the container with all the necessary dependencies.
|
55
src/bot_aiogram/bot.py
Normal file
55
src/bot_aiogram/bot.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
import aiogram
|
||||
import aiogram.contrib.fsm_storage.memory as fsm_storage_memory
|
||||
|
||||
import tgbot.handlers as tgbot_handlers
|
||||
import tgbot.middlewares as tgbot_middlewares
|
||||
import tgbot.settings as tgbot_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def register_all_middlewares(dp: aiogram.Dispatcher):
|
||||
dp.setup_middleware(tgbot_middlewares.environment.EnvironmentMiddleware())
|
||||
|
||||
|
||||
def register_all_handlers(dp: aiogram.Dispatcher):
|
||||
tgbot_handlers.register_user(dp)
|
||||
tgbot_handlers.register_echo(dp)
|
||||
tgbot_handlers.register_voice_response(dp)
|
||||
|
||||
|
||||
async def main():
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(filename)s:%(lineno)d #%(levelname)-8s [%(asctime)s] - %(name)s - %(message)s",
|
||||
)
|
||||
logger.info("Starting bot")
|
||||
config = tgbot_settings.Settings()
|
||||
|
||||
storage = fsm_storage_memory.MemoryStorage()
|
||||
bot = aiogram.Bot(token=config.tgbot.token.get_secret_value(), parse_mode="HTML")
|
||||
dp = aiogram.Dispatcher(bot, storage=storage)
|
||||
|
||||
bot["config"] = config
|
||||
|
||||
register_all_middlewares(dp)
|
||||
register_all_handlers(dp)
|
||||
|
||||
# start
|
||||
try:
|
||||
await dp.start_polling()
|
||||
finally:
|
||||
await dp.storage.close()
|
||||
await dp.storage.wait_closed()
|
||||
if bot.session:
|
||||
await bot.session.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
logger.error("Bot stopped!")
|
22
src/bot_aiogram/docker-compose.yml
Executable file
22
src/bot_aiogram/docker-compose.yml
Executable file
|
@ -0,0 +1,22 @@
|
|||
version: "3.3"
|
||||
|
||||
services:
|
||||
bot:
|
||||
image: "${BOT_IMAGE_NAME:-tg_bot-image}"
|
||||
container_name: "${BOT_CONTAINER_NAME:-tg_bot-container}"
|
||||
stop_signal: SIGINT
|
||||
build:
|
||||
context: .
|
||||
working_dir: "/usr/src/app/${BOT_NAME:-tg_bot}"
|
||||
volumes:
|
||||
- .:/usr/src/app/${BOT_NAME:-tg_bot}
|
||||
command: python3 -m bot
|
||||
restart: always
|
||||
env_file:
|
||||
- ".env"
|
||||
networks:
|
||||
- tg_bot
|
||||
|
||||
networks:
|
||||
tg_bot:
|
||||
driver: bridge
|
1349
src/bot_aiogram/poetry.lock
generated
Normal file
1349
src/bot_aiogram/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
src/bot_aiogram/requirements.txt
Normal file
3
src/bot_aiogram/requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
aiogram~=2.18
|
||||
aioredis<2.0
|
||||
environs~=9.0
|
5
src/bot_aiogram/tgbot/__init__.py
Normal file
5
src/bot_aiogram/tgbot/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from .settings import Settings
|
||||
|
||||
__all__ = [
|
||||
"Settings",
|
||||
]
|
0
src/bot_aiogram/tgbot/filters/__init__.py
Normal file
0
src/bot_aiogram/tgbot/filters/__init__.py
Normal file
9
src/bot_aiogram/tgbot/handlers/__init__.py
Normal file
9
src/bot_aiogram/tgbot/handlers/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from .echo import *
|
||||
from .user import *
|
||||
from .voice import *
|
||||
|
||||
__all__ = [
|
||||
"register_echo",
|
||||
"register_user",
|
||||
"register_voice_response",
|
||||
]
|
11
src/bot_aiogram/tgbot/handlers/echo.py
Normal file
11
src/bot_aiogram/tgbot/handlers/echo.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
import aiogram
|
||||
|
||||
|
||||
async def bot_echo(message: aiogram.types.Message):
|
||||
text = ["Эхо без состояния.", "Сообщение:", message.text]
|
||||
|
||||
await message.answer("\n".join(text))
|
||||
|
||||
|
||||
def register_echo(dp: aiogram.Dispatcher):
|
||||
dp.register_message_handler(bot_echo)
|
9
src/bot_aiogram/tgbot/handlers/user.py
Normal file
9
src/bot_aiogram/tgbot/handlers/user.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
import aiogram
|
||||
|
||||
|
||||
async def user_start(message: aiogram.types.Message):
|
||||
await message.reply("Hello, user! Send me a voice message and I'll try to recognize it and answer you.")
|
||||
|
||||
|
||||
def register_user(dp: aiogram.Dispatcher):
|
||||
dp.register_message_handler(user_start, commands=["start"], state="*")
|
0
src/bot_aiogram/tgbot/keyboards/__init__.py
Normal file
0
src/bot_aiogram/tgbot/keyboards/__init__.py
Normal file
0
src/bot_aiogram/tgbot/keyboards/inline.py
Normal file
0
src/bot_aiogram/tgbot/keyboards/inline.py
Normal file
0
src/bot_aiogram/tgbot/keyboards/reply.py
Normal file
0
src/bot_aiogram/tgbot/keyboards/reply.py
Normal file
5
src/bot_aiogram/tgbot/middlewares/__init__.py
Normal file
5
src/bot_aiogram/tgbot/middlewares/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from .environment import *
|
||||
|
||||
__all__ = [
|
||||
"EnvironmentMiddleware",
|
||||
]
|
14
src/bot_aiogram/tgbot/middlewares/environment.py
Normal file
14
src/bot_aiogram/tgbot/middlewares/environment.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
import typing
|
||||
|
||||
import aiogram.dispatcher.middlewares as dispatcher_middlewares
|
||||
|
||||
|
||||
class EnvironmentMiddleware(dispatcher_middlewares.LifetimeControllerMiddleware):
|
||||
skip_patterns = ["error", "update"]
|
||||
|
||||
def __init__(self, **kwargs: typing.Any):
|
||||
super().__init__()
|
||||
self.kwargs = kwargs
|
||||
|
||||
async def pre_process(self, obj: typing.Any, data: dict[typing.Any, typing.Any], *args: typing.Any):
|
||||
data.update(**self.kwargs)
|
0
src/bot_aiogram/tgbot/misc/__init__.py
Normal file
0
src/bot_aiogram/tgbot/misc/__init__.py
Normal file
0
src/bot_aiogram/tgbot/misc/states.py
Normal file
0
src/bot_aiogram/tgbot/misc/states.py
Normal file
0
src/bot_aiogram/tgbot/models/__init__.py
Normal file
0
src/bot_aiogram/tgbot/models/__init__.py
Normal file
0
src/bot_aiogram/tgbot/services/__init__.py
Normal file
0
src/bot_aiogram/tgbot/services/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user