Web-виджет Shopping Assistant

Справочник относится к готовому виджету 1.42. Для первого запуска используйте Web-гайд; возможности сервера описаны в API-справочнике.

Параметры конструктора

Передайте объект в new ShoppingAssistant(options).

Параметр Тип По умолчанию Назначение
apiUrl string https://shopping-assistant-api.gravityfield.ai/shopping/generate Адрес генерации.
feedbackUrl string Выводится из apiUrl: /generate → /feedback. Адрес PUT-оценки ответа.
historyUrl string Выводится из apiUrl: /generate → /history. Адрес загрузки сообщений диалога.
guestSessionsUrl string Выводится из apiUrl: /generate → /guest-sessions. Адрес регистрации гостевой сессии.
dialogsUrl string Выводится из apiUrl: /generate → /dialogs. Адрес списка диалогов.
resourceId string "api request" В интеграции обязательно передайте GF.userData.uid.
auth { mode: 'guest' } Не задан. Включает получение и сохранение гостевого токена.
resumeDialog boolean false Восстанавливает текущий разговор после перехода между страницами или перезагрузки.
resumeDialogTtlHours number 24 Срок возобновления с момента последнего сохранения диалога, в часах.
dialogHistory boolean false Показывает кнопку истории и список диалогов; требует auth: { mode: 'guest' }.
historyLimit number 50 Число последних сообщений при восстановлении; задавайте от 1 до 100.
startScreenTitle string Помогу подобрать товар Заголовок стартового экрана и шапки до первого сообщения. После отправки в шапке показывается первый вопрос пользователя.
startScreenDescription string Пустая строка. Описание стартового экрана.
startScreenLogoUrl string Логотип Gravity Field из CDN. Изображение стартового экрана.
placeholder string Задать вопрос... Подсказка поля сообщения.
quickQuestions Array<{title: string, sub?: string}> Два примера о смартфонах. Стартовые вопросы. Замените их под ваш магазин или передайте [].
autoInsertTrigger boolean true Создать встроенную кнопку открытия.
focusInputOnOpen boolean true Перевести фокус в поле при открытии.
enableCopyResponse boolean false Показать копирование у завершающего текстового блока с оценкой. У товарного блока кнопки копирования нет.
textareaMaxLines number 3 Высота поля сообщения до появления прокрутки.
loadingTexts string[] Три текста о поиске товаров. Сменяющиеся тексты ожидания; пустой массив возвращает значения по умолчанию.
icons Object Встроенные SVG. Иконки likeButton, dislikeButton, copyButton, historyButton. Передавайте только доверенную разметку.
apiKey string Не задан. Дополнительный Bearer-заголовок, если он предусмотрен вашим подключением и не задан поставщик токена. Для Web-примера не требуется; серверный API-ключ в браузер не передавайте.

runtimeContext.tenant_id и runtimeContext.ctx виджет берёт из текущих window.SL.section и window.SL.pageContext при отправке. В feedback-запросе tenant_id также берётся из SL.section. Для сайта с GF используйте совместимость с SL. Передача tenant_id, ctx или trafficType как произвольных параметров конструктора не меняет эти значения в запросе.

Методы

Метод Что делает
attachTo(elementOrSelector) Вставляет контейнер в элемент или по CSS-селектору. Элемент должен существовать.
open() Открывает чат, заранее запрашивает токен при настроенной авторизации и запускает восстановление сохранённого диалога. Если диалога нет, создаёт threadId.
close() Закрывает чат, сохраняя текущую переписку.
toggle() Переключает открытое и закрытое состояние.
getContainer() Возвращает DOM-контейнер экземпляра для ручной вставки или работы с оформлением.
updateStartScreen(params) Обновляет startScreenTitle, startScreenDescription и quickQuestions, пересоздаёт стартовый экран с сохранением его видимости.
startNewChat() Отменяет генерацию и загрузку истории, очищает переписку и сохранённый текущий диалог, создаёт новый threadId. Сохраняет resourceId и гостевую сессию.
setAuthProvider(provider) Подключает внешний поставщик с методом getAccessToken({ forceRefresh }). Значение null отключает поставщик токена.
openDialogs() / closeDialogs() / toggleDialogs() Управляет экраном списка диалогов, если включён dialogHistory в гостевом режиме.
selectDialog(threadId) Выбирает разговор, загружает его сообщения и делает текущим. При resumeDialog: true запоминает выбор.
destroy() Удаляет контейнер из DOM. Не закрывает чат, не отменяет запрос и не снимает все внутренние обработчики.

Объект assistant.config содержит параметры экземпляра. Если меняется пользователь, сначала вызовите startNewChat(), затем обновите assistant.config.resourceId. Обработчики кнопок, оверлея и товарных событий, добавленные вашей командой, снимайте в собственном коде.

Чтобы обновить стартовый экран без создания второго экземпляра:

assistant.updateStartScreen({
  startScreenTitle: 'Помощник магазина',
  startScreenDescription: 'Помогу выбрать подарок и сравнить товары.',
  quickQuestions: [
    { title: 'Выбрать подарок', sub: 'Подберём по интересам и бюджету' },
    { title: 'Сравнить товары' }
  ]
});

Метод не меняет текущую переписку и не обновляет логотип. Если заголовок чата уже взят из первого вопроса, новый startScreenTitle появится в шапке после startNewChat(). В версии 1.42 этот сброс всегда переводит фокус в поле, даже при focusInputOnOpen: false.

Гостевой токен

Включите auth: { mode: 'guest' }, чтобы виджет сам зарегистрировал сессию через POST /shopping/guest-sessions. Регистрация начинается при открытии чата. Нужны секция и реальный resourceId: значение "api request" не подходит.

Токен и ID сессии сохраняются в localStorage отдельно для каждой пары «секция + пользователь» и используются после перезагрузки. Генерация, история, список диалогов и PUT-оценки передают Authorization: Bearer …. При недоступном localStorage токен сохраняется только в памяти; после перезагрузки прежняя сессия автоматически не восстановится. Параллельные обращения в одном экземпляре ожидают одну регистрацию; между вкладками она координируется через Web Locks, если браузер их поддерживает.

При 401 INVALID_GUEST_TOKEN сохранённый токен сбрасывается. Следующий запрос регистрирует новую сессию с тем же resourceId. Если ошибка возникла при генерации, виджет один раз повторяет текущее сообщение в новом диалоге и показывает сообщение об истечении сессии. Прежние диалоги в новую сессию не переносятся. Ошибки регистрации не переключают запросы на режим без токена; при 429 или 503 виджет предлагает повторить позже.

Для собственного источника токена:

assistant.setAuthProvider({
  getAccessToken: ({ forceRefresh }) =>
    shopAuth.getAssistantToken({ forceRefresh })
});

Здесь shopAuth — ваш адаптер получения токена. Он заменяет встроенный гостевой поставщик. При 401 запрос повторяется один раз с forceRefresh: true и прежним телом. setAuthProvider(null) отключает авторизацию через поставщик; если задан apiKey, снова используется он. Встроенный список диалогов рассчитан на гостевой режим. Контракт сессий и ограничения доступа: Гостевые токены.

Продолжение и история диалогов

Это две отдельные настройки, обе по умолчанию выключены:

Настройка Поведение
resumeDialog: true Запоминает threadId, ID сессии и время после успешного ответа; при первом открытии на следующей странице загружает последние historyLimit сообщений через POST /shopping/history в режиме backward.
dialogHistory: true Добавляет кнопку истории в шапку. Список загружается через GET /shopping/dialogs от новых к старым, по 20 диалогов, с кнопкой «Показать ещё». Требует auth: { mode: 'guest' }.

Восстановленные ответы показываются с товарами, сохранёнными оценками и подсказками последнего сообщения. Для товарных блоков снова приходит shopping-assistant-recs. Виджет не отправляет события получения нового ответа и новой подборки при восстановлении. Показы карточек при этом учитывает товарный шаблон.

Выбор разговора в списке загружает его сообщения и продолжает тот же threadId. Кнопка «Новый чат» очищает текущую переписку и создаёт другой диалог в той же гостевой сессии. Действия «Убрать из истории» в готовом виджете нет, хотя API скрытия доступен.

Автовосстановление пропускается, если истёк resumeDialogTtlHours или в гостевом режиме сохранённый диалог относится к другой сессии. При 404 или INVALID_GUEST_TOKEN во время загрузки истории виджет показывает стартовый экран и создаёт новый ID. При другой ошибке показывает сообщение о сбое загрузки и сохраняет выбранный threadId. Виджет загружает только последние сообщения в пределах historyLimit; подгрузки более ранних сообщений в интерфейсе нет.

Состояние хранится на текущем origin в ключах gf-sa:session:{tenant_id}:{resourceId} и gf-sa:thread:{tenant_id}:{resourceId}. Новый origin или потеря токена не восстанавливают прежнюю гостевую историю. Подробности: История диалога.

Товарное событие

Виджет создаёт контейнер для блока товаров и отправляет DOM-событие shopping-assistant-recs на document. Самостоятельного рендеринга полноценных товарных карточек в нём нет.

Поле event.detail Значение
element Элемент товарного контейнера.
uniqueId ID контейнера; используйте его как селектор вставки.
skus SKU в порядке ответа ассистента.
title Необязательный заголовок товарного блока.
data Исходный блок products.

Событие отправляется синхронно, до вставки контейнера в DOM, отдельно для каждого непустого блока products. Если товарный шаблон ищет контейнер по селектору, отложите вставку карточек через queueMicrotask, как в Web-гайде. Не используйте событие получения подборки как подтверждение видимости товаров.

Формат текста и копирование

Формат берётся из поля messageFormat верхнего уровня ответа генерации или истории. При markdown виджет отображает абзацы, жирное выделение, курсив, маркированные и нумерованные списки, а также экранированные символы. Заголовки, Markdown-ссылки, таблицы и HTML выводятся как текст; HTML из ответа не исполняется. Обычные URL становятся ссылками.

Если поле отсутствует или равно plain_text, используется прежнее текстовое отображение. Отдельного параметра конструктора messageFormat нет. При enableCopyResponse: true копируется текст консультации без Markdown-разметки; структура абзацев и списков сохраняется.

Кнопки-ссылки

Блок button с action: "follow_url" и полем url создаёт ссылку с текстом из value. Принимаются только HTTP(S)-адреса; по умолчанию ссылка открывается в новой вкладке. Для собственного перехода подпишитесь на отменяемое событие:

document.addEventListener('shopping-assistant-follow-url', event => {
  const { url, text, element, threadId, data } = event.detail;
  event.preventDefault();
  // Откройте нужный экран или обработайте URL в своём интерфейсе.
});

element — ссылка в чате, data — исходный блок ответа. Без preventDefault() обработчик только наблюдает за кликом, а переход выполняется как обычно. Кнопка open_support_chat закрывает ассистента и вызывает window.$flomni.chat.openThread(), если этот API доступен; параметра для замены сервиса поддержки нет.

Оценка ответа и новый диалог

Кнопки оценки появляются у последнего блока message или products в ответе. Если ответ содержит кнопку open_support_chat, оценки для этого ответа скрываются.

При лайке или дизлайке виджет:

  1. Выделяет выбранную кнопку и блокирует обе кнопки оценки этого ответа.
  2. Отправляет custom event и PUT на feedbackUrl. Для запроса сохраняет ID ответа и диалога, зафиксированные при создании кнопок.
  3. Отправляет chat_dialog_end, но сохраняет текущий threadId, счётчик сообщений и переписку.

Следующая отправка после оценки продолжает тот же диалог. Для нового разговора используйте «Новый чат»: он очищает видимую переписку и создаёт другой ID. Обычное закрытие через close() сохраняет ID и сообщения, не отменяет отправленный запрос.

Интерфейс 1.42 не позволяет изменить или снять уже выбранную оценку, хотя PUT API принимает reaction: null. При ошибке сохранения кнопки остаются заблокированными, а состояние не откатывается; сообщение об ошибке появляется в консоли. Проверяйте HTTP-ответ, а не только вид кнопки. Контракт: Оценка ответа.

Что поддерживает версия 1.42

Виджет отправляет текстовые сообщения, отображает текст и поддерживаемый Markdown, быстрые подсказки и кнопки, создаёт товарные контейнеры и отправляет оценки через PUT. Гостевой токен, автовосстановление и список диалогов включаются отдельными настройками выше.

Версия 1.42 не передаёт messages[].id. Повторная отправка после потери ответа может создать второе сообщение. Если нужны управляемые повторы без дублей, используйте собственный API-клиент со стабильным ID сообщения.

Запрос содержит trafficType: "test", если адрес страницы включает sl_preview; иначе — "real". Отдельного параметра trafficType в конструкторе нет. Обычная предпросмотрная вкладка должна действительно содержать этот признак, чтобы запросы не попали в боевой трафик.

Изображения, публичный шаринг, скрытие диалогов и GET feedback требуют отдельной реализации интерфейса.

После изменения версии проверьте параметры, события, PUT-оценки и товарный шаблон на тестовом сценарии. Не обновляйте только JS или только CSS.