Product

Solutions

Resources

Company

Product

Solutions

Resources

Company

Comment créer un bot WhatsApp pour les listes de tâches en utilisant l'API des Conversations Programmables de Bird.

Oiseau

5 févr. 2020

WhatsApp

1 min read

Comment créer un bot WhatsApp pour les listes de tâches en utilisant l'API des Conversations Programmables de Bird.

Bird a récemment lancé des Conversations Programmables. Cela permet aux entreprises de mélanger des plateformes de communication telles que WhatsApp, Messenger et SMS dans leurs systèmes - en utilisant une seule API.

Bird a récemment lancé Programmable Conversations. Cela permet aux entreprises d'intégrer des plateformes de communication comme WhatsApp, Messenger et SMS dans leurs systèmes — en utilisant une seule API.

Je voulais l'essayer, alors j'ai conçu un bot de liste de tâches WhatsApp, parce que qui n'a pas besoin d'une liste de tâches automatisée pour aider à organiser sa journée ? Cela peut sembler compliqué, mais c'était en fait facile, et je voudrais tout vous raconter à ce sujet.

Maintenant, je travaille chez MessageBird, donc je pouvais simplement me lancer et commencer à construire. Si vous essayez cela, vous devrez demander un accès anticipé. Mais une fois que vous êtes configuré avec un canal WhatsApp, vous pouvez vous connecter au Tableau de bord sur le site de MessageBird et commencer.

La première chose que j'ai faite a été de lire la documentation. J'ai appris que, pour recevoir des messages du bot, je devrais utiliser un webhook. Cela signifiait que mon bot devait être accessible depuis Internet. Lors de la création d'APIs comme celle-ci, il est important de suivre les meilleures pratiques de versionnage des API pour assurer la maintenabilité. Comme je venais de commencer à le coder, j'ai décidé d'utiliser ngrok. Cela crée un tunnel depuis l'internet public vers votre port localhost 5007 cher. Engagez !

ngrok http 5007 -region eu -subdomain todobot

Ensuite, j'avais besoin de faire un appel à l'API Programmable Conversations pour créer le webhook. C’est un POST vers https://conversations.messagebird.com/v1/webhooks et cela ressemble à ceci :


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

Génial. Maintenant, l'API Conversations va faire une requête POST à :

https://todobot.eu.ngrok.io/create-hook chaque fois qu'un nouveau message est créé sur le canal WhatsApp que vous avez configuré plus tôt.

Voici à quoi ressemble une charge utile de 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"
}

Nous voulons répondre à ces messages. Commençons par les répéter, qu'en pensez-vous ?


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

Maintenant, pour la partie intéressante. Faites une requête POST à :

https://conversations.messagebird.com/v1/conversations/<conversationID>/messages pour répondre à la requête.


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
}

Voilà. C'est tout ce dont vous avez besoin pour créer un bot qui agit comme un enfant de 5 ans.

Maintenant, faisons un pas vers la construction de la liste de tâches complète. Tout d'abord, modifiez légèrement la fonction createHookHandler pour qu'elle appelle la nouvelle fonction handleMessage au lieu de répondre.

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

handle analysera les messages de manière simpliste, fera un certain travail, et choisira la réponse. Jetons un coup d'œil à la commande « ajouter » :

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

Ici, nous avons configuré : list := manager.fetch(whp.Conversation.ID). Fondamentalement, « manager » est une carte sûre pour la concurrence qui mappe les identifiants de conversation aux listes de tâches.

Une liste de tâches est une tranche de chaîne sécurisée pour la concurrence. Tout cela en mémoire !

Une autre chose importante ! Vous pouvez archiver les conversations. Dans certaines applications, comme les CRM, il est important de garder une trace de certaines interactions — pour suivre l'efficacité des employés du support client, par exemple. L'API Conversations vous permet d'archiver une conversation pour « fermer » le sujet. Si l'utilisateur/client envoie un autre message, l'API Conversations ouvrira automatiquement un nouveau sujet.

De plus. Faire une requête PATCH à https://conversations.messagebird.com/v1/conversations/{id} avec le bon statut dans le corps vous permet d'archiver la conversation avec cet ID. Nous faisons cela avec la commande « au revoir » :

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

archiveConversation fera la requête PATCH et manager.close(whp.Conversation.ID) supprimera la conversation de la liste des tâches.

Mais hé, Programmable Conversations est une solution omni-canal. Et si vous vouliez réutiliser le code du bot pour une autre plateforme, comme WeChat ? Cette approche multi-canal fait partie de la stratégie déflecter les demandes vers des canaux à moindre coût. Comment procéderiez-vous ?

Créez simplement un nouveau webhook pour cibler ce canal ! Un webhook qui envoie des requêtes à la même url https://todobot.eu.ngrok.io/create-hook que nous avons utilisée pour WhatsApp !

Cela fonctionnera car le code gestionnaire utilise toujours le conversationID de la charge utile du webhook pour répondre aux messages au lieu d'un channelID codé en dur. L'API Conversations de MessageBird déterminera automatiquement le canal pour la conversation afin d'envoyer votre message.

Vous voulez construire votre propre bot ? Jetez un coup d'œil au code complet sur Github : Wabot sur Github, demandez un accès anticipé à WhatsApp en visitant la page WhatsApp et en cliquant sur le bouton Contacter les Ventes pour remplir le formulaire. Bon botting !

Autres news

Lire la suite de cette catégorie

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

La plateforme AI-native complète qui évolue avec votre business.

Product

Solutions

Resources

Company

À venir bientôt

Social

Newsletter

Restez à jour avec Bird grâce aux mises à jour hebdomadaires dans votre boîte de réception.

S'inscrire

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

La plateforme AI-native complète qui évolue avec votre business.

Product

Solutions

Resources

Company

Social

Newsletter

Restez à jour avec Bird grâce aux mises à jour hebdomadaires dans votre boîte de réception.

S'inscrire