Всё больше компаний используют чат-боты в WhatsApp, чтобы взаимодействовать с клиентами, выявлять их потребности и получать важные данные. Однако эффективно собирать и упорядочивать информацию непросто. В этом поможет WhatsApp Flows.
Интеграция WhatsApp Flows в чат-боты помогает компаниям эффективнее анализировать входящие данные о клиентах. В зависимости от содержания переписки чат-бот может отправить клиенту сценарий, адаптированный для сбора данных.
Из этой статьи вы узнаете, как создать чат-бот с помощью Llama 2 и Python, а также подключить его к WhatsApp Flows, чтобы улучшить сбор данных. Вы узнаете, как WhatsApp Flows делает чат-бот более понятным для пользователей и помогает улучшить точность и эффективность сбора данных о клиентах.
Ваш чат-бот будет отвечать на запросы пользователей с помощью WhatsApp Flows и таким образом собирать данные. Другими словами, пользователи смогут общаться с чат-ботом, задавать вопросы об услугах вымышленного отеля в Испании и обращаться в компанию за поддержкой.
Чат-бот будет использовать простые утверждения if
в сочетании со стандартной моделью Llama 2, чтобы предоставлять доступ к достаточной общей базе знаний.
Часть 1:
Создайте сценарий с помощью Flow Builder в WhatsApp Manager.
Часть 2:
Преобразуйте модель Llama 2 из формата GGML в GGUF.
На этом этапе для создания сценария вы будете использовать Flow Builder. Вы также можете использовать Flows API (этот способ не описывается в этой статье).
Чтобы приступить к работе, убедитесь, что вы:
Установили ngrok.
Подтвердили аккаунт разработчика на сайте Meta for Developers и умеете работать с облачным API от Meta.
Кроме того, выполните обязательные условия для использования Flows. Вы также можете открыть предварительный просмотр полного кода проекта.
Откройте страницу Сценарии в своем аккаунте WhatsApp Business. Если вы впервые работаете с Flows, то увидите кнопку Начать создание сценариев. В ином случае вы увидите кнопку Создать сценарий в правом верхнем углу страницы.
Нажмите кнопку, чтобы открыть диалоговое окно, где вы сможете указать данные о сценарии.
Сначала вы создадите сценарий, который позволит клиенту задать вопрос об услугах туристической компании.
Введите название в поле Название. Далее в раскрывающемся меню Категории нажмите Зарегистрироваться, а в раскрывающемся меню Шаблон выберите Нет. Нажмите Отправить.
В левой части следующей страницы находится редактор, а в правой — предпросмотр.
Замените содержимое редактора разметкой JSON для нужного сценария. Узнать больше о JSON сценария можно в документации для разработчиков.
Сохраните сценарий. Предварительный предпросмотр должен выглядеть примерно так, как на скриншоте ниже.
Сценарий содержит один экран, который позволяет клиенту ввести свои данные, выбрать нужные услуги и одно дополнительное сообщение (по желанию). Когда пользователь нажимает Отправить, сценарий закрывается и отправляет собранные данные в компанию для обработки. Один из способов передачи этой информации подразумевает использование конечных точек. Однако в этом проекте конечные точки не нужны. Эти данные будут переданы тому же веб-перехватчику Webhook, на базе которого работает чат-бот.
Передачу данных можно запустить с помощью действий. Определите данные для передачи на следующий экран с помощью объекта payload
.
... "on-click-action": { "name": "complete", "payload": { "firstname": "${form.first_name}", "secondname": "${form.second_name}", "services_interested": "${form.services_interested}", "additional_info": "${form.additional_info}", "flow_key": "agentconnect" } } ...
В этом фрагменте кода нажатие пользователем кнопки вызывает действие on-click-action
, что влечет за собой сбор полезных данных. Затем полезные данные отправляются на ваш сервер Webhook, а сценарий закрывается через действие complete
.
Вы можете присвоить ключи payload
любой переменной. Соответствующие значения могут отражать объекты данных или названия компонентов сценария (примерно как со свойством названия HTML-формы).
Теперь вы можете увидеть сценарий в работе и симулировать реальное взаимодействие с пользователем с помощью переключателя Интерактивный предпросмотр.
После тестирования вы можете опубликовать сценарий (до этого он будет находиться в черновиках). Для этого откройте меню справа от кнопки Сохранить и нажмите Опубликовать. Сценарий готов к использованию.
Теперь давайте создадим сценарий "Связаться с нами".
Повторите шаги по созданию сценария. В качестве категории выберите Связаться с нами. Замените содержимое редактора разметкой JSON для отображения данных, как на скриншоте ниже.
Опубликуйте сценарий и приступайте к инструкциям в следующем разделе, чтобы настроить чат-бот. В этом разделе используются три функции: send_message
, flow_details
и flow_reply_processor
. Они содержат логику, необходимую для отправки сценария пользователям. В этом разделе также содержится логика для обработки входящих полезных данных сценария. Поэтому рекомендуем просмотреть этот раздел, даже если у вас уже есть чат-бот.
Теперь давайте настроим чат-бот и интегрируем его со сценарием.
Прежде чем продолжить, убедитесь, что:
У вас есть базовые знания и последняя версия Python.
Вы скачали версию HuggingFace модели Llama 2. Модель HuggingFace Llama не требует дополнительных инструментов или специального оборудования. Вы также можете использовать официальную версию, однако тогда потребуется дополнительная настройка.
У вас есть маркер доступа к вашему аккаунту и ID номера телефона.
У вас есть редактор кода.
Чат-бот будет работать на основе заранее определенного скрипта, чтобы помогать пользователям в зависимости от введенных ими данных. При первом взаимодействии чат-бот предлагает персонализированное приветствие и текстовое меню в зависимости от сообщения пользователя. Предлагаемые варианты удовлетворяют различные потребности: запрос информации об услугах отеля, обращение к одному из агентов или взаимодействие с чат-ботом на базе Llama.
Когда пользователь ответит с помощью алфавитно-цифрового символа, то увидит соответствующую услугу или действие. Однако любой другой ответ вызовет функционал чат-бота по умолчанию, связанный с общими запросами. Чат-бот сможет предложить доступные услуги на основе последующей переписки.
Для начала создайте виртуальную среду, выполнив в терминале указанную ниже команду.
python -m venv venv
Активируйте ее.
source venv/bin/activate
Затем установите требуемые пакеты.
pip install requests flask llama-cpp-python python-dotenv
Используйте Flask
для создания маршрутов и взаимодействия с API, requests
— для отправки интерпретированных запросов, llama-cpp-python
— для взаимодействия с моделью и python-dotenv
— для загрузки переменных среды.
Далее создайте файл среды под названием .env
и указанный ниже контент, соответствующе присвоив значения. Для TOKEN
можно использовать любую строку.
TOKEN = ACCESS_TOKEN = PHONE_NUMBER_ID =
В этом же каталоге создайте файл под названием main.py
и начните добавлять пакеты, которые вы будете использовать.
import os import re import time import uuid import requests from dotenv import load_dotenv from flask import Flask, request, make_response, json from llama_cpp import Llama
Теперь инициализируйте переменные и классы. Этот фрагмент также инициализирует Flask и вызывает пакет load_dotenv()
, чтобы загрузить переменные.
app = Flask(__name__) load_dotenv() PHONE_NUMBER_ID = os.getenv('PHONE_NUMBER_ID') url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages" TOKEN = os.getenv('TOKEN') ACCESS_TOKEN = os.getenv('ACCESS_TOKEN') code_prompt_texts = ["Contact us", "Chat with our chatbot", "YES", "NO"] service_list = [ "Accommodation Services", "Spa Services", "Dining Services", "Recreational Facilities", "Business & Conference Services", "Transportation Services", "Accessibility Services", "Pet-Friendly Services" ]
В списке service_list указаны услуги, предлагаемые отелем. В списке code_prompt_texts
содержатся варианты, соответствующие вводимым пользователями данным: 1, 2, Y и N с использованием функции ниже. Функция ниже помогает сопоставить ответы пользователя с нужным вариантом.
def extract_string_from_reply(user_input): match user_input: case "1": user_prompt = code_prompt_texts[0].lower() case "2": user_prompt = code_prompt_texts[1].lower() case "Y": user_prompt = code_prompt_texts[2].lower() case "N": user_prompt = code_prompt_texts[3].lower() case _: user_prompt = str(user_input).lower() return user_prompt
Код преобразует регистр строк в нижний, чтобы избежать отсутствия совпадений при запуске логики условий. Структура match…case
сопоставляет запросы пользователей с выводом данных. Например, если пользователь нажмет "1", будет вызвана функция "Contact us"
.
Указанная ниже функция содержит утверждение if
, для которого используется пакет Python RegEx, а также re
для поиска определенных слов в сообщении клиента и определения типа ответа.
def user_message_processor(message, phonenumber, name): user_prompt = extract_string_from_reply(message) if user_prompt == "yes": send_message(message, phonenumber, "TALK_TO_AN_AGENT", name) elif user_prompt == "no": print("Chat terminated") else: if re.search("service", user_prompt): send_message(message, phonenumber, "SERVICE_INTRO_TEXT", name) elif re.search( "help|contact|reach|email|problem|issue|more|information", user_prompt ): send_message(message, phonenumber, "CONTACT_US", name) elif re.search("hello|hi|greetings", user_prompt): if re.search("this", user_prompt): send_message(message, phonenumber, "CHATBOT", name) else: send_message(message, phonenumber, "SEND_GREETINGS_AND_PROMPT", name) else: send_message(message, phonenumber, "CHATBOT", name)
Сообщение типа "Hello there"
вызовет метод send_message
с SEND_GREETINGS_AND_PROMPT
в качестве второго аргумента. Ниже указан метод send_message
. Соответствующе замените содержимое между <xxx>
.
def send_message(message, phone_number, message_option, name): greetings_text_body = ( "\nHello " + name + ". Welcome to our hotel. What would you like us to help you with?\nPlease respond with a numeral between 1 and 2.\n\n1. " + code_prompt_texts[0] + "\n2. " + code_prompt_texts[1] + "\n\nAny other reply will connect you with our chatbot." ) # loading the list's entries into a string for display to the user services_list_text = "" for i in range(len(service_list)): item_position = i + 1 services_list_text = ( f"{services_list_text} {item_position}. {service_list[i]} \n" ) service_intro_text = f"We offer a range of services to ensure a comfortable stay, including but not limited to:\n\n{services_list_text}\n\nWould you like to connect with an agent to get more information about the services?\n\nY: Yes\nN: No" contact_flow_payload = flow_details( flow_header="Contact Us", flow_body="You have indicated that you would like to contact us.", flow_footer="Click the button below to proceed", flow_id=str("<FLOW-ID>"), flow_cta="Proceed", recipient_phone_number=phone_number, screen_id="CONTACT_US", ) agent_flow_payload = flow_details( flow_header="Talk to an Agent", flow_body="You have indicated that you would like to talk to an agent to get more information about the services that we offer.", flow_footer="Click the button below to proceed", flow_id=str("<FLOW-ID>"), flow_cta="Proceed", recipient_phone_number=phone_number, screen_id="TALK_TO_AN_AGENT", ) match message_option: case "SEND_GREETINGS_AND_PROMPT": payload = json.dumps( { "messaging_product": "whatsapp", "to": str(phone_number), "type": "text", "text": {"preview_url": False, "body": greetings_text_body}, } ) case "SERVICE_INTRO_TEXT": payload = json.dumps( { "messaging_product": "whatsapp", "to": str(phone_number), "type": "text", "text": {"preview_url": False, "body": service_intro_text}, } ) case "CHATBOT": LLM = Llama( model_path="/home/incognito/Downloads/llama-2-7b-chat.ggmlv3.q8_0.gguf.bin", n_ctx=2048, ) # create a text prompt prompt = message # generate a response (takes several seconds) output = LLM(prompt) payload = json.dumps( { "messaging_product": "whatsapp", "to": str(phone_number), "type": "text", "text": { "preview_url": False, "body": output["choices"][0]["text"], }, } ) case "CONTACT_US": payload = contact_flow_payload case "TALK_TO_AN_AGENT": payload = agent_flow_payload case "FLOW_RESPONSE": payload = json.dumps( { "messaging_product": "whatsapp", "to": str(phone_number), "type": "text", "text": {"preview_url": False, "body": message}, } ) headers = { "Content-Type": "application/json", "Authorization": "Bearer " + ACCESS_TOKEN, } requests.request("POST", url, headers=headers, data=payload) print("MESSAGE SENT")
Если в сообщении содержится только приветствие (SEND_GREETINGS_AND_PROMPT
), ответ будет включать в себя дополнительные варианты продолжения разговора (greetings_text_body
).
Точно так же, когда пользователь задает вопрос об услугах, он получает сообщение (service_intro_text
) с этой информацией. В ответе также будут содержаться дополнительные варианты взаимодействия на случай, если человек хочет продолжить общение с агентом.
Если введенная информация требует ответа от чат-бота (CHATBOT
), вам нужно инициализировать модель, передать ей содержимое сообщения и обработать ответ, чтобы отправить его пользователю. FLOW_RESPONSE
отображает ответ сценария.
Другие варианты (CONTACT_US
и TALK_TO_AN_AGENT
) отправят пользователю полезные данные сценария. Такие данные извлекаются из функции flow_details
, основной текст которой показан ниже. Полезные данные содержат важные сведения о сценарии, в том числе FLOW_ID
, который можно извлечь со страницы Сценарии в вашем аккаунте WhatsApp Business. Вы также можете определить эти ID с помощью переменных среды.
def flow_details(flow_header, flow_body, flow_footer, flow_id, flow_cta, recipient_phone_number, screen_id ): # Generate a random UUID for the flow token flow_token = str(uuid.uuid4()) flow_payload = json.dumps({ "type": "flow", "header": { "type": "text", "text": flow_header }, "body": { "text": flow_body }, "footer": { "text": flow_footer }, "action": { "name": "flow", "parameters": { "flow_message_version": "3", "flow_token": flow_token, "flow_id": flow_id, "flow_cta": flow_cta, "flow_action": "navigate", "flow_action_payload": { "screen": screen_id } } } }) payload = json.dumps({ "messaging_product": "whatsapp", "recipient_type": "individual", "to": str(recipient_phone_number), "type": "interactive", "interactive": json.loads(flow_payload) }) return payload
Этот метод создает action.parameters.flow_token
, генерируя случайный UUID. action.parameters.flow_action_payload.screen
передается в качестве параметра (screen_id
). В идеале этот параметр должен отражать ID первого экрана, который вы планируете показывать пользователю при выполнении функции action.parameters.flow_cta
.
Наконец, добавьте маршруты Webhook. Webhook GET
запрашивает инициализацию, когда Webhook добавляется в ваше приложение на сайте Meta for Developers. Если запрос успешный, он возвращает hub.challenge
запроса.
@app.route("/webhook", methods=["GET"]) def webhook_get(): if request.method == "GET": if ( request.args.get("hub.mode") == "subscribe" and request.args.get("hub.verify_token") == TOKEN ): return make_response(request.args.get("hub.challenge"), 200) else: return make_response("Success", 403)
Запрос POST
извлекает и обрабатывает полезные данные сообщения с помощью метода user_message_processor
, описанного ранее. Поскольку код работает только с полезными данными сообщения, он возвращает ошибку, если получает другие полезные данные. В связи с этим можно использовать утверждение if
, чтобы проверить наличие основного текста сообщения (messages
).
@app.route("/webhook", methods=["POST"]) def webhook_post(): if request.method == "POST": request_data = json.loads(request.get_data()) if ( request_data["entry"][0]["changes"][0]["value"].get("messages") ) is not None: name = request_data["entry"][0]["changes"][0]["value"]["contacts"][0][ "profile" ]["name"] if ( request_data["entry"][0]["changes"][0]["value"]["messages"][0].get( "text" ) ) is not None: message = request_data["entry"][0]["changes"][0]["value"]["messages"][ 0 ]["text"]["body"] user_phone_number = request_data["entry"][0]["changes"][0]["value"][ "contacts" ][0]["wa_id"] user_message_processor(message, user_phone_number, name) else: # checking that there is data in a flow's response object before processing it if ( request_data["entry"][0]["changes"][0]["value"]["messages"][0][ "interactive" ]["nfm_reply"]["response_json"] ) is not None: flow_reply_processor(request) return make_response("PROCESSED", 200)
Также можно использовать вспомогательную функцию flow_reply_processor
, чтобы извлечь ответ из сценария и отправить его назад пользователю.
def flow_reply_processor(request): request_data = json.loads(request.get_data()) name = request_data["entry"][0]["changes"][0]["value"]["contacts"][0]["profile"]["name"] message = request_data["entry"][0]["changes"][0]["value"]["messages"][0]["interactive"]["nfm_reply"][ "response_json"] flow_message = json.loads(message) flow_key = flow_message["flow_key"] if flow_key == "agentconnect": firstname = flow_message["firstname"] reply = f"Thank you for reaching out {firstname}. An agent will reach out to you the soonest" else: firstname = flow_message["firstname"] secondname = flow_message["secondname"] issue = flow_message["issue"] reply = f"Your response has been recorded. This is what we received:\n\n*NAME*: {firstname} {secondname}\n*YOUR MESSAGE*: {issue}" user_phone_number = request_data["entry"][0]["changes"][0]["value"]["contacts"][0][ "wa_id"] send_message(reply, user_phone_number, "FLOW_RESPONSE", name)
Здесь используется ключ (flow_key
) для различия двух сценариев и правильного извлечения ответов при передаче ID нужных первых экранов.
Перед запуском кода сравните его с полной версией и убедитесь, что всё совпадет.
Прежде чем продолжить, выполните в терминале указанную ниже команду.
flask --app main run --port 5000
Если всё сделано правильно, вы увидите указанное ниже сообщение.
* Running on http://127.0.0.1:5000
Выполните в терминале команду ngrok http 5000
, чтобы получить URL, связанный с вашим приложением. Скопируйте ссылку.
Далее в своем аккаунте на сайте Meta for Developers нажмите меню Конфигурация под пунктом WhatsApp на панели навигации в левой части экрана.
На карточке Webhook нажмите Редактировать.
В поле URL обратного вызова диалогового окна добавьте скопированный URL и добавьте в него /webhook
.
Добавьте маркер из переменной TOKEN
файла .env
в поле Маркер подтверждения. Нажмите Подтвердить и сохранить, чтобы закрыть диалоговое окно.
На этой же карточке нажмите Управлять и проверьте поле messages. Карточка должна выглядеть примерно так, как на скриншоте ниже.
Настройка Webhook завершена.
Вы можете отправить сообщение, например "Привет", на номер своего аккаунта. Вы должны получить соответствующее сообщение. Попробуйте ответить с помощью предложенного варианта меню, чтобы протестировать сценарий.
Ниже показан другой скриншот с ответом чат-бота. Пользователь просит быстро перевести сообщение, что бот и делает.
WhatsApp Flows — это эффективный инструмент, который помогает компаниям собирать структурированную информацию, улучшать взаимодействие с клиентами и упрощать коммуникацию между бизнесом и клиентами. Один из способов создать сценарий — использовать Flow Builder в WhatsApp Manager с простым интерфейсом.
Это демо-приложение помогает посмотреть, как использовать WhatsApp Flows для улучшения взаимодействия с клиентами и выполнения анализа на основе данных. Для большей персонализации вы также можете настроить Llama 2 и WhatsApp Flows, чтобы подключить чат-бот к собственной модели или натренировать ее на своем источнике данных. В таком случае чат-бот сможет отвечать на вопросы на естественном языке о вашем продукте и его функциях.
Используйте WhatsApp Flows, чтобы улучшить взаимодействие с клиентами и упростить сбор данных в ваших приложениях. Скорее попробуйте этот инструмент.