496 lines
29 KiB
Markdown
496 lines
29 KiB
Markdown
# Документация по проектной практике
|
||
|
||
## Реализация телеграм-бота "МосПолиХелпер"
|
||
|
||
В данном документе представлена подробная документация по разработке и реализации телеграм-бота "МосПолиХелпер" в рамках вариативной части проектной практики. Документ содержит детальное описание технических аспектов разработки, архитектурных решений, использованных технологий и методологий.
|
||
|
||
## Исследование предметной области
|
||
|
||
### Анализ проблемы навигации в кампусе
|
||
|
||
Перед началом разработки был проведен анализ существующей проблемы ориентирования в кампусах Московского Политехнического Университета. Основные выявленные сложности:
|
||
|
||
1. **Разнородность кампусов**:
|
||
- Пять различных кампусов с уникальной планировкой
|
||
- Отсутствие унифицированной системы навигации между корпусами
|
||
|
||
2. **Сложность обозначения кабинетов**:
|
||
- Разные форматы нумерации в зависимости от корпуса
|
||
- Неинтуитивные префиксы в обозначениях (например, "ав" для Автозаводской)
|
||
|
||
3. **Потребности пользователей**:
|
||
- Новые студенты и сотрудники часто теряются в кампусе
|
||
- Гости университета испытывают сложности при поиске аудиторий
|
||
- Необходимость быстрого ориентирования при плотном расписании
|
||
|
||
### Обзор существующих решений
|
||
|
||
В рамках исследования были рассмотрены различные подходы к решению проблемы навигации:
|
||
|
||
1. **Статические карты и указатели**:
|
||
- Недостаточно интерактивны
|
||
- Не обеспечивают персонализированные маршруты
|
||
|
||
2. **Мобильные приложения с GPS-навигацией**:
|
||
- Требуют специальной инфраструктуры для точного позиционирования внутри зданий
|
||
- Высокая стоимость разработки и поддержки
|
||
|
||
3. **Текстовые инструкции**:
|
||
- Сложны для восприятия без визуального сопровождения
|
||
- Трудности с описанием сложных маршрутов
|
||
|
||
После анализа было принято решение разработать решение на базе Telegram, объединяющее доступность мессенджера и наглядность видеоинструкций.
|
||
|
||
## Архитектурное проектирование
|
||
|
||
### Определение требований
|
||
|
||
На основе проведенного анализа были сформулированы следующие функциональные и нефункциональные требования:
|
||
|
||
**Функциональные требования**:
|
||
1. Предоставление интерфейса для выбора корпуса университета
|
||
2. Возможность указать конкретный кабинет в соответствии с принятыми обозначениями
|
||
3. Формирование видеомаршрута от территории кампуса или от входа в корпус
|
||
4. Создание комбинированных маршрутов из отдельных видеофрагментов
|
||
5. Кеширование сгенерированных маршрутов для оптимизации
|
||
|
||
**Нефункциональные требования**:
|
||
1. Время отклика не более 5 секунд на запрос маршрута (при наличии в кеше)
|
||
2. Максимальное время генерации нового маршрута не более 30 секунд
|
||
3. Поддержка обработки до 100 одновременных пользователей
|
||
4. Оптимизация видеоинструкций для минимизации объема данных
|
||
5. Модульная архитектура для упрощения дальнейшего расширения
|
||
|
||
### Выбор технологического стека
|
||
|
||
Для реализации проекта были выбраны следующие технологии и инструменты:
|
||
|
||
1. **Python 3.10+**:
|
||
- Высокоуровневый язык программирования с богатой экосистемой библиотек
|
||
- Простота интеграции с различными API и сервисами
|
||
- Наличие специализированных библиотек для обработки мультимедиа
|
||
|
||
2. **Aiogram 3.x**:
|
||
- Асинхронный фреймворк для работы с Telegram Bot API
|
||
- Поддержка современных паттернов разработки (FSM, роутеры)
|
||
- Встроенная поддержка обработки интерактивных элементов интерфейса
|
||
|
||
3. **MoviePy**:
|
||
- Библиотека для обработки видео на Python
|
||
- Возможности для конкатенации, ускорения и модификации видеопотоков
|
||
- Простой и понятный API для манипуляции видеофайлами
|
||
|
||
4. **JSON для хранения данных**:
|
||
- Легковесный формат для хранения структурированной информации
|
||
- Нативная поддержка в Python без дополнительных зависимостей
|
||
- Достаточная производительность для данных объемов данных
|
||
|
||
### Проектирование модульной структуры
|
||
|
||
Для обеспечения масштабируемости и поддержки кода в будущем, была разработана модульная архитектура с четким разделением ответственности:
|
||
|
||
```
|
||
src/code/
|
||
├── bot.py # Точка входа в приложение
|
||
├── config.py # Конфигурационные параметры
|
||
├── database.py # Модуль работы с данными пользователя
|
||
├── handlers.py # Обработчики команд и сообщений
|
||
├── init.py # Инициализация компонентов бота
|
||
└── scripts.py # Модуль обработки видео
|
||
```
|
||
|
||
**Взаимодействие модулей**:
|
||
|
||
1. `bot.py` инициализирует приложение и подключает роутеры из `handlers.py`
|
||
2. `init.py` настраивает экземпляр бота, используя конфигурацию из `config.py`
|
||
3. `handlers.py` содержит логику обработки сообщений и вызывает функции из `scripts.py`
|
||
4. `scripts.py` отвечает за обработку видео и использует путь из `database.py`
|
||
5. `database.py` обеспечивает хранение и получение данных о пользовательских сессиях
|
||
|
||
## Реализация программных компонентов
|
||
|
||
### Модуль инициализации (init.py)
|
||
|
||
Модуль отвечает за настройку экземпляра бота, инициализацию диспетчера сообщений и подготовку команд меню:
|
||
|
||
```python
|
||
from aiogram import Bot, Dispatcher
|
||
from aiogram.enums.parse_mode import ParseMode
|
||
from aiogram.fsm.storage.memory import MemoryStorage
|
||
from aiogram.client.bot import DefaultBotProperties
|
||
from aiogram.types import BotCommand, BotCommandScopeDefault
|
||
from aiogram.methods import SetMyCommands
|
||
|
||
import config
|
||
|
||
# Структурированное определение команд для меню
|
||
async def setup_bot_commands():
|
||
commands = [
|
||
BotCommand(command="help", description="Получить помощь"),
|
||
BotCommand(command="route", description="Построить маршрут")
|
||
]
|
||
|
||
await bot(SetMyCommands(
|
||
commands=commands,
|
||
scope=BotCommandScopeDefault()
|
||
))
|
||
|
||
bot = Bot(token=config.BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
||
dp = Dispatcher(storage=MemoryStorage())
|
||
```
|
||
|
||
Использование `MemoryStorage` обеспечивает хранение состояний пользовательских сессий в оперативной памяти, что оптимально для данной задачи, учитывая относительно небольшое количество состояний.
|
||
|
||
### Модуль обработки маршрутов (scripts.py)
|
||
|
||
Ключевой модуль, отвечающий за формирование и обработку видеомаршрутов:
|
||
|
||
```python
|
||
def get_routes(id_building: str, id_cab: str, other=False):
|
||
"""
|
||
Формирует список путей к видеофрагментам для маршрута.
|
||
|
||
Args:
|
||
id_building: Идентификатор корпуса
|
||
id_cab: Идентификатор кабинета
|
||
other: Флаг для специальных случаев
|
||
|
||
Returns:
|
||
list: Список путей к видеофрагментам
|
||
"""
|
||
# Логика определения путей к видеофрагментам
|
||
# в зависимости от выбранного корпуса и кабинета
|
||
|
||
def make_full_clip(paths):
|
||
"""
|
||
Создает полный видеоклип из фрагментов маршрута.
|
||
|
||
Args:
|
||
paths: Список путей к видеофрагментам
|
||
|
||
Returns:
|
||
str: Путь к готовому видеоклипу или None в случае ошибки
|
||
"""
|
||
# Проверка наличия файлов
|
||
if not all(os.path.exists(path) for path in paths):
|
||
print("Некоторые файлы не найдены")
|
||
return None
|
||
|
||
# Создание клипов из файлов
|
||
clips = [VideoFileClip(path) for path in paths]
|
||
|
||
# Объединение клипов
|
||
full_clip = concatenate_videoclips(clips)
|
||
|
||
# Оптимизация видео
|
||
full_clip = full_clip.without_audio() # Удаление звука
|
||
full_clip = full_clip.time_transform(lambda t: t * 1.5).with_duration(full_clip.duration / 1.5) # Ускорение в 1.5 раза
|
||
full_clip = full_clip.resized(height=512) # Оптимизация размера
|
||
|
||
# Генерация имени выходного файла
|
||
full_clip_name = f"{paths[-1][21:].replace('.mp4', '')}-{'all' if len(paths) == 3 else 'small'}.mp4"
|
||
|
||
# Рендеринг видео с оптимизированными параметрами
|
||
full_clip.write_videofile(
|
||
f"../data/cache/{full_clip_name}",
|
||
fps=30,
|
||
codec="libx264",
|
||
bitrate="1500k",
|
||
preset="fast",
|
||
ffmpeg_params=["-crf", "23"]
|
||
)
|
||
|
||
return f"../data/cache/{full_clip_name}"
|
||
```
|
||
|
||
Функция `make_full_clip` выполняет следующие оптимизации:
|
||
- Удаление аудиодорожки для уменьшения размера файла
|
||
- Ускорение видео в 1.5 раза для сокращения продолжительности
|
||
- Уменьшение разрешения для оптимизации передачи через Telegram
|
||
- Применение эффективных параметров кодирования H.264
|
||
|
||
### Модуль обработчиков команд (handlers.py)
|
||
|
||
Модуль содержит обработчики команд и событий пользовательского интерфейса:
|
||
|
||
```python
|
||
@router.message(CommandStart())
|
||
async def start_handler(msg: Message) -> None:
|
||
"""Обработчик команды /start"""
|
||
await msg.answer("Здравствуйте! Этот бот поможет вам добраться до кабинета в структуре корпусов Московского "
|
||
"Политехнического Университета. Для начала работы просто пропишите команду <b>/route</b>")
|
||
|
||
@router.message(Command("route"))
|
||
async def route_handler(msg: Message) -> None:
|
||
"""Обработчик команды /route"""
|
||
buttons = [[InlineKeyboardButton(text=f"На Большой Семёновской", callback_data="edu:bs")],
|
||
[InlineKeyboardButton(text=f"На Павла Корчагина", callback_data="edu:pk")],
|
||
[InlineKeyboardButton(text=f"На Прянишкова", callback_data="edu:pr"),
|
||
InlineKeyboardButton(text=f"На Михалковской", callback_data="edu:mi")],
|
||
[InlineKeyboardButton(text=f"На Автозаводской", callback_data="edu:av")]]
|
||
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
|
||
|
||
await msg.answer(text="Выберите корпус на котором вы хотите проложить маршрут:", reply_markup=keyboard)
|
||
|
||
@router.callback_query(F.data.startswith("route:"))
|
||
async def var_button(call: CallbackQuery) -> None:
|
||
"""Обработчик выбора типа маршрута"""
|
||
action = call.data.split(":")[1]
|
||
|
||
# Получение данных о сессии пользователя
|
||
jsn = JsonTools(call.from_user.id)
|
||
user_dict = jsn.read_json()
|
||
edu_keys = list(user_dict.keys())
|
||
lst_routes = user_dict[edu_keys[0]]
|
||
|
||
# Уведомление о начале обработки
|
||
msg = await call.message.answer("1. Получение видео...")
|
||
path = ""
|
||
|
||
# Логика выбора или генерации маршрута
|
||
if action == "build": # От входа на территорию
|
||
# Проверка наличия в кеше
|
||
if os.path.exists(f"../data/cache/{lst_routes[-1][21:].replace('.mp4', '-all.mp4')}"):
|
||
path = f"../data/cache/{lst_routes[-1][21:].replace('.mp4', '-all.mp4')}"
|
||
else:
|
||
# Генерация нового маршрута
|
||
path = make_full_clip(lst_routes)
|
||
if not path:
|
||
await msg.edit_text("Данного маршрута в нашей базе пока нет, извините за неудобство...")
|
||
return 0
|
||
elif action == "floor": # От входа в корпус
|
||
# Аналогичная логика для маршрута от входа в корпус
|
||
# ...
|
||
|
||
# Отправка результата
|
||
msg_finally = await msg.edit_text("2. Видео готово!")
|
||
await msg.answer_video_note(video_note=FSInputFile(path))
|
||
await msg_finally.delete()
|
||
```
|
||
|
||
Применен декларативный подход с использованием роутеров и фильтров, что делает код модульным и легко расширяемым.
|
||
|
||
### Модуль работы с данными (database.py)
|
||
|
||
Модуль реализует хранение и получение данных о пользовательских сессиях:
|
||
|
||
```python
|
||
class JsonTools:
|
||
"""
|
||
Класс для работы с JSON-данными пользователей.
|
||
|
||
Attributes:
|
||
f_name (str): Путь к файлу пользовательской сессии
|
||
"""
|
||
|
||
def __init__(self, user_id):
|
||
"""
|
||
Инициализация инструмента работы с данными.
|
||
|
||
Args:
|
||
user_id: Идентификатор пользователя Telegram
|
||
"""
|
||
self.f_name = f"../data/users/{user_id}.json"
|
||
|
||
def save_json(self, data):
|
||
"""
|
||
Сохранение данных в JSON-файл.
|
||
|
||
Args:
|
||
data: Данные для сохранения
|
||
|
||
Returns:
|
||
dict: Результат операции сохранения
|
||
"""
|
||
with open(self.f_name, "w", encoding="utf8") as f:
|
||
return json.dump(data, f)
|
||
|
||
def read_json(self):
|
||
"""
|
||
Чтение данных из JSON-файла.
|
||
|
||
Returns:
|
||
dict: Прочитанные данные
|
||
"""
|
||
with open(self.f_name, "r", encoding="utf8") as f:
|
||
return json.load(f)
|
||
|
||
def get_buildings(self):
|
||
"""
|
||
Получение списка корпусов из данных пользователя.
|
||
|
||
Returns:
|
||
list: Список идентификаторов корпусов
|
||
"""
|
||
return self.read_json().keys()
|
||
```
|
||
|
||
Использование файлового хранилища обеспечивает сохранность данных между перезапусками бота и обладает достаточной производительностью для данной задачи.
|
||
|
||
### Основной модуль приложения (bot.py)
|
||
|
||
Модуль является точкой входа в приложение и отвечает за запуск и общую координацию работы бота:
|
||
|
||
```python
|
||
import asyncio, logging
|
||
|
||
from init import *
|
||
from handlers import router
|
||
|
||
async def main() -> None:
|
||
"""
|
||
Основная функция запуска бота.
|
||
Настраивает роутеры, веб-хук и команды.
|
||
"""
|
||
dp.include_router(router)
|
||
await bot.delete_webhook(drop_pending_updates=True)
|
||
|
||
await setup_bot_commands()
|
||
await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())
|
||
|
||
if __name__ == "__main__":
|
||
logging.basicConfig(level=logging.INFO)
|
||
|
||
try:
|
||
asyncio.run(main())
|
||
except KeyboardInterrupt:
|
||
pass
|
||
```
|
||
|
||
Использование асинхронного подхода позволяет эффективно обрабатывать множество одновременных запросов и обеспечивает высокую производительность бота.
|
||
|
||
## Тестирование и валидация
|
||
|
||
### Разработка тестовых сценариев
|
||
|
||
Для проверки работоспособности бота были разработаны следующие тестовые сценарии:
|
||
|
||
1. **Базовая функциональность**:
|
||
- Тестирование команды `/start` и получение приветственного сообщения
|
||
- Проверка команды `/help` и полноты предоставляемой информации
|
||
- Тестирование команды `/route` и корректности отображения интерфейса выбора корпуса
|
||
|
||
2. **Выбор корпуса и кабинета**:
|
||
- Проверка обработки выбора каждого из корпусов через интерактивные кнопки
|
||
- Тестирование ввода корректных номеров кабинетов для каждого корпуса
|
||
- Проверка реакции на некорректный формат номера кабинета
|
||
|
||
3. **Формирование видеомаршрутов**:
|
||
- Тестирование генерации маршрутов "от входа на территорию"
|
||
- Проверка формирования маршрутов "от входа в корпус"
|
||
- Тестирование системы кеширования и повторного использования маршрутов
|
||
|
||
4. **Обработка ошибок**:
|
||
- Проверка поведения при отсутствии необходимых видеофрагментов
|
||
- Тестирование обработки сетевых ошибок и сбоев при рендеринге видео
|
||
- Проверка корректного информирования пользователя о проблемах
|
||
|
||
### Результаты тестирования
|
||
|
||
В ходе тестирования были выявлены и устранены следующие проблемы:
|
||
|
||
1. **Производительность**:
|
||
- Оптимизированы параметры рендеринга видео для ускорения процесса
|
||
- Реализовано кеширование для минимизации повторной обработки маршрутов
|
||
- Улучшена асинхронная обработка запросов для повышения отзывчивости
|
||
|
||
2. **Обработка ошибок**:
|
||
- Добавлена проверка наличия файлов перед объединением видеофрагментов
|
||
- Реализованы информативные сообщения при невозможности построения маршрута
|
||
- Добавлена корректная обработка прерываний и исключений
|
||
|
||
3. **Улучшение пользовательского опыта**:
|
||
- Добавлено отображение прогресса обработки видео
|
||
- Оптимизированы размер и продолжительность видеомаршрутов
|
||
- Улучшены подсказки и инструкции для пользователей
|
||
|
||
## Развертывание и сопровождение
|
||
|
||
### Подготовка среды выполнения
|
||
|
||
Для эффективной работы бота требуется следующая инфраструктура:
|
||
|
||
1. **Серверные требования**:
|
||
- Операционная система: Linux (Ubuntu 20.04 или новее)
|
||
- Python 3.10 или выше
|
||
- Не менее 2 ГБ оперативной памяти
|
||
- Не менее 10 ГБ дискового пространства для хранения видеофрагментов и кеша
|
||
|
||
2. **Необходимые зависимости**:
|
||
- aiogram==3.0.0
|
||
- moviepy==1.0.3
|
||
- ffmpeg (системный пакет)
|
||
|
||
3. **Структура каталогов**:
|
||
```
|
||
/
|
||
├── src/
|
||
│ └── code/ # Исходный код бота
|
||
├── data/
|
||
│ ├── cache/ # Сгенерированные видеомаршруты
|
||
│ ├── users/ # Пользовательские данные
|
||
│ └── videos/ # Исходные видеофрагменты маршрутов
|
||
└── logs/ # Журналы работы бота
|
||
```
|
||
|
||
### Мониторинг и обслуживание
|
||
|
||
Для обеспечения стабильной работы бота рекомендуется:
|
||
|
||
1. **Регулярное обслуживание**:
|
||
- Мониторинг использования дискового пространства
|
||
- Периодическая очистка устаревших кешированных маршрутов
|
||
- Обновление исходных видеофрагментов при изменениях в кампусе
|
||
|
||
2. **Резервное копирование**:
|
||
- Создание резервных копий видеофрагментов маршрутов
|
||
- Периодическое копирование пользовательских данных
|
||
- Хранение копий конфигурационных файлов
|
||
|
||
3. **Обновление и расширение**:
|
||
- Добавление новых маршрутов по запросам пользователей
|
||
- Актуализация существующих маршрутов при изменениях в кампусе
|
||
- Расширение функциональности по результатам обратной связи
|
||
|
||
## Выводы и перспективы развития
|
||
|
||
### Результаты проекта
|
||
|
||
В результате выполнения вариативной части проектной практики:
|
||
|
||
1. Разработан и внедрен телеграм-бот "МосПолиХелпер", предоставляющий интерактивные видеомаршруты по кампусам Московского Политехнического Университета.
|
||
|
||
2. Реализована модульная архитектура с четким разделением ответственности, обеспечивающая масштабируемость и поддерживаемость кода.
|
||
|
||
3. Создана эффективная система обработки видеофрагментов с оптимизацией для использования в мессенджере Telegram.
|
||
|
||
4. Реализовано кеширование маршрутов для повышения производительности и оптимизации пользовательского опыта.
|
||
|
||
5. Проведено комплексное тестирование и оптимизация производительности бота.
|
||
|
||
### Перспективы развития
|
||
|
||
Проект имеет следующие перспективы дальнейшего развития:
|
||
|
||
1. **Расширение функциональности**:
|
||
- Добавление текстовых инструкций к видеомаршрутам
|
||
- Интеграция с расписанием занятий для автоматического определения нужного кабинета
|
||
- Добавление статических карт и схем кампуса
|
||
|
||
2. **Технологические улучшения**:
|
||
- Переход на базу данных (SQLite или PostgreSQL) для более эффективного хранения данных
|
||
- Внедрение системы аналитики для отслеживания популярных маршрутов
|
||
- Оптимизация алгоритмов обработки видео для дальнейшего повышения производительности
|
||
|
||
3. **Расширение охвата**:
|
||
- Добавление маршрутов между корпусами университета
|
||
- Включение маршрутов до близлежащих объектов инфраструктуры (общежития, столовые и т.д.)
|
||
- Интеграция с общественным транспортом для полной навигации до университета
|
||
|
||
## Заключение
|
||
|
||
Телеграм-бот "МосПолиХелпер" является практическим решением реальной проблемы ориентирования в кампусах Московского Политехнического Университета. Проект демонстрирует применение современных технологий разработки и обработки мультимедиа для создания полезного интерактивного инструмента.
|
||
|
||
Модульная архитектура и тщательное проектирование обеспечивают надежность работы бота и возможности для дальнейшего расширения функциональности. Оптимизация обработки видео и система кеширования позволяют обеспечить высокую производительность и хороший пользовательский опыт.
|
||
|
||
В ходе выполнения проекта были успешно применены знания и навыки, полученные в рамках основного обучения, а также приобретен ценный практический опыт в разработке асинхронных приложений, обработке мультимедиа и создании удобных пользовательских интерфейсов.
|