بناء روبوت محادثة تفاعلي باستخدام React: دليل شامل لمطوري الويب

دقائق القراءة: 13

مقدمة إلى عالم روبوتات المحادثة التفاعلية مع React

في عالم البرمجة المتسارع، يكمن الإتقان الحقيقي في الممارسة المستمرة والتطبيق العملي. إن بناء مشاريع شيقة وجذابة بصريًا لا يثري مهاراتك فحسب، بل يوقد شغفك ويمنحك نتائج ملموسة تفخر بها. من هذا المنطلق، قمت بتطوير روبوت محادثة (chatbot) تحول لاحقًا إلى حزمة npm، واليوم سنتعاون لبناء واحد معًا. سواء كنت تفضل التعلم الذاتي عبر التوثيقات (التي هي بحد ذاتها روبوت محادثة)، أو كنت متعلمًا بصريًا وتفضل مشاهدة الدروس المصورة على YouTube، فإن هذا الدليل سيوفر لك كل ما تحتاجه. نفترض أن لديك Node.js مثبتًا وتستطيع الوصول إلى أمر npx. إذا لم يكن الأمر كذلك، يمكنك تثبيتهما أولاً.

الإعداد الأولي لمشروع React

لنبدأ بإعداد بيئة العمل الخاصة بنا. اتبع الخطوات التالية من سطر الأوامر لإنشاء تطبيق React جديد وتثبيت مكتبة روبوت المحادثة:

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

يجب أن تقوم هذه الأوامر بتثبيت حزمة npm وفتح خادم التطوير على localhost:3000. بعد ذلك، توجه إلى الملف App.js وقم بإجراء التغييرات التالية:

 import Chatbot from 'react-chatbot-kit'

 function App ( ) {
   return (
     < div className = "App" >
       < header className = "App-header" >
         < Chatbot />
       </ header >
     </ div >
   );
 }

 export default App;

عمل رائع! نحن نقترب من الهدف. يجب أن ترى الآن هذا في خادم التطوير الخاص بك:

الشكل الأولي لروبوت المحادثة بعد الإعداد الأساسي في React

المكونات الأساسية لروبوت المحادثة

يتطلب مكون Chatbot ثلاثة خصائص (props) أساسية ليعمل بشكل صحيح:

  1. config: يجب أن يتضمن هذا الكائن خاصية initialMessages تحتوي على كائنات رسائل روبوت المحادثة الأولية.
  2. MessageParser: فئة يجب أن تطبق الدالة parse.
  3. ActionProvider: فئة ستطبق الإجراءات التي نريد اتخاذها بناءً على تحليل الرسالة.

سنتعمق في هذه الخصائص لاحقًا. في الوقت الحالي، يمكنك الحصول على الكود الأساسي (boilerplate code) من هنا للبدء. قم بوضع:

  • كود MessageParser في ملف يسمى MessageParser.js.
  • كود ActionProvider في ملف يسمى ActionProvider.js.
  • كود config في ملف يسمى config.js.

عند الانتهاء من ذلك، عد إلى ملف App.js وأضف هذا الكود:

 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 (
     < div className = "App" >
       < header className = "App-header" >
         < Chatbot
           config = {config}
           actionProvider = {ActionProvider}
           messageParser = {MessageParser}
         />
       </ header >
     </ div >
   );
 }

 export default App;

يجب أن ترى الآن هذا على localhost:3000:

روبوت المحادثة مع إعدادات التهيئة الأولية في تطبيق React

ممتاز! لقد قمنا الآن بعرض روبوت المحادثة على الشاشة ويمكننا الكتابة في حقل الإدخال وإرسال الرسائل. ولكن عندما نحاول ذلك، لا يحدث شيء.

فهم آلية عمل روبوت المحادثة

هنا نحتاج إلى التوقف قليلًا ونلقي نظرة على كيفية تفاعل MessageParser و ActionProvider لجعل الروبوت يتخذ إجراءً. عند تهيئة الروبوت، يتم وضع خاصية initialMessages من كائن config في الحالة الداخلية لروبوت المحادثة في خاصية تسمى messages، والتي تُستخدم لعرض الرسائل على الشاشة. علاوة على ذلك، عندما نكتب ونضغط على زر الإرسال في حقل الدردشة، يقوم MessageParser (الذي مررناه كـ props إلى روبوت المحادثة) باستدعاء دالة parse الخاصة به. لهذا السبب يجب تطبيق هذه الدالة.

تعديل MessageParser لاستقبال الرسائل

دعنا نلقي نظرة فاحصة على الكود الأولي لـ MessageParser:

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

   parse(message) {
     // ... parse logic
   }
 }

 export default MessageParser;

إذا نظرنا عن كثب، فإن دالة constructor لهذه الفئة تستقبل actionProvider. هذه هي نفس فئة ActionProvider التي نمررها كـ props إلى روبوت المحادثة. هذا يعني أننا نتحكم في أمرين: كيفية تحليل الرسالة، والإجراء الذي يجب اتخاذه بناءً على هذا التحليل. دعنا نستخدم هذه المعلومات لإنشاء استجابة بسيطة لروبوت المحادثة. أولًا، قم بتعديل MessageParser على النحو التالي:

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

   parse(message) {
     const lowerCaseMessage = message.toLowerCase()
     if (lowerCaseMessage.includes( "hello" )) {
       this .actionProvider.greet()
     }
   }
 }

 export default MessageParser

الآن، يستقبل MessageParser رسالة المستخدم، ويتحقق مما إذا كانت تتضمن كلمة "hello". إذا كانت كذلك، فإنه يستدعي دالة greet على actionProvider. في الوقت الحالي، سيؤدي هذا إلى خطأ لأننا لم نقم بتطبيق دالة greet بعد. دعنا نفعل ذلك الآن.

تطبيق الإجراءات في ActionProvider

توجه إلى ملف 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

رائع! الآن إذا كتبنا "hello" في حقل الدردشة، سنحصل على هذه الاستجابة:

استجابة روبوت المحادثة لكلمة 'hello' بعد تعديل MessageParser و ActionProvider

ممتاز! بعد أن أصبح بإمكاننا التحكم في تحليل الرسائل والاستجابة بإجراء، دعنا نحاول بناء شيء أكثر تعقيدًا. لننشئ روبوتًا يوفر لك موارد تعليمية للغة البرمجة التي تطلبها.

بناء روبوت تعليمي (Learning Bot)

تخصيص إعدادات روبوت المحادثة

أولًا، دعنا نعود إلى ملف config.js ونجري بعض التغييرات الطفيفة:

 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;

لقد أضفنا بعض الخصائص هنا وغيرنا رسالتنا الأولية. أبرز ما في الأمر هو أننا أعطينا الروبوت اسمًا وغيرنا لون مكوني messagebox و chatbutton.

شات بوت التعلم (LearningBot) بتصميم مخصص ورسالة ترحيب جديدة

إنشاء مكونات React مخصصة (Widgets)

حسنًا، الآن نصل إلى الجزء الممتع. لا يمكننا فقط تحليل الرسائل والاستجابة للمستخدم برسالة من روبوت المحادثة، بل يمكننا أيضًا تعريف مكونات React مخصصة نريد عرضها مع الرسالة. يمكن أن تكون هذه المكونات أي شيء نريده – إنها مجرد مكونات React عادية. دعنا نجرب ذلك بإنشاء مكون خيارات (options component) يرشد المستخدم إلى الخيارات الممكنة.

مكون خيارات التعلم (LearningOptions)

أولًا، نقوم بتعريف مكون خيارات التعلم:

 // 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 ) => (
     < button className = "learning-option-button" key = {option.id} onClick = {option.handler} >
       {option.text}
     </ button >
   ));

   return < div className = "learning-options-container" > {optionsMarkup} </ div > ;
 };

 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.5 rem;
   border-radius: 25 px;
   background: transparent;
   border: 1 px solid green;
   margin: 3 px;
 }

الآن بعد أن أصبح لدينا المكون الخاص بنا، نحتاج إلى تسجيله في روبوت المحادثة. توجه إلى ملف config.js وأضف ما يلي:

 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 ) => < LearningOptions { ...props } /> ,
     },
   ],
 }

 export default config;

فهم Widgets في react-chatbot-kit

حسنًا. دعنا نأخذ استراحة ونستكشف ما قمنا به. لقد أنشأنا مكون LearningOptions. قمنا بتسجيل المكون ضمن widgets في ملف config الخاص بنا. أعطينا دالة createChatbotMessage كائن خيارات يحدد أي widget يجب عرضه مع هذه الرسالة. النتيجة:

خيارات التعلم المعروضة كـ Widget داخل روبوت المحادثة

رائع، ولكن لماذا احتجنا إلى تسجيل المكون الخاص بنا في config كدالة widget؟ من خلال إعطائه دالة، نتحكم في وقت تنفيذ الاستدعاء. يتيح لنا هذا مساحة لتزيين widget بخصائص مهمة داخل روبوت المحادثة. سيتلقى widget الذي نحدده عددًا من الخصائص من روبوت المحادثة (يمكن التحكم في بعضها بواسطة خصائص config):

  • actionProvider: نمرر actionProvider إلى widget لتنفيذ الإجراءات إذا احتجنا لذلك.
  • setState: نمرر دالة setState الرئيسية لروبوت المحادثة إلى widget في حال احتجنا إلى التلاعب بالحالة.
  • scrollIntoView: دالة مساعدة للتمرير إلى أسفل نافذة الدردشة، إذا احتجنا إلى ضبط العرض.
  • props: إذا قمنا بتعريف أي props في widget config، فسيتم تمريرها إلى widget تحت اسم الخاصية configProps.
  • state: إذا قمنا بتعريف حالة مخصصة في config، يمكننا ربطها بـ widget باستخدام خاصية mapStateToProps.

إذا تذكرت، لقد عرفنا بعض الخيارات في مكون LearningOptions:

 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
   },
 ];

حاليًا، هذه الخيارات تحتوي على دالة handler فارغة. ما نريد القيام به الآن هو استبدال هذا الـ handler باستدعاء لـ actionProvider. فماذا نريد أن يحدث عندما ننفذ هذه الدوال؟ من الناحية المثالية، سيكون لدينا نوع من رسالة روبوت المحادثة، ومكون widget مصاحب يعرض قائمة بالروابط لموارد مفيدة لكل موضوع. لذا دعنا نرى كيف يمكننا تطبيق ذلك.

مكون قائمة الروابط (LinkList)

أولًا، نحتاج إلى إنشاء مكون قائمة الروابط:

 // in src/components/LinkList/LinkList.jsx
 import React from "react" ;
 import "./LinkList.css" ;

 const LinkList = ( props ) => {
   const linkMarkup = props.options.map( ( link ) => (
     < li key = {link.id} className = "link-list-item" >
       < a href = {link.url} target = "_blank" rel = "noopener noreferrer" className = "link-list-item-url" >
         {link.text}
       </ a >
     </ li >
   ));

   return < ul className = "link-list" > {linkMarkup} </ ul > ;
 };

 export default LinkList;

 // in src/components/LinkList/LinkList.css
 .link-list {
   padding : 0 ;
 }

 .link-list-item {
   text-align: left;
   font-size: 0.9 rem;
 }

 .link-list-item-url {
   text-decoration: none;
   margin: 6 px;
   display: block;
   color: # 1 d1d1d;
   background-color: #f1f1f1;
   padding: 8 px;
   border-radius: 3 px;
   box-shadow: 2 px 2 px 4 px rgba( 150 , 149 , 149 , 0.4 );
 }

عظيم. لدينا الآن مكون يمكنه عرض قائمة من الروابط. الآن نحتاج إلى تسجيله في قسم widget في ملف 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 ) => < LearningOptions { ...props } /> ,
     },
     {
       widgetName : "javascriptLinks" ,
       widgetFunc : ( props ) => < LinkList { ...props } /> ,
     },
   ],
 };

 export default config;

حتى الآن كل شيء جيد، ولكننا نريد تمرير props ديناميكيًا إلى هذا المكون حتى نتمكن من إعادة استخدامه للخيارات الأخرى أيضًا. هذا يعني أننا نحتاج إلى إضافة خاصية أخرى إلى كائن widget في ملف 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 : [
     // ... باقي الـ widgets
     {
       widgetName : "javascriptLinks" ,
       widgetFunc : ( props ) => < LinkList { ...props } /> ,
       props: {
         options : [
           {
             text : "Introduction to JS" ,
             url : "https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/" ,
             id : 1 ,
           },
           {
             text : "Mozilla JS Guide" ,
             url : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide" ,
             id : 2 ,
           },
           {
             text : "Frontend Masters" ,
             url : "https://frontendmasters.com" ,
             id : 3 ,
           },
         ],
       },
     },
   ],
 };

 export default config;

الآن سيتم تمرير هذه الـ props إلى مكون LinkList كـ props. الآن نحتاج إلى القيام بشيئين آخرين.

ربط قائمة الروابط بـ ActionProvider

نحتاج إلى إضافة دالة إلى 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;

نحتاج إلى إضافة هذه الدالة كـ handler في مكون LearningOptions:

 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 ) => (
     < button className = "learning-option-button" key = {option.id} onClick = {option.handler} >
       {option.text}
     </ button >
   ));

   return < div className = "learning-options-container" > {optionsMarkup} </ div > ;
 };

 export default LearningOptions;

تمام! كانت هذه كمية كبيرة من المعلومات. ولكن إذا حاولنا الآن النقر على خيار JavaScript في روبوت المحادثة، فسنحصل على هذه النتيجة:

قائمة موارد JavaScript المعروضة بواسطة روبوت المحادثة بعد النقر على الخيار

الاستجابة لإدخال المستخدم

مثالي. لكننا لا نريد التوقف عند هذا الحد، فهذا روبوت محادثة في النهاية. نريد أن نكون قادرين على الاستجابة للمستخدمين الذين يرغبون في استخدام حقل الإدخال أيضًا. لذلك نحتاج إلى إنشاء قاعدة جديدة في MessageParser. دعنا نحدّث ملف MessageParser.js ليبدو كالتالي:

 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;

الآن حاول كتابة "javascript" في حقل الإدخال وإرسال الرسالة. يجب أن تحصل على نفس القائمة كاستجابة من روبوت المحادثة. وهكذا، قمنا بإعداد روبوت محادثة يعرض قائمة بالخيارات الممكنة ويستجيب لإدخال المستخدم. في الوقت الحالي، قمنا فقط بإعداد الروبوت للتعامل مع النقر أو الكتابة عن JavaScript، ولكن يمكنك محاولة توسيع الخيارات الأخرى بنفسك. إليك رابط إلى المستودع. كل الكود موجود على GitHub، لذا لا تتردد في الغوص في كود أو وثائق react-chatbot-kit.

الخلاصة التقنية

يُعد بناء روبوتات المحادثة باستخدام React ومكتبة react-chatbot-kit تجربة مثرية تُظهر قوة بيئة React في إنشاء واجهات مستخدم تفاعلية ومرنة. لقد استعرضنا في هذا الدليل كيفية هيكلة روبوت محادثة من الصفر، بدءًا من الإعداد الأولي وصولًا إلى تخصيص الاستجابات ودمج المكونات التفاعلية (widgets). تبرز أهمية فصل الاهتمامات بين MessageParser و ActionProvider في تمكين منطق معالجة الرسائل والإجراءات بشكل نظيف وقابل للتوسع. كما أن استخدام widgets يفتح الباب أمام إمكانيات لا حصر لها لتضمين عناصر React مخصصة، مما يحول روبوت المحادثة من مجرد صندوق نصي إلى واجهة غنية بالوظائف. هذه المرونة تجعل react-chatbot-kit أداة قوية لتطوير حلول متنوعة، من روبوتات الدعم الفني البسيطة إلى أنظمة التجارة الإلكترونية المعقدة التي توجه المستخدمين عبر مسارات تفاعلية. إن الاستمرار في بناء وتجربة هذه التقنيات هو السبيل الأمثل لتعزيز مهاراتك كمطور.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *