Files
dataset-tg-bot/README.md
2026-02-03 11:18:00 +03:00

82 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Телеграм бот для сбора датасета для автоматического протоколирования совещаний
## Запуск
### Локально
```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",
"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. После перезагрузки бота его состояние полностью восстанавливается из базы данных.
## Интерфейс бота
### Состояния пользовательской сессии
![Состояния бота](./bot-states.png)
- **INTRO** - начальное состояние сессии сразу после команды `/start`. Выводится сообщение о том, что это за бот и небольшое пользовательское соглашение, уведомляющее о целях сбора данных. Единственная кнопка - `Принять и продолжить`. После нажатия на неё условный переход либо в **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-кнопки. При этом кнопки под старыми сообщениями автоматически удаляются.
История сообщений остаётся в чате с ботом. UX не строится на редактировании сообщений.
В первую очередь пользователям предлагается озвучить дорожки, которые никто ещё не начал озвучивать. Затем те дорожки, которые кто-то начал озвучивать, но ещё не закончил. И топлько потом дорожки, для которых уже озвучка. Тем не менее, одна дорожка может быть озвучена несколькими дикторами.
## Администрирование
Бот управляется единственным администратором, чей 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**.