Wie man einen WhatsApp-Bot für To-Do-Listen mit der Programmable Conversations API von Bird erstellt

Vogel

05.02.2020

WhatsApp

1 min read

Wie man einen WhatsApp-Bot für To-Do-Listen mit der Programmable Conversations API von Bird erstellt

Wichtige Erkenntnisse

    • Bird’s Programmable Conversations API vereint WhatsApp, Messenger und SMS zu einer einzigen Kommunikationsschicht und vereinfacht die Entwicklung von Multi-Channel-Bots.

    • Sie können schnell einen WhatsApp-To-do-Listen-Bot mit Webhooks und einfachen POST-Anfragen prototypisieren.

    • Tools wie ngrok ermöglichen es Ihnen, Ihren lokalen Server für Webhook-Tests ohne komplexe Hosting-Einrichtung zu veröffentlichen.

    • Die API verwaltet Konversationen über mehrere Kanäle, sodass eine einzige Logikbasis für WhatsApp, WeChat und andere Apps genutzt werden kann.

    • Verwenden Sie den archiveConversation-Endpunkt, um Konversationen zu schließen oder „Themen“ zu archivieren, ideal für Support- oder Workflow-Tracking.

    • Die Bot-Logik kann gleichzeitige Konversationen sicher im Speicher mit einer einfachen Datenstruktur verwalten.

    • Der gleiche Webhook-Handler funktioniert kanalübergreifend—Bird leitet Antworten automatisch basierend auf der ursprünglichen Konversations-ID weiter.

Q&A Highlights

  • Wie schwer ist es, einen WhatsApp-Bot mit der Bird API zu bauen?

    Es ist überraschend einfach. Mit einem Webhook und ein paar API-Aufrufen können Sie innerhalb von Minuten einen funktionierenden Bot erstellen, der Nachrichten liest und darauf antwortet.

  • Brauche ich eine spezielle Einrichtung, um Nachrichten zu empfangen?

    Ja — der Bot muss aus dem Internet erreichbar sein. Tools wie ngrok helfen, einen sicheren Tunnel von Ihrem lokalen Rechner zu erstellen.

  • Kann ich denselben Codebase für verschiedene Messaging-Apps verwenden?

    Absolut. Die Conversations API abstrahiert Kanäle, sodass Ihr Bot auf WhatsApp, WeChat oder Messenger mit identischer Logik laufen kann.

  • Wie schließe oder setze ich einen Chat-Thread zurück?

    Senden Sie eine PATCH-Anfrage an den Endpunkt des Gesprächs mit dem richtigen Status, um es zu archivieren. Jede neue Nachricht öffnet automatisch ein neues Gespräch.

  • Wo kann ich Beispielcode finden?

    A: Die vollständige funktionierende Demo — Wabot auf GitHub — zeigt die Implementierung der Nachrichtenverarbeitung, Gleichzeitigkeit und Archivierung.

Bird hat kürzlich programmierbare Gespräche eingeführt. Damit können Unternehmen Kommunikationsplattformen wie WhatsApp, Messenger und SMS in ihre Systeme integrieren – mithilfe einer einzigen API.

Bird hat kürzlich Programmable Conversations eingeführt. Es ermöglicht Unternehmen, Kommunikationsplattformen wie WhatsApp, Messenger und SMS in ihre Systeme zu integrieren — mit einer einzigen API.

Ich wollte es ausprobieren, also habe ich einen WhatsApp-Bot für eine To-Do-Liste gebaut, weil wer braucht nicht eine automatisierte To-Do-Liste, um den Tag zu organisieren? Es mag kompliziert klingen, aber es war tatsächlich einfach, und ich möchte Ihnen alles darüber erzählen.

Jetzt arbeite ich bei MessageBird, also konnte ich sofort loslegen und anfangen zu bauen. Wenn Sie es versuchen, müssen Sie frühzeitigen Zugang anfordern. Aber sobald Sie mit einem WhatsApp-Kanal eingerichtet sind, können Sie auf das Dashboard auf der MessageBird-Website zugreifen und loslegen.

Das Erste, was ich tat, war, die Dokumentation zu lesen. Ich habe gelernt, dass ich, um Nachrichten vom Bot zu erhalten, einen Webhook verwenden müsste. Das bedeutete, dass mein Bot vom Internet aus zugänglich sein musste. Beim Erstellen von APIs wie dieser ist es wichtig, API-Versionierung Best Practices zu befolgen, um die Wartbarkeit zu gewährleisten. Da ich gerade erst anfing, es zu programmieren, entschied ich mich, ngrok zu verwenden. Es erstellt einen Tunnel vom öffentlichen Internet zu Ihrem localhost-Port 5007. Los geht's!

ngrok http 5007 -region eu -subdomain todobot

Als Nächstes musste ich einen Aufruf an die Programmable Conversations API machen, um den Webhook zu erstellen. Es ist ein POST zu https://conversations.messagebird.com/v1/webhooks und sieht in etwa so aus:


func main() {// define the webhook json payload
  wh := struct {
         Events    []string `json:"events"`
         ChannelID string   `json:"channelId"`
         URL       string   `json:"url"`
  } {
    // we would like to be notified on the URL
    URL:       "https://todobot.eu.ngrok.io/create-hook",
    // whenever a message gets created
    Events:    []string{"message.created"},
    // on the WhatsApp channel with ID
    ChannelID: "23a780701b8849f7b974d8620a89a279",
  }
  
  // encode the payload to json
  var b bytes.Buffer
  err := json.NewEncoder(&b).Encode(&wh)
  if err != nil {
    panic(err)
  }
  
  // create the http request and set authorization header
  req, err := http.NewRequest("POST", "https://conversations.messagebird.com/v1/webhooks", &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json") // fire the http request
  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
         panic(err)
  }
  defer resp.Body.Close()// is everything ok?
  body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode >= http.StatusBadRequest {
    panic(fmt.Errorf("Bad response code from api when trying to create webhook: %s. Body: %s", resp.Status, string(body)))
  } else {
    log.Println("All good. response body: ", string(body))
  }
}

Super. Jetzt wird die Conversations API eine POST-Anfrage an:

https://todobot.eu.ngrok.io/create-hook senden, wenn eine neue Nachricht auf dem zuvor eingerichteten WhatsApp-Kanal erstellt wird.

So sieht eine Webhook-Nutzlast aus:


{
  "conversation":{
    "id":"55c66895c22a40e39a8e6bd321ec192e",
    "contactId":"db4dd5087fb343738e968a323f640576",
    "status":"active",
    "createdDatetime":"2018-08-17T10:14:14Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z",
    "lastReceivedDatetime":"2018-08-17T14:30:31.898389294Z"
  },
  "message":{
    "id":"ddb150149e2c4036a48f581544e22cfe",
    "conversationId":"55c66895c22a40e39a8e6bd321ec192e",
    "channelId":"23a780701b8849f7b974d8620a89a279",
    "status":"received",
    "type":"text",
    "direction":"received",
    "content":{
      "text":"add buy milk"
    },
    "createdDatetime":"2018-08-17T14:30:31.898389294Z",
    "updatedDatetime":"2018-08-17T14:30:31.915292912Z"
  },
  "type":"message.created"
}

Wir möchten diese Nachrichten beantworten. Lassen Sie uns damit beginnen, sie zu wiederholen, was meinen Sie?


// define the structs where we'll parse the webhook payload into
type whPayload struct {
  Conversation conversation `json:"conversation"`
  Message      message      `json:"message"`
  Type         string       `json:"type"`
}

type message struct {
  ID        string  `json:"id"`
  Direction string  `json:"direction"`
  Type      string  `json:"type"`
  Content   content `json:"content"`
}

type content struct {
  Text string `json:"text"`
}

type conversation struct {
  ID string `json:"id"`
}

func main() {
  http.HandleFunc("/create-hook", createHookHandler)
  log.Fatal(http.ListenAndServe(*httpListenAddress, nil))
}
// createHookHandler is an http handler that will handle webhook requests
func createHookHandler(w http.ResponseWriter, r *http.Request) {
  // parse the incoming json payload
  whp := &whPayload{}
  err := json.NewDecoder(r.Body).Decode(whp)
  if err != nil {
    log.Println("Err: got weird body on the webhook")
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")
    return
  } 
  if whp.Message.Direction != "received" {
    // you will get *all* messages on the webhook. Even the ones this bot sends to the channel. We don't want to answer those.
    fmt.Fprintf(w, "ok")
    return
  } // echo: respond what we get
  err = respond(whp.Conversation.ID, whp.Message.Content.Text)
  
  if err != nil {
    log.Println("Err: ", err)
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, "Internal Server Error")return
  }
  w.WriteHeader(http.StatusOK)
  fmt.Fprintf(w, "ok")
}

Nun zum interessanten Teil. Machen Sie eine POST-Anfrage an:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages, um auf die Anfrage zu antworten.


func respond(conversationID, responseBody string) error {
  u := fmt.Sprintf("https://conversations.messagebird.com/v1/conversations/%s/messages", conversationID)msg := message{
  Content: content{
    Text: responseBody,
  },
  Type: "text",
  }
  var b bytes.Buffer
  err := json.NewEncoder(&b).Encode(&msg)
  if err != nil {
    return fmt.Errorf("Error encoding buffer: %v", err)
  }
  req, err := http.NewRequest("POST", u.String(), &b)
  req.Header.Set("Authorization", "AccessKey todo-your-access-key")
  req.Header.Set("Content-Type", "application/json")client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    return err
  }
  defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)
  if resp.StatusCode != http.StatusCreated {
    return fmt.Errorf("Bad response code from api when trying to create message: %s. Body: %s", resp.Status, string(body))
  }
  log.Println("All good. Response body: ", string(body))
  return nil
}

Da. Das ist alles, was Sie brauchen, um einen Bot zu erstellen, der sich wie ein 5-jähriger Mensch verhält.

Jetzt machen wir einen Vorstoß, um die ganze To-Do-Liste zu erstellen. Ändern Sie zunächst die Funktion createHookHandler ein wenig, damit sie die neue Funktion handleMessage anstelle von respond aufruft.

func createHookHandler(w http.ResponseWriter, r *http.Request) {
  ...
  err = handleMessage(whp)
  ...
}

handle wird die Nachrichten vereinfacht analysieren, etwas Arbeit erledigen und die Antwort auswählen. Schauen wir uns den „add“-Befehl an:

func handleMessage(whp *whPayload) error {
  // every conversation has a todo list
  list := manager.fetch(whp.Conversation.ID)
  // parse the command from the message body: it's the first word
  text := whp.Message.Content.Text
  text = regexp.MustCompile(" +").ReplaceAllString(text, " ")
  parts := strings.Split(text, " ")
  command := strings.ToLower(parts[0])
  // default message
  responseBody := "I don't understand. Type 'help' to get help."
  switch command {
  ...
  case "add":
    if len(parts) < 2 {
           return respond(whp.Conversation.ID, "err... the 'add' command needs a second param: the todo item you want to save. Something like 'add buy milk'.")
    }
    // get the item from the message body
    item := strings.Join(parts[1:], " ")list.add(item)
    responseBody = "added."
  ...
  return respond(whp.Conversation.ID, responseBody)
}

Hier richten wir ein:list := manager.fetch(whp.Conversation.ID). Im Wesentlichen ist „manager“ eine sicher konkurrierende Karte, die Konversations-IDs auf To-Do-Listen abbildet.

Eine To-Do-Liste ist ein sicher konkurrierender String-Abschnitt. Alles im Speicher!

Eine weitere wichtige Sache! Sie können Gespräche archivieren. In einigen Anwendungen, wie CRM, ist es wichtig, bestimmte Interaktionen zu verfolgen - um die Effektivität von Kundensupportmitarbeitern zu bewerten, zum Beispiel. Die Conversations API ermöglicht es Ihnen, ein Gespräch zu archivieren, um das Thema zu „schließen“. Wenn der Benutzer/Kunde eine weitere Nachricht sendet, öffnet die Conversations API automatisch ein neues Thema.

Außerdem. Durch das Durchführen einer PATCH-Anfrage an https://conversations.messagebird.com/v1/conversations/{id} mit dem richtigen Status im Körper können Sie die Konversation mit dieser ID archivieren. Wir machen das mit dem „bye“-Befehl:

case "bye":
  archiveConversation(whp.Conversation.ID)
  manager.close(whp.Conversation.ID)
  responseBody = "bye!"

archiveConversation wird die PATCH-Anfrage ausführen und manager.close(whp.Conversation.ID) wird die To-Do-Listen-Konversation entfernen.

Aber hey, Programmable Conversations ist eine Omnichannel-Lösung. Was wäre, wenn Sie den Code des Bots für eine andere Plattform, wie WeChat, wiederverwenden wollten? Dieser Multichannel-Ansatz ist Teil der Abweisungsstrategie bei Anfragen zu kostengünstigeren Kanälen. Wie würden Sie das machen?

Erstellen Sie einfach einen neuen Webhook, der auf diesen Kanal abzielt! Ein Webhook, der Anfragen an dieselbe URL https://todobot.eu.ngrok.io/create-hook sendet, die wir für WhatsApp verwendet haben!

Das wird funktionieren, weil der Handler-Code immer die conversationID aus der Webhook-Nutzlast verwendet, um die Nachrichten zu beantworten, anstatt einer fest kodierten channelID. Die Conversations API von MessageBird wird automatisch den Kanal für die Konversation bestimmen, über den Ihre Nachricht gesendet wird.

Möchten Sie Ihren eigenen Bot erstellen? Schauen Sie sich den vollständigen Code auf Github an: Wabot auf Github, fordern Sie frühzeitigen Zugang zu WhatsApp an, indem Sie die WhatsApp-Seite besuchen und auf den Kontakt-Button klicken, um das Formular auszufüllen. Viel Spaß beim Botten!

Andere Neuigkeiten

Mehr lesen aus dieser Kategorie

A person is standing at a desk while typing on a laptop.

Die vollständige AI-native Plattform, die mit Ihrem Business skaliert.

A person is standing at a desk while typing on a laptop.

Die vollständige AI-native Plattform, die mit Ihrem Business skaliert.