OvidijusParsiunas / deep-chat

Fully customizable AI chatbot component for your website
https://deepchat.dev
MIT License
1.26k stars 170 forks source link

how to update current bubble with a stream of characters and not use overwrite? #138

Open MTCMarkFranco opened 3 months ago

MTCMarkFranco commented 3 months ago

If I want to call a WebSocket stream and get a response back in chunks, the cheat way is to set overwrite=true. is there a way to correlate the request with the response for the current bubble so that the stream updates the current bubble only using your framework. I could just use a standard observable variable and tie it to the bubble, but not sure I have access to your internal code for that without changing it. thoughts? what am I missing?

issue-overwrite-current-bubble-only

OvidijusParsiunas commented 3 months ago

Hi @MTCMarkFranco.

You can facilitate a steam-like experience when using sockets via the stream property by assigning it a string that servers as an end-phrase. This is mentioned and documented in more detail in the following issue.

I can see that you are using a request handler which is not supported for the aforementioned solution. If you want to continue to use the handler - I have made a quick change in the the latest deep-chat-dev and deep-chat-react-dev packages version 9.0.144 which will allow you to do this. The only issue is that the dev packages have accrued quite a lot of changes for our next big release, hence whilst things will continue work, you might get quite a few warnings in the console to switch to the new properties. E.g. the request property has been renamed to connect and stream has been moved to the connect object. Here is a very quick example of how you would use the new connect property:

connect = {
  handler: (_, signals) => {
    signals.onOpen();
    setTimeout(() => {
      signals.onResponse({text: '1'});
      setTimeout(() => {
        signals.onResponse({text: '2'});
        setTimeout(() => {
          signals.onResponse({text: '3'});
          setTimeout(() => {
            signals.onResponse({text: 'end'});
          }, 500);
        }, 500);
      }, 500);
    }, 500);
  },
  websocket: true,
  stream: {simulation: 'end'},
}

Let me know if you have any questions. It is late where I currently live, hence I will be able to respond later tomorrow. Thanks!

MTCMarkFranco commented 3 months ago

Thank you, I've updated my component and packages, but it seems it is even worse now, that overwrite is not honoured anymore as well. here is my code: https://github.com/MTCMarkFranco/chatbot/blob/websockets/src/App.tsx

Line 68

any suggestion on how to modify my code? I really want the stream effect from the server via websockets.

Appreciate it :-)

OvidijusParsiunas commented 3 months ago

Hey @MTCMarkFranco. I just found out that the end-phrase did not work for html messages, I have updated this in version 9.0.145. I have briefly looked at your code and have to say there is quite a lot of it, and the problem is I can't really reproduce it on my machine. Hence, the best thing I can recommend you is to temporarily remove/comment out code until you see where the problems start occurring. Then comment a simplified example so I can try to reproduce it locally on my machine. I would best advise starting with this simple handler's signals example and incrementally moving up to your solution:

connect = {
  websocket: true,
  stream: {simulation: 'end'},
  handler: (_, signals) => {
    signals.onOpen();
    setTimeout(() => {
      signals.onResponse({html: '<div>div 1</div>'});
      setTimeout(() => {
        signals.onResponse({html: '<button>button 2</button>'});
        setTimeout(() => {
          signals.onResponse({html: '<span>span 3</span>'});
          setTimeout(() => {
            signals.onResponse({html: 'end'});
            setTimeout(() => {
              signals.onResponse({text: 'New message'});
            }, 500);
          }, 500);
        }, 500);
      }, 500);
    }, 500);
  },
};

This is as much as I can currently do unfortunately from my machine, but please let me know where can I assist as I am keen to help you solve your problem.

Thankyou!

MTCMarkFranco commented 3 months ago

Thank you!

My code structure follows your WebSocket skeleton code verbatim here: https://deepchat.dev/docs/connect/#Handler

// this handler is invoked when the component is loaded chatElementRef.request = { websocket: true, handler: (_, signals) => { try { const websocket = new WebSocket('custom-url'); websocket.onopen = () => { signals.onOpen(); // enables the user to send messages }; websocket.onmessage = (message) => { const response = JSON.parse(message.data); signals.onResponse(response); // displays a text message from the server }; websocket.onclose = () => { signals.onClose(); // stops the user from sending messages }; websocket.onerror = () => { // 'Connection error' is a special string that will also display in Deep Chat signals.onResponse({error: 'Connection error'}); }; // triggered when the user sends a message signals.newUserMessage.listener = (body) => { websocket.send(JSON.stringify(body)); }; } catch (e) { signals.onResponse({error: 'error'}); // displays an error message signals.onClose(); // stops the user from sending messages } }, };

MTCMarkFranco commented 3 months ago

further investigation: signals.onResponse() is thinking that every call should be a separate response hence it creates a new message in the messages list instead of updating the latest response message. Maybe for stream=true, you could set a condition to update instead of create a new message? I haven't looked at your internal code yet, but just an idea.

OvidijusParsiunas commented 3 months ago

Apologies for the late reply @MTCMarkFranco.

That is quite interesting. I'm scratching my head as to why your signals.onResponse() call creates a new message bubble. In terms of debugging your code, I would recommend removing/commenting-out as much as possible to get to the cause of your issues.

If you use the configuration I pasted above, each call for signals.onResponse() should be incrementally adding to a message bubble, hence I am not sure as to why your case is creating a new message bubble every time. Perhaps I have misunderstood something.

Just to double check, which version of deep-chat-react-dev are you using? Any more info would be greatly appreciated!