Hogyan készítsünk Chatbotot a React-lel

Filozófiám egyszerű. Ahhoz, hogy valamiben jó legyen, sokat kell tennie.

Nem elég egyszer megtenni. Meg kell csinálnia újra, és újra és újra. Ennek soha nem lesz vége. Ugyanazt a filozófiát használtam a programozás terén.

Egy dolgot vettem észre ezen az úton, hogy sokkal szórakoztatóbb olyan dolgokat építeni, amelyek érdekesek és jól mutatnak. Olyan dolgok, amelyeket megmutathat barátainak, és amelyekre büszke lehet. Valami, ami izgatja Önt a kezdéshez, amikor leül a billentyűzet elé.

Ezért építettem chatbotot.

Ami npm csomagba formálódott.

Tehát építsünk egyet. Ha egyedül akarja vállalni ezt a kihívást, akkor keresse fel közvetlenül a dokumentációt (ami valójában egy chatbot). Vagy ha vizuális tanuló vagy, létrehoztam egy oktatóanyagot a YouTube-on.

Ellenkező esetben menjünk. Feltételezem, hogy telepítve van a Node, és hozzáfér az npx parancshoz. Ha nem, menjen ide.

Kezdeti beállítás

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

Ezzel telepítenie kell az npm csomagot, és meg kell nyitnia a fejlesztőkiszolgálót a localhost: 3000 címen.

Következő lépés: hajtsa App.jsvégre ezeket a módosításokat:

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

Nagyszerű munka. Odaérünk. Ezt most látnia kell a fejlesztőkiszolgálón:

A chatbot három támaszt igényel, amelyeket be kell vonni, hogy működjön. Először is szüksége van egy konfigurációra, amelynek tartalmaznia kell egy initialMessagestulajdonságot a chatbot üzenetobjektumokkal.

Másodszor, szüksége van egy MessageParserosztályra, amelynek végrehajtania kell egy elemzési módszert.

Harmadszor, szüksége van egy ActionProviderosztályra, amely olyan műveleteket hajt végre, amelyeket az üzenet elemzése alapján meg akarunk tenni.

Később elmélyülünk ebben. Most kezdjen ide, és szerezze be a kazánlap kódját az induláshoz.

  • Helyezze a MessageParserkódot egy fájlbaMessageParser.js
  • Helyezze a ActionProviderkódot egy fájlbaActionProvider.js
  • Helyezze a konfigurációs kódot egy fájlba config.js

Ha ez megtörtént, térjen vissza a App.jsfájljához, és adja hozzá ezt a kódot:

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

Ezt most látnia kell a localhost: 3000-n:

Édes. Most a chatbotot megjelenítettük a képernyőn, és beírhatjuk a beviteli mezőbe, és elküldhetjük, hogy üzenetet küldhessünk a chatre. De amikor megpróbáljuk, semmi sem történik.

A chatbot működésének megértése

Itt egy pit-stopot kell megtenni, és meg kell vizsgálnunk, hogy a MessageParserés hogyan ActionProviderlépnek kapcsolatba, hogy botunk cselekedhessen.

A bot inicializálásakor initialMessagesa config tulajdonságai a chatbot belső állapotába kerülnek egy úgynevezett tulajdonságban messages, amelyet üzenetek megjelenítésére használnak a képernyőn.

Sőt, amikor írunk és megnyomjuk a beküldés gombot a csevegési mezőben, a mi MessageParser(amit átadtunk a csevegőrobotnak) meghívjuk a parsemódszerét. Ezért kell ezt a módszert megvalósítani.

Vizsgáljuk meg közelebbről az MessageParserindító kódot:

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

Ha jól megnézzük, akkor ezt a módszert egy actionProvider. Ez ugyanaz az ActionProviderosztály, amelyet átadunk kellékként a chatbotnak. Ez azt jelenti, hogy két dolgot irányítunk - az üzenet elemzésének módját és az említett elemzés alapján milyen intézkedéseket kell tennünk.

Használjuk ezeket az információkat egy egyszerű chatbot-válasz létrehozásához. Először változtassa meg a következőket MessageParser:

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

Most MessageParsermegkapjuk a felhasználói üzenetet, és ellenőrizzük, hogy tartalmazza-e a "hello" szót. Ha mégis, akkor meghívja a greetmetódust a actionProvider.

Jelenleg ez összeomlik, mert nem implementáltuk a greetmódszert. Tegyük ezt legközelebb. Menjen át 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

Szép. Ha most beírjuk a "hello" szót a csevegési mezőbe, ezt visszakapjuk:

Fantasztikus. Most, hogy ellenőrizhetjük az üzenet elemzését és a cselekvéssel való reagálást, próbáljunk meg bonyolultabbá tenni valamit. Próbáljunk meg olyan botot készíteni, amely biztosítja a szükséges programozási nyelv tanulási forrásait.

Tanuló bot létrehozása

Először térjünk vissza a config.jsfájlunkhoz, és tegyünk néhány apró változtatást:

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

Rendben, ezért itt hozzáadtunk néhány tulajdonságot, és megváltoztattuk a kezdeti üzenetünket. Legfőképpen nevet adtunk a botnak, és megváltoztattuk a messageboxés az chatbuttonösszetevők színét .

Rendben. Most eljutottunk a jó részhez.

Nemcsak elemezhetjük az üzeneteket, és chatbot-üzenettel válaszolhatunk a felhasználóra, hanem meghatározhatunk egyedi React komponenseket is, amelyeket az üzenettel szeretnénk megjeleníteni. Ezek az alkatrészek bármi lehetnek, amire vágyunk - csak egyszerű React alkatrészek.

Próbáljuk ki egy opció komponens létrehozásával, amely a felhasználót a lehetséges opciókhoz vezeti.

Először meghatározzuk a tanulási lehetőségek összetevőt:

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