OvidijusParsiunas / deep-chat

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

Set OpenAI assistant configuration after key is set. #110

Closed bruffridge closed 4 months ago

bruffridge commented 5 months ago

Scenario:

directConnection to OpenAI. User enters API key into deep-chat. I want to use their API key to make an API call to OpenAI to see if they have an assistant with a specific name. I'm planning to implement this in onNewMessage when they submit their first message. If they do, I want to tell deep-chat to use that assistant ID.

If they don't, I want to have deep-chat make a new assistant.

Seems like I need a way to change the assistant parameter of deep-chat after initialization (and after they enter their key) but before the assistant is created. Is this possible, or is there another way to accomplish this?

Here's some pseudocode of what I'm thinking.

<deep-chat
  onNewMessage = function() {
    let asst_id = findAsst(deepChatRef._activeService.key)
    if(asst_id) {
      deepChatRef._activeService.assistant.assistant_id = asst_id;
      deepChatRef._activeService.assistant.new_assistant = null;
    }
    else {
      deepChatRef._activeService.assistant.assistant_id = null;
      deepChatRef._activeService.assistant.new_assistant = { model: "gpt-4", ... };
    }
  }
OvidijusParsiunas commented 4 months ago

Hi @bruffridge.

This is a very unique use-case. By default, Deep Chat creates an assistant before a message is sent because it needs a valid assistant to send a message to, hence onNewMessage event will be triggered after an assistant has been created.

One way you can get around this is to first access the API key via chatElementRef._activeService.key, use it to get the id of the assistant you need and then assign it to the Deep Chat Assistant object. The code would be something like this: Check my code below in comments below

bruffridge commented 4 months ago

Thank you for the help. I was able to accomplish what I needed using config.assistant_id. I found that there wasn't an openAI key on chatElementRef.

EDIT: I eventually found openAI under directConnection: chatElementRef.directConnection.openAI.assistant.assistant_id, but it did not work for this use case.

let isIdAsssigned = false; // this value is used to prevent infinite recursion for re-rendering
chatElementRef.onComponentRender = () => {
  if (!isIdAsssigned) {
    const key = chatElementRef._activeService.key;
    // call OpenAI to get the assistant_id you require
    const newAssistantId = '';
    isIdAsssigned = true;
    chatElementRef._activeService.config.assistant_id = newAssistantId;
  }
};
OvidijusParsiunas commented 4 months ago

Could you elaborate on what did you mean by it did not work for this use case. Is there anything I can help with. Thanks.

bruffridge commented 4 months ago

When I set chatElementRef.directConnection.openAI.assistant.assistant_id in onComponentRender it would create a new assistant instead of using chatElementRef.directConnection.openAI.assistant.assistant_id

OvidijusParsiunas commented 4 months ago

Oh gosh, my apologies. The code I was using was incorrect as I was not resetting the directConnection property. After fixing it, there is actually another problem - Deep Chat is optimized not to reinitialize the service settings on a new render. We can get around this by setting chatElementRef._activeService to undefined. I admit it is a little hacky, but it is enough for your unique use-case. Please see the update code below:

let isIdAsssigned = false; // this value is used to prevent infinite recursion for re-rendering
chatElementRef.onComponentRender = async () => {
  if (!isIdAsssigned) {
    const key = chatElementRef._activeService.key;
    // call OpenAI to get the assistant_id you require (make sure to use await)
    const newAssistantId = '';
    isIdAsssigned = true;
    chatElementRef._activeService = undefined;
    chatElementRef.directConnection = {
      openAI: {
        assistant: {assistant_id: newAssistantId},
        key,
      },
    };
  }
};

Let me know if this works for you.

bruffridge commented 4 months ago

OK, that works. Here is my final code in case it helps anyone.

let openAIKeySet = false;
let openAIAsstIdSet = false;

chatElementRef.onComponentRender = async () => {
  // save key to localStorage.
  if (!openAIKeySet && this._activeService.key) {
    // if key set through UI, save it to localStorage.
    setOpenAIKey(this._activeService.key);
    openAIKeySet = true;
  }

  // check for existing asst, if user enters key in UI.
  if(openAIKeySet && !openAIAsstIdSet) {
    this.directConnection.openAI.assistant.assistant_id = await getAssistant();
    if(this.directConnection.openAI.assistant.assistant_id) {
      this._activeService = undefined;
      setAsst(this.directConnection.openAI.assistant.assistant_id);
      openAIAsstIdSet = true;
    }
  }
}
OvidijusParsiunas commented 4 months ago

Happy to hear it works. I will close this issue since the issue has been resolved. Thanks!