react-chatbot-kit icon indicating copy to clipboard operation
react-chatbot-kit copied to clipboard

Displaying the message Loading .....

Open shubham-vEngageAi opened this issue 3 years ago • 18 comments

Hello Fredrik, I want to show the loading in bot message before I receive the message from the backend. i tried to show the loading in bot message with "loading:true" . But this is not working . Please help me .

Thanks Shubhnam Kumar image

shubham-vEngageAi avatar Dec 13 '21 10:12 shubham-vEngageAi

any update on this ?

MAfzalKhan1997 avatar Jan 18 '23 12:01 MAfzalKhan1997

I need this too. I don't want to manually add a new spinner component

ToJen avatar Mar 30 '23 20:03 ToJen

^ +1 agreed @FredrikOseberg

pranav-manik avatar May 09 '23 21:05 pranav-manik

Also trying to figure out how to make this ... in the message show however long I want it to while I do an async Action. Any advise @FredrikOseberg ? image

derekfreed avatar May 11 '23 20:05 derekfreed

Any update?

kikychow avatar May 25 '23 13:05 kikychow

In our case, the solution was to move the slow api request out of the MessageParser into the ActionProvider and create (createChatBotMessage('') and append the new empty before the api call is made. Does that help in your case as well @kikychow ?

clemenspeters avatar May 25 '23 19:05 clemenspeters

@clemenspeters Hi, thank you for your response. I am trying to create an empty bot message before the API call. I would like to ask how did you update the message after a response is returned from the API call? Thanks!

kikychow avatar May 25 '23 21:05 kikychow

This will be super useful when the backend api call takes few seconds... Any suggestion on how to make the loading status in the bot message?

sunxivincent avatar Jun 26 '23 11:06 sunxivincent

It is unfortunate that having more control over the loader isn't possible.

A workaround I implemented is to immediately post a chatbot message that a response was being crafted. Then, when the actual response is ready I replace the "Formulating a response" message with it.

Not ideal, but in some ways helpful to be able to show the user text that could help them know how long they'll be waiting.

kyleguate avatar Aug 02 '23 21:08 kyleguate

Also trying to figure out how to make this ... in the message show however long I want it to while I do an async Action. Any advise @FredrikOseberg ?

HI All, So I found a Solution for this. The basic logic behind the solution is to create a dummy message just before the API call. & Render a loader instead of dummy message Till API response is pending. Remove the dummy message once API call is fulfilled.

Below are the accurate steps to do so.

  1. Create custom bot Response message component (Refer here )

  2. Create a constant DUMMY_MESSAGE = <ANY_UUID>

  3. Pull out your API call from Message parser to Action provider & send the API call through clientMessage function in Action provider. This same function is accessible in message parser.

  4. Whenever user sends a message, in action provider, just before API call send that dummy message (which we kept in constants as shown below) this.greet({ message: DUMMY_MESSAGE }); // I am using message object due to some reason, you can use string too

  5. Your clientMessage function in action provider will look like this

clientMessage = async (clientMessage) => {
    this.addMessageToState(clientMessage);
    const data = {
      payloadName: clientMessage,
    };
    try {
      this.greet({ message: DUMMY_MESSAGE });    // I am using message object, you can use string too
      const apiResp = await apiCall(data);
      if (apiResp.status == 200) {
        this.greet({message : apiResp?.data?.response}, true);    // Sending true as second parameter as  i need to stop loading that chat object response once API call is finished. Will discuss it further in next steps
      } else {
        this.greet({
          message: 'FAIL_TO_ANSWER',
        }, true);
      }
    } catch {
      this.greet({
        message: 'FAIL_TO_ANSWER',
      }, , true);
    }
  };
  1. In that component (step 1) style your text as you want, and apply a condition, if message === DUMMY_MESSAGE, show bouncing loader instead of instead of dummy message (Refer this).

  2. Add one method in your Action provider below. This will remove your loader message by updating state and adding API response message here.

  removeLoadingMessage = (prevstateArray, removeLoading) => {
    if (removeLoading) {
      prevstateArray?.messages?.splice(
        prevstateArray?.messages?.findIndex(
          (a) => a?.message?.message === DUMMY_MESSAGE
        ),
        1
      );
      return prevstateArray;
    } else {
      return prevstateArray;
    }
  };
  1. Update your addMessageToState by below. The parameter removeLoading will be by default false
addMessageToState = (message, removeLoading = false) => {
    this.setState((prevstate) => ({
      ...this.removeLoadingMessage(prevstate, removeLoading),
      messages: [...prevstate.messages, message],
    }));
  };
  1. Update your greet method as below
greet = (botMessage, removeLoading = false) => {
    const message = this.createChatBotMessage(botMessage);
    this.addMessageToState(message, removeLoading);
  };

You should be good to go now.

nikunjmishra81 avatar Aug 03 '23 15:08 nikunjmishra81

I found a solution to this problem. Please create a new file called "Loader.js" and then add the following code:


import React from 'react';

const Loader = () => {
  return (
    <div className='chatbot-loader-container'>
      <svg
        id='dots'
        width='50px'
        height='21px'
        viewBox='0 0 132 58'
        version='1.1'
        xmlns='http://www.w3.org/2000/svg'
      >
        <g stroke='none' fill='none'>
          <g id='chatbot-loader' fill='#fff'>
            <circle id='chatbot-loader-dot1' cx='25' cy='30' r='13'></circle>
            <circle id='chatbot-loader-dot2' cx='65' cy='30' r='13'></circle>
            <circle id='chatbot-loader-dot3' cx='105' cy='30' r='13'></circle>
          </g>
        </g>
      </svg>
    </div>
  );
};

export default Loader;

Now, if it's loading, use this loader. It's the same loader from the react-chatbot-kit, so you won't notice any difference. You don't have to add any CSS, but please don't change anything in this file.

AswathyRajM avatar Sep 10 '23 17:09 AswathyRajM

Thanks @nikunjmishra81 , that helped me out. It's a bit hacky though. I feel there needs to be some kind of loading state on the chatbot which you could set pre and post API call and some kind of loader icon or message is shown which isn't an actual chatbot message. Being able to customize the loader icon would be helpful too.

greendinosaur avatar Sep 13 '23 23:09 greendinosaur

Had anyone found an easy way to handle this? Ideally, I would like to see the standard chatbot loader with dots appear until the backend responds. Right now, the client just sits there for 10 seconds until the backend provides the answer.

jamesmonek avatar Feb 05 '24 01:02 jamesmonek

In our case, the solution was to move the slow api request out of the MessageParser into the ActionProvider and create (createChatBotMessage('') and append the new empty before the api call is made. Does that help in your case as well @kikychow ?

@clemenspeters I was hoping you could clarify how you got this working? I started going down this path but I still get nothing until the API call is done which takes 2-7 seconds so I really would like to have the loader appear while the call is happening.

`class ActionProvider { constructor(createChatBotMessage, setStateFunc) { this.createChatBotMessage = createChatBotMessage; this.setState = setStateFunc; }

async helloWorldHandler(inputmes) { this.createChatBotMessage(''); const airesults = await ( await fetch (...) .... some cleanup var message = this.createChatBotMessage(<div dangerouslySetInnerHTML={{ __html: finalresult }} />); this.setChatbotMessage(message);` }

setChatbotMessage = (message) => { this.setState(state => ({ ...state, messages: [...state.messages, message] })) } }`

jamesmonek avatar Feb 08 '24 13:02 jamesmonek

Very simple solution to this problem. The idea is that you setState with createChatBotMessage(<Loader />) before API fetch. When the fetch is complete you just remove the last state message (yes I am well aware that if user submits again this will remove their message but...) Code below

const handleBotApi = async (usrMsg) => {
        // Add Loading before API call
        const loading = createChatBotMessage(<Loader />)
        setState((prev) => ({ ...prev, messages: [...prev.messages, loading], }))

        const botRes = await postAPI('/message', usrMsg)

        // Stop Loading after call is returned
        const botMessage = createChatBotMessage(botRes.bot)
        setState((prev) => {
            // Remove Loading here
            const newPrevMsg = prev.messages.slice(0, -1)
            return { ...prev, messages: [...newPrevMsg, botMessage], }
        })
    }

jacobcravinho avatar Feb 26 '24 13:02 jacobcravinho

Very simple solution to this problem. The idea is that you setState with createChatBotMessage() before API fetch. When the fetch is complete you just remove the last state message (yes I am well aware that if user submits again this will remove their message but...) Code below

const handleBotApi = async (usrMsg) => {
        // Add Loading before API call
        const loading = createChatBotMessage(<Loader />)
        setState((prev) => ({ ...prev, messages: [...prev.messages, loading], }))

        const botRes = await postAPI('/message', usrMsg)

        // Stop Loading after call is returned
        const botMessage = createChatBotMessage(botRes.bot)
        setState((prev) => {
            // Remove Loading here
            const newPrevMsg = prev.messages.slice(0, -1)
            return { ...prev, messages: [...newPrevMsg, botMessage], }
        })
    }

@jacobcravinho Thanks so much, I was able to get it working using your example!

jamesmonek avatar Mar 14 '24 16:03 jamesmonek

@jacobcravinho but this solution causing the chatbox to flicker once received reponse from API , then display loading again and then show message.

abduu11aahh avatar Jun 26 '24 05:06 abduu11aahh