COM.lounge GmbH

So programmierst du einen Facebook Messenger-Bot

Tutorial: Facebook Messenger-Bots mit Python

Wie letztens berichtet, hat Facebook auf der diesjährigen f8-Entwicklerkonferenz ein neues Feature präsentiert: Facebook Messenger-Bots. Zeit also, sich einmal anzuschauen, was man mit diesen Chat-Bots so machen kann. In diesem Tutorial beschreibe ich daher zunächst das Setup und anschließend eine Beispiel-Implementierung eines einfachen Bots mit Hilfe von Flask und Python. Dies in einer anderen Sprache zu implementieren sollte dabei aber kaum komplizierter sein. Alles, was du können musst, ist, einen Web-Server aufzusetzen, JSON zu verarbeiten und HTTP-Requests abzusenden. Die Facebook-Dokumentation findest du ansonsten hier.

[toc]

Was du für einen Facebook Messenger-Bot brauchst

Um einen Facebook Messenger-Bot zu implementieren brauchst du nicht viel. Hauptsächlich benötigst du einen Web-Server mit SSL-Unterstützung, auf dem der Bot dann laufen soll. Weiterhin bedarf es einer Facebook-Seite und einer Facebook-App. Es können dazu auch bestehende Seiten und Apps genutzt werden. Beides muss nicht zwangsläufig veröffentlicht sein, um den Bot damit betreiben zu können.

Die Seite dient dabei als Ankerpunkt des Bots, denn auf Facebook sendet man Nachrichten ja entweder an Personen oder an Seiten. Die App dient dazu, die notwendige Infrastruktur (wie den Webhook) bereitzustellen. Damit kann dann ein Mensch über die Seite mit deiner App und damit deinem Server kommunizieren.

Für dieses Tutorial benötigst du außerdem noch Python 3, flask und die requests-Library. Python-Kenntnisse sind sicherlich auch hilfreich. Wie oben schon gesagt, sollten die Konzept aber recht einfach auf andere Sprachen zu übertragen sein.

Python aufsetzen

Zunächst setzen wir die Server-Seite auf. Ich gehe davon aus, dass Python 3 installiert ist. Python 2.7 tut es sicherlich auch, nur die Syntax ist dann leicht anders. Zudem braucht man das venv-Paket. Wechsel dann in das Verzeichnis, in dem der Bot leben soll. Dort erstellst Du dann ein virtual environment und installierst die notwendigen Pakete:

pyvenv .
source bin/activate
pip install flask requests

Danach erstellst Du zum Testen eine einfache Flask-App mit dem Namen bot1.py. Diese dient zunächst nur zum Testen des Servers.

https://gist.github.com/mrtopf/e8604b71ac9e54370628eafa45f9b160

Danach kann man den Server mit python bot1.py starten.

Als nächstes musst du dann deinen Web-Server so konfigurieren, dass er diesen Python-Server unter einer öffentlichen URL bereitstellt. Wichtig ist dabei, dass er unter https, also verschlüsselt, erreichbar sein muss. Da dies hier ein bisschen zu weit führen würde, verweise ich dazu mal auf Google. (Dort findet man z.B. eine Anleitung für nginx mit uwsgi). Ich persönlich habe das einfach auf unserer Domain laufen lassen (denn die hat schon SSL) und unter nginx wie folgt konfiguriert:

    location /testbot {
          proxy_pass http://127.0.0.1:8888;
    }

Wenn alles funktioniert hat, sollte der Server dann unter dem Pfad /testbot mit Hello, World! antworten.

Seite und App einrichten

Wenn du noch keine Seite hast,  die du mit dem Bot assoziieren willst, musst du eine erstellen. Dies geht unter diesem Link. Der Typ dürfte egal sein, für meinen Test habe ich einfach Community genommen. Die Seite selbst muss dazu nicht veröffentlich werden, sie muss aber existieren.

Auch bei der App kann man entweder eine bestehende App nutzen oder eine neue erstellen. Dies geht mit Hilfe dieses Links. Ich habe dazu den Typ „Website“ gewählt und das sieht dann wie folgt aus:

Facebook Messenger-Bot: App erstellen

Facebook Messenger-Bot: App erstellen

Als nächstes musst du eine Kontakt-E-Mail-Adresse angeben und die Kategorie auf „Apps für Seiten“ stellen. Test-Version bleibt ausgeschaltet. Nach Absenden des Formulars bist du an sich fertig, du kannst dann auf „Skip Quickstart“ oben rechts klicken. Danach erscheint das App-Dashbord.

Seite und App für den Facebook Messenger-Bot verknüpfen

Im App-Dashboard gibt es jetzt einen neuen Menüpunkt „Messenger“. Klickt man auf diesen zum ersten Mal, erscheint eine Info-Box, die man bestätigen muss. Danach erscheint dann folgender Screen:

 

Facebook Messenger-Bot: Das App-Dashboard

Facebook Messenger-Bot: Das App-Dashboard

Dort kannst du diese App mit der entsprechenden Seite verknüpfen. Wähle dazu in dem oberen Bereich (hier blau umrahmt) die zu verknüpfende Seite aus (ggf. gehen dabei ein paar Facebook-Popups auf, die nach weiteren Berechtigungen fragen). Ist dies geschehen, erscheint ein Access-Token neben der Seitenauswahl. Klicke darauf, um es zu kopieren. Beachte, dass dies dort nicht stehen bleibt. Wenn du es also erneut brauchst, musst du erneut die Seite auswählen und es erscheint wieder (bleibt wohl auch immer gleich).

Dieses Token wird dann im folgenden Aufruf genutzt, den du in einer Shell tätigen musst:

curl -ik -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<token>"

Der Aufruf sollte ein {"success":true} zurückgeben. 

Damit erhält dann die App Updates von der Seite (denn normalerweise empfängt ja eine Seite Chat-Nachrichten und keine App). Wenn Du das nicht tust, dann wird nie eine Nachricht an die Seite bei der App und damit bei deinem Bot/Server ankommen. Das Token ist zudem nur für genau diese App- und Seiten-Kombination gültig.

Webhooks einrichten

Damit nun die App auch Nachrichten empfängt, muss ein Webhook eingerichtet werden. Dies ist der Server-Endpunkt auf deiner Seite, wo Facebook dann die vom Benutzer empfangenen Nachrichten hinschickt.

Dazu kannst du folgendes flask-Programm nutzen, das du unter bot2.py speichern kannst.

https://gist.github.com/mrtopf/1e7f1500ae1277fd04ec8887a9bcba25

Wichtig dabei ist die Zeichenkette cd7czs87czds8chsiuh9eh3k3bcjhdbjhb. Diese kannst du selbst wählen und dient dazu, dass Facebook weiß, dass dieser Server und die App vom selben Autor kommen (also ein shared secret). Diese Zeichenkette muss sowohl in deinem Programm als auch im Webhook-Dialog eingetragen sein.

Sobald der Bot mit python bot2.py dann läuft, kannst du auf den Button „Webhooks“ im Messenger-Bereich der App klicken (nicht den Menüpunkt „Webhooks“).

Folgendes erscheint und hier trägst du dieselbe Zeichenkette wie im Script ein:

Setup der Facebook Messenger Webhooks

Setup der Facebook Messenger Webhooks

Am besten nutzt du natürlich ein eigenes Token. Die Berechtigungen klickst du am besten alle an.

Wenn alles funktioniert hat, sollte nach Absenden des Formulars ein „Abgeschlossen“ im Webhook-Bereich erscheinen.

Und damit haben wir jetzt die Seite und die App verknüpft sowie die App mit dem Server.

Nachrichten empfangen und senden

Das heißt, dass wir jetzt bereit sind, Nachrichten zu empfangen. Dazu braucht es natürlich noch etwas Code.

Regeln wir zunächst den Empfang. Sendet ein Benutzer nun etwas an den Bot (bzw. der Seiten-Administrator, solange der Bot noch nicht von Facebook freigeschaltet wurde), so kommt dies an dem Webhook an, der auch die Verifizierung geregelt hat. Es ist also dieselbe URL, nur ein POST- statt einem GET-Request.

Die Nachricht selbst ist JSON-kodiert und sieht bei einem „Hallo Bot!“ wie folgt aus:

https://gist.github.com/mrtopf/9c2220729a7b7cff683f290597470cff

Wichtig ist der messaging-Teil, der eine Liste von Nachrichten enthält. Diese wiederum enthalten eine Message-ID (mid), eine Sequenz-Nummer (mir ist nicht bekannt, ob die auch gemischt angekommen können), den Empfänger (die Seiten-ID) sowie den Sender als ID und einen Timestamp. Die Sender-ID ist dabei nicht die Facebook-ID des Benutzers, sondern eine eigene ID für diese Anwendung.

Mit bot3.py können wir dies nun lesen und mit einer einfachen Textnachricht antworten:

https://gist.github.com/mrtopf/91b2b3fbe970c7b4849fc77a8272a6d2

Wie man sieht, braucht man zum Senden ein Page-Token. Dies ist dasselbe Token, das man oben im curl-Befehl benutzt hat. Du findest es wie gehabt im Menüpunkt „Messenger“ im App-Dashboard ganz oben nach Auswahl der verknüpften Seite. Solange PAGE_TOKEN nicht das richtige Token enthält, wird der Bot nicht antworten.

Mit Hilfe dieses Tokens kann dann die Graph-API angesprochen werden. Der Bot sendet die Nachricht also nicht als Antwort direkt an den Webhook zurück, sondern asynchron. Dies hat den Vorteil, dass man auch später noch Nachrichten schicken kann, ohne dass der Benutzer erst wieder etwas sagen muss. Man sollte dabei nur die Facebook-Richtlinien und den gesunden Menschenverstand beachten. So dürfen z.B. keine reinen Werbenachrichten darüber versendet werden.

Das Format der Nachrichten werde ich ausführlicher in einem separaten Artikel beschreiben (zusammen mit den strukturierten Nachrichten). Im Prinzip sieht eine Text-Nachricht aber wie folgt aus:

https://gist.github.com/mrtopf/9db67af2036b9cee390df382011358c2

Die Recipient-ID ist dabei die Sender-ID aus der Anfrage.

Ein Bild senden

Ein Bild sagt mehr als 1000 Worte! Wie also sendet man ein Bild? Ironischerweise, indem man gefühlt 1000 Worte schreibt, denn der Code für ein Bild ist schon ein bisschen größer. Hier ist die Methode send_image():

https://gist.github.com/mrtopf/3b63c5eb1e43a518a5e21c9d683f352e

Diese kann man einfach in bot3.py einfügen und dann wie folgt aufrufen:

https://gist.github.com/mrtopf/936e0ddae9c4cf21b44cea60b9ad77e8

Hier wird also zusätzlich zum Text noch eine weitere Text-Nachricht und dann ein Bild gesendet. Das sieht im Messenger dann wie folgt aus:

Messenger Bot Beispiel: Antwort mit Text und Bild

Messenger Bot Beispiel: Antwort mit Text und Bild

Die Struktur der Nachricht ist dabei so komplex, da es schon in Richtung strukturierter Nachrichten geht. Da dieser Artikel aber schon ein wenig lang ist, gibt es weitere Details und eine Beispiel-Implementierung im nächsten Artikel.

Troubleshooting

Wenn man einen Bot implementiert, funktioniert natürlich nicht immer alles. Ein paar der Probleme, die ich hin und wieder hatte und wie man diese behebt, findest du hier:

Der Bot bekommt keine Nachrichten

Wenn der Bot keine Requests bekommt, kann es sein, dass man vergessen hat, die Page-App-Verbindung herzustellen. Dazu führt man einfach den oben beschriebenen curl-Befehl mit dem Page-Access-Token aus.

Die Webhooks konnten nicht (mehr) erreicht werden

Es kann manchmal bei der Entwicklung sein, dass der Server nicht immer läuft. Facebook merkt das ggf. und beendet dann die Webhook-Verbindung. Dies sieht man dann im Menüpunkt „Benachrichtigungen“ im App-Dashboard. Der einfachste Weg, diese wieder zu aktivieren, ist eine erneute Aktivierung des Webhooks. Dazu entfernt man den bestehenden Webhook im Menüpunkt „Webhooks“ im App-Dashboard. Danach kann man den ihn mit dem Verifizierungs-Token im Menüpunkt „Messenger“, wie oben beschrieben, neu erstellen. Danach sollte wieder alles funktionieren (soweit der Server funktioniert).

Ein Fehler im Script ist aufgetreten

Hat man einen Fehler in seinem Server und antwortet dieser daher mit etwas anderem als Status-Code 200, gibt es ein kleines Timeout bei Facebook. D.h. nach Fixen des Fehlers muss man ca. 1 Minute warten, bis Facebook wieder Nachrichten an den Server schickt. Leider etwas nervig und es wäre schön, wenn unveröffentlichte Bots diese Einschränkung nicht hätten.

Ich hoffe, diese Tutorial war hilfreich. Im nächsten Artikel beschreibe ich dann, wie man strukturierte Nachrichten sendet, wie diese strukturiert sind und wie man einen Willkommens-Screen erstellt.

 

Bildnachweis:
D J Shin, S.H Horikawa – Star Strider Robot (スターストライダーロボット) – Front, D J Shin, QSH Tin Wind Up Mechanical Robot (Giant Easelback Robot) Side, Collage von Christian Scholz, CC BY-SA 3.0