Jak zbudować bota WhatsApp do list zadań przy użyciu API Programowalnych Rozmów firmy Bird

Ptak

5 lut 2020

WhatsApp

1 min read

Jak zbudować bota WhatsApp do list zadań przy użyciu API Programowalnych Rozmów firmy Bird

Bird niedawno uruchomił Programowalne Rozmowy. Umożliwia to firmom łączenie platform komunikacyjnych, takich jak WhatsApp, Messenger i SMS, w ich systemach - przy użyciu jednego interfejsu API.

Bird niedawno uruchomił Programowalne Rozmowy. Umożliwia firmom integrację platform komunikacyjnych takich jak WhatsApp, Messenger i SMS z ich systemami — za pomocą pojedynczego API.

Chciałem to wypróbować, więc zbudowałem listę rzeczy do zrobienia w formie bota WhatsApp, ponieważ kto nie potrzebuje zautomatyzowanej listy rzeczy do zrobienia, aby zorganizować swój dzień? Może to brzmieć skomplikowanie, ale było to naprawdę łatwe i chciałbym Wam o tym opowiedzieć.

Teraz pracuję w MessageBird, więc mogłem od razu przystąpić do budowy. Jeśli chcesz to wypróbować, musisz złożyć wniosek o wcześniejszy dostęp. Ale gdy masz już skonfigurowany kanał WhatsApp, możesz zalogować się do Dashboardu na stronie MessageBird i rozpocząć pracę.

Pierwszą rzeczą, którą zrobiłem, było przeczytanie dokumentacji. Dowiedziałem się, że aby otrzymywać wiadomości od bota, musiałbym użyć webhooka. Oznaczało to, że mój bot musiałby być dostępny z internetu. Przy budowie takich API ważne jest przestrzeganie najlepszych praktyk wersjonowania API dla utrzymania. Ponieważ dopiero zaczynałem go kodować, postanowiłem użyć ngrok. Tworzy tunel z publicznego internetu do lokalnego portu 5007. Do dzieła!

ngrok http 5007 -region eu -subdomain todobot

Następnie musiałem wykonać wywołanie do API Programowalnych Rozmów, aby utworzyć webhook. To POST do https://conversations.messagebird.com/v1/webhooks i wygląda to mniej więcej tak:


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))
  }
}

Świetnie. Teraz API Rozmów będzie wykonywać żądanie POST do:

https://todobot.eu.ngrok.io/create-hook za każdym razem, gdy zostanie utworzona nowa wiadomość na kanale WhatsApp, który wcześniej skonfigurowałeś.

Tak wygląda ładunek webhooka:


{
  "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"
}

Chcemy odpowiedzieć na te wiadomości. Zacznijmy od ich powtarzania, co Ty na to?


// 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")
}

Teraz, dla ciekawej części. Wykonaj żądanie POST do:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages aby odpowiedzieć na żądanie.


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
}

Voila. To wszystko, czego potrzebujesz, aby stworzyć bota, który zachowuje się jak 5-letni człowiek.

Teraz zróbmy krok w kierunku budowy całej listy rzeczy do zrobienia. Najpierw zmodyfikuj funkcję createHookHandler nieco, aby wywoływała nową funkcję handleMessage zamiast respondować.

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

handle będzie prosto przetwarzać wiadomości, wykonywać pewne zadania i wybierać odpowiedź. Spójrzmy na komendę „dodaj”:

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)
}

Tutaj ustawiamy: list := manager.fetch(whp.Conversation.ID). Zasadniczo „manager” to bezpieczna mapka współbieżności, która mapuje ID konwersacji na listy rzeczy do zrobienia.

Lista rzeczy do zrobienia to bezpieczny względem współbieżności łańcuch znaków. Wszystko w pamięci!

Kolejna ważna rzecz! Możesz archiwizować rozmowy. W niektórych aplikacjach, takich jak CRM, ważne jest śledzenie niektórych interakcji — aby śledzić skuteczność pracowników wsparcia klienta, na przykład. API Rozmów pozwala Ci na archiwizację rozmowy, aby „zamknąć” temat. Jeśli użytkownik/klient wyśle kolejną wiadomość, API Rozmów automatycznie otworzy nowy temat.

Również wysłanie żądania PATCH do https://conversations.messagebird.com/v1/conversations/{id} z odpowiednim statusem w treści pozwala Ci zarchiwizować rozmowę z tym ID. Robimy to za pomocą komendy „pa”:

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

archiveConversation wykona żądanie PATCH, a manager.close(whp.Conversation.ID) usunie rozmowę z listą zadań do wykonania.

Ale hej, Programowalne Rozmowy to rozwiązanie dla wielu kanałów. Co jeśli chciałbyś ponownie użyć kodu bota na inną platformę, taką jak WeChat? To podejście multi-channel jest częścią strategii kierowania zapytań do kanałów o niższych kosztach. Jak byś to zrobił?

Po prostu utwórz nowy webhook, aby celować w ten kanał! Webhook, który wysyła żądania do tego samego url https://todobot.eu.ngrok.io/create-hook którego użyliśmy dla WhatsApp!

To będzie działać, ponieważ kod obsługi zawsze używa conversationID z ładunku webhooka, aby odpowiedzieć na wiadomości zamiast zakodowanego na stałe channelID. Conversations API MessageBird automatycznie określi kanał dla rozmowy, aby wysłać wiadomość.

Czy chcesz stworzyć własnego bota? Zajrzyj do pełnego kodu na Githubie: Wabot na Githubie, złożyć wniosek o wcześniejszy dostęp do WhatsApp odwiedzając stronę WhatsApp i klikając przycisk Skontaktuj się z działem sprzedaży, aby wypełnić formularz. Szczęśliwego bottingu!

Inne wiadomości

Czytaj więcej z tej kategorii

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

Kompletna, AI-native platforma, która skaluje się wraz z Twoim business.

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

Kompletna, AI-native platforma, która skaluje się wraz z Twoim business.

Produkt

Rozwiązania

Zasoby

Company

Ustawienia prywatności

Social

Biuletyn

Bądź na bieżąco z Bird dzięki cotygodniowym aktualizacjom do Twojej skrzynki odbiorczej.

Zarejestruj się