Comment créer un chatbot avec React

Ma philosophie est simple. Pour devenir bon dans quelque chose, vous devez le faire beaucoup.

Il ne suffit pas de le faire une fois. Vous devez le faire encore et encore et encore. Cela ne finira jamais. J'ai utilisé la même philosophie pour devenir bon en programmation.

Une chose que j'ai remarquée au cours de ce voyage est qu'il est beaucoup plus amusant de construire des choses intéressantes et qui ont l'air bien. Des choses que vous pouvez montrer à vos amis et dont vous pouvez être fier. Quelque chose qui vous excite de commencer lorsque vous vous asseyez devant votre clavier.

C'est pourquoi j'ai construit un chatbot.

Qui s'est transformé en un package npm.

Alors construisons un ensemble. Si vous souhaitez relever ce défi par vous-même, vous pouvez accéder directement à la documentation (qui est en fait un chatbot). Ou, si vous êtes un apprenant visuel, j'ai créé un tutoriel sur YouTube.

Sinon, allons-y. Je vais supposer que vous avez installé Node et que vous avez accès à la commande npx. Sinon, allez le chercher ici.

La configuration initiale

// Run these commands from your command line npx create-react-app chatbot cd chatbot yarn add react-chatbot-kit yarn start

Cela devrait installer le package npm et ouvrir le serveur de développement à localhost: 3000.

Ensuite, dirigez-vous vers App.jset apportez ces modifications:

import Chatbot from 'react-chatbot-kit' function App() { return ( ); }

Bon travail. Nous y arrivons. Vous devriez voir ceci dans votre serveur de développement maintenant:

Le chatbot prend trois accessoires qui doivent être inclus pour que cela fonctionne. Tout d'abord, il a besoin d'une configuration qui doit inclure une initialMessagespropriété avec des objets de message chatbot.

Deuxièmement, il a besoin d'une MessageParserclasse qui doit implémenter une méthode d'analyse.

Troisièmement, il a besoin d'une ActionProviderclasse qui implémentera les actions que nous voulons prendre en fonction de l'analyse du message.

Nous approfondirons cela plus tard. Pour l'instant, allez ici pour obtenir le code passe-partout pour commencer.

  • Mettez le MessageParsercode dans un fichier appeléMessageParser.js
  • Mettez le ActionProvidercode dans un fichier appeléActionProvider.js
  • Mettez le code de configuration dans un fichier appelé config.js

Quand c'est fait, revenez à votre App.jsfichier et ajoutez ce code:

import React from 'react'; import Chatbot from 'react-chatbot-kit' import './App.css'; import ActionProvider from './ActionProvider'; import MessageParser from './MessageParser'; import config from './config'; function App() { return ( ); }

Vous devriez maintenant voir ceci sur localhost: 3000:

Sucré. Maintenant, nous avons le chatbot rendu à l'écran et nous pouvons écrire dans le champ de saisie et le soumettre pour envoyer un message au chat. Mais lorsque nous essayons cela, rien ne se passe.

Comprendre le fonctionnement du chatbot

Ici, nous devons faire un arrêt au stand et regarder comment le MessageParseret ActionProviderinteragit pour que notre robot agisse.

Lorsque le bot est initialisé, la initialMessagespropriété de la configuration est placée dans l'état interne du chatbot dans une propriété appelée messages, qui est utilisée pour afficher les messages à l'écran.

De plus, lorsque nous écrivons et appuyons sur le bouton de soumission dans le champ de discussion, notre MessageParser(que nous avons passé comme accessoire au chatbot) appelle sa parseméthode. C'est pourquoi cette méthode doit être mise en œuvre.

Regardons de plus près le MessageParsercode de démarrage:

class MessageParser { constructor(actionProvider) { this.actionProvider = actionProvider; } parse(message) { ... parse logic } }

Si nous regardons de près, cette méthode est construite avec un actionProvider. C'est la même ActionProviderclasse que nous passons comme accessoires au chatbot. Cela signifie que nous contrôlons deux choses: la façon dont le message est analysé et l'action à entreprendre en fonction de cette analyse.

Utilisons ces informations pour créer une réponse de chatbot simple. Commencez par modifier MessageParsercomme ceci:

class MessageParser { constructor(actionProvider) { this.actionProvider = actionProvider; } parse(message) { const lowerCaseMessage = message.toLowerCase() if (lowerCaseMessage.includes("hello")) { this.actionProvider.greet() } } } export default MessageParser

Maintenant, nous MessageParserrecevons le message de l'utilisateur, vérifiant s'il contient le mot "bonjour". Si tel est le cas, il appelle la greetméthode sur le actionProvider.

Pour le moment, cela planterait, car nous n'avons pas implémenté la greetméthode. Faisons cela ensuite. Rendez-vous sur ActionProvider.js:

class ActionProvider { constructor(createChatBotMessage, setStateFunc) { this.createChatBotMessage = createChatBotMessage; this.setState = setStateFunc; } greet() { const greetingMessage = this.createChatBotMessage("Hi, friend.") this.updateChatbotState(greetingMessage) } updateChatbotState(message) { // NOTE: This function is set in the constructor, and is passed in // from the top level Chatbot component. The setState function here // actually manipulates the top level state of the Chatbot, so it's // important that we make sure that we preserve the previous state. this.setState(prevState => ({ ...prevState, messages: [...prevState.messages, message] })) } } export default ActionProvider

Agréable. Maintenant, si nous tapons "bonjour" dans le champ de discussion, nous récupérons ceci:

Fantastique. Maintenant que nous pouvons contrôler l'analyse du message et répondre par une action, essayons de rendre quelque chose de plus compliqué. Essayons de créer un robot qui vous fournisse des ressources d'apprentissage pour le langage de programmation que vous demandez.

Créer un robot d'apprentissage

Tout d'abord, revenons à notre config.jsfichier et apportons quelques légères modifications:

import { createChatBotMessage } from 'react-chatbot-kit'; const config = { botName: "LearningBot", initialMessages: [createChatBotMessage("Hi, I'm here to help. What do you want to learn?")], customStyles: { botMessageBox: { backgroundColor: "#376B7E", }, chatButton: { backgroundColor: "#376B7E", }, }, } export default config

OK, nous avons donc ajouté quelques propriétés ici et changé notre message initial. Plus particulièrement, nous avons donné un nom au bot et changé la couleur des composants messageboxet chatbutton.

Bien. Nous arrivons maintenant à la bonne partie.

Non seulement pouvons-nous analyser les messages et répondre à l'utilisateur avec un message de chatbot, nous pouvons également définir des composants React personnalisés que nous voulons rendre avec le message. Ces composants peuvent être tout ce que nous voulons - ce ne sont que de vieux composants React.

Essayons-le en créant un composant d'options qui guidera l'utilisateur vers les options possibles.

Tout d'abord, nous définissons le composant des options d'apprentissage:

// in src/components/LearningOptions/LearningOptions.jsx import React from "react"; import "./LearningOptions.css"; const LearningOptions = (props) => { const options = [ { text: "Javascript", handler: () => {}, id: 1 }, { text: "Data visualization", handler: () => {}, id: 2 }, { text: "APIs", handler: () => {}, id: 3 }, { text: "Security", handler: () => {}, id: 4 }, { text: "Interview prep", handler: () => {}, id: 5 }, ]; const optionsMarkup = options.map((option) => (  {option.text}  )); return {optionsMarkup} ; }; export default LearningOptions; // in src/components/LearningOptions/LearningOptions.css .learning-options-container { display: flex; align-items: flex-start; flex-wrap: wrap; } .learning-option-button { padding: 0.5rem; border-radius: 25px; background: transparent; border: 1px solid green; margin: 3px; }

Now that we have our component, we need to register it with our chatbot. Head over to config.js and add the following:

import React from "react"; import { createChatBotMessage } from "react-chatbot-kit"; import LearningOptions from "./components/LearningOptions/LearningOptions"; const config = { initialMessages: [ createChatBotMessage("Hi, I'm here to help. What do you want to learn?", { widget: "learningOptions", }), ], ..., widgets: [ { widgetName: "learningOptions", widgetFunc: (props) => , }, ], }

Understanding widgets

Alright. Let's take a breather and explore what we've done.

  1. We created the LearningOptions component.
  2. We registered the component under widgets in our config.
  3. We gave the createChatbotMessage function an options object specifying which widget to render with this message.

The result:

Fantastic, but why did we need to register our component in the config as a widget function?

By giving it a function, we control when we perform the invocation. This allows us room to decorate the widget with important properties inside the chatbot.

The widget that we define will receive a number of properties from the chatbot (some of which can be controlled by config properties):

  1. actionProvider - we give the actionProvider to the widget in order to execute actions if we need to.
  2. setState - we give the top level chatbot setState function to the widget in case we need to manipulate state.
  3. scrollIntoView - utility function to scroll to the bottom of the chat window, should we need to adjust the view.
  4. props - if we define any props in the widget config, those will be passed to the widget under the property name configProps.
  5. state - if we define custom state in the config, we can map it to the widget by using the mapStateToProps property

If you recall, we defined some options in the LearningOptions component:

 const options = [ { text: "Javascript", handler: () => {}, id: 1 }, { text: "Data visualization", handler: () => {}, id: 2 }, { text: "APIs", handler: () => {}, id: 3 }, { text: "Security", handler: () => {}, id: 4 }, { text: "Interview prep", handler: () => {}, id: 5 }, ];

Currently these have an empty handler. What we want to do now is to replace this handler by a call to the actionProvider.

So what do we want to have happen when we execute these functions? Ideally, we'd have some sort of chatbot message, and an accompanying widget that displays a list of links to helpful resources for each topic. So let's see how we can implement that.

First, we need to create the link list component:

// in src/components/LinkList/LinkList.jsx import React from "react"; import "./LinkList.css"; const LinkList = (props) => { const linkMarkup = props.options.map((link) => ( 
  • {link.text}
  • )); return
      {linkMarkup}
    ; }; export default LinkList; // in src/components/LinkList/LinkList.css .link-list { padding: 0; } .link-list-item { text-align: left; font-size: 0.9rem; } .link-list-item-url { text-decoration: none; margin: 6px; display: block; color: #1d1d1d; background-color: #f1f1f1; padding: 8px; border-radius: 3px; box-shadow: 2px 2px 4px rgba(150, 149, 149, 0.4); }

    Great. We now have a component that can display a list of links. Now we need to register it in in the widget section of the config:

    import React from "react"; import { createChatBotMessage } from "react-chatbot-kit"; import LearningOptions from "./components/LearningOptions/LearningOptions"; import LinkList from "./components/LinkList/LinkList"; const config = { ... widgets: [ { widgetName: "learningOptions", widgetFunc: (props) => , }, { widgetName: "javascriptLinks", widgetFunc: (props) => , }, ], }; export default config; 

    So far so good, but we want to dynamically pass in props to this component so that we can reuse it for the other options as well. This means that we need to add another property to the widget object in the config:

    import React from "react"; import { createChatBotMessage } from "react-chatbot-kit"; import LearningOptions from "./components/LearningOptions/LearningOptions"; import LinkList from "./components/LinkList/LinkList"; const config = { ..., widgets: [ ..., { widgetName: "javascriptLinks", widgetFunc: (props) => , props: { options: [ { text: "Introduction to JS", url: "//www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/", id: 1, }, { text: "Mozilla JS Guide", url: "//developer.mozilla.org/en-US/docs/Web/JavaScript/Guide", id: 2, }, { text: "Frontend Masters", url: "//frontendmasters.com", id: 3, }, ], }, }, ], }; export default config; 

    Now these props will be passed to the LinkList component as props.

    Now we need to do two more things.

    1. We need to add a method to the actionProvider
    class ActionProvider { constructor(createChatBotMessage, setStateFunc) { this.createChatBotMessage = createChatBotMessage; this.setState = setStateFunc; } handleJavascriptList = () => { const message = this.createChatBotMessage( "Fantastic, I've got the following resources for you on Javascript:", { widget: "javascriptLinks", } ); this.updateChatbotState(message); }; updateChatbotState(message) { // NOTICE: This function is set in the constructor, and is passed in from the top level Chatbot component. The setState function here actually manipulates the top level state of the Chatbot, so it's important that we make sure that we preserve the previous state. this.setState((prevState) => ({ ...prevState, messages: [...prevState.messages, message], })); } } export default ActionProvider; 

    2.  We need to add this method as the handler in the LearningOptions component:

    import React from "react"; import "./LearningOptions.css"; const LearningOptions = (props) => { const options = [ { text: "Javascript", handler: props.actionProvider.handleJavascriptList, id: 1, }, { text: "Data visualization", handler: () => {}, id: 2 }, { text: "APIs", handler: () => {}, id: 3 }, { text: "Security", handler: () => {}, id: 4 }, { text: "Interview prep", handler: () => {}, id: 5 }, ]; const optionsMarkup = options.map((option) => (  {option.text}  )); return {optionsMarkup} ; }; export default LearningOptions; 

    Alright! That was quite a lot of information. But if we now try to click the JavaScript option in the chatbot, we get this result:

    Perfect. But we don't want to stop there, this is a chatbot after all. We want to be able to respond to users who want to use the input field as well. So we need to make a new rule in MessageParser.

    Let's update our MessageParser.js file to look like this:

    class MessageParser { constructor(actionProvider) { this.actionProvider = actionProvider; } parse(message) { const lowerCaseMessage = message.toLowerCase(); if (lowerCaseMessage.includes("hello")) { this.actionProvider.greet(); } if (lowerCaseMessage.includes("javascript")) { this.actionProvider.handleJavascriptList(); } } } export default MessageParser; 

    Now try typing "javascript" into the input field and sending the message. You should get the same list in response from the chatbot.

    So there you have it. We've set up a chatbot that renders a list of possible options and responds to user input.

    For now, we've only set up the bot to handle when someone clicks or types in JavaScript, but you can try to expand the other options on your own. Here's a link to the repository.

    All the code is on GitHub, so feel free to dive into the react-chatbot-kit code or docs.

    Conclusion

    Building things is fun, and a great way to expand your skillset. There are no limits to where you could take this next.

    Perhaps you could make a chatbot that finds the ideal product in webshop based on some simple questions (utilising routing in the app), or maybe you can make one for your company taking care of the most common customer inquiries.

    Feel free to expand, come up with new ideas, and test them out. And if you see something that can be improved, send a pull request.

    If you want to improve as a developer, I encourage you to keep building. It truly is the only path forward. If you enjoyed this article, and would like to know when I post more content, you can follow me on Twitter.