skip to Main Content

So, I have this chat bot where you could ask a question and the bot will analyze the question and reply to it accordingly. So, the user just needs to input text in the input bar the question he/she wants to ask, and when he/she clicks submit button or just hit enter, the question is pushed to the conversation array and the bot replies based on the question asked and also the reply of the bot is also added to the conversation array. then the conversation array is mapped so that all conversations are rendered in the chat page in a way similar to facebook messenger; the chat bot’s reply are in the left side of the chat page and the question a user asks are on the right side of the chat page.(this is done when mapping the conversation array, all chats on the odd index are questions asked by the user, and the conversation on the even index is that of the bot’s reply). However, the problem I am facing now is, if the user inputs text and submits it very fast and repeatedly, the order of the conversation array gets messed up(for example, if I input and hit submit/enter four times at a very fast speed, all my 4 conversations I typed are rendered as if it’s a conversation between me and the bot and once the bot has a reply for the first question I asked, it’s displayed after 4 consecutive texts of mine and it might be even displayed either on the right side of the chat page or the left side. How can I solve this problem in react web app? I tried using setTimeout, but it’s not working for me or I am using it not in a correct way?

here is few of the code:

const SendChat = (e) => {
    e.preventDefault();

    // add text to show on conversation
    dispatch(pushToChatConvArray({ user_conv: UserConversation }));
    // Send API Call
    // setTimeout(() => dispatch(botConvrse({ id: parseInt(sessionId), utt_user: userUtter })), 5000);
    dispatch(botConvrse({ id: parseInt(sessionId), user_conv: UserConversation }));

    setUserConversation("");
  };


<div>
<form onSubmit={SendChat}>
          <input
            autoFocus
            className="user-chat-form"
            placeholder="What's on your mind?"
            onChange={(e) => setUserConversation(e.target.value)}
            value={UserConversation}
          ></input>
          <IconButton type="submit">
            <SendIcon />
          </IconButton>
        </form>
</div>
// the this content is displayed on the chatpage
let content = chatList.map((item, idx) =>
    idx % 2 == 0 ? (
      <motion.div
        key={`chat ${idx}`}
      >
        <ChatContainer userOrBot={idx % 2 === 0 ? 0 : 1} conversation={item} />
      </motion.div>
    ) : (
      <motion.div
        key={`chat ${idx}`}
      >
        <ChatContainer userOrBot={idx % 2 === 0 ? 0 : 1} conversation={item} />
      </motion.div>
    )

I tried to explain the main problem and provided few of the base code for the problem

3

Answers


  1. Assuming the conversation should be contextual (waiting and responding to what has been previously messaged), one way would be to disable the form when the chatbot is thinking.

    <form onSubmit={SendChat}>
       <fieldset disabled={botThinking}>
       ... your form elements
       </fieldset>       
    </form>
    

    You can then set botThinking using useState before and after using your your botConverse method.

    You might also want to add something to your sendChat handler:

    if (botThinking) return;
    
    Login or Signup to reply.
  2. Yes I saw what your problem is.
    You probably have the chatList as react state.
    And that is the array of text.

    chatList - ["Hi", "How are you?", "I am fine" ...]
    

    what about you update this state like

    chatList - [{text: "Hi", from: "you"}, {text: "How are you?", from: "bot"}, {text: "I am fine", from: "you"}, ...]
    

    In this way, you can easily determine which is yours and bot’s.

    Login or Signup to reply.
  3. It seems very unsafe to assume the conversation takes turns one-to-one like this.

    My suggestion here would be to either block the input while a chat submission is being processed.

    Example:

    const [canChat, setCanChat] = React.useState(true);
    
    const sendChat = async (e) => {
      e.preventDefault();
    
      try {
        setCanChat(false); // <-- block user chat input
        
        // add text to show on conversation
        dispatch(pushToChatConvArray({ user_conv: UserConversation }));
        
        // Send API Call
        await dispatch(botConvrse({
          id: parseInt(sessionId),
          user_conv: UserConversation
        }));
      } catch {
        // handle or ignore rejected Promises/thrown errors/etc
      } finally {
        setCanChat(true); // <-- enable user chat input
        setUserConversation("");
      }
    };
    
    ...
    
    <div>
      <form onSubmit={sendChat}>
        <input
          autoFocus
          disabled={!canChat} // <-- disable input element when user can't chat
          className="user-chat-form"
          placeholder="What's on your mind?"
          onChange={(e) => setUserConversation(e.target.value)}
          value={UserConversation}
        />
        <IconButton type="submit">
          <SendIcon />
        </IconButton>
      </form>
    </div>
    

    Or input which user is the owner of their part of the conversation. This part appears could be set as part of the dispatched actions when processed.

    Example:

    const sendChat = (e) => {
      e.preventDefault();
    
      // add text to show on conversation, sets user as owner
      dispatch(pushToChatConvArray({ user_conv: UserConversation }));
    
      // Send API Call, sets bot as owner
      dispatch(botConvrse({
        id: parseInt(sessionId),
        user_conv: UserConversation
      }));
    
      setUserConversation("");
    };
    
    ...
    
    // the this content is displayed on the chatpage
    const content = chatList.map((conversation) => (
      <motion.div key={conversation.id}>
        <ChatContainer
          userOrBot={conversation.isUserOwner}
          conversation={conversation}
        />
      </motion.div>
    ));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search