Good Student - это FastAPI-сервис для запуска ботов-слушателей, которые автоматически заходят на онлайн-лекцию в BigBlueButton, пишут приветствие, следят за чатом и выходят из встречи, когда лекция закончилась.
Проект полезен как backend-обёртка над браузерной автоматизацией: ботами можно управлять через HTTP API, а сама работа внутри лекции выполняется через Playwright.
- создаёт бота по HTTP-запросу;
- открывает браузер Chromium через Playwright;
- заходит по ссылке на лекцию под указанным именем;
- подключается в режиме
Listen only; - отправляет приветственное сообщение в чат;
- периодически читает чат и ищет фразы, указывающие на окончание лекции;
- может завершать работу также по времени
lecture_end; - отправляет прощальное сообщение и выходит из конференции;
- позволяет получить список активных/завершённых ботов и остановить бота вручную.
- Python
3.13+- основной язык проекта - FastAPI - HTTP API и lifecycle приложения
- Uvicorn - ASGI-сервер
- Pydantic / pydantic-settings - схемы запросов и конфигурация через переменные окружения
- Playwright - управление браузером Chromium
- Ruff - линтер и форматирование
- Pytest / pytest-playwright - подготовка окружения для тестирования
Основной сценарий такой:
- Клиент отправляет
POST /botsс параметрами лекции и сообщениями бота. BotManagerсоздаёт экземплярLectureBotи отдельнуюasyncio-задачу.- Для бота поднимается Playwright-клиент
BBBPlaywrightClient. - Бот при необходимости ждёт
lecture_start. - Бот открывает страницу лекции, вводит имя, нажимает
Join, затемListen only. - После входа бот отправляет приветствие.
- Дальше он циклически читает чат и проверяет:
- встретились ли ключевые фразы окончания лекции;
- наступило ли время
lecture_end.
- Когда условие завершения выполнено, бот отправляет прощание и выходит из встречи.
- При остановке сервиса или удалении бота задача отменяется, браузер закрывается.
Проект разделён на слои:
app/api- HTTP-роуты и Pydantic-схемыapp/application- orchestration-логика и менеджер ботовapp/domain- доменные модели, интерфейсы и поведениеLectureBotapp/infrastructure- реализация клиента для BigBlueButton через Playwrightapp/core- конфигурация, фабрики, исключения
Такое разделение упрощает замену инфраструктуры. Например, вместо BBBPlaywrightClient можно реализовать другой LectureClient, не меняя логику LectureBot.
.
├── app/
│ ├── api/
│ │ ├── routes.py # REST API для управления ботами
│ │ └── schemas.py # схемы запросов и ответов
│ ├── application/
│ │ └── bot_manager.py # создание, хранение и остановка ботов
│ ├── core/
│ │ ├── config.py # настройки из env
│ │ ├── exceptions.py # доменные исключения
│ │ └── factories.py # фабрика Playwright-клиента
│ ├── domain/
│ │ ├── interfaces.py # абстракции LectureClient
│ │ ├── lecture_bot.py # сценарий поведения бота
│ │ └── models.py # LectureConfig, ChatMessage
│ ├── infrastructure/
│ │ ├── bbb_playwright_client.py # интеграция с BigBlueButton
│ │ └── selectors.py # CSS-селекторы элементов страницы
│ └── main.py # создание FastAPI-приложения
├── main.py # локальная точка входа для запуска uvicorn
├── pyproject.toml # зависимости и настройки инструментов
└── pytest.ini # базовая конфигурация pytest
- Python
3.13+ - установленный браузер Chromium для Playwright
- доступ к странице BigBlueButton, совместимой с селекторами из
app/infrastructure/selectors.py
Важно: интеграция жёстко завязана на текущую HTML-разметку BigBlueButton. Если селекторы или UI платформы изменятся, бот перестанет корректно входить в лекцию, читать чат или выходить из неё.
python3.13 -m venv .venv
source .venv/bin/activatepip install -e .playwright install chromiumВариант через корневую точку входа:
python main.pyИли напрямую через Uvicorn:
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reloadПосле запуска API будет доступно по адресу:
http://127.0.0.1:8000
Swagger UI:
http://127.0.0.1:8000/docs
Настройки читаются из переменных окружения с префиксом LECTURE_BOT_.
LECTURE_BOT_HEADLESS=true|false- запуск браузера в headless-режимеLECTURE_BOT_CHAT_POLL_INTERVAL_MS=3000- интервал чтения чатаLECTURE_BOT_LECTURE_START_POLL_INTERVAL_MS=3000- интервал ожидания времени стартаLECTURE_BOT_POST_JOIN_DELAY_MS=1000- пауза после входа перед приветствиемLECTURE_BOT_PRE_GOODBYE_DELAY_MS=1000- пауза перед прощальным сообщениемLECTURE_BOT_PRE_LEAVE_DELAY_MS=1000- пауза после прощания перед выходомLECTURE_BOT_PAGE_TIMEOUT_MS=15000- timeout Playwright для элементов страницыLECTURE_BOT_BROWSER_SLOW_MO_MS=0- замедление действий браузера для отладкиLECTURE_BOT_KEYPHRASE_MATCH_THRESHOLD=3- сколько совпадений по ключевым фразам считать окончанием лекцииLECTURE_BOT_RECENT_MESSAGES_LIMIT=10- сколько последних сообщений анализировать
Пример:
export LECTURE_BOT_HEADLESS=false
export LECTURE_BOT_BROWSER_SLOW_MO_MS=300
uvicorn app.main:app --reloadPOST /bots
Пример тела запроса:
{
"lecture_url": "https://bbb.example.com/rooms/lecture-1/join",
"student_name": "Иван Иванов",
"greetings_message": "Здравствуйте! Я подключился.",
"goodbye_message": "Спасибо за лекцию, до свидания!",
"lecture_start": "2026-04-27T09:00:00+04:00",
"lecture_end": "2026-04-27T10:30:00+04:00",
"keyphrase_lecture_over": [
"до свидания",
"спасибо за лекцию",
"на сегодня всё"
]
}Что важно:
lecture_url,student_name,greetings_message,goodbye_messageобязательны;lecture_startиlecture_endдолжны быть timezone-aware datetime;- если переданы обе даты,
lecture_endдолжна быть позжеlecture_start; keyphrase_lecture_overнормализуется: пустые и повторяющиеся фразы удаляются.
Пример запроса:
curl -X POST "http://127.0.0.1:8000/bots" \
-H "Content-Type: application/json" \
-d '{
"lecture_url": "https://bbb.example.com/rooms/lecture-1/join",
"student_name": "Иван Иванов",
"greetings_message": "Здравствуйте! Я подключился.",
"goodbye_message": "Спасибо за лекцию, до свидания!"
}'GET /bots
Возвращает массив с краткой информацией:
idstudent_namelecture_urlstatuscreated_at
GET /bots/{bot_id}
Возвращает расширенную информацию о конкретном боте.
DELETE /bots/{bot_id}
Поведение:
- отменяет
asyncio-задачу бота; - закрывает браузер;
- удаляет бота из
BotManager; - возвращает
204 No Content.
Статус вычисляется по состоянию асинхронной задачи:
running- бот работаетfinished- бот завершился без ошибкиfailed- бот завершился с исключениемcancelled- задача была отменена
- Сейчас поддерживается только сценарий входа в BigBlueButton через конкретные CSS-селекторы.
- Бот работает через реальный браузер Chromium, поэтому на сервере должны быть доступны зависимости Playwright.
- В проекте нет постоянного хранилища: список ботов живёт в памяти процесса.
- После перезапуска приложения информация о ранее созданных ботах теряется.
- Если бот завершился, запись остаётся в памяти менеджера до ручного удаления или завершения приложения.
- Значение
wait_time_till_lecture_start_in_secondsв моделиLectureConfigфактически используется как timeout ожидания кнопкиListen only; по текущему коду это миллисекунды, несмотря на имя поля.
Линтер:
ruff check .Форматирование:
ruff format .Тесты:
pytestНа текущий момент в репозитории практически нет собственных тестов приложения, поэтому основной способ проверки - локальный запуск API и ручная проверка сценария входа в BigBlueButton.