82 lines
12 KiB
Markdown
82 lines
12 KiB
Markdown
# Телеграм бот для сбора датасета для автоматического протоколирования совещаний
|
||
|
||
## Запуск
|
||
|
||
### Локально
|
||
|
||
```sh
|
||
cp .env.example .env
|
||
# Заполнить .env
|
||
uv run main.py
|
||
```
|
||
|
||
### Docker
|
||
|
||
```sh
|
||
cp .env.example .env
|
||
# Заполнить .env
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Данные сохраняются в `data/`, `data_partial/` и `bot.db` — они монтируются как volumes.
|
||
|
||
## Данные
|
||
|
||
### Формат входных данных
|
||
|
||
Телеграм бот получает сценарии совещаний. Каждый сценарий представлен в виде отдельного файла в формате `json` с названием `<scenario_id>.json`. Сценарий состоит из списка реплик, для каждой из которых указан текст реплики и идентификатор диктора в рамках одного сценария.
|
||
|
||
```json
|
||
[
|
||
{
|
||
"text": "text of the replica",
|
||
"gender": "male",
|
||
"speaker_id": 0
|
||
},
|
||
{
|
||
...
|
||
}
|
||
]
|
||
```
|
||
|
||
### Результат работы бота
|
||
|
||
Бот сохраняет аудиофайлы с озвученными репликами в файлы `data/<scenario_id>/<replica_number>_<dataset_speaker_id>.wav`, где `<replica_number>` - это номер реплики в сценарии (0-indexed), `<dataset_speaker_id>` - это идентификатор диктора во всём датасете, по-сути, соответствует уникальному пользователю бота. Один диктор может озвучить несколько дорожек из разных совещаний. При этом он не может озвучивать две разные дорожки в рамках одного совещания, таким образом гарантируется, что разным `speaker_id` соответствуют разные дикторы в рамках одного совещания.
|
||
|
||
В `data` попадают только полностью озвученные дорожки. Под дорожкой подразумевается набор всех реплик одного диктора в рамках сценария. Дорожки, озвученные частично, хранятся в `data_partial/<scenario_id>/<replica_number>_<dataset_speaker_id>.wav`. Они автоматически переносятся в `data` после завершения озвучивания.
|
||
|
||
### База данных
|
||
|
||
Служебные данные, такие как состояния пользовательских сессий, соответствие `dataset_speaker_id` и `telegram_user_id` и т. п., сохраняются в базе данных SQLite. После перезагрузки бота его состояние полностью восстанавливается из базы данных.
|
||
|
||
## Интерфейс бота
|
||
|
||
### Состояния пользовательской сессии
|
||
|
||

|
||
|
||
- **INTRO** - начальное состояние сессии сразу после команды `/start`. Выводится сообщение о том, что это за бот и небольшое пользовательское соглашение, уведомляющее о целях сбора данных. Единственная кнопка - `Принять и продолжить`. После нажатия на неё происходит переход в **SPECIFY_GENDER**.
|
||
- **SPECIFY_GENDER** - выводится сообщение с предложением указать пол пользователя. Две кнопки для выбора мужского и женского пола. После нажатия на любую из кнопок происходит условный переход либо в **NO_MORE_SCENARIOS**, если нету доступных сценариев для озвучивания, либо в **FIRST_REPLICA**.
|
||
- **NO_MORE_SCENARIOS** - выводится сообщение о том, что пока больше нет сценариев для озвучивания. Из **NO_MORE_SCENARIOS** может произойти переход в **FIRST_REPLICA**, когда на сервер загружается новый сценарий, при этом выводится дополнительное уведомление. Самостоятельно пользователь не может покинуть это состояние.
|
||
- **FIRST_REPLICA** - выводится первая реплика дорожки с дополнительными инструкциями для пользователя (`i = 0`). При отправке аудиосообщения с озвучкой реплики, происходит условный переход в **SHOW_REPLICA** (`i += 1`), если это не последняя реплика в дорожке, либо в **CONFIRM_SAVE**.
|
||
- **SHOW_REPLICA** - выводится i-ая (0-indexed) реплика дорожки и её номер (1-indexed для пользователя, то есть i + 1). Есть две кнопки. Кнопка "Перезаписать предыдущую реплику", по ней условный переход в **FIRST_REPLICA**, если `i == 1`, либо в **SHOW_REPLICA** (`i -= 1`). Кнопка "Начать заново", по ней переход в **CONFIRM_RESTART**. При отправке аудиосообщения с озвучкой реплики, происходит условный переход в **SHOW_REPLICA** (`i += 1`), если это не последняя реплика в дорожке, либо в **CONFIRM_SAVE**.
|
||
- **CONFIRM_RESTART** - выводится сообщение с предупреждением о том, что текущие результаты озвучивания будут удалены и информация о том, что в конце записи дорожки, можно будет перезаписать отдельные реплики. Две кнопки. Кнопка "Да, перезаписать", по ней переход в **FIRST_REPLICA**. Кнопка "Нет, продолжить", по ней возврат в **SHOW_REPLICA**.
|
||
- **CONFIRM_SAVE** - выводится сообщение с предложением сохранить результаты озвучивания. Три кнопки. Кнопка "Да, сохранить", по ней условный переход в **FIRST_REPLICA** с выводом уведомления сообщения о сохранении дорожки, если ещё есть сценарии не озвученные этим диктором, иначе в **NO_MORE_SCENARIOS**. Кнопка "Перезаписать последнюю реплику", по ней возврат в **SHOW_REPLICA**. Кнопка "Перезаписать реплику по номеру", по ней переход в **ASK_REPLICA_NUMBER**.
|
||
- **ASK_REPLICA_NUMBER** - выводится сообщение с предложением ввести номер реплики для перезаписи. Есть кнопка "Отмена", по ней возврат в **CONFIRM_SAVE**. После сообщения с номером реплики происходит переход в **REPEAT_REPLICA**.
|
||
- **REPEAT_REPLICA** - выводится реплика с указанным номером (1-indexed для пользователя). После отправки аудиосообщения с озвучкой реплики возврат в **CONFIRM_SAVE**.
|
||
|
||
Некорректные пользовательский ввод не изменяет состояние, лишь выводится уведомление об ошибке.
|
||
|
||
### Другие особенности
|
||
|
||
Везде используются inline-кнопки. При этом кнопки под старыми сообщениями автоматически удаляются.
|
||
|
||
В первую очередь пользователям предлагается озвучить дорожки, которые никто ещё не начал озвучивать. Затем те дорожки, которые кто-то начал озвучивать, но ещё не закончил. И топлько потом дорожки, для которых уже озвучка. Тем не менее, одна дорожка может быть озвучена несколькими дикторами.
|
||
|
||
## Администрирование
|
||
|
||
Бот управляется единственным администратором, чей Telegram логин указывается в переменной окружения `ADMIN_LOGIN`. Только у администратора доступна команда `/admin`, переводящая пользовательскую сессию в состояние **ADMIN**. Команда доступна из любого другого состояния. В **ADMIN** доступна кнопка "Вернуться в пользовательский режим", переводящая пользовательскую сессию в то состояние, из которого она была переведена в **ADMIN**. Исключением является случай, когда админ озвучивал дорожку из сценария, который только что был удалён. После перехода режим администратора выводится сообщение с информацией о текущем состоянии датасета: количество полностью озвученных сценариев, общее количество сценариев, количество полностью озвученных дорожек, общее количество дорожек, количество уникальных дикторов, количество озвученных реплик, общее количество реплик, количество уникальных пользователей бота и т. п.
|
||
|
||
В **ADMIN** администратор может отправить боту `json`-файл с новым сценарием. Это переводит пользовательскую сессию в состояние **ADMIN_UPLOAD_CONFIRM**, если файл корректен, иначе выводится сообщение об ошибке в формате файла. В **ADMIN_UPLOAD_CONFIRM** выводится сообщение с предложением добавить сценарий, а также дополнительная информация о сценарии: количество дорожек, количество реплик. Две кнопки: "Да, добавить" и "Отмена". Обе кнопки возвращают администратора в состояние **ADMIN**.
|
||
|
||
В **ADMIN** доступна кнопка "Удалить сценарий". По нажатию выводится список всех сценариев в виде inline-кнопок, а также кнопка "Отмена". Выбор сценария переводит в состояние **ADMIN_DELETE_CONFIRM**. В этом состоянии выводится информация о сценарии: количество дорожек, количество реплик, количество записей. Две кнопки: "Да, удалить" и "Отмена". При удалении удаляются записи из базы данных и файлы из `data/` и `data_partial/`, а все пользователи, которые озвучивали этот сценарий, переводятся в **FIRST_REPLICA** с выводом уведомления сообщения о сохранении дорожки, если ещё есть сценарии не озвученные этим диктором, иначе в **NO_MORE_SCENARIOS**. Обе кнопки возвращают в **ADMIN**. |