Reach

Grow

Manage

Automate

Reach

Grow

Manage

Automate

Come costruire un bot WhatsApp per elenchi di cose da fare utilizzando l'API di Conversazioni Programmabili di Bird.

Uccello

5 feb 2020

WhatsApp

1 min read

Come costruire un bot WhatsApp per elenchi di cose da fare utilizzando l'API di Conversazioni Programmabili di Bird.

Uccello

5 feb 2020

WhatsApp

1 min read

Come costruire un bot WhatsApp per elenchi di cose da fare utilizzando l'API di Conversazioni Programmabili di Bird.

Bird ha recentemente lanciato Conversazioni Programmabili. Consente alle aziende di integrare piattaforme di comunicazione come WhatsApp, Messenger e SMS nei loro sistemi - utilizzando una sola API.

Business in a box.

Scopri le nostre soluzioni.

Bird ha recentemente lanciato Programmable Conversations. Consente alle aziende di integrare piattaforme di comunicazione come WhatsApp, Messenger e SMS nei loro sistemi — utilizzando un unico API.

Volevo provarlo, quindi ho costruito un elenco di cose da fare con un bot WhatsApp, perché chi non ha bisogno di un elenco di cose da fare automatizzato per organizzare la propria giornata? Può sembrare complicato, ma in realtà è stato facile e vorrei raccontarti tutto a riguardo.

Ora, lavoro da MessageBird, quindi potrei semplicemente tuffarmi e iniziare a costruire. Se ci provi, dovrai richiedere l'accesso anticipato. Ma una volta configurato un canale WhatsApp, puoi accedere alla Dashboard sul sito web di MessageBird e iniziare.

La prima cosa che ho fatto è stata leggere i documenti. Ho appreso che, per ricevere messaggi dal bot, avrei dovuto utilizzare un webhook. Ciò significava che il mio bot doveva essere accessibile da internet. Quando si costruiscono API come questa, è importante seguire le migliori pratiche di versioning delle API per la manutenzione. Poiché stavo appena iniziando a programmarlo, ho deciso di utilizzare ngrok. Crea un tunnel da Internet pubblico al tuo caro localhost porta 5007. Vai!

ngrok http 5007 -region eu -subdomain todobot

Successivamente, avevo bisogno di fare una chiamata al Programmable Conversations API per creare il webhook. È un POST a https://conversations.messagebird.com/v1/webhooks e appare così:


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

Perfetto. Ora l'API di Conversations effettuerà una richiesta POST a:

https://todobot.eu.ngrok.io/create-hook ogni volta che viene creato un nuovo messaggio sul canale WhatsApp che hai configurato in precedenza.

Questo è l'aspetto di un payload di webhook:


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

Vogliamo rispondere a quei messaggi. Iniziamo riecheggiandoli, che ne dici?


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

Ora, per la parte interessante. Esegui una richiesta POST a:

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages per rispondere alla richiesta.


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
}

Ecco fatto. Questo è tutto ciò di cui hai bisogno per creare un bot che agisca come un umano di 5 anni.

Ora, facciamo un passo avanti verso la costruzione dell'intero elenco di cose da fare. Innanzitutto, modifica un po' la funzione createHookHandler affinché chiami la nuova funzione handleMessage invece di respond.

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

handle analizzerà semplicemente i messaggi, eseguirà del lavoro e sceglierà la risposta. Diamo un'occhiata al comando “add”:

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

Qui, configuriamo:list := manager.fetch(whp.Conversation.ID). Fondamentalmente, “manager” è una mappa sicura per la concorrenza che mappa gli ID delle conversazioni agli elenchi di cose da fare.

Un elenco di cose da fare è una slice di stringhe sicura per la concorrenza. Tutto in memoria!

Un'altra cosa importante! Puoi archiviare le conversazioni. In alcune applicazioni, come i CRM, è importante tenere traccia di determinate interazioni — per monitorare l'efficacia dei dipendenti del supporto clienti, ad esempio. L'API di Conversations ti permette di archiviare una conversazione per “chiudere” l'argomento. Se l'utente/cliente invia un altro messaggio, l'API di Conversations aprirà automaticamente un nuovo argomento.

Inoltre. Fare una richiesta PATCH a https://conversations.messagebird.com/v1/conversations/{id} con lo stato corretto nel corpo ti consente di archiviare la conversazione con quell'id. Lo facciamo con il comando “bye”:

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

archiveConversation eseguirà la richiesta PATCH e manager.close(whp.Conversation.ID) rimuoverà la conversazione dell'elenco di cose da fare.

Ma ehi, Programmable Conversations è una soluzione omni-canale. E se volessi riutilizzare il codice del bot per una piattaforma diversa, come WeChat? Questo approccio multi-canale fa parte della strategia di deflessione delle richieste verso canali a costo inferiore. Come procederesti?

Basta creare un nuovo webhook per indirizzare quel canale! Un webhook che invia richieste allo stesso URL https://todobot.eu.ngrok.io/create-hook che abbiamo utilizzato per WhatsApp!

Questo funzionerà perché il codice del gestore utilizza sempre il conversationID dal payload del webhook per rispondere ai messaggi invece di un channelID codificato. L'API di Conversations di MessageBird determinerà automaticamente il canale per la conversazione su cui inviare il tuo messaggio.

Vuoi costruire il tuo bot? Dai un'occhiata al codice completo su Github: https://github.com/marcelcorso/wabot, richiedi l'accesso anticipato a WhatsApp tramite questo link e inizia a costruire direttamente. Buon botting!

Connettiamoci con un esperto di Bird.
Scopri tutta la potenza del Bird in 30 minuti.

Inviando, accetti che Bird possa contattarti riguardo ai nostri prodotti e servizi.

Puoi annullare l'iscrizione in qualsiasi momento. Consulta la Informativa sulla Privacy di Bird per i dettagli sul trattamento dei dati.

Azienda

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.

Connettiamoci con un esperto di Bird.
Scopri tutta la potenza del Bird in 30 minuti.

Inviando, accetti che Bird possa contattarti riguardo ai nostri prodotti e servizi.

Puoi annullare l'iscrizione in qualsiasi momento. Consulta la Informativa sulla Privacy di Bird per i dettagli sul trattamento dei dati.

Azienda

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.

Connettiamoci con un esperto di Bird.
Scopri tutta la potenza del Bird in 30 minuti.

Inviando, accetti che Bird possa contattarti riguardo ai nostri prodotti e servizi.

Puoi annullare l'iscrizione in qualsiasi momento. Consulta la Informativa sulla Privacy di Bird per i dettagli sul trattamento dei dati.

R

Raggiungi

G

Grow

M

Manage

A

Automate

Azienda

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.