Product

Lösungen

Ressourcen

Company

Product

Lösungen

Ressourcen

Company

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

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

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.

Business in a box.

Entdecken Sie unsere Lösungen.

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

Ich wollte es ausprobieren und habe deshalb einen WhatsApp-Bot-aufgabenliste erstellt, denn wer braucht nicht eine automatisierte Aufgabenliste, um seinen Tag zu organisieren? Es mag kompliziert klingen, aber es war tatsächlich einfach und ich möchte Ihnen alles darüber erzählen.

Nun, ich arbeite bei MessageBird, also konnte ich einfach loslegen und anfangen zu bauen. Wenn Sie das ausprobieren, müssen Sie frühen Zugang anfordern. Sobald Sie jedoch mit einem WhatsApp-Kanal eingerichtet sind, können Sie sich auf dem Dashboard der MessageBird-Website anmelden und loslegen.

Das Erste, was ich tat, war die Dokumentation zu lesen. Ich erfuhr, dass ich, um Nachrichten vom Bot zu erhalten, einen Webhook verwenden müsste. Das bedeutete, dass mein Bot vom Internet aus zugänglich sein müsste. Bei der Erstellung von APIs wie dieser ist es wichtig, den Best Practices für API-Versionierung zu folgen, um die Wartbarkeit zu gewährleisten. Da ich gerade erst anfing, es zu codieren, entschied ich mich, ngrok zu verwenden. Es erstellt einen Tunnel vom öffentlichen Internet zu Ihrem lokalen Host-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 handelt sich um ein POST an https://conversations.messagebird.com/v1/webhooks und es sieht ungefähr 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 stellen, wann immer eine neue Nachricht in dem von Ihnen eingerichteten WhatsApp-Kanal erstellt wird.

So sieht eine Webhook-Payload 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")
}

Jetzt zum interessanten Teil. Eine POST-Anfrage an:

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


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 fünfjähriger Mensch verhält.

Machen wir uns jetzt daran, die gesamte Aufgabenliste zu erstellen. Zuerst ändern Sie die createHookHandler-Funktion ein wenig, sodass sie die neue handleMessage-Funktion anstelle von respond aufruft.

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

handle wird die Nachrichten einfach analysieren, einige Arbeiten ausführen 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: liste := manager.fetch(whp.Conversation.ID). Im Grunde ist „manager“ eine threadsichere Karte, die Konversations-IDs auf Aufgabenlisten abbildet.

Eine Aufgabenliste ist ein threadsicherer String-Slice. Alles im Speicher!

Noch etwas Wichtiges! Sie können Konversationen archivieren. In einigen Anwendungen, wie CRMs, ist es wichtig, bestimmte Interaktionen im Auge zu behalten – zum Beispiel, um die Effektivität von Kundenservicemitarbeitern zu verfolgen. Die Conversations API ermöglicht es Ihnen, eine Konversation 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 können Sie mit der richtigen Statusangabe im Body eine PATCH-Anfrage an https://conversations.messagebird.com/v1/conversations/{id} senden und so die Konversation mit dieser ID archivieren. Wir tun dies 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 Aufgabenlisten-Konversation entfernen.

Aber hey, Programmable Conversations ist eine Omnichannel-Lösung. Was ist, wenn Sie den Code des Bots für eine andere Plattform wie WeChat wiederverwenden möchten? Dieser Multi-Channel-Ansatz ist Teil der Strategie zur Ablenkung von Anfragen auf kostengünstigere Kanäle. Wie würden Sie das angehen?

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

Das funktioniert, weil der Handler-Code immer die conversationID aus der Webhook-Payload verwendet, um die Nachrichten zu beantworten, anstatt eine fest codierte channelID zu verwenden. MessageBird’s Conversations API wird automatisch den Kanal für die Konversation bestimmen, um Ihre Nachricht zu senden.

Möchten Sie Ihren eigenen Bot erstellen? Werfen Sie einen Blick auf den vollständigen Code auf Github: https://github.com/marcelcorso/wabot, fordern Sie frühzeitigen Zugang zu WhatsApp an, indem Sie die WhatsApp-Seite besuchen und auf die Schaltfläche „Kontaktieren Sie den Vertrieb“ klicken, um das Formular auszufüllen. Viel Spaß beim Bot-Erstellen!

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

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

Product

Lösungen

Ressourcen

Company

Datenschutzeinstellungen

Demnächst verfügbar

Über

Preise

Partner

Careers

Legal

Terms

Datenschutzeinstellungen

Sozial

Newsletter

Bleiben Sie mit Bird auf dem Laufenden durch wöchentliche Updates in Ihrem Posteingang.

Anmelden

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

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

Product

Lösungen

Ressourcen

Company

Datenschutzeinstellungen

Sozial

Newsletter

Bleiben Sie mit Bird auf dem Laufenden durch wöchentliche Updates in Ihrem Posteingang.

Anmelden