import { ChangeEvent, useEffect, useRef, useState } from 'react' import { useContext } from 'use-context-selector' import { useTranslation } from 'react-i18next' import { debounce } from 'lodash-es' import Link from 'next/link' import useSWR from 'swr' import { ArrowTopRightOnSquareIcon, PencilIcon } from '@heroicons/react/24/outline' import { CheckCircleIcon, ExclamationCircleIcon } from '@heroicons/react/24/solid' import Button from '@/app/components/base/button' import s from './index.module.css' import classNames from 'classnames' import { fetchTenantInfo, validateProviderKey, updateProviderAIKey } from '@/service/common' import { ToastContext } from '@/app/components/base/toast' import Indicator from '../../../indicator' import I18n from '@/context/i18n' type IStatusType = 'normal' | 'verified' | 'error' | 'error-api-key-exceed-bill' type TInputWithStatusProps = { value: string onChange: (v: string) => void onValidating: (validating: boolean) => void verifiedStatus: IStatusType onVerified: (verified: IStatusType) => void } const InputWithStatus = ({ value, onChange, onValidating, verifiedStatus, onVerified }: TInputWithStatusProps) => { const { t } = useTranslation() const validateKey = useRef(debounce(async (token: string) => { if (!token) return onValidating(true) try { const res = await validateProviderKey({ url: '/workspaces/current/providers/openai/token-validate', body: { token } }) onVerified(res.result === 'success' ? 'verified' : 'error') } catch (e: any) { if (e.status === 400) { e.json().then(({ code }: any) => { if (code === 'provider_request_failed') { onVerified('error-api-key-exceed-bill') } }) } else { onVerified('error') } } finally { onValidating(false) } }, 500)) const handleChange = (e: ChangeEvent) => { const inputValue = e.target.value onChange(inputValue) if (!inputValue) { onVerified('normal') } validateKey.current(inputValue) } return (
{ verifiedStatus === 'error' && } { verifiedStatus === 'verified' && }
) } const OpenaiProvider = () => { const { t } = useTranslation() const { locale } = useContext(I18n) const { data: userInfo, mutate } = useSWR({ url: '/info' }, fetchTenantInfo) const [inputValue, setInputValue] = useState('') const [validating, setValidating] = useState(false) const [editStatus, setEditStatus] = useState('normal') const [loading, setLoading] = useState(false) const [editing, setEditing] = useState(false) const [invalidStatus, setInvalidStatus] = useState(false) const { notify } = useContext(ToastContext) const provider = userInfo?.providers?.find(({ provider }) => provider === 'openai') const handleReset = () => { setInputValue('') setValidating(false) setEditStatus('normal') setLoading(false) setEditing(false) } const handleSave = async () => { if (editStatus === 'verified') { try { setLoading(true) await updateProviderAIKey({ url: '/workspaces/current/providers/openai/token', body: { token: inputValue ?? '' } }) notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) } catch (e) { notify({ type: 'error', message: t('common.provider.saveFailed') }) } finally { setLoading(false) handleReset() mutate() } } } useEffect(() => { if (provider && !provider.token_is_valid && provider.token_is_set) { setInvalidStatus(true) } }, [userInfo]) const showInvalidStatus = invalidStatus && !editing const renderErrorMessage = () => { if (validating) { return (
{t('common.provider.validating')}
) } if (editStatus === 'error-api-key-exceed-bill') { return (
{t('common.provider.apiKeyExceedBill')}  {locale === 'en' ? 'this link' : '这篇文档'}
) } if (showInvalidStatus || editStatus === 'error') { return (
{t('common.provider.invalidKey')}
) } return null } return (
{t('common.provider.apiKey')}
{ provider && !editing && (
setEditing(true)} > {t('common.operation.edit')}
) } { (inputValue || editing) && ( <> ) }
{ (!provider || (provider && editing)) && ( setInputValue(v)} verifiedStatus={editStatus} onVerified={v => setEditStatus(v)} onValidating={v => setValidating(v)} /> ) } { (provider && !editing) && (
sk-0C...skuA
) } {renderErrorMessage()} {t('appOverview.welcome.getKeyTip')}
) } export default OpenaiProvider