feat: save last chat config and make it default one (#1266)

* fix(RBAC): skip validation for unplug

* feat(chatSettings): set last config as default

---------

Co-authored-by: Zineb El Bachiri <100568984+gozineb@users.noreply.github.com>
This commit is contained in:
Mamadou DICKO 2023-09-26 18:41:02 +02:00 committed by GitHub
parent da6d5b698d
commit c8f045dfad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 88 additions and 84 deletions

View File

@ -195,6 +195,13 @@ async def create_question_handler(
)
# Retrieve user's OpenAI API key
if brain_id:
validate_brain_authorization(
brain_id=brain_id,
user_id=current_user.id,
required_roles=[RoleEnum.Viewer, RoleEnum.Editor, RoleEnum.Owner],
)
current_user.openai_api_key = request.headers.get("Openai-Api-Key")
brain = Brain(id=brain_id)
brain_details: BrainEntity | None = None

View File

@ -42,6 +42,22 @@ vi.mock("@/lib/api/chat/useChatApi", () => ({
getHistory: () => [],
}),
}));
vi.mock("@/lib/hooks", async () => {
const actual = await vi.importActual<typeof import("@/lib/hooks")>(
"@/lib/hooks"
);
return {
...actual,
useAxios: () => ({
axiosInstance: {
get: vi.fn(() => ({ data: [] })),
},
}),
};
});
vi.mock("@tanstack/react-query", async () => {
const actual = await vi.importActual<typeof import("@tanstack/react-query")>(
"@tanstack/react-query"

View File

@ -7,7 +7,7 @@ import { defineMaxTokens } from "@/lib/helpers/defineMaxTokens";
import { useConfigModal } from "./hooks/useConfigModal";
export const ConfigModal = ({ chatId }: { chatId?: string }): JSX.Element => {
export const ConfigModal = (): JSX.Element => {
const {
handleSubmit,
isConfigModalOpen,
@ -17,11 +17,7 @@ export const ConfigModal = ({ chatId }: { chatId?: string }): JSX.Element => {
maxTokens,
model,
accessibleModels,
} = useConfigModal(chatId);
if (chatId === undefined) {
return <div />;
}
} = useConfigModal();
return (
<Modal
@ -79,7 +75,7 @@ export const ConfigModal = ({ chatId }: { chatId?: string }): JSX.Element => {
<input
type="range"
min="10"
max={defineMaxTokens(model ?? "gpt-3.5-turbo")}
max={defineMaxTokens(model)}
value={maxTokens}
{...register("maxTokens")}
/>

View File

@ -1,28 +1,27 @@
/* eslint-disable max-lines */
import { useQuery } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { useBrainApi } from "@/lib/api/brain/useBrainApi";
import {
getChatConfigFromLocalStorage,
saveChatConfigInLocalStorage,
getChatsConfigFromLocalStorage,
saveChatsConfigInLocalStorage,
} from "@/lib/api/chat/chat.local";
import { USER_DATA_KEY, USER_IDENTITY_DATA_KEY } from "@/lib/api/user/config";
import { useUserApi } from "@/lib/api/user/useUserApi";
import { defaultBrainConfig } from "@/lib/config/defaultBrainConfig";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { ChatConfig } from "@/lib/context/ChatProvider/types";
import { defineMaxTokens } from "@/lib/helpers/defineMaxTokens";
import { getAccessibleModels } from "@/lib/helpers/getAccessibleModels";
import { useToast } from "@/lib/hooks";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useConfigModal = (chatId?: string) => {
export const useConfigModal = () => {
const { publish } = useToast();
const [isConfigModalOpen, setIsConfigModalOpen] = useState(false);
const { getBrain } = useBrainApi();
const { currentBrain } = useBrainContext();
const { currentBrainId } = useBrainContext();
const { getUser, getUserIdentity } = useUserApi();
const { data: userData } = useQuery({
@ -34,10 +33,12 @@ export const useConfigModal = (chatId?: string) => {
queryFn: getUserIdentity,
});
const defaultValues: ChatConfig = {};
const { register, watch, setValue } = useForm({
defaultValues,
const { register, watch, setValue } = useForm<ChatConfig>({
defaultValues: {
model: defaultBrainConfig.model,
temperature: defaultBrainConfig.temperature,
maxTokens: defaultBrainConfig.maxTokens,
},
});
const model = watch("model");
@ -49,23 +50,18 @@ export const useConfigModal = (chatId?: string) => {
userData,
});
useEffect(() => {
const fetchChatConfig = async () => {
if (chatId === undefined) {
return;
}
const chatConfig = getChatConfigFromLocalStorage(chatId);
const fetchChatConfig = useCallback(async () => {
const chatConfig = getChatsConfigFromLocalStorage();
if (chatConfig !== undefined) {
setValue("model", chatConfig.model);
setValue("temperature", chatConfig.temperature);
setValue("maxTokens", chatConfig.maxTokens);
} else {
if (currentBrain === undefined) {
if (currentBrainId === null) {
return;
}
const relatedBrainConfig = await getBrain(currentBrainId);
const relatedBrainConfig = await getBrain(currentBrain.id);
if (relatedBrainConfig === undefined) {
return;
}
@ -79,24 +75,15 @@ export const useConfigModal = (chatId?: string) => {
relatedBrainConfig.max_tokens ?? defaultBrainConfig.maxTokens
);
}
};
void fetchChatConfig();
}, []);
useEffect(() => {
if (maxTokens === undefined || model === undefined) {
return;
}
void fetchChatConfig();
}, [fetchChatConfig]);
setValue("maxTokens", Math.min(maxTokens, defineMaxTokens(model)));
}, [maxTokens, model, setValue]);
const handleSubmit = () => {
if (chatId === undefined) {
return;
}
const handleSubmit = useCallback(() => {
try {
saveChatConfigInLocalStorage(chatId, {
saveChatsConfigInLocalStorage({
maxTokens,
model,
temperature,
@ -112,7 +99,7 @@ export const useConfigModal = (chatId?: string) => {
text: "An error occurred while updating chat config",
});
}
};
}, [maxTokens, model, publish, temperature]);
return {
isConfigModalOpen,

View File

@ -25,7 +25,7 @@ export const ChatInput = ({
setShouldDisplayUploadCard,
hasContentToFeedBrain,
}: ChatInputProps): JSX.Element => {
const { setMessage, submitQuestion, chatId, generatingAnswer, message } =
const { setMessage, submitQuestion, generatingAnswer, message } =
useChatInput();
const { t } = useTranslation(["chat"]);
const { currentBrainId } = useBrainContext();
@ -80,7 +80,7 @@ export const ChatInput = ({
<>
{isEmptyMessage ? (
<div className="md:hidden flex items-center">
<ConfigModal chatId={chatId} />
<ConfigModal />
</div>
) : (
<Button
@ -95,7 +95,7 @@ export const ChatInput = ({
</Button>
)}
<div className="hidden md:flex items-center">
<ConfigModal chatId={chatId} />
<ConfigModal />
</div>
</>
)}

View File

@ -4,7 +4,7 @@ import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { getChatConfigFromLocalStorage } from "@/lib/api/chat/chat.local";
import { getChatsConfigFromLocalStorage } from "@/lib/api/chat/chat.local";
import { useChatApi } from "@/lib/api/chat/useChatApi";
import { useChatContext } from "@/lib/context";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
@ -64,7 +64,7 @@ export const useChat = () => {
promptId: currentPromptId,
});
const chatConfig = getChatConfigFromLocalStorage(currentChatId);
const chatConfig = getChatsConfigFromLocalStorage();
const chatQuestion: ChatQuestion = {
model: chatConfig?.model,

View File

@ -6,14 +6,17 @@ import { ChatHeader } from "./components/ChatHeader";
const SelectedChatPage = (): JSX.Element => {
return (
<main className="flex flex-col w-full h-[calc(100vh-61px)] overflow-hidden" data-testid="chat-page">
<main
className="flex flex-col w-full h-[calc(100vh-61px)] overflow-hidden"
data-testid="chat-page"
>
<section className="flex flex-col flex-1 items-center w-full h-full overflow-y-auto">
<ChatHeader /> {/* Added margin-bottom */}
<ChatHeader />
<div className="flex-1 flex flex-col mt-4 md:mt-8 w-full shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl overflow-hidden bg-white dark:bg-black border border-black/10 dark:border-white/25 p-2 md:p-12 pt-4 md:pt-10">
<div className="flex flex-1 flex-col overflow-y-auto">
<ChatDialogueArea />
</div>
<ActionsBar/> {/* Added margin-top */}
<ActionsBar />
</div>
</section>
</main>

View File

@ -1,16 +1,11 @@
import { ChatConfig } from "@/lib/context/ChatProvider/types";
export const saveChatConfigInLocalStorage = (
chatId: string,
chatConfig: ChatConfig
): void => {
localStorage.setItem(`chat-config-${chatId}`, JSON.stringify(chatConfig));
const chatConfigLocalStorageKey = "chat-config";
export const saveChatsConfigInLocalStorage = (chatConfig: ChatConfig): void => {
localStorage.setItem(chatConfigLocalStorageKey, JSON.stringify(chatConfig));
};
export const getChatConfigFromLocalStorage = (
chatId: string
): ChatConfig | undefined => {
const config = localStorage.getItem(`chat-config-${chatId}`);
export const getChatsConfigFromLocalStorage = (): ChatConfig | undefined => {
const config = localStorage.getItem(chatConfigLocalStorageKey);
if (config === null) {
return undefined;

View File

@ -3,9 +3,9 @@ import { ChatMessage, Notification } from "@/app/chat/[chatId]/types";
import { Model } from "../../types/brainConfig";
export type ChatConfig = {
model?: Model;
temperature?: number;
maxTokens?: number;
model: Model;
temperature: number;
maxTokens: number;
};
export type ChatContextProps = {