Спросите помощника
0/400
Вопрос обрабатывается ИИ-сервисом и сохраняется для улучшения ответов. Не вводите персональные данные.

    Assistant

    ИИ-помощник сайта: посетитель задаёт вопрос и получает ответ по базе знаний самого сайта — со ссылкой на страницу под каждым утверждением.

    Тип: wrapper Только веб: отвечает сервер, который раздаёт сайт. В приложении, в превью редактора и на экспортированном сайте отвечать некому: элемент рисует ребёнка, state — unavailable , ask ничего не делает.

    State @q:""
      Assistant question:$q consent:true ask:@ask state:@st message:@msg blocks:@blocks action:@next pending:@busy
        Column crossAxisAlignment:stretch size:min spacing:12
          TextField value:$q onSubmitted:(){ask()}
          ElevatedButton onPressed:(){ask()}
            Text "Спросить"
          Text "Вопрос обрабатывает ИИ-сервис, и он может храниться."
          Text "Ищу…" if:$busy
          Text $msg
          ListView.builder itemCount:{length(blocks)} shrinkWrap:true
            @Macros id:itemBuilder index:0
              Column crossAxisAlignment:stretch size:min
                Text {blocks[index]["text"]}
                Container
                  #web href:{blocks[index]["source"]["url"] ?? ""}
                  Text {blocks[index]["source"]["title"] ?? ""}
          Container
            #web href:{next["url"] ?? ""}
            Text {next["title"] ?? ""}

    По чему помощник отвечает, для чего он и какие у него лимиты, в разметке не пишется — это лежит в каталоге проекта: ИИ-помощник сайта .

    Параметры

    Параметр Тип Описание
    question string Вопрос посетителя. Читается в момент вызова ask — привяжите к переменной поля
    consent bool Согласился ли посетитель на обработку вопроса. Читается в момент вызова ask . Параметра нет — согласия нет
    ask выход, функция Её зовёт кнопка. Отправляет вопрос
    state выход, string Одно слово, см. ниже
    message выход, string Фраза для посетителя, когда показать ответ нельзя. Уже на его языке
    blocks выход, список Ответ по порядку. У блока есть kind : text — утверждение ( text , source с title и url ), любой другой — карточка из каталога владельца (см. ниже)
    action выход, объект Следующий шаг, который предлагает владелец: id , title , url — или пусто
    pending выход, bool true , пока идёт поиск

    Карточки в ответе

    Ответ бывает не только сказан, но и показан: рядом с утверждениями помощник может вывести записи из каталога владельца — тариф, услугу, раздел. Каждая такая запись приходит блоком со своим kind (по умолчанию card ) и полями, которые владелец записал в каталоге: title , text , image , url , цена — что угодно. Плюс scenario и id .

    Макет карточки пишет автор страницы. Строка списка переключает его по kind :

    ListView.builder itemCount:{length(blocks)} shrinkWrap:true
      @Macros id:itemBuilder index:0
        Column crossAxisAlignment:stretch size:min
          // Утверждение с источником.
          Column crossAxisAlignment:stretch size:min if:{blocks[index]["kind"] == "text"}
            Text {blocks[index]["text"] ?? ""}
            Container
              #web href:{blocks[index]["source"]["url"] ?? ""}
              Text {blocks[index]["source"]["title"] ?? ""}
          // Карточка: всё, что на ней написано, — из записи каталога.
          Container if:{blocks[index]["kind"] == "card"}
            #web href:{blocks[index]["url"] ?? ""}
            Column crossAxisAlignment:stretch size:min
              Image src:{blocks[index]["image"] ?? ""} if:{blocks[index]["image"] != null}
              Text {blocks[index]["title"] ?? ""}
              Text {blocks[index]["text"] ?? ""}
    • Поле, которого в записи нет, приходит пустым: читайте его через ?? "" , а картинку показывайте, только когда она есть — иначе на странице останется пустой img .
    • Ни названия, ни цены, ни картинки, ни адреса модель не пишет: она называет записи по идентификатору, поля подставляет сервер. Выдуманной цены в карточке быть не может.
    • Как завести каталог — в описании помощника .

    Состояния

    state Когда
    idle до первого вопроса
    asking идёт поиск; это несколько секунд — показывайте pending
    answered ответ в blocks
    notFound вопрос по теме, но в базе этого нет; в message и action — куда обратиться
    offTopic вопрос не о том, для чего помощник
    paused посетитель исчерпал ответы на сейчас
    needsConsent нет согласия — вопрос никуда не ушёл
    unavailable помощник не отвечает; страница при этом цела

    Как это работает

    • Обёртка. Выходы элемента видит только его поддерево: поле, кнопка и ответ лежат внутри. Кнопка рядом вопроса не задаст.
    • Без согласия вопрос не уходит. Привяжите consent: к галочке ( consent:$agreed ) или напишите consent:true , если согласие сказано словами рядом с полем и нажатие кнопки им и является.
    • Ни адреса, ни ключа. Вопрос идёт на адрес этого же сайта.
    • Проверку «я не бот» писать не нужно. Незнакомец после первого вопроса проходит невидимую проверку, и вопрос повторяется за него сам; для страницы это по-прежнему один asking . Это собственная проверка платформы — элемент Captcha и settings.captcha в ней не участвуют.
    • Лимиты держит сервер. Сколько вопросов можно задать и пауза за вопросы не по теме страницей не считаются: ей приходит paused .
    • Ссылку под утверждением строит сервер. source.url ведёт на страницу и раздел, откуда взято утверждение; пусто, если у документа нет страницы.

    Чего не делать

    • Не собирайте то же самое из HttpData : запрос уйдёт, а согласие, проверка и счётчики посетителя — нет.
    • Не выводите text как разметку или HTML: это обычный текст.
    • Не ждите ответа в превью редактора: помощника смотрят на опубликованном сайте.
    menu_baseline