
Créer une application de rappel d'événements WhatsApp
Temps de lecture : 7 minutes
Introduction
Dans ce tutoriel, nous allons apprendre à mettre en place une conversation WhatsApp de rappel d'événements qui vous permet de recevoir des messages quotidiens contenant les événements du jour afin de vous en souvenir et d'interroger les événements futurs. Nous mettrons en place un bac à sable WhatsApp pour les messages entrants et sortants et récupérerons les événements à partir d'une instance de base de données Firebase Firestore.
Vous pouvez trouver le pour ce projet sur GitHub.
Conditions préalables
Un éditeur de texte ou un IDE
Schéma du projet
À la fin de ce projet, voici à quoi devrait ressembler votre dossier de projet :
[node_modules]
.env
index.js
package-lock.json
package.json
events-reminder-store-credentials.json Créer un projet Node et ajouter les dépendances
Dans le répertoire de votre projet nouvellement créé, initialisez un nouveau projet node. Cela créera un nouveau fichier package.json nouveau fichier. L'indicateur -y remplit automatiquement les valeurs par défaut sans demander de détails.
npm init -yEt installez les dépendances suivantes pour notre projet. Alternativement, vous pouvez cloner le projet depuis GitHub et installer les dépendances.
npm install axios dotenv express node-cronCes dépendances sont importantes dans notre projet pour effectuer et gérer les requêtes HTTP vers des services externes, gérer les variables d'environnement, configurer notre serveur et programmer les messages quotidiens contenant les événements.
Créer un bac à sable WhatsApp
Nous utiliserons l'application WhatsApp Sandbox pour ce tutoriel, mais vous pouvez également intégrer le compte WhatsApp de votre entreprise.
Utilisation de l'Environnement de test
Les étapes à suivre pour utiliser l'Environnement de test de l'API Messages afin d'envoyer des messages de test sur les plateformes de messagerie prises en charge sont les suivantes :
Variables d'environnement
Créez un fichier .env pour votre projet et ajoutez les variables d'environnement trouvées dans l'extrait de code ci-dessous.
VONAGE_API_KEY=
VONAGE_API_SECRET=
VONAGE_WHATSAPP_NUMBER=
TO_NUMBER=L'article de Michael sur son blog fournit une merveilleuse explication de l'utilisation des variables d'environnement dans Node.js.
Les VONAGE_API_KEY et VONAGE_API_SECRET se trouvent sur le tableau de bord de Vonage.
Vonage DashboardLe numéro VONAGE_WHATSAPP_NUMBER se trouve au bas de la page Sandbox de l'API Messages. Messages API Sandbox.
TO_NUMBER est le numéro à partir duquel vous allez envoyer un message à la sandbox WhatsApp.
REMARQUE : N'utilisez pas de
+ou00lors de la saisie d'un numéro de téléphone, commencez par l'indicatif du pays, par exemple 16600800000.
Envoyer un message WhatsApp
Une fois que nous avons ouvert la page Sandbox de l'API Page de l'Environnement de test de l'API Messagesune commande cURL montre comment ajouter un point de terminaison et envoyer un message à un numéro WhatsApp en bas de la page. J'ai pris ce code et je l'ai transformé en Node.js.
//index.js
require("dotenv").config();
const user = process.env.VONAGE_API_KEY;
const password = process.env.VONAGE_API_SECRET;
const from_number = process.env.VONAGE_WHATSAPP_NUMBER;
const to_number = process.env.VONAGE_TO_NUMBER;
const data = JSON.stringify({
from: { type: "whatsapp", number: from_number },
to: { type: "whatsapp", number: to_number },
message: {
content: {
type: "text",
text: "The events we have today are: event",
},
},
});
const https = require("https");
const options = {
hostname: "messages-sandbox.nexmo.com",
port: 443,
path: "/v0.1/messages",
method: "POST",
authorization: {
username: user,
password: password,
},
headers: {
Authorization: "Basic " + btoa(`${user}:${password}`),
"Content-Type": "application/json",
},
};
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on("data", (d) => {
process.stdout.write(d);
});
});
req.on("error", (e) => {
console.error(e);
});
req.write(data);
req.end();Dans cette forme basique, chaque fois que j'exécute le fichier que j'ai créé, je reçois en retour un message contenant ce qui est contenu dans la variable text. Ce billet de blog montre un exemple d'utilisation du bac à sable de WhatsApp en réception. Mais comme nous voulons que nos événements nous rappellent, nous utiliserons la sortie pour l'exemple de ce tutoriel.
Générer un localtunnel.me à l'aide du code de commande : lt --port 8000ajoutez l'URL générée et ajoutez /inbound et /eventrespectivement, et cliquez sur "Enregistrer les webhooks".
Maintenant, nous basculons ; le bac à sable de WhatsApp réagit dès que l'utilisateur envoie un message. Répondons "Les événements que nous avons aujourd'hui sont : events", une fois que l'utilisateur a envoyé un message. Mais il n'a pas encore choisi d'événements ; nous envoyons simplement cette chaîne de texte. Jusqu'à présent, vous avez vu comment recevoir un WhatsApp une fois le fichier exécuté et comment recevoir une réponse sortante. Passons à l'étape suivante, où nous allons récupérer des événements dans une base de données.
//index.js
require("dotenv").config();
const express = require("express");
const https = require("https");
const app = express();
app.use(express.json());
const PORT = 8000;
const from_number = process.env.VONAGE_WHATSAPP_NUMBER; // Your Vonage WhatsApp number
app.post("/inbound", (req, res) => {
console.log("Inbound message received:", req.body);
// Assuming the structure of req.body is as expected
const to_number = req.body.from.number; // Sender's number to which you're replying
console.log({to_number});
const data = JSON.stringify({
from: { type: "whatsapp", number: from_number },
to: { type: "whatsapp", number: process.env.TO_NUMBER },
message: {
content: {
type: "text",
text: "The events we have today are: events",
},
},
});
const options = {
hostname: "messages-sandbox.nexmo.com",
port: 443,
path: "/v0.1/messages",
method: "POST",
headers: {
Authorization:
"Basic " +
Buffer.from(
${process.env.VONAGE_API_KEY}:${process.env.VONAGE_API_SECRET}
).toString("base64"),
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(data),
},
};
const reqOut = https.request(options, (resOut) => {
console.log(`statusCode: ${resOut.statusCode}`);
resOut.on("data", (d) => {
process.stdout.write(d);
});
});
reqOut.on("error", (e) => {
console.error(e);
});
reqOut.write(data);
reqOut.end();
res.status(200).send("Inbound message processed");
});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
}); Firebase
Comme indiqué au début de ce tutoriel, vous aurez besoin d'un Account Firebase. Connectez-vous à votre Account Firebase, créez un projet Firebase, définissez l'emplacement et créer un Account de facturation.
Magasin de feu
Créer une nouvelle instance de base de données Firestore. Vous devez également créer un Account de service et ajouter le fichier JSON à votre projet node.
Vous devez créer une collection. Remplissez les champs Firestore avec les événements. Créez chaque nœud d'événement, qui doit contenir trois champs : date, de type timestamp ; details; et event_type, tous deux de type chaîne de caractères.
Ajouter le code
Ce bloc de code montre comment importer le SDK Firebase Admin, initialiser l'application Firebase, charger votre Account de service à partir d'un fichier JSON local et accéder à votre base de données Firestore.
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.cert(
require("./events-reminder-store-credentials.json")
),
});
const db = admin.firestore(); Créer la fonction qui récupère les événements du jour
Cette fonction initialise une plage de dates pour le jour en cours, commençant à minuit et se terminant juste avant minuit le jour suivant. Elle interroge ensuite Firestore pour trouver les documents de la collection d'événements dont le champ de date est compris dans cette plage. Si des documents sont trouvés, une chaîne de caractères résumant les événements de la journée est construite.
async function getEventsForToday() {
const today = new Date();
today.setHours(0, 0, 0, 0); // Set the time to the start of the day (midnight)
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1); // Set to the start of the next day (midnight next day)
try {
// Query Firestore for events within today's date range
const snapshot = await db.collection('events')
.where('date', '>=', admin.firestore.Timestamp.fromDate(today))
.where('date', '<', admin.firestore.Timestamp.fromDate(tomorrow))
.get();
if (snapshot.empty) {
return 'No events found for today.'; // Return message if no events are found
}
let eventsText = 'Today\'s events: ';
snapshot.forEach(doc => {
const event = doc.data();
eventsText += ${event.details}; ; // Concatenate each event detail into a string
});
return eventsText; // Return the string of today's events
} catch (error) {
console.error("Error fetching events:", error);
return "Failed to fetch events."; // Handle errors in fetching data
}
}La même fonction getEventsForToday gère la vérification des événements du jour comme décrit ci-dessus. Elle définit la date de manière à couvrir tous les événements survenant entre le début et la fin de la journée en cours, ce qui permet de récupérer les événements programmés pour aujourd'hui.
async function handleDateRequest(dateString, requesterNumber) {
const queryDate = new Date(dateString + 'T00:00:00Z'); // Set the query date start
const queryDateEnd = new Date(queryDate);
queryDateEnd.setDate(queryDate.getDate() + 1); // Set the query date end to the next day
try {
const snapshot = await db.collection('events')
.where('date', '>=', admin.firestore.Timestamp.fromDate(queryDate))
.where('date', '<', admin.firestore.Timestamp.fromDate(queryDateEnd))
.get();
if (snapshot.empty) {
sendMessage('No events found for ' + dateString, requesterNumber); // Inform no events found
return;
}
let eventsText = Events on ${dateString}: ;
snapshot.forEach(doc => {
const event = doc.data();
eventsText += ${event.details}; ; // Aggregate event details
});
sendMessage(eventsText, requesterNumber); // Send the aggregated event details
} catch (error) {
console.error("Error retrieving events:", error);
}
}Le code utilise admin.firestore.Timestamp.fromDate() pour convertir les objets JavaScript Date en formats d'horodatage compatibles avec Firestore. Cette conversion est essentielle pour interroger avec précision les champs de date stockés dans Firestore.
Toutes les interactions Firestore comprennent des blocs try-catch pour gérer et enregistrer efficacement les erreurs, ce qui permet de détecter et de diagnostiquer tout problème survenant au cours des opérations de la base de données.
Programmer des messages ultérieurs
Nous pourrions programmer une fonction en nuage et la déployer avec des fonctions cloud. Cependant, pour ce tutoriel, nous utiliserons node-cron. Je l'ai configuré pour envoyer des messages tous les jours à 09h50 dans le fuseau horaire "Europe/Londres", mais vous pouvez l'ajuster à une heure et un fuseau horaire qui vous conviennent mieux.
const cron = require("node-cron");
cron.schedule("50 09 *", async () => {
console.log("Running a job at 09:50 at Europe/London timezone");
const eventsText = await getEventsForToday();
sendMessage(eventsText, TO_NUMBER);
}, {
scheduled: true,
timezone: "Europe/London",
}); Bonus : Ajouter des messages personnalisés à l'aide d'Open AI
Nous sommes nombreux à nous enthousiasmer pour l'utilisation des LLM (grands modèles de langage) ces jours-ci. Que diriez-vous d'ajouter des messages personnalisés à envoyer pour ces événements qui vous sont rappelés ? Vous pouvez faire des appels d'API à OpenAI pour générer un message d'événement personnalisé pour vous - vous pouvez ensuite le copier et le coller et l'utiliser !
Installez la dépendance OpenAI npm depuis votre terminal.
npm install openai
Importez la dépendance dans votre fichier JavaScript.
const OpenAI = require("openai");
Générer une clé API et configurer le client OpenAI.
const openai = new OpenAI({ apiKey: OPENAI_API_KEY });
Ajoutez le OPENAI_API_KEY à votre fichier .env.
OPENAI_API_KEY=
Créer une fonction generateCreativeMessage() qui utilise l'API d'OpenAI pour générer un texte personnalisé basé sur les informations d'un événement. La fonction envoie une requête à l'API, lui demandant de créer un texte basé sur une invite qui inclut les détails de l'événement. La fonction spécifie un nombre de mots maximum pour la réponse. Si la demande aboutit, le texte généré est découpé et renvoyé. En cas d'erreur, un message de remplacement reprend les détails de l'événement.
async function generateCreativeMessage(eventsText) {
try {
const response = await openai.completions.create({
model: "gpt-3.5-turbo-instruct",
prompt: Create a friendly and engaging message based on the following events: ${eventsText},
max_tokens: 150,
});
return response.choices[0].text.trim();
} catch (error) {
console.error("Failed to generate message with OpenAI:", error);
return Here's what's happening today: ${eventsText}; // Fallback text
}
}N'oublions pas non plus de mettre à jour le message programmé en y ajoutant la fonction generateCreativeMessage() pour créer un message personnalisé en fonction des événements. Les détails de l'événement original et le message nouvellement créé sont envoyés à un numéro de téléphone spécifié à l'aide de la fonction sendMessage() à l'aide de la fonction
cron.schedule(
"50 09 *",
async () => {
console.log("Running a job at 09:50 at Europe/London timezone");
const eventsText = await getEventsForToday();
const creativeText = await generateCreativeMessage(eventsText);
sendMessage(
${eventsText}\n\nSuggested message to send: ${creativeText},
TO_NUMBER
);
},
{
scheduled: true,
timezone: "Europe/London",
}
);
Remarque : tenez compte des coûts de l'API, des limites du taux de l'API et de la confidentialité des données lorsque vous utilisez l'API d'OpenAI.
Exécuter l'application
L'application est programmée pour vérifier les événements du jour et envoyer un message via WhatsApp à une heure précise chaque jour. Vous pouvez rechercher des événements à des dates spécifiques en envoyant des messages au format "Événements le AAAA-MM-JJ ?" via WhatsApp.
Exécutez la commande lt pour démarrer le tunnel.
lt --port 8000
Ajoutez l'URL générée à votre Messages API Sandbox et n'oubliez pas de cliquer sur Save Webhooks.
Messages API WebhooksExécutez le fichier JavaScript que vous avez créé sur le même port que celui sur lequel le tunnel écoute.
node index.js
Vous pouvez mettre à jour la fonction node.cron pour envoyer un message à n'importe quel moment, et vous pouvez également envoyer un message au numéro de WhatsApp Sandbox pour demander les événements du jour dans le format.
Extension possible - Vonage AI Studio
Nous avons réalisé cela en utilisant l'API de messages de Vonage, mais vous auriez également pu utiliser Vonage AI Studio pour concevoir la conversation et intégrer votre backend. Il existe même un module complémentaire Gen AI node qui vous permet d'utiliser la puissance du Large Language Model d'OpenAI pour dynamiser votre assistant virtuel afin qu'il traite les requêtes de l'utilisateur avec la connaissance des nuances spécifiques au contexte et l'avantage d'avoir l'internet comme source de données. Voici un tutoriel pour Construire un service de réponse aux FAQ avec OpenAI et Vonage AI Studio.
Conclusion
Aujourd'hui, vous avez vu comment utiliser l'API Messages Sandbox de Vonage intégrée à Firebase Firestore et Cloud Functions for Firestore pour recevoir des messages de rappel d'événements. Rejoignez-nous sur notre Communauté Vonage Slack ou envoyez-nous un message sur X, anciennement connu sous le nom de Twitter.