-
Notifications
You must be signed in to change notification settings - Fork 5
Widget
Настройка мультиинстансных чат-виджетов для встраивания на веб-сайты.

Виджет — это чат-окно, которое встраивается на любой сайт одним <script> тегом:
- Посетители сайта общаются с ИИ-ассистентом
- Каждый виджет имеет независимые настройки AI, TTS и внешнего вида
- Виджет можно отключить удалённо без переразвёртывания сайта
- Все сообщения сохраняются в системе с привязкой к виджету
Левая панель отображает все инстансы:
| Элемент | Описание |
|---|---|
| Индикатор | Зелёный = включён, серый = отключён |
| Название | Имя виджета |
| Действия | Настройки / Удалить |
- Нажмите "Создать виджет"
- Введите название (из него генерируется slug-ID)
- Настройте параметры (см. ниже)
- Сохраните
- Скопируйте код для вставки на сайт
Конфигурация организована по вкладкам:
| Параметр | Описание |
|---|---|
| Название | Имя инстанса |
| Описание | Описание виджета |
| Enabled | Включить/отключить виджет |
| Параметр | Описание | По умолчанию |
|---|---|---|
| Заголовок | Текст в шапке чат-окна | AI Ассистент |
| Приветствие | Первое сообщение бота | Здравствуйте! Чем могу помочь? |
| Placeholder | Текст в поле ввода | Введите сообщение... |
| Цвет | Основной цвет (hex). 6 пресетов + произвольный | #c2410c |
| Позиция | Кнопка чата: right или left
|
right |
| Параметр | Описание |
|---|---|
| Allowed Domains | Список доменов, на которых работает виджет |
| Tunnel URL | Переопределение API URL (для ngrok/Cloudflare Tunnel) |
Правила доменов:
- Пустой список = виджет работает на любом домене
- Проверка по подстроке:
example.comразрешаетwww.example.com,shop.example.com - Проверяется на стороне сервера при загрузке
widget.js
| Параметр | Описание |
|---|---|
| LLM Backend |
vllm, gemini или cloud:{provider_id}
|
| Персона |
anna или marina
|
| System Prompt | Кастомный системный промпт |
| LLM Params | JSON с параметрами: temperature, max_tokens
|
| Параметр | Описание |
|---|---|
| Engine |
xtts, piper или openvoice
|
| Voice | ID голоса (anna, marina) |
| Preset | Опциональный пресет TTS |
| Параметр | Описание |
|---|---|
| RAG Mode |
all — все коллекции, selected — выбранные, none — отключить |
| Коллекции | Multi-select чекбоксы для выбора коллекций знаний (при mode=selected) |
Настройки RAG определяют, какие документы из базы знаний (Wiki RAG) будут подставляться в контекст LLM при ответах виджета. Подробнее о коллекциях: Wiki-RAG.
| Параметр | Описание | По умолчанию |
|---|---|---|
| Rate Limit Count | Максимум сообщений за период | 5 |
| Rate Limit Hours | Период в часах | 5 |
Вкладка автоматически генерирует HTML-сниппет для вставки на сайт. Кнопка "Копировать" копирует код в буфер обмена.
Встроенный тестовый чат прямо в админ-панели:
- Использует AI/TTS настройки именно этого виджета
- Создаёт временную сессию
- Позволяет проверить поведение перед размещением на сайте
<script>
window.aiChatSettings = {
apiUrl: 'https://your-server.com',
instanceId: 'sales-widget',
title: 'Sales Assistant',
greeting: 'Чем могу помочь?',
placeholder: 'Введите сообщение...',
primaryColor: '#c2410c',
position: 'right'
};
</script>
<script src="https://your-server.com/widget.js?instance=sales-widget"></script>Вставьте код перед закрывающим тегом </body> на вашем сайте.
Каждый виджет имеет свой instanceId и изолированную сессию:
<!-- На странице продаж -->
<script src="https://api.example.com/widget.js?instance=sales"></script>
<!-- На странице поддержки -->
<script src="https://api.example.com/widget.js?instance=support"></script>1. Браузер запрашивает GET /widget.js?instance={id}
2. Сервер загружает конфиг инстанса из БД
3. Проверяет домен запроса по allowed_domains
4. Инжектит window.aiChatSettings в JS-код
5. Возвращает полный виджет-скрипт с CORS-заголовками
6. JS выполняет GET /widget/status?instance={id} (публичный, без auth)
7. Если enabled=true → рендерит кнопку чата
8. Если enabled=false → ничего не показывает
Это позволяет отключить виджет удалённо — при следующей загрузке страницы кнопка чата исчезнет.
9. Пользователь нажимает кнопку → окно чата
10. Первое сообщение → POST /admin/chat/sessions
(source=widget, source_id={instance_id})
11. Каждое сообщение → POST /admin/chat/sessions/{id}/stream
с widget_instance_id → бэкенд использует AI/TTS конфиг виджета
12. Ответ стримится через SSE: {type: "chunk", content: "..."}
Виджет сохраняет историю чата при переходе между страницами:
- Session ID хранится в cookie (
SameSite=None; Secure, 30 дней) и localStorage (cookie-first, localStorage-fallback) - При загрузке страницы
preloadHistory()запрашивает сессию черезGET /widget/chat/session/{id}(публичный, без auth,source="widget") - Состояние open/closed отслеживается в
sessionStorage— если чат был открыт, он auto-opens на следующей странице -
clearSession()очищает cookie + localStorage + sessionStorage
После загрузки виджета доступен глобальный объект:
window.aiChat = {
open(), // Открыть окно чата
close(), // Закрыть окно чата
clearSession() // Очистить сессию
};- Desktop: кнопка 60x60px, окно 380x520px
- Mobile (<=480px): полноэкранный режим
- CSS-переменные:
--ai-primary,--ai-primary-hover
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/widget/instances |
Список всех инстансов |
| POST | /admin/widget/instances |
Создать инстанс |
| GET | /admin/widget/instances/{id} |
Конфиг инстанса |
| PUT | /admin/widget/instances/{id} |
Обновить инстанс |
| DELETE | /admin/widget/instances/{id} |
Удалить инстанс |
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /widget.js?instance={id} |
Динамический JS-скрипт виджета |
| GET | /widget/status?instance={id} |
Проверка enabled-статуса |
| GET | /widget/chat/session/{id} |
Загрузка истории сессии |
- Admin — видит и управляет всеми виджетами в workspace
-
User/Web — только свои виджеты (
owner_id) - Guest — только чтение
Все CRUD-эндпоинты фильтруются по workspace_id из JWT. Публичные эндпоинты (widget.js, /widget/status, /widget/chat/session/{id}) не фильтруются — работают без JWT-контекста.
| Механизм | Описание |
|---|---|
| Проверка доменов |
allowed_domains проверяются server-side при загрузке widget.js
|
| CORS |
/widget.js возвращает Access-Control-Allow-Origin: *
|
| Изоляция сессий | Каждый виджет имеет отдельную сессию в localStorage |
| Fail-open | Если /widget/status недоступен — виджет всё равно рендерится |