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.

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 eine WhatsApp-Bot-To-Do-Liste erstellt, denn wer braucht nicht eine automatisierte To-Do-Liste, 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 direkt einsteigen und mit dem Aufbau beginnen. Wenn Sie das versuchen, müssen Sie frühzeitigen Zugriff anfordern. Aber sobald Sie einen WhatsApp-Kanal eingerichtet haben, 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, Best Practices für die API-Versionierung zur Wartbarkeit zu befolgen. 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. Auf geht’s!

ngrok http 5007 -region eu -subdomain todobot

Als nächstes musste ich einen Aufruf an die Programmable Conversations API durchführen, um den Webhook zu erstellen. Es ist ein POST an https://conversations.messagebird.com/v1/webhooks und 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 senden:

https://todobot.eu.ngrok.io/create-hook wann immer eine neue Nachricht im vorher 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 auf diese Nachrichten antworten. Fangen wir an, sie zu wiederholen, was sagen Sie dazu?


// 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. Machen Sie eine POST-Anfrage an:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages 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 haben Sie es. Das ist alles, was Sie brauchen, um einen Bot zu erstellen, der sich wie ein fünfjähriges Kind verhält.

Jetzt, machen wir einen Vorstoß, um die gesamte To-Do-Liste zu erstellen. Zuerst ändern wir die createHookHandler-Funktion ein wenig, damit 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, etwas Arbeit leisten und die Antwort auswählen. Sehen 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). Grundsätzlich ist „manager“ eine nebenläufige sichere Karte, die Konversations-IDs auf To-Do-Listen abbildet.

Eine To-Do-Liste ist eine nebenläufig sichere Zeichenfolgenfolge. Alles im Speicher!

Eine weitere wichtige Sache! Sie können Konversationen archivieren. In einigen Anwendungen, wie z.B. CRMs, ist es wichtig, bestimmte Interaktionen zu verfolgen – um z.B. die Effektivität der Kundensupport-Mitarbeiter zu überwachen. Die Conversations API ermöglicht es Ihnen, eine Konversation zu archivieren, um das Thema „abzuschließen“. Wenn der Benutzer/Kunde eine weitere Nachricht sendet, wird die Conversations API automatisch ein neues Thema eröffnen.

Auch. Durch eine PATCH-Anfrage an https://conversations.messagebird.com/v1/conversations/{id} mit dem richtigen Status im Body können Sie 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 To-Do-Listen-Konversation entfernen.

Aber hey, Programmable Conversations ist eine Omni-Channel-Lösung. Was, 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 Abwicklung von Anfragen zu kostengünstigeren Kanälen. 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 wird funktionieren, da der Handler-Code immer die conversationID aus der Webhook-Nutzlast verwendet, um die Nachrichten zu beantworten, anstatt eines fest kodierten channelID. MessageBird’s Conversations API wird automatisch den Kanal für die Konversation ermitteln, über den Ihre Nachricht gesendet werden soll.

Möchten Sie Ihren eigenen Bot erstellen? Schauen Sie sich den vollständigen Code auf Github an: Wabot auf Github, beantragen Sie frühzeitigen Zugang zu WhatsApp, indem Sie die WhatsApp-Seite besuchen und auf die Schaltfläche Kontakt zu Vertrieb 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.