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.

Bird ha recentemente lanciato Programmable Conversations. Permette 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 bot WhatsApp per la lista delle cose da fare, perché chi non ha bisogno di una lista delle cose da fare automatizzata per aiutare a organizzare la giornata? Può sembrare complicato, ma è stato in realtà facile e vorrei raccontarvi tutto al riguardo.

Ora, lavoro a MessageBird, quindi potevo semplicemente immergermi e iniziare a costruire. Se provi questo, avrai bisogno di richiedere l'accesso anticipato. Ma una volta configurato un canale WhatsApp, puoi accedere al Dashboard sul sito di MessageBird e iniziare.

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

ngrok http 5007 -region eu -subdomain todobot

Successivamente, avevo bisogno di fare una chiamata all'API di Programmable Conversations per creare il webhook. È un POST a https://conversations.messagebird.com/v1/webhooks e appare qualcosa di simile a questo:


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

Bene. Ora l'API di Conversations farà una richiesta POST a:

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

Questo è come appare 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 replicandoli, 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. Fai una richiesta POST su:

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. Questo è tutto ciò che ti serve per creare un bot che si comporta come un umano di 5 anni.

Ora, facciamo un passo avanti verso la costruzione dell'intera lista di cose da fare. Per prima cosa, modifica un po' la funzione createHookHandler in modo che chiami la nuova funzione handleMessage invece di rispondere.

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

handle analizzerà i messaggi in modo semplicistico, farà qualche 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, impostiamo:list := manager.fetch(whp.Conversation.ID). Fondamentalmente, “manager” è una mappa sicura per la concorrenza che mappa gli ID delle conversazioni alle liste di cose da fare.

Una lista di cose da fare è una fetta 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 consente 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 il giusto stato nel corpo ti permette di archiviare la conversazione con quell'id. Facciamo questo con il comando “bye”:

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

archiveConversation farà la richiesta PATCH e manager.close(whp.Conversation.ID) rimuoverà la conversazione della lista delle 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 è parte della strategia di deviazione delle richieste verso canali a costo inferiore. Come faresti?

Crea semplicemente un nuovo webhook per raggiungere quel canale! Un webhook che invii richieste alla stessa URL https://todobot.eu.ngrok.io/create-hook che abbiamo usato per WhatsApp!

Funzionerà perché il codice del gestore usa sempre il conversationID dal payload del webhook per rispondere ai messaggi invece di un channel ID 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: Wabot su Github, richiedi l'accesso anticipato a WhatsApp visitando la pagina WhatsApp e cliccando sul pulsante Contatta Vendite per compilare il modulo. Buon botting!

Altre notizie

Leggi di più da questa categoria

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

La piattaforma AI-native completa che scala con il tuo business.

© 2025 Bird

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

La piattaforma AI-native completa che scala con il tuo business.

© 2025 Bird