Un nombre croissant d’entreprises utilisent aujourd’hui des bots de discussion sur WhatsApp afin d’entrer en contact avec leurs client·es, de comprendre leurs besoins et de recueillir des données essentielles. Ce processus de collecte et d’organisation des données peut néanmoins représenter un défi en matière d’efficacité. Découvrez WhatsApp Flows.
L’intégration de bots de discussion à WhatsApp Flows permet aux entreprises d’interpréter plus efficacement les informations obtenues sur la clientèle. Les bots de discussion peuvent lancer des flux spécifiques destinés à recueillir des informations en fonction du contexte de la conversation.
Dans ce tutoriel, vous développerez un bot de discussion à l’aide de Llama 2 et de Python, et vous le connecterez à WhatsApp Flows afin de booster ses capacités de collecte de données. Ce faisant, vous découvrez comment WhatsApp Flows améliore la convivialité de l’expérience du bot de discussion, ainsi que la précision et l’efficacité de la collecte des données de la clientèle.
Votre bot de discussion répond aux questions et invites des utilisateur·ices à l’aide de WhatsApp Flows afin de collecter des données. Il leur permet plus précisément d’échanger, de chercher des informations concernant les services proposés par un hôtel fictif en Espagne et d’entrer en contact avec l’entreprise afin d’obtenir de l’aide.
Le bot de discussion utilise de simples instructions if
en parallèle du modèle Llama 2 standard afin d’offrir un accès à une base de connaissances générale suffisante.
Étape 1 :
Créez des flux à l’aide de l’éditeur de flux du Gestionnaire WhatsApp.
Étape 2 :
Convertissez le modèle Llama 2 du format GGML au format GGUF.
Pour cette étape, vous utiliserez l’éditeur de flux afin de créer des flux. Vous pouvez également utiliser l’API Flows, dont nous ne parlerons pas ici.
Avant de continuer, vérifiez que les conditions suivantes sont remplies :
ngrok est installé.
Vous disposez d’un compte de développeur sur Meta for Developers qui a été vérifié et vous êtes familiarisé·e avec l’API Cloud, hébergée par Meta.
Pour finir, assurez-vous que vous avez effectué les étapes obligatoires pour pouvoir utiliser WhatsApp Flows. Vous pouvez également prévisualiser le code de l’intégralité du projet.
Pour commencer, accédez à la page Flux sur votre compte WhatsApp Business. Si vous utilisez les flux pour la première fois, vous devriez voir un bouton intitulé Commencer à créer des flux. Si ce n’est pas le cas, vous trouverez un bouton Créer un flux en haut à droite de la page.
Cliquez sur le bouton disponible pour afficher une boîte de dialogue dans laquelle vous pouvez saisir des informations relatives à votre flux :
Vous allez commencer par créer un flux permettant à l’utilisateur·ice de chercher des informations sur les services proposés par une société hôtelière.
Saisissez un nom dans le champ Nom. Sous le menu déroulant Catégories, choisissez ensuite Inscription. Ne modifiez pas le menu déroulant Modèle, qui doit être défini sur Aucun. Cliquez sur Envoyer.
Sur la page suivante, vous pouvez voir un éditeur sur la gauche et un aperçu sur la droite.
Remplacez les données de l’éditeur par le balisage JSON de votre flux. (Pour en savoir plus sur les flux JSON, consultez la documentation de développement.)
Enregistrez le flux. Votre aperçu devrait ressembler à l’image ci-dessous :
Le flux comporte un écran permettant à l’utilisateur·ice de saisir ses données, de sélectionner les services qui l’intéressent et d’ajouter un message facultatif. Lorsque l’utilisateur·ice clique sur Envoyer, le flux se ferme et envoie les données capturées à votre entreprise pour qu’elle les traite. L’une des méthodes de transfert des données consiste à utiliser des points de terminaison. Nous n’avons néanmoins pas besoin de point de terminaison dans le cadre de ce projet. Les données seront transférées au webhook qui gère le bot de discussion.
Vous pouvez réaliser ce transfert grâce aux actions. Il vous suffit de définir les données à transférer vers l’écran suivant à l’aide de l’objet 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" } } ...
Dans l’extrait de code, le clic de l’utilisateur·ice sur le bouton déclenche on-click-action
, qui permet de capturer les données de la charge utile. La charge utile est ensuite envoyée à votre serveur webhook, ce qui a pour effet de fermer le flux via l’action complete
.
Vous pouvez affecter les clés payload
comme pour toute autre variable. Les valeurs correspondantes peuvent représenter des objets de données ou bien les noms des composants du flux (à l’instar d’un attribut de nom du formulaire HTML).
Votre flux est désormais opérationnel, et vous pouvez simuler l’expérience réelle des utilisateur·ices grâce au bouton à bascule Aperçu interactif :
Après avoir effectué des tests, vous pouvez publier le flux, qui se trouve actuellement à l’état Brouillon. Pour ce faire, ouvrez le menu à droite du libellé Enregistrer et cliquez sur Publier. Le flux est désormais opérationnel et fonctionnel.
Vous allez désormais créer un flux Nous contacter.
Commencez par répéter le processus de création de flux initial. Sélectionnez Nous contacter comme catégorie. Remplacez les données de l’éditeur par ce balisage JSON de votre flux pour obtenir le rendu suivant :
Publiez le flux et passez à la section suivante pour configurer un bot de discussion. La section comprend trois fonctions (send_message
, flow_details
et flow_reply_processor
) qui renferment la logique permettant l’envoi des flux aux utilisateur·ices. Cette section contient également la logique de traitement des charges utiles de flux entrantes. C’est pourquoi nous vous recommandons de la vérifier même si vous avez déjà développé un bot de discussion.
Vous allez ensuite configurer le bot de discussion et l’intégrer dans vos flux.
Avant de continuer, vérifiez que les conditions suivantes sont remplies :
Vous disposez de connaissances de base sur Python, ainsi que d’une version récente du logiciel.
La version HuggingFace de Llama 2 doit être téléchargée. Le modèle HuggingFace de Llama 2 ne nécessite aucun outil supplémentaire ou matériel spécialisé. Vous pouvez également utiliser la version officielle, mais celle-ci nécessite une configuration supplémentaire.
Vous disposez du token d’accès à votre compte et de l’ID du numéro de téléphone.
Vous disposez d’un éditeur de code.
Le bot de discussion fonctionne grâce à un script prédéfini conçu pour aider les utilisateur·ices en fonction des informations saisies. Lors de la première interaction, il affiche un texte de bienvenue personnalisé et un menu textuel en fonction du message de l’utilisateur·ice. Ces options répondent à des besoins spécifiques : consulter les services proposés par l’hôtel, contacter l’un des membres de son personnel ou échanger avec un bot de discussion fonctionnant grâce à Llama.
En répondant par un caractère alphanumérique, l’utilisateur·ice sera redirigé·e vers l’action ou le service correspondants. Toute autre réponse déclenche cependant la fonctionnalité par défaut du bot de discussion, qui répond aux demandes d’ordre général ou oriente l’utilisateur·ice vers les services disponibles en fonction de la suite de la conversation.
Pour commencer, créez un environnement virtuel en exécutant la commande ci-dessous sur votre terminal :
python -m venv venv
Activez-la :
source venv/bin/activate
Installez ensuite les packages nécessaires :
pip install requests flask llama-cpp-python python-dotenv
Utilisez Flask
pour créer des routes et interagir avec l’API, requests
pour envoyer des requêtes Internet, llama-cpp-python
pour interagir avec le modèle, et python-dotenv
pour charger les variables de l’environnement.
Créez ensuite un fichier d’environnement intitulé .env
, ainsi que le contenu suivant. Veillez à affecter les valeurs appropriées. (Vous pouvez utiliser n’importe quelle chaîne pour TOKEN
.)
TOKEN = ACCESS_TOKEN = PHONE_NUMBER_ID =
Dans le même répertoire, créez un fichier intitulé main.py
et commencez par ajouter les packages à utiliser :
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
Vous devez désormais définir les variables et les classes. L’extrait de code initialise également Flask et appelle la méthode load_dotenv()
pour charger les variables :
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" ]
La liste service_list répertorie les services proposés par l’hôtel. La liste code_prompt_texts
répertorie les options correspondant aux saisies des utilisateur·ices, à savoir 1, 2, Y et N, en utilisant la fonction indiquée au-dessous. Cette dernière vous permet de mapper les réponses de l’utilisateur·ice avec l’option correspondante.
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
Le code modifie la casse des chaînes et les passe en minuscules afin d’éviter les incohérences lors de l’exécution de la logique conditionnelle. Sa structure match…case
associe les invites saisies par les utilisateur·ices aux sorties. Par exemple, lorsqu’un·e utilisateur·ice saisit « 1 », la fonctionnalité "Contact us"
est déclenchée.
Par ailleurs, la fonction suivante comporte une instruction if
qui utilise le package Python RegEx, re
, afin de rechercher certains termes dans le message d’un·e client·e pour décider du type de réponse à envoyer :
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)
Désormais, un message tel que "Hello there"
déclenchera la méthode send_message
avec SEND_GREETINGS_AND_PROMPT
comme deuxième argument. Vous trouverez ci-dessous la méthode send_message
. Remplacez le contenu entre <xxx>
par les informations appropriées.
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")
S’il s’agit d’un simple message de bienvenue (SEND_GREETINGS_AND_PROMPT
), la réponse comporte automatiquement des invites supplémentaires (greetings_text_body
).
De la même manière, lorsqu’un·e utilisateur·ice pose une question concernant les services proposés, un message (service_intro_text
) énumérant les différents services est lui envoyé. Celui-ci comporte également une invite qui permet d’échanger avec un·e agent·e en cas de besoin.
Si les données saisies nécessitent une réponse du bot de discussion (CHATBOT
), vous devez initialiser le modèle, lui transmettre le contenu du message et traiter la réponse à envoyer à l’utilisateur·ice. FLOW_RESPONSE
affiche la réponse capturée par un flux.
Les autres options, CONTACT_US
et TALK_TO_AN_AGENT
, envoient les charges utiles du flux à l’utilisateur·ice. Les charges utiles du flux proviennent de la fonction flow_details
, dont le corps est présenté ci-dessous. La charge utile comprend les informations essentielles du flux, notamment l’élément FLOW_ID
, que vous pouvez récupérer sur la page Flux de votre compte WhatsApp Business. Il est également possible de définir ces ID dans vos variables d’environnement.
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
Cette méthode crée l’élément action.parameters.flow_token
en générant un UUID aléatoire. L’élément action.parameters.flow_action_payload.screen
est transmis en tant que paramètre (screen_id
). Dans l’idéal, il doit comporter l’ID du premier écran que vous souhaitez montrer à l’utilisateur·ice lorsque l’élément action.parameters.flow_cta
s’exécute.
Pour finir, ajoutez les routes de webhook. La requête GET
de webhook s’initialise lors de l’ajout du webhook à votre application Meta for Developers. Elle renvoie l’élément hub.challenge
de la requête en cas de succès.
@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)
La requête POST
extrait et traite la charge utile du message à l’aide de la méthode user_message_processor
présentée précédemment. Comme le code ne s’occupe que de la charge utile du message, il émet des erreurs lors de la capture de toute autre charge utile. C’est pourquoi vous pouvez utiliser une instruction if
pour vérifier s’il y a un corps 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)
En outre, vous pouvez utiliser la fonction d’aide appelée flow_reply_processor
pour extraire la réponse du flux et la renvoyer à l’utilisateur·ice :
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)
Elle se sert d’une clé (flow_key
) pour différencier les deux flux et ainsi extraire correctement les réponses tout en transmettant les ID exacts du premier écran.
Avant d’exécuter le code, comparez-le à la version complète et vérifiez que tout est correct.
Avant de continuer, exécutez la commande suivante à partir de votre terminal :
flask --app main run --port 5000
Si tout se passe bien, vous devriez obtenir le message suivant :
* Running on http://127.0.0.1:5000
Exécutez ensuite ngrok http 5000
afin d’obtenir une URL qui correspond à votre application. Copiez le lien.
Dans votre compte de développeur sur Meta for Developers, cliquez ensuite sur le menu Configuration sous WhatsApp dans le volet de navigation de gauche :
Dans la fiche Webhook, cliquez sur Modifier.
Ensuite, dans le champ URL de rappel de la boîte de dialogue qui s’affiche, ajoutez l’URL copiée, puis /webhook
.
Ajoutez le token de la variable TOKEN
de votre fichier .env
dans le champ Vérifier le token. Cliquez sur Vérifier et enregistrer pour fermer la boîte de dialogue.
Depuis la même fiche, cliquez maintenant sur Gérer et activez le champ Messages. La fiche devrait ressembler à ce qui suit :
Le webhook est maintenant prêt.
Vous pouvez envoyer un message tel que « Bonjour » à votre numéro de compte. Vous devriez recevoir la réponse appropriée. Essayez de répondre à l’aide d’une invite affichée dans le menu afin de tester les flux :
Vous trouverez ci-dessous une autre capture d’écran montrant la réponse du bot de discussion. L’utilisateur·ice demande une traduction rapide, que le bot peut lui fournir.
WhatsApp Flows représente un outil performant pour les entreprises. Il leur permet de recueillir des informations structurées, d’améliorer les interactions avec la clientèle et de simplifier la communication entre les entreprises et les consommateur·ices. L’une des méthodes pour créer des flux consiste à utiliser l’éditeur de flux du Gestionnaire WhatsApp, qui propose une interface conviviale.
Cette application de démonstration propose un aperçu de la manière dont vous pouvez utiliser WhatsApp Flows pour améliorer les interactions avec la clientèle et l’analyse orientée données. Pour des usages plus spécialisés, vous pouvez également configurer Llama 2 et WhatsApp Flows afin de connecter votre bot de discussion à un modèle personnalisé ou de l’entraîner sur une source de données dont vous êtes propriétaire. Ce procédé lui permet de fournir des réponses qui semblent naturelles concernant votre produit et d’autres fonctionnalités.
Utilisez WhatsApp Flows dès maintenant pour améliorer vos interactions avec la clientèle et simplifier la collecte de données dans vos applications. Essayez sans plus attendre.