改变用户输入和聊天机器人回复的渲染顺序。

huangapple go评论73阅读模式
英文:

Change the rendering order of input from a user and chatbot reply

问题

我有一个聊天机器人,您可以向其提问,机器人将分析问题并相应地回答。用户只需在输入栏中输入要提出的问题,然后单击提交按钮或按回车键,问题将被推送到对话数组,并机器人将根据提出的问题回复,机器人的回复也将添加到对话数组中。然后对话数组被映射,以便在聊天页面上以类似Facebook Messenger的方式呈现所有对话;聊天机器人的回复位于聊天页面的左侧,用户提出的问题位于聊天页面的右侧。(这是在映射对话数组时完成的,所有奇数索引上的聊天都是用户提出的问题,而偶数索引上的对话是机器人的回复)。然而,我现在面临的问题是,如果用户快速且重复地输入文本并提交,对话数组的顺序会混乱(例如,如果我快速输入并连续4次点击提交/回车,我输入的4个对话都会被渲染成我和机器人之间的对话,一旦机器人回答了我提出的第一个问题,它会显示在我连续4次输入的文本之后,甚至可能显示在聊天页面的右侧或左侧。我如何在React Web应用程序中解决这个问题?我尝试使用setTimeout,但对我来说不起作用,或者我使用它的方式不正确?

以下是一些代码示例:

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

    // 将文本添加到对话中以显示
    dispatch(pushToChatConvArray({ user_conv: UserConversation }));
    // 发送API调用
    // 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="您有什么问题?"
      onChange={(e) => setUserConversation(e.target.value)}
      value={UserConversation}
    ></input>
    <IconButton type="submit">
      <SendIcon />
    </IconButton>
  </form>
</div>

// 此内容显示在聊天页面上
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>
  )
);

我尝试解释了主要问题并提供了一些与问题相关的基础代码。

英文:

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) =&gt; {
e.preventDefault();
// add text to show on conversation
dispatch(pushToChatConvArray({ user_conv: UserConversation }));
// Send API Call
// setTimeout(() =&gt; dispatch(botConvrse({ id: parseInt(sessionId), utt_user: userUtter })), 5000);
dispatch(botConvrse({ id: parseInt(sessionId), user_conv: UserConversation }));
setUserConversation(&quot;&quot;);
};
&lt;div&gt;
&lt;form onSubmit={SendChat}&gt;
&lt;input
autoFocus
className=&quot;user-chat-form&quot;
placeholder=&quot;What&#39;s on your mind?&quot;
onChange={(e) =&gt; setUserConversation(e.target.value)}
value={UserConversation}
&gt;&lt;/input&gt;
&lt;IconButton type=&quot;submit&quot;&gt;
&lt;SendIcon /&gt;
&lt;/IconButton&gt;
&lt;/form&gt;
&lt;/div&gt;
// the this content is displayed on the chatpage
let content = chatList.map((item, idx) =&gt;
idx % 2 == 0 ? (
&lt;motion.div
key={`chat ${idx}`}
&gt;
&lt;ChatContainer userOrBot={idx % 2 === 0 ? 0 : 1} conversation={item} /&gt;
&lt;/motion.div&gt;
) : (
&lt;motion.div
key={`chat ${idx}`}
&gt;
&lt;ChatContainer userOrBot={idx % 2 === 0 ? 0 : 1} conversation={item} /&gt;
&lt;/motion.div&gt;
)

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

答案1

得分: 1

很不安全假设对话是一对一轮流进行的。

我建议要么在聊天提交正在处理时阻止输入。

示例:

const [canChat, setCanChat] = React.useState(true);

const sendChat = async (e) => {
  e.preventDefault();

  try {
    setCanChat(false); // &lt;-- 阻止用户聊天输入
    
    // 添加文本以显示在对话中
    dispatch(pushToChatConvArray({ user_conv: UserConversation }));
    
    // 发送 API 调用
    await dispatch(botConvrse({
      id: parseInt(sessionId),
      user_conv: UserConversation
    }));
  } catch {
    // 处理或忽略被拒绝的 Promises、抛出的错误等
  } finally {
    setCanChat(true); // &lt;-- 启用用户聊天输入
    setUserConversation("");
  }
};

...

<div>
  <form onSubmit={sendChat}>
    <input
      autoFocus
      disabled={!canChat} // &lt;-- 当用户无法聊天时禁用输入元素
      className="user-chat-form"
      placeholder="你有什么想说的?"
      onChange={(e) => setUserConversation(e.target.value)}
      value={UserConversation}
    />
    <IconButton type="submit">
      <SendIcon />
    </IconButton>
  </form>
</div>

或者,用户是对话中他们部分的所有者。在处理时,此部分似乎可以作为分派的操作的一部分进行设置。

示例:

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

  // 添加文本以显示在对话中,将用户设置为所有者
  dispatch(pushToChatConvArray({ user_conv: UserConversation }));

  // 发送 API 调用,将机器人设置为所有者
  dispatch(botConvrse({
    id: parseInt(sessionId),
    user_conv: UserConversation
  }));

  setUserConversation("");
};

...

// 此内容显示在聊天页面上
const content = chatList.map((conversation) => (
  <motion.div key={conversation.id}>
    <ChatContainer
      userOrBot={conversation.isUserOwner}
      conversation={conversation}
    />
  </motion.div>
));
英文:

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) =&gt; {
  e.preventDefault();

  try {
    setCanChat(false); // &lt;-- 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); // &lt;-- enable user chat input
    setUserConversation(&quot;&quot;);
  }
};

...

&lt;div&gt;
  &lt;form onSubmit={sendChat}&gt;
    &lt;input
      autoFocus
      disabled={!canChat} // &lt;-- disable input element when user can&#39;t chat
      className=&quot;user-chat-form&quot;
      placeholder=&quot;What&#39;s on your mind?&quot;
      onChange={(e) =&gt; setUserConversation(e.target.value)}
      value={UserConversation}
    /&gt;
    &lt;IconButton type=&quot;submit&quot;&gt;
      &lt;SendIcon /&gt;
    &lt;/IconButton&gt;
  &lt;/form&gt;
&lt;/div&gt;

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) =&gt; {
  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(&quot;&quot;);
};

...

// the this content is displayed on the chatpage
const content = chatList.map((conversation) =&gt; (
  &lt;motion.div key={conversation.id}&gt;
    &lt;ChatContainer
      userOrBot={conversation.isUserOwner}
      conversation={conversation}
    /&gt;
  &lt;/motion.div&gt;
));

答案2

得分: 0

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.

&lt;form onSubmit={SendChat}&gt;
   &lt;fieldset disabled={botThinking}&gt;
   ... your form elements
   &lt;/fieldset&gt;       
&lt;/form&gt;

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

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

if (botThinking) return;
英文:

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.

&lt;form onSubmit={SendChat}&gt;
&lt;fieldset disabled={botThinking}&gt;
... your form elements
&lt;/fieldset&gt;       
&lt;/form&gt;

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;
</details>
# 答案3
**得分**: 0
是的,我看到你的问题了。
你可能将**chatList**作为React状态。
这是文本数组。
chatList - ["Hi", "How are you?", "I am fine" ...]
你可以像这样更新状态:
chatList - [{text: "Hi", from: "you"}, {text: "How are you?", from: "bot"}, {text: "I am fine", from: "you"}, ...]
这样,你可以轻松确定哪个是你的,哪个是机器人的。
<details>
<summary>英文:</summary>
Yes I saw what your problem is.
You probably have the **chatList** as react state.
And that is the array of text.
chatList - [&quot;Hi&quot;, &quot;How are you?&quot;, &quot;I am fine&quot; ...]
what about you update this state like
chatList - [{text: &quot;Hi&quot;, from: &quot;you&quot;}, {text: &quot;How are you?&quot;, from: &quot;bot&quot;}, {text: &quot;I am fine&quot;, from: &quot;you&quot;}, ...]
In this way, you can easily determine which is yours and bot&#39;s.
</details>

huangapple
  • 本文由 发表于 2023年3月7日 11:52:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75657904.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定