diff --git a/backend/config/__init__.py b/backend/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/config/utils.py b/backend/config/utils.py new file mode 100644 index 0000000..f2aec09 --- /dev/null +++ b/backend/config/utils.py @@ -0,0 +1,18 @@ +import openai + +def is_valid_api_key(openai_api_key: str): + openai.api_key = openai_api_key + try: + openai.ChatCompletion.create( + model="gpt-3.5-turbo", + messages=[ + {"role": "system", "content": "You are a helpful assistant."} + ] + ) + return { 'validApiKey': True } + except Exception as e: + return { + 'validApiKey': False, + 'message': e.error.message + } + \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 229a67a..c100f0c 100644 --- a/backend/main.py +++ b/backend/main.py @@ -9,6 +9,7 @@ from schemas.question import Question, Document from schemas.file import UploadRequestBody from schemas.prompt import Prompt +from config import utils from utils import FILE_HANDLERS from embeddings.index_files import Genie from loaders.website_loader import extract_text_from_website @@ -67,6 +68,9 @@ async def capture_posthog(): return response +@app.post("/config/validate-api-key/") +def validate_api_key(config: Config): + return utils.is_valid_api_key(config.apiKey) @app.get("/config/") def get_config(): @@ -75,7 +79,6 @@ def get_config(): return False return True - @app.post("/config/") def add_config(config: Config): db = Database().get_session() diff --git a/frontend/src/renderer/components/ErrorNotification.tsx b/frontend/src/renderer/components/ErrorNotification.tsx index f6fa026..06df600 100644 --- a/frontend/src/renderer/components/ErrorNotification.tsx +++ b/frontend/src/renderer/components/ErrorNotification.tsx @@ -1,9 +1,9 @@ import { notifications } from '@mantine/notifications'; -export function ErrorNotification(endpoint, method) { +export function ErrorNotification(endpoint, method, customMsg=null, title="Error!") { notifications.show({ - title: "Error!", - message: "An error occurred with the " + method + " request to endpoint " + endpoint, + title: title, + message: customMsg || "An error occurred with the " + method + " request to endpoint " + endpoint, color: 'red', autoClose: false, }); diff --git a/frontend/src/renderer/pages/config/Config.tsx b/frontend/src/renderer/pages/config/Config.tsx index b9774a0..d76b011 100644 --- a/frontend/src/renderer/pages/config/Config.tsx +++ b/frontend/src/renderer/pages/config/Config.tsx @@ -10,7 +10,7 @@ import {connect, disconnect} from '../../store/slices/externalDbSlice'; import {apiCall} from "../../utils/api"; import {useState} from "react"; import PromptConfiguration from "./PromptConfig"; - +import { ErrorNotification } from "../../../renderer/components/ErrorNotification"; function saveConfig(OPENAI_API_KEY: string, model: string, embeddingsmodel: string) { const payload = { @@ -18,6 +18,35 @@ function saveConfig(OPENAI_API_KEY: string, model: string, embeddingsmodel: stri model: model, embeddingsModel: embeddingsmodel }; + + // validate api key before saving config + return apiCall('/config/validate-api-key', 'POST', payload).then((response) => { + if (response?.data.validApiKey === false) return ErrorNotification('/config/validate-api-key', 'POST', response?.data.message, 'Invalid OpenAI API Key'); + + apiCall('/config', 'POST', payload).then((response) => { + const fetchedConfig = response.data; + console.log(fetchedConfig); + + if (Object.keys(fetchedConfig).length === 0) { + return false; + } + + // The fetched config is not an empty object, save it and return true + localStorage.setItem('config', JSON.stringify(fetchedConfig)); + console.log(fetchedConfig); + window.location.reload(); + + return true; + }) + .catch((error) => { + console.log('Error fetching config:', error); + return false; + } + ); + }).catch((error) => { + console.log('error:', error) + return false; + }); // return axios.post(`${config.REACT_APP_BACKEND_URL}/config`, payload) // .then((response) => { // const fetchedConfig = response.data; @@ -38,36 +67,13 @@ function saveConfig(OPENAI_API_KEY: string, model: string, embeddingsmodel: stri // return false; // }); // } - return apiCall('/config', 'POST', payload).then((response) => { - const fetchedConfig = response.data; - console.log(fetchedConfig); - - if (Object.keys(fetchedConfig).length === 0) { - return false; - } - - // The fetched config is not an empty object, save it and return true - localStorage.setItem('config', JSON.stringify(fetchedConfig)); - console.log(fetchedConfig); - window.location.reload(); - - return true; - } - ) - .catch((error) => { - console.log('Error fetching config:', error); - return false; - } - ); } - function Config() { const isConnected = useSelector((state) => state.connectedExternalDb.value); const dispatch = useDispatch(); const [opened, {open, close}] = useDisclosure(false); const [focused, setFocused] = useState(false); - const form = useForm({ initialValues: { OPENAI_API_KEY: '',