OvidijusParsiunas / deep-chat

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

Issues while referencing DeepChat element #99

Closed K-Jadeja closed 8 months ago

K-Jadeja commented 8 months ago

I've been following issue #59 and am trying to wrap the DeepChat element and reference the wrapper element. I am trying to get your first suggestion to work with my code but I am facing a lot of errors like Property 'children' does not exist on type 'never' and 'ref.current' is possibly 'null'.

Sorry, I am new to typescript and would really appreciate any help getting this to work My code:

import React, { useEffect } from 'react';
import Box from '@mui/material/Box';
import dynamic from 'next/dynamic';
import { useUser } from '@clerk/nextjs';
import { RequestInterceptor, ResponseInterceptor } from 'deep-chat/dist/types/interceptors';
import { DeepChat as DeepChatCore } from 'deep-chat';

const DeepChat = dynamic(() => import('deep-chat-react').then((mod) => mod.DeepChat), {
  ssr: false,
});

export const ChatComponent = () => {
  const { user } = useUser();
  const ref = React.useRef(null);

  useEffect(() => {
    setTimeout(() => {
      if (ref.current) {
        const component = ref.current.children[0] as DeepChatCore;
        component.initialMessages = [
          { role: 'user', text: 'Hi' },
          { role: 'ai', text: 'Bye' },
        ];
      }
    });
  }, []);

  const requestInterceptor: RequestInterceptor = (details) => {
    details.body = {
      input: {
        text: details.body.messages[0].text,
      },
      config: {},
      kwargs: {},
    };
    return details;
  };

  const responseInterceptor: ResponseInterceptor = (details) => {
    // console.log(details);
    return { text: details.content || '' };
  };

  return (
    <Box
      display="flex"
      justifyContent="space-between"
      alignItems="center"
      // mb={2}
    >
      <div ref={ref}>
        <DeepChat
          request={{ url: 'https://test.up.railway.app/test/stream' }}
          requestInterceptor={requestInterceptor}
          responseInterceptor={responseInterceptor}
          requestBodyLimits={{ maxMessages: -1 }}
          stream={true}
        />
      </div>
    </Box>
  );
};

export default ChatComponent;

My main aim is to use methods like getMessages() to store and retrieve chat history from a database.

Thanks

OvidijusParsiunas commented 8 months ago

Hi @K-Jadeja. If you want to apply certain properties to Deep Chat as soon as it renders, I would highly recommend using the onComponentRender event. That way you do not have to set an arbitrary timeout and can know exactly when the reference is available.

So your code would look something like this:

let isSet = false;

return (
  <div ref={ref}>
    <DeepChat
      onComponentRender={() => {
        if (!isSet) {
          const component = ref.current.children[0] as DeepChatCore;
          component.initialMessages = [
            {role: 'user', text: 'Hi'},
            {role: 'ai', text: 'Bye'},
          ];
          isSet = true;
        }
      }}
      request={{url: 'https://test.up.railway.app/test/stream'}}
      requestInterceptor={requestInterceptor}
      responseInterceptor={responseInterceptor}
      requestBodyLimits={{maxMessages: -1}}
      stream={true}
    />
  </div>
);

The isSet variable is used to prevent infinite recursion as onComponentRender is triggered every time a property is set.

Let me know if you need any further assistance.

I have thought about this a little more and will update the onComponentRender event to pass the actual component as an argument, so it would be easier to access it. I'll include it in the next release. For now, the above example should work just fine.

K-Jadeja commented 8 months ago

Thanks @OvidijusParsiunas!

The code works but I still get these errors Property 'children' does not exist on type 'never' and 'ref.current' is possibly 'null'. image

Did I miss something?

OvidijusParsiunas commented 8 months ago

My apologies, for some reason the example NextJs project wasn't giving me that Type error. Please use the following code for better Type inference:


const ref = React.useRef<HTMLDivElement>(null);

let isSet = false;

return (
 <div ref={ref}>
    <DeepChat
      onComponentRender={() => {
        if (!isSet && ref.current) {
          const component = ref.current.children[0] as DeepChatCore;
          component.initialMessages = [
            {role: 'user', text: 'Hi'},
            {role: 'ai', text: 'Bye'},
          ];
          isSet = true;
        }
      }}
      request={{url: 'https://test.up.railway.app/test/stream'}}
      requestInterceptor={requestInterceptor}
      responseInterceptor={responseInterceptor}
      requestBodyLimits={{maxMessages: -1}}
      stream={true}
    />
  </div>
);
K-Jadeja commented 8 months ago

Thank you so much @OvidijusParsiunas! It works now :)

OvidijusParsiunas commented 8 months ago

Happy to hear it helped! I will close this issue. Thanks!