101 lines
11 KiB
Markdown
101 lines
11 KiB
Markdown
# Техподдержка онлайн-школы ЕГЭ
|
||
|
||
На сайте два чата поддержки. Пользователь пишет в общий чат, сотрудник — в служебный. Оба чата ведут историю и передают сообщения в панель оператора. Уточнения продолжают ту же заявку. Оператор видит историю, проверяет предложенный черновик и отправляет ответ в диалог.
|
||
|
||
[Схема процесса и план внедрения](support-process-and-pilot.pdf)
|
||
|
||
## Запуск
|
||
|
||
Клонируйте репозиторий или распакуйте исходники релиза. Откройте PowerShell в папке с `server.mjs`. Понадобится Node.js 24 или новее. Устанавливать зависимости не нужно.
|
||
|
||
```powershell
|
||
node server.mjs
|
||
```
|
||
|
||
Оставьте терминал открытым и перейдите в браузер. `Ctrl+C` останавливает сервер. По умолчанию работает локальное демо с правилами и учебными шаблонами. В нём можно открыть оба чата и проверить модерацию без API-ключа.
|
||
|
||
- [Чат пользователей](http://127.0.0.1:8787/site-chat)
|
||
- [Чат сотрудников](http://127.0.0.1:8787/staff-chat)
|
||
- [Панель оператора](http://127.0.0.1:8787/)
|
||
|
||
Если хотите хранить настройки в файле, скопируйте `.env.example` в `.env`, заполните нужные параметры и запустите `node --env-file=.env server.mjs`. Настройки также можно задать через переменные окружения PowerShell.
|
||
|
||
## Что проверить
|
||
|
||
1. В чате пользователей отправьте «Не открывается вебинар, который уже идёт». Вторым сообщением добавьте «Пишет 503, смотрю с телефона». В панели откройте одну заявку и проверьте оба сообщения в истории.
|
||
2. Отправьте ответ из карточки заявки. Он появится в том же чате. Кнопка сохранения черновика хранит внутренний текст, а отправка добавляет реплику в историю.
|
||
3. В новом пользовательском диалоге попросите выдать права администратора или прислать внутренние данные другого ученика. В чате появится отказ, а сообщение можно найти в папке «Спам». Строки из случайных букв тоже попадают туда.
|
||
4. Добавьте мат к описанию обычной проблемы. Чат попросит писать вежливо. Повторите в том же диалоге, чтобы увидеть предупреждение о возможной блокировке. Сама блокировка учётной записи остаётся действием оператора по правилам школы.
|
||
5. В чате сотрудников отправьте «Нужны права для нового куратора». Заявка попадёт во внутреннюю очередь на проверку полномочий. Если сотрудник сообщает о текущем сбое у учеников, заявку поднимет пользовательский приоритет.
|
||
|
||
В панели доступны правки категории, черновика и статуса, ручной ввод и выгрузка CSV. Для отдельного обращения начните новый диалог в чате.
|
||
|
||
Правила против бессмысленных сообщений и мата действуют в обоих чатах. Ограничение на запрос админских прав и закрытой информации относится к пользовательскому чату. Демо отправляет в спам клавиатурный шум, явные заглушки и короткие бессвязные фразы, которые распознают локальные правила. В режиме ИИ модель дополнительно оценивает смысл последнего сообщения с учётом диалога. Коды ошибок и короткие уточнения остаются в заявке.
|
||
|
||
## Выход и очистка базы
|
||
|
||
Кнопка «Выход» закрывает текущий экран. При выходе из чата браузер забывает открытый диалог. Для продолжения работы используйте кнопку возврата на странице выхода.
|
||
|
||
В панели оператора нажмите «Очистить буфер» и подтвердите удаление. Из SQLite удалятся все заявки, включая спам, и история обоих чатов. Для следующего обращения откройте новый диалог. Очистка применяется к базе, которую использует запущенный сервер.
|
||
|
||
## Подключение к сайту школы
|
||
|
||
Сервис слушает `127.0.0.1`. При интеграции сайт проксирует нужные страницы и маршруты чатов, а панель и операторские API размещает в закрытой зоне. Укажите внешний HTTPS-адрес сайта без пути в `SUPPORT_WEB_ORIGIN`, например `https://school.example`. При проксировании передайте локальный `Host` сервиса, например `127.0.0.1:8787`.
|
||
|
||
Для нового диалога используется `POST /api/chat/users/sessions` или `POST /api/chat/staff/sessions`. Идентификатор сессии даёт доступ к её истории. Храните его как секрет диалога и передавайте только его участнику. Для отправки `POST /api/chat/{users|staff}/sessions/{id}/messages` принимает JSON `{ "requestId": "<UUID>", "text": "..." }`. При повторной доставке используйте тот же `requestId`. История доступна через `GET /api/chat/{users|staff}/sessions/{id}`.
|
||
|
||
В режиме ИИ создавайте служебную сессию только с сервера сайта после проверки роли сотрудника. Передайте `Authorization: Bearer <SUPPORT_STAFF_TOKEN>`. Держите секрет в окружении серверов и передайте браузеру только ID созданного диалога, например через `/staff-chat#session=<id>`. Открытый служебный чат деморежима предназначен для локальной проверки.
|
||
|
||
Для старой интеграции разовых заявок доступен `POST /api/intake/site` с `SUPPORT_SITE_TOKEN` и JSON `{ "externalId": "<стабильный ID>", "text": "..." }`. Для диалога с ответами и уточнениями используйте маршруты сессий.
|
||
|
||
## Режим ИИ с Qwen3.6 35B
|
||
|
||
Остановите запущенное демо и укажите настройки в PowerShell. Для ключа AI Studio нужна область `yc.ai.foundationModels.execute`, для сервисного аккаунта — роль `ai.languageModels.user`. [Документация Yandex AI Studio](https://aistudio.yandex.ru/ru/docs/ai-studio/operations/generation/completions-structured).
|
||
|
||
```powershell
|
||
$env:SUPPORT_MODE = 'llm'
|
||
$env:SUPPORT_PROVIDER = 'yandex'
|
||
$env:YANDEX_FOLDER_ID = Read-Host 'Идентификатор каталога'
|
||
$env:YANDEX_API_KEY = [System.Net.NetworkCredential]::new('', (Read-Host 'Ключ AI Studio' -AsSecureString)).Password
|
||
node server.mjs
|
||
```
|
||
|
||
Запросы тарифицируются по токенам. Правила доступа и предупреждения срабатывают на сервере, а черновики модели отображаются оператору. [Тарифы Yandex AI Studio](https://aistudio.yandex.ru/ru/docs/ai-studio/pricing).
|
||
|
||
## Хранение и материалы
|
||
|
||
SQLite создаётся в `data/support.sqlite`. Чтобы использовать историю предыдущей версии, остановите сервер и перенесите папку `data` в распакованный проект. Для пути базы и порта доступны `SUPPORT_DB` и `SUPPORT_PORT`. Для CSV в Excel при необходимости выберите UTF-8 и разделитель «запятая».
|
||
|
||
Для демонстрации используйте учебные тексты. Оператор проверяет закрытые сведения в админке, выдаёт права по согласованной заявке и добавляет материалы в датасет с согласия автора.
|
||
|
||
- [Постановка для разработки](assignment-ege-support.md)
|
||
- [Инструкция для модели](triage-prompt.md)
|
||
- [Лог работы с ИИ](ai-log.md)
|
||
- [История версий](CHANGELOG.md)
|
||
|
||
## Проверки перед релизом
|
||
|
||
```powershell
|
||
node --test
|
||
```
|
||
|
||
Проверки используют временную SQLite и синтетические обращения. Ключ модели не нужен.
|
||
|
||
## Публикация в Gitea
|
||
|
||
Для первой публикации создайте в Gitea пустой репозиторий `ege-support-prototype`. Скопируйте его URL для клонирования. В папке проекта выполните следующие команды. Сначала просмотрите список подготовленных файлов, затем сделайте коммит.
|
||
|
||
```powershell
|
||
git init -b main
|
||
git add -- .gitignore .env.example package.json README.md CHANGELOG.md server.mjs classify.mjs chat-policy.mjs examples.mjs triage-prompt.md public test ai-log.md assignment-ege-support.md support-process-and-pilot.pdf
|
||
git diff --cached --name-only
|
||
git commit -m "Prepare release v0.1.0"
|
||
$repoUrl = Read-Host 'URL для клонирования из Gitea'
|
||
git remote add origin $repoUrl
|
||
git push -u origin main
|
||
git tag -a v0.1.0 -m "Release v0.1.0"
|
||
git push origin v0.1.0
|
||
```
|
||
|
||
В Gitea откройте раздел **Releases**, создайте релиз для тега `v0.1.0` и возьмите описание из `CHANGELOG.md`. Если репозиторий уже содержит коммиты, сначала клонируйте его и внесите проект в существующую историю. [Документация Gitea о релизах](https://docs.gitea.com/api/1.26/operations/repo-create-release/).
|