diff --git a/gui/src/app/settings/SettingsOptions/Models.tsx b/gui/src/app/settings/SettingsOptions/Models.tsx index 86e3ef0c..de6f07f5 100644 --- a/gui/src/app/settings/SettingsOptions/Models.tsx +++ b/gui/src/app/settings/SettingsOptions/Models.tsx @@ -6,9 +6,13 @@ import toast from 'react-hot-toast'; import CustomInput from '@/components/CustomInput/CustomInput'; import imagePath from '@/app/imagePath'; import { ModelsList } from '../../../../types/settingTypes'; +import { validateOpenAIKey } from '@/app/utils'; export default function Models() { const [modelsList, setModelsList] = useState(null); + const [validationErrors, setValidationErrors] = useState< + Record + >({}); const modelDetails = { 'gpt-4o': { text: 'Open AI API Key (gpt-4o)', icon: imagePath.openAIIcon }, 'claude-3': { @@ -17,7 +21,24 @@ export default function Models() { }, }; + const validateApiKeys = (): boolean => { + const errors: Record = {}; + + modelsList?.forEach((model) => { + if (model.model_name === 'gpt-4o' && !validateOpenAIKey(model.api_key)) { + errors[model.model_name] = + 'Invalid OpenAI API key. Key must start with "sk-" and be at least 20 characters.'; + } + }); + + setValidationErrors(errors); + return Object.keys(errors).length === 0; + }; + const handleButtonClick = () => { + if (!validateApiKeys()) { + return; + } toCreateOrUpdateLLMAPIKey().then().catch(); }; @@ -30,6 +51,13 @@ export default function Models() { : model, ) || null, ); + if (validationErrors[model_name]) { + setValidationErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors[model_name]; + return newErrors; + }); + } }; useEffect(() => { @@ -94,6 +122,8 @@ export default function Models() { icon={model.icon} iconCSS={'size-4'} alt={`${model.model_name}_icon`} + isError={!!validationErrors[model.model_name]} + errorMessage={validationErrors[model.model_name]} /> ))} diff --git a/gui/src/app/utils.tsx b/gui/src/app/utils.tsx index f07633a1..e1dbe312 100644 --- a/gui/src/app/utils.tsx +++ b/gui/src/app/utils.tsx @@ -179,6 +179,13 @@ export function validateEmail(email: string) { return emailRegex.test(email); } +export function validateOpenAIKey(apiKey: string): boolean { + if (!apiKey || apiKey.trim() === '') { + return true; + } + return apiKey.startsWith('sk-') && apiKey.length >= 20; +} + export function handleStoryInReviewIssue(data: { story: { reason: any }; }): StoryInReviewIssue {