Noch nie zuvor haben so viele Unternehmen auf WhatsApp-Chatbots gesetzt, um mit ihrer Kundschaft in Kontakt zu treten, mehr über ihre Bedürfnisse zu erfahren und wichtige Daten zu erheben. Das Erfassen und Organisieren dieser Daten effizient zu gestalten, kann jedoch eine Herausforderung darstellen. Und genau da kommt WhatsApp Flows ins Spiel.
Die Integration von Chatbots mit WhatsApp Flows erleichtert Unternehmen die effiziente Auswertung eingehender Kund*inneninformationen. Je nach Gesprächskontext können die Chatbots dann speziell auf die Datenerfassung ausgerichtete Flows starten.
Im Rahmen dieses Tutorials erstellst du auf Basis von Llama 2 und Python einen Chatbot und verknüpfst diesen mit WhatsApp Flows, um seine Datenerfassungsmöglichkeiten zu verbessern. Du erfährst dabei, wie WhatsApp Flows die Nutzer*innenfreundlichkeit des Chatbots steigert und die Genauigkeit und Effizienz der Erfassung von Kund*innendaten optimiert.
Wenn dein Chatbot Nutzer*innenanfragen oder Eingabeaufforderungen erhält, reagiert er darauf mit WhatsApp Flows zur Datenerfassung. Konkret bedeutet das: Die Nutzer*innen können sich mit dem Chatbot unterhalten, sich über die Dienstleistungen eines fiktiven Hotels in Spanien informieren und dann das Unternehmen kontaktieren, sollten sie Unterstützung benötigen.
Der Chatbot greift auf einfache if
-Anweisungen in Verbindung mit dem Standardmodell von Llama 2 zurück, um Zugang zu einer ausreichend großen allgemeinen Wissensdatenbank zu schaffen.
Teil 1:
Erstelle Flows mit dem WhatsApp Manager Flow Builder.
Teil 2:
Konvertiere das Llama 2-Modell von GGML in GGUF.
In diesem Lernabschnitt erstellst du Flows mit dem Flow Builder. Alternativ kannst du auch die Flows API nutzen, auf die wir hier jedoch nicht näher eingehen.
Das benötigst du für dieses Tutorial:
Eine abgeschlossene Installation von ngrok.
Ein verifiziertes Entwickler*innenkonto bei Meta for Developers und Erfahrung mit der von Meta gehosteten Cloud API.
Du musst außerdem die erforderlichen Schritte für die Verwendung von Flows abgeschlossen haben. Du kannst dir auch eine Vorschau des kompletten Projektcodes ansehen.
Rufe zunächst in deinem WhatsApp-Unternehmenskonto die Seite Flows auf. Falls du zum ersten Mal mit Flows arbeitest, solltest du nun den Button Mit Flows loslegen sehen. Andernfalls findest du oben rechts auf der Seite den Button Flow erstellen.
Klicke auf den entsprechenden Button, um ein Dialogfeld zu öffnen. Dort kannst du ein paar Details zu deinem Flow eingeben:
Erstelle als Erstes einen Flow, der es Nutzenden ermöglicht, sich über die Dienstleistungen des Hotels zu informieren.
Gib einen Namen in das Feld Name ein. Wähle dann im Dropdown-Menü Kategorien die Option Registrieren aus und belasse beim Dropdown-Menü Vorlage die Auswahl auf Keine. Klicke auf Senden.
Auf der nächsten Seite siehst du links einen Editor und rechts eine Vorschau.
Ersetze die Inhalte im Editor mit dem JSON-Markup für deinen Flow. (Weitere Informationen zur Flow-JSON findest du in der Entwickler*innen-Dokumentation.)
Wenn du den Flow speicherst, sollte deine Vorschau so aussehen wie hier im Bild:
Der Flow besteht aus einem Bildschirm, in dem die Nutzer*innen ihre Daten eingeben, die relevanten Dienste auswählen und optional eine zusätzliche Nachricht einfügen können. Sobald die Nutzenden auf Senden klicken, wird der Flow geschlossen und die erfassten Daten werden zur Verarbeitung an dein Unternehmen weitergeleitet. Eine Methode zur Übermittlung dieser Daten ist der Einsatz von Endpunkten. Für dieses Projekt wird jedoch kein Endpunkt benötigt. Die Daten werden an denselben Webhook weitergeleitet, über den auch der Chatbot läuft.
In diesem Fall kannst du die Daten mithilfe von Aktionen übertragen. Welche Daten an den nächsten Bildschirm weitergegeben werden sollen, legst du mit dem payload
-Objekt fest:
... "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" } } ...
Im Code-Ausschnitt wird durch den Button-Klick der Nutzer*innen on-click-action
ausgelöst, wodurch die Daten in der Payload erfasst werden. Anschließend wird die Payload an deinen Webhook-Server gesendet und der Flow mit der complete
-Aktion abgeschlossen.
Du kannst die payload
-Schlüssel genauso zuweisen wie jede andere Variable. Die entsprechenden Werte können Datenobjekte oder die Namen von Flow-Komponenten darstellen (ähnlich wie das Namensattribut eines HTML-Formulars).
Nun kannst du dir den Flow im Einsatz ansehen und ein echtes Nutzer*innenerlebnis simulieren, indem du die interaktive Vorschau aktivierst:
Aktuell ist der Flow noch im Entwurf-Status. Nachdem du das Testen abgeschlossen hast, kannst du ihn veröffentlichen. Öffne dazu das Menü rechts neben Speichern und klicke auf Veröffentlichen. Der Flow ist jetzt fertig und einsatzbereit.
Nun erstellst du einen „Kontaktiere uns“-Flow.
Wiederhole zunächst die ersten Schritte der Flow-Erstellung. Wähle dieses Mal als Kategorie Kontaktiere uns aus. Ersetze die Inhalte im Editor mit diesem JSON-Markup, um die folgende Darstellung zu erhalten:
Veröffentliche den Flow und fahre mit dem nächsten Abschnitt fort, um einen Chatbot einzurichten. Der Abschnitt behandelt drei Funktionen, die wichtige Logik für das Senden der Flows an die Nutzer*innen enthalten: send_message
, flow_details
und flow_reply_processor
. Darüber hinaus findest du dort auch die Logik für die Verarbeitung eingehender Flow-Payloads. Wir empfehlen dir daher, den Abschnitt auch dann durchzugehen, wenn du schon einen Chatbot erstellt hast.
Als Nächstes konfigurierst du den Chatbot und integrierst ihn in deine Flows.
Das benötigst du zum Fortfahren mit diesem Teil des Tutorials:
Eine aktuelle Version von Python und entsprechende Grundkenntnisse.
Die heruntergeladene HuggingFace-Version von Llama 2. Für das HuggingFace Llama 2-Modell benötigst du keine zusätzlichen Tools oder spezielle Hardware. Du kannst auch die offizielle Version nutzen, allerdings ist dann eine weitergehende Einrichtung erforderlich.
Den Zugriffsschlüssel und die Telefonnummer-ID deines Kontos.
Einen Code-Editor.
Der Chatbot funktioniert über ein vorgefertigtes Skript, das den Nutzer*innen je nach ihren Eingaben weiterhilft. Bei der ersten Interaktion erscheint ein personalisierter Begrüßungstext und ein textbasiertes Menü, das von der Nachricht der Nutzenden abhängt. Die Optionen sind auf die jeweiligen Bedürfnisse zugeschnitten: Abfrage der vom Hotel angebotenen Dienstleistungen, Kontaktaufnahme mit Hotelmitarbeiter*innen oder Interaktion mit einem Llama-basierten Chatbot.
Wenn die Nutzer*innen mit einem alphanumerischen Zeichen antworten, werden sie zum entsprechenden Dienst oder zur entsprechenden Aktion weitergeleitet. Alle sonstigen Antworten stoßen die standardmäßigen Chatbot-Funktionalitäten an, die bei allgemeinen Anfragen weiterhelfen oder den Nutzenden in Abhängigkeit von der weiteren Unterhaltung die verfügbaren Dienste vorstellen.
Erstelle zunächst eine virtuelle Umgebung, indem du den folgenden Befehl in deinem Terminal ausführst:
python -m venv venv
Nimm die Aktivierung vor:
source venv/bin/activate
Installiere dann die erforderlichen Pakete:
pip install requests flask llama-cpp-python python-dotenv
Für die Erstellung von Routen und die Interaktion mit der API verwendest du Flask
, für das Senden von Internetanfragen requests
, für die Interaktion mit dem Modell llama-cpp-python
und für das Laden von Umgebungsvariablen python-dotenv
.
Anschließend erstellst du eine Umgebungsdatei mit der Endung .env
und den folgenden Inhalten, wobei du die Werte entsprechend zuweist. (Als TOKEN
kannst du einen beliebigen String nutzen.)
TOKEN = ACCESS_TOKEN = PHONE_NUMBER_ID =
Erstelle im selben Verzeichnis eine Datei mit dem Namen main.py
und füge als Erstes die Pakete hinzu, die du verwenden möchtest:
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
Initialisiere jetzt die Variablen und Klassen. Der Code-Ausschnitt startet zudem Flask und ruft die Methode load_dotenv()
auf, um die Variablen zu laden:
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" ]
In „service_list“ werden die vom Hotel angebotenen Dienstleistungen gespeichert. Die Liste code_prompt_texts
enthält die Optionen, die den Eingabemöglichkeiten der Nutzer*innen entsprechen. Das sind in diesem Fall 1, 2, Y und N unter Verwendung der folgenden Funktion. Die nachstehende Funktion dient dazu, die Antworten der Nutzenden der richtigen Option zuzuordnen.
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
Der Code wandelt die Strings in Kleinbuchstaben um, damit es bei der Ausführung der bedingten Logik zu keinen Fehlern kommt. Die match…case
-Struktur ordnet die Eingaben der Nutzer*innen den Ausgaben zu. Gibt ein*e Nutzer*in zum Beispiel die Zahl „1“ ein, wird die Funktionalität "Contact us"
ausgelöst.
Die folgende Funktion enthält eine if
-Anweisung, die das Python RegEx-Paket re
nutzt, um nach bestimmten Begriffen in der Nachricht des*der Kund*in zu suchen und zu entscheiden, welche Art von Antwort gesendet werden soll:
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)
Eine Nachricht wie "Hello there"
löst etwa die Methode send_message
mit SEND_GREETINGS_AND_PROMPT
als zweitem Argument aus. Unten siehst du die Methode send_message
. Ändere den Inhalt zwischen <xxx>
entsprechend deinen Wünschen ab.
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")
Handelt es sich bei der Nachricht um eine einfache Begrüßung (SEND_GREETINGS_AND_PROMPT
), enthält die Antwort zusätzliche Eingabeaufforderungen (greetings_text_body
).
Wenn Nutzende eine Frage zu den angebotenen Dienstleistungen stellen, wird ihnen analog dazu eine SMS (service_intro_text
) mit den Dienstleistungen gesendet. Neben den Dienstleistungen enthält die SMS auch eine Eingabeaufforderung, über die sie angeben können, ob sie mit einem*einer Mitarbeiter*in sprechen möchten.
Falls die Eingabe eine Chatbot-Antwort (CHATBOT
) erfordert, initialisierst du das Modell, übermittelst ihm den Inhalt der Nachricht, verarbeitest die Antwort und sendest diese an den*die Nutzer*in zurück. FLOW_RESPONSE
zeigt die erfasste Antwort eines Flows an.
Die beiden anderen Optionen – CONTACT_US
und TALK_TO_AN_AGENT
– senden Flow-Payloads an den*die Nutzer*in. Die Flow-Payloads stammen aus der Funktion flow_details
. Den Body dazu siehst du unten. Die Payload enthält die wesentlichen Flow-Details einschließlich der FLOW_ID
, die du in deinem WhatsApp-Unternehmenskonto auf der Seite Flows abrufen kannst. Du kannst diese IDs aber auch in deinen Umgebungsvariablen definieren.
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
Bei dieser Methode wird der action.parameters.flow_token
durch die Generierung einer zufälligen UUID erstellt. action.parameters.flow_action_payload.screen
wird als Parameter (screen_id
) übermittelt. Im Idealfall handelt es sich dabei um die ID des ersten Bildschirms, den du den Nutzenden bei der Ausführung von action.parameters.flow_cta
zeigen möchtest.
Füge abschließend die Webhook-Routen hinzu. Die GET
-Anfrage für den Webhook wird gestartet, wenn du den Webhook zu deiner App auf Meta for Developers hinzufügst. Bei erfolgreicher Ausführung wird die hub.challenge
der Anfrage ausgegeben.
@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)
Die POST
-Anfrage extrahiert und verarbeitet die Payload der Nachricht mithilfe der bereits erwähnten Methode user_message_processor
. Da der Code nur für die Nachrichten-Payload gilt, wird ein Fehler ausgegeben, wenn andere Payloads erfasst werden. Du kannst daher mithilfe einer if
-Anweisung prüfen, ob es einen messages
-Body gibt.
@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)
Daneben kannst du mit der Hilfstool-Funktion flow_reply_processor
die Antwort aus dem Flow extrahieren und an den*die Nutzer*in senden:
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)
Die Funktion verwendet einen Schlüssel (flow_key
), um zwischen den beiden Flows zu unterscheiden und die passenden Antworten zu extrahieren, wobei die korrekten IDs des ersten Bildschirms übertragen werden.
Vergleiche den Code vor dem Ausführen mit der vollständigen Version und vergewissere dich, dass alles passt.
Bevor du fortfährst, führst du diesen Befehl in deinem Terminal aus:
flask --app main run --port 5000
Bei erfolgreicher Ausführung solltest du die folgende Meldung sehen:
* Running on http://127.0.0.1:5000
Führe anschließend den Befehl ngrok http 5000
aus, um eine URL zu erhalten, die zu deiner App führt. Kopiere den Link.
Klicke dann in deinem Entwickler*innenkonto auf Meta for Developers in der linken Navigationsleiste unter WhatsApp auf das Menü Konfiguration:
Klicke in der Karte Webhook auf Bearbeiten.
Daraufhin öffnet sich ein Dialogfenster. Füge dort unter Callback-URL die kopierte URL ein und hänge /webhook
an.
Füge den Schlüssel aus der TOKEN
-Variablen deiner .env
-Datei in das Feld Verifizierungstoken ein. Klicke auf Bestätigen und speichern, um den Dialog zu schließen.
Klicke nun in derselben Karte auf Verwalten und aktiviere das Feld Nachrichten. Die Karte sollte jetzt folgendermaßen aussehen:
Der Webhook ist nun bereit.
Sende eine Nachricht wie „Hallo“ an die Nummer deines Kontos. Du solltest dann die passende Antwort erhalten. Versuche, mit einer der im Menü angezeigten Eingabeaufforderungen zu antworten, um die Flows zu testen:
Unten siehst du einen weiteren Screenshot, der die Antwort des Chatbots zeigt. Der*Die Nutzer*in bittet um die Übersetzung eines kurzen Textes, was der Bot umgehend erledigt.
WhatsApp Flows sind ein leistungsstarkes Tool für Unternehmen, um strukturierte Informationen zu erfassen, die Interaktion mit Kund*innen zu verbessern und die Kommunikation zwischen Unternehmen und Verbraucher*innen zu optimieren. Für die Erstellung von Flows steht dir unter anderem der WhatsApp Manager Flow Builder zur Verfügung, in dem du über eine bedienfreundliche Oberfläche Flows gestalten kannst.
Diese Demo bietet dir einen kleinen Eindruck davon, wie du WhatsApp Flows für eine verbesserte Kund*inneninteraktion und datengestützte Analysen nutzen kannst. Auch ganz individuelle Anwendungsfälle sind möglich. Du kannst über die Konfiguration von Llama 2 und WhatsApp Flows deinen Chatbot mit einem eigenen Modell verknüpfen oder ihn anhand einer eigenen Datenquelle trainieren, damit er in natürlicher Sprache gestellte Fragen zu deinem Produkt und anderen Funktionen beantworten kann.
Mithilfe von WhatsApp Flows kannst du die Interaktion mit deinen Kund*innen verbessern und die Datenerfassung in deinen Anwendungen optimieren. Probiere es gleich aus!