| @@ -5,7 +5,7 @@ import Link from 'next/link' | |||
| import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline' | |||
| import { useState, useEffect } from 'react' | |||
| import ProviderInput from '../provider-input' | |||
| import useValidateToken, { ValidatedStatus } from '../provider-input/useValidateToken' | |||
| import useValidateToken, { ValidatedStatus, ValidatedStatusState } from '../provider-input/useValidateToken' | |||
| import { | |||
| ValidatedErrorIcon, | |||
| ValidatedSuccessIcon, | |||
| @@ -15,7 +15,7 @@ import { | |||
| interface IAzureProviderProps { | |||
| provider: Provider | |||
| onValidatedStatus: (status?: ValidatedStatus) => void | |||
| onValidatedStatus: (status?: ValidatedStatusState) => void | |||
| onTokenChange: (token: ProviderAzureToken) => void | |||
| } | |||
| const AzureProvider = ({ | |||
| @@ -31,7 +31,7 @@ const AzureProvider = ({ | |||
| token[type] = '' | |||
| setToken({...token}) | |||
| onTokenChange({...token}) | |||
| setValidatedStatus(undefined) | |||
| setValidatedStatus({}) | |||
| } | |||
| } | |||
| const handleChange = (type: keyof ProviderAzureToken, v: string, validate: any) => { | |||
| @@ -41,7 +41,7 @@ const AzureProvider = ({ | |||
| validate({...token}, { | |||
| beforeValidating: () => { | |||
| if (!token.openai_api_base || !token.openai_api_key) { | |||
| setValidatedStatus(undefined) | |||
| setValidatedStatus({}) | |||
| return false | |||
| } | |||
| return true | |||
| @@ -49,10 +49,10 @@ const AzureProvider = ({ | |||
| }) | |||
| } | |||
| const getValidatedIcon = () => { | |||
| if (validatedStatus === ValidatedStatus.Error || validatedStatus === ValidatedStatus.Exceed) { | |||
| if (validatedStatus.status === ValidatedStatus.Error || validatedStatus.status === ValidatedStatus.Exceed) { | |||
| return <ValidatedErrorIcon /> | |||
| } | |||
| if (validatedStatus === ValidatedStatus.Success) { | |||
| if (validatedStatus.status === ValidatedStatus.Success) { | |||
| return <ValidatedSuccessIcon /> | |||
| } | |||
| } | |||
| @@ -60,8 +60,8 @@ const AzureProvider = ({ | |||
| if (validating) { | |||
| return <ValidatingTip /> | |||
| } | |||
| if (validatedStatus === ValidatedStatus.Error) { | |||
| return <ValidatedErrorOnAzureOpenaiTip /> | |||
| if (validatedStatus.status === ValidatedStatus.Error) { | |||
| return <ValidatedErrorOnAzureOpenaiTip errorMessage={validatedStatus.message ?? ''} /> | |||
| } | |||
| } | |||
| useEffect(() => { | |||
| @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next' | |||
| import ProviderInput from '../provider-input' | |||
| import Link from 'next/link' | |||
| import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline' | |||
| import useValidateToken, { ValidatedStatus } from '../provider-input/useValidateToken' | |||
| import useValidateToken, { ValidatedStatus, ValidatedStatusState } from '../provider-input/useValidateToken' | |||
| import { | |||
| ValidatedErrorIcon, | |||
| ValidatedSuccessIcon, | |||
| @@ -15,7 +15,7 @@ import { | |||
| interface IOpenaiProviderProps { | |||
| provider: Provider | |||
| onValidatedStatus: (status?: ValidatedStatus) => void | |||
| onValidatedStatus: (status?: ValidatedStatusState) => void | |||
| onTokenChange: (token: string) => void | |||
| } | |||
| @@ -31,7 +31,7 @@ const OpenaiProvider = ({ | |||
| if (token === provider.token) { | |||
| setToken('') | |||
| onTokenChange('') | |||
| setValidatedStatus(undefined) | |||
| setValidatedStatus({}) | |||
| } | |||
| } | |||
| const handleChange = (v: string) => { | |||
| @@ -40,7 +40,7 @@ const OpenaiProvider = ({ | |||
| validate(v, { | |||
| beforeValidating: () => { | |||
| if (!v) { | |||
| setValidatedStatus(undefined) | |||
| setValidatedStatus({}) | |||
| return false | |||
| } | |||
| return true | |||
| @@ -54,10 +54,10 @@ const OpenaiProvider = ({ | |||
| }, [validatedStatus]) | |||
| const getValidatedIcon = () => { | |||
| if (validatedStatus === ValidatedStatus.Error || validatedStatus === ValidatedStatus.Exceed) { | |||
| if (validatedStatus?.status === ValidatedStatus.Error || validatedStatus.status === ValidatedStatus.Exceed) { | |||
| return <ValidatedErrorIcon /> | |||
| } | |||
| if (validatedStatus === ValidatedStatus.Success) { | |||
| if (validatedStatus.status === ValidatedStatus.Success) { | |||
| return <ValidatedSuccessIcon /> | |||
| } | |||
| } | |||
| @@ -65,11 +65,11 @@ const OpenaiProvider = ({ | |||
| if (validating) { | |||
| return <ValidatingTip /> | |||
| } | |||
| if (validatedStatus === ValidatedStatus.Exceed) { | |||
| if (validatedStatus?.status === ValidatedStatus.Success) { | |||
| return <ValidatedExceedOnOpenaiTip /> | |||
| } | |||
| if (validatedStatus === ValidatedStatus.Error) { | |||
| return <ValidatedErrorOnOpenaiTip /> | |||
| if (validatedStatus?.status === ValidatedStatus.Error) { | |||
| return <ValidatedErrorOnOpenaiTip errorMessage={validatedStatus.message ?? ''} /> | |||
| } | |||
| } | |||
| @@ -38,22 +38,22 @@ export const ValidatedExceedOnOpenaiTip = () => { | |||
| ) | |||
| } | |||
| export const ValidatedErrorOnOpenaiTip = () => { | |||
| export const ValidatedErrorOnOpenaiTip = ({ errorMessage }: { errorMessage: string }) => { | |||
| const { t } = useTranslation() | |||
| return ( | |||
| <div className={`mt-2 text-[#D92D20] text-xs font-normal`}> | |||
| {t('common.provider.invalidKey')} | |||
| {t('common.provider.validatedError')}{errorMessage} | |||
| </div> | |||
| ) | |||
| } | |||
| export const ValidatedErrorOnAzureOpenaiTip = () => { | |||
| export const ValidatedErrorOnAzureOpenaiTip = ({ errorMessage }: { errorMessage: string }) => { | |||
| const { t } = useTranslation() | |||
| return ( | |||
| <div className={`mt-2 text-[#D92D20] text-xs font-normal`}> | |||
| {t('common.provider.invalidApiKey')} | |||
| {t('common.provider.validatedError')}{errorMessage} | |||
| </div> | |||
| ) | |||
| } | |||
| @@ -8,11 +8,16 @@ export enum ValidatedStatus { | |||
| Error = 'error', | |||
| Exceed = 'exceed' | |||
| } | |||
| export type SetValidatedStatus = Dispatch<SetStateAction<ValidatedStatus | undefined>> | |||
| export type ValidatedStatusState = { | |||
| status?: ValidatedStatus, | |||
| message?: string | |||
| } | |||
| // export type ValidatedStatusState = ValidatedStatus | undefined | ValidatedError | |||
| export type SetValidatedStatus = Dispatch<SetStateAction<ValidatedStatusState>> | |||
| export type ValidateFn = DebouncedFunc<(token: any, config: ValidateFnConfig) => void> | |||
| type ValidateTokenReturn = [ | |||
| boolean, | |||
| ValidatedStatus | undefined, | |||
| ValidatedStatusState, | |||
| SetValidatedStatus, | |||
| ValidateFn | |||
| ] | |||
| @@ -22,7 +27,7 @@ export type ValidateFnConfig = { | |||
| const useValidateToken = (providerName: string): ValidateTokenReturn => { | |||
| const [validating, setValidating] = useState(false) | |||
| const [validatedStatus, setValidatedStatus] = useState<ValidatedStatus | undefined>() | |||
| const [validatedStatus, setValidatedStatus] = useState<ValidatedStatusState>({}) | |||
| const validate = useCallback(debounce(async (token: string, config: ValidateFnConfig) => { | |||
| if (!config.beforeValidating(token)) { | |||
| return false | |||
| @@ -30,19 +35,12 @@ const useValidateToken = (providerName: string): ValidateTokenReturn => { | |||
| setValidating(true) | |||
| try { | |||
| const res = await validateProviderKey({ url: `/workspaces/current/providers/${providerName}/token-validate`, body: { token } }) | |||
| setValidatedStatus(res.result === 'success' ? ValidatedStatus.Success : ValidatedStatus.Error) | |||
| setValidatedStatus( | |||
| res.result === 'success' | |||
| ? { status: ValidatedStatus.Success } | |||
| : { status: ValidatedStatus.Error, message: res.error }) | |||
| } catch (e: any) { | |||
| if (e.status === 400) { | |||
| e.json().then(({ code }: any) => { | |||
| if (code === 'provider_request_failed' && providerName === 'openai') { | |||
| setValidatedStatus(ValidatedStatus.Exceed) | |||
| } else { | |||
| setValidatedStatus(ValidatedStatus.Error) | |||
| } | |||
| }) | |||
| } else { | |||
| setValidatedStatus(ValidatedStatus.Error) | |||
| } | |||
| setValidatedStatus({ status: ValidatedStatus.Error, message: e.message }) | |||
| } finally { | |||
| setValidating(false) | |||
| } | |||
| @@ -140,6 +140,7 @@ const translation = { | |||
| apiKey: "API Key", | |||
| enterYourKey: "Enter your API key here", | |||
| invalidKey: "Invalid OpenAI API key", | |||
| validatedError: "Validation failed: ", | |||
| validating: "Validating key...", | |||
| saveFailed: "Save api key failed", | |||
| apiKeyExceedBill: "This API KEY has no quota available, please read", | |||
| @@ -141,6 +141,7 @@ const translation = { | |||
| apiKey: "API 密钥", | |||
| enterYourKey: "输入你的 API 密钥", | |||
| invalidKey: '无效的 OpenAI API 密钥', | |||
| validatedError: "校验失败:", | |||
| validating: "验证密钥中...", | |||
| saveFailed: "API 密钥保存失败", | |||
| apiKeyExceedBill: "此 API KEY 已没有可用配额,请阅读", | |||