Product

Soluzioni

Risorse

Company

Product

Soluzioni

Risorse

Company

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. Permette alle aziende di integrare piattaforme di comunicazione come WhatsApp, Messenger e SMS nei loro sistemi — utilizzando un singolo API.

Volevo provarlo, quindi ho costruito un bot WhatsApp per la lista delle cose da fare, perché chi non ha bisogno di una lista di cose da fare automatizzata per organizzare la propria giornata? Può sembrare complicato, ma è stato effettivamente semplice, e mi piacerebbe raccontarvi tutto al riguardo.

Ora, lavoro da MessageBird, quindi potrei semplicemente iniziare subito a costruire. Se ci provate, avrete bisogno di richiedere un accesso anticipato. Ma una volta che vi siete impostati con un canale WhatsApp, potete accedere al 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 usare un webhook. Questo significava che il mio bot doveva essere accessibile da internet. Quando si costruiscono API come questa, è importante seguire le migliori pratiche di versionamento API per la manutenibilità. Siccome stavo appena iniziando a programmarlo, ho deciso di usare ngrok. Crea un tunnel da internet pubblico al caro localhost alla porta 5007. All'attacco!

ngrok http 5007 -region eu -subdomain todobot

Successivamente, dovevo effettuare una chiamata all'API delle Programmable Conversations per creare il webhook. È un POST su 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))
  }
}

Fantastico. Ora l'API delle Conversations farà una richiesta POST a:

https://todobot.eu.ngrok.io/create-hook ogni volta che viene creato un nuovo messaggio sul canale WhatsApp che avete già impostato.

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 a rispecchiarli, che ne dite?


// 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, la parte interessante. Fare 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. Questo è tutto ciò di cui avete bisogno per creare un bot che si comporta come un bambino di 5 anni.

Ora, spingiamoci verso la costruzione dell'intera lista delle cose da fare. Prima, modificate leggermente 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à semplicemente i messaggi, farà qualche lavoro e sceglierà la risposta. Diamo un'occhiata al comando "aggiungi":

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, abbiamo impostato:list := manager.fetch(whp.Conversation.ID). Fondamentalmente, “manager” è una mappa sicura per la concorrenza che mappa gli ID delle conversazioni alle liste delle cose da fare.

Una lista delle cose da fare è una slice di stringa sicura per la concorrenza. Tutto in memoria!

Un'altra cosa importante! Potete archiviare le conversazioni. In alcune applicazioni, come i CRM, è importante tenere traccia di certe interazioni — per monitorare l'efficacia dei dipendenti nel supporto clienti, per esempio. L'API delle Conversations vi permette di archiviare una conversazione per “chiudere” l'argomento. Se l'utente/cliente invia un altro messaggio, l'API delle 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 vi permette di archiviare la conversazione con quell'ID. Facciamo questo con il comando “ciao”:

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 voleste riutilizzare il codice del bot per una piattaforma diversa, come WeChat? Questo approccio multi-canale fa parte della strategia di deviazione delle richieste verso canali a costo inferiore. Come lo affrontereste?

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 usato per WhatsApp!

Funzionerà perché il codice del gestore utilizza sempre l'ID della conversazione dal payload del webhook per rispondere ai messaggi invece di un channelID codificato. L'API delle Conversations di MessageBird determinerà automaticamente il canale per la conversazione a cui inviare il vostro 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 visitando la pagina di WhatsApp e cliccando il pulsante Contatta Vendite per compilare il modulo. Buon botting!

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

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

Product

Soluzioni

Risorse

Company

Impostazioni sulla privacy

In arrivo

Sociale

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.

Registrati

© 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.

Product

Soluzioni

Risorse

Company

Impostazioni sulla privacy

Sociale

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.

Registrati

© 2025 Bird