diff --git a/backend/routes/chat_routes.py b/backend/routes/chat_routes.py index f0919a235..953ce217a 100644 --- a/backend/routes/chat_routes.py +++ b/backend/routes/chat_routes.py @@ -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 diff --git a/frontend/app/chat/[chatId]/__tests__/page.test.tsx b/frontend/app/chat/[chatId]/__tests__/page.test.tsx index 0311c9d46..b6f74d746 100644 --- a/frontend/app/chat/[chatId]/__tests__/page.test.tsx +++ b/frontend/app/chat/[chatId]/__tests__/page.test.tsx @@ -42,6 +42,22 @@ vi.mock("@/lib/api/chat/useChatApi", () => ({ getHistory: () => [], }), })); + +vi.mock("@/lib/hooks", async () => { + const actual = await vi.importActual( + "@/lib/hooks" + ); + + return { + ...actual, + useAxios: () => ({ + axiosInstance: { + get: vi.fn(() => ({ data: [] })), + }, + }), + }; +}); + vi.mock("@tanstack/react-query", async () => { const actual = await vi.importActual( "@tanstack/react-query" diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/ConfigModal.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/ConfigModal.tsx index 99bbb7b94..dfa46ce99 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/ConfigModal.tsx +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/ConfigModal.tsx @@ -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
; - } + } = useConfigModal(); return ( { diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/hooks/useConfigModal.ts b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/hooks/useConfigModal.ts index 28b40c434..75b64af47 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/hooks/useConfigModal.ts +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ConfigModal/hooks/useConfigModal.ts @@ -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({ + defaultValues: { + model: defaultBrainConfig.model, + temperature: defaultBrainConfig.temperature, + maxTokens: defaultBrainConfig.maxTokens, + }, }); const model = watch("model"); @@ -49,54 +50,40 @@ export const useConfigModal = (chatId?: string) => { userData, }); - useEffect(() => { - const fetchChatConfig = async () => { - if (chatId === undefined) { + const fetchChatConfig = useCallback(async () => { + const chatConfig = getChatsConfigFromLocalStorage(); + if (chatConfig !== undefined) { + setValue("model", chatConfig.model); + setValue("temperature", chatConfig.temperature); + setValue("maxTokens", chatConfig.maxTokens); + } else { + if (currentBrainId === null) { return; } + const relatedBrainConfig = await getBrain(currentBrainId); - const chatConfig = getChatConfigFromLocalStorage(chatId); - if (chatConfig !== undefined) { - setValue("model", chatConfig.model); - setValue("temperature", chatConfig.temperature); - setValue("maxTokens", chatConfig.maxTokens); - } else { - if (currentBrain === undefined) { - return; - } - - const relatedBrainConfig = await getBrain(currentBrain.id); - if (relatedBrainConfig === undefined) { - return; - } - setValue("model", relatedBrainConfig.model ?? defaultBrainConfig.model); - setValue( - "temperature", - relatedBrainConfig.temperature ?? defaultBrainConfig.temperature - ); - setValue( - "maxTokens", - relatedBrainConfig.max_tokens ?? defaultBrainConfig.maxTokens - ); + if (relatedBrainConfig === undefined) { + return; } - }; - void fetchChatConfig(); + setValue("model", relatedBrainConfig.model ?? defaultBrainConfig.model); + setValue( + "temperature", + relatedBrainConfig.temperature ?? defaultBrainConfig.temperature + ); + setValue( + "maxTokens", + relatedBrainConfig.max_tokens ?? defaultBrainConfig.maxTokens + ); + } }, []); 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, diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx index dc3f0ae24..e48c7c92a 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx @@ -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 ? (
- +
) : (