mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-18 21:36:12 +00:00
🐛 fix: fix api key input issue (#6112)
* fix api key input issue * try to fix clerk auth
This commit is contained in:
@@ -45,5 +45,3 @@ const Page = async (props: PagePropsWithId) => {
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
||||
export const dynamic = 'auto';
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
interface LoadingContextValue {
|
||||
loading: boolean;
|
||||
setLoading: (loading: boolean) => void;
|
||||
}
|
||||
|
||||
export const LoadingContext = createContext<LoadingContextValue>({
|
||||
loading: false,
|
||||
setLoading: () => {},
|
||||
});
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { Button, Input } from 'antd';
|
||||
import { Network } from 'lucide-react';
|
||||
import { ReactNode, memo, useState } from 'react';
|
||||
import { Button } from 'antd';
|
||||
import { Loader2Icon, Network } from 'lucide-react';
|
||||
import { ReactNode, memo, useContext, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { FormInput, FormPassword } from '@/components/FormInput';
|
||||
import { LoadingContext } from '@/features/Conversation/Error/APIKeyForm/LoadingContext';
|
||||
import { useProviderName } from '@/hooks/useProviderName';
|
||||
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
||||
import { GlobalLLMProviderKey } from '@/types/user/settings';
|
||||
@@ -27,6 +29,7 @@ const ProviderApiKeyForm = memo<ProviderApiKeyFormProps>(
|
||||
const { apiKey, baseURL, setConfig } = useApiKey(provider);
|
||||
const { showOpenAIProxyUrl } = useServerConfigStore(featureFlagsSelectors);
|
||||
const providerName = useProviderName(provider);
|
||||
const { loading } = useContext(LoadingContext);
|
||||
|
||||
return (
|
||||
<FormAction
|
||||
@@ -34,25 +37,25 @@ const ProviderApiKeyForm = memo<ProviderApiKeyFormProps>(
|
||||
description={t(`unlock.apiKey.description`, { name: providerName, ns: 'error' })}
|
||||
title={t(`unlock.apiKey.title`, { name: providerName, ns: 'error' })}
|
||||
>
|
||||
<Input.Password
|
||||
<FormPassword
|
||||
autoComplete={'new-password'}
|
||||
onChange={(e) => {
|
||||
setConfig(provider, { apiKey: e.target.value });
|
||||
onChange={(value) => {
|
||||
setConfig(provider, { apiKey: value });
|
||||
}}
|
||||
placeholder={apiKeyPlaceholder || 'sk-***********************'}
|
||||
type={'block'}
|
||||
suffix={<div>{loading && <Icon icon={Loader2Icon} spin />}</div>}
|
||||
value={apiKey}
|
||||
/>
|
||||
|
||||
{showEndpoint &&
|
||||
showOpenAIProxyUrl &&
|
||||
(showProxy ? (
|
||||
<Input
|
||||
onChange={(e) => {
|
||||
setConfig(provider, { baseURL: e.target.value });
|
||||
<FormInput
|
||||
onChange={(value) => {
|
||||
setConfig(provider, { baseURL: value });
|
||||
}}
|
||||
placeholder={'https://api.openai.com/v1'}
|
||||
type={'block'}
|
||||
suffix={<div>{loading && <Icon icon={Loader2Icon} spin />}</div>}
|
||||
value={baseURL}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ProviderIcon } from '@lobehub/icons';
|
||||
import { Button } from 'antd';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { memo, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Center, Flexbox } from 'react-layout-kit';
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useChatStore } from '@/store/chat';
|
||||
import { GlobalLLMProviderKey } from '@/types/user/settings';
|
||||
|
||||
import BedrockForm from './Bedrock';
|
||||
import { LoadingContext } from './LoadingContext';
|
||||
import ProviderApiKeyForm from './ProviderApiKeyForm';
|
||||
|
||||
interface APIKeyFormProps {
|
||||
@@ -18,6 +19,7 @@ interface APIKeyFormProps {
|
||||
|
||||
const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
|
||||
const { t } = useTranslation('error');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [resend, deleteMessage] = useChatStore((s) => [s.regenerateMessage, s.deleteMessage]);
|
||||
|
||||
@@ -62,38 +64,41 @@ const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
|
||||
}, [provider]);
|
||||
|
||||
return (
|
||||
<Center gap={16} style={{ maxWidth: 300 }}>
|
||||
{provider === ModelProvider.Bedrock ? (
|
||||
<BedrockForm />
|
||||
) : (
|
||||
<ProviderApiKeyForm
|
||||
apiKeyPlaceholder={apiKeyPlaceholder}
|
||||
avatar={<ProviderIcon provider={provider} size={80} type={'avatar'} />}
|
||||
provider={provider as GlobalLLMProviderKey}
|
||||
showEndpoint={provider === ModelProvider.OpenAI}
|
||||
/>
|
||||
)}
|
||||
<Flexbox gap={12} width={'100%'}>
|
||||
<Button
|
||||
block
|
||||
onClick={() => {
|
||||
resend(id);
|
||||
deleteMessage(id);
|
||||
}}
|
||||
style={{ marginTop: 8 }}
|
||||
type={'primary'}
|
||||
>
|
||||
{t('unlock.confirm')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
deleteMessage(id);
|
||||
}}
|
||||
>
|
||||
{t('unlock.closeMessage')}
|
||||
</Button>
|
||||
</Flexbox>
|
||||
</Center>
|
||||
<LoadingContext value={{ loading, setLoading }}>
|
||||
<Center gap={16} style={{ maxWidth: 300 }}>
|
||||
{provider === ModelProvider.Bedrock ? (
|
||||
<BedrockForm />
|
||||
) : (
|
||||
<ProviderApiKeyForm
|
||||
apiKeyPlaceholder={apiKeyPlaceholder}
|
||||
avatar={<ProviderIcon provider={provider} size={80} type={'avatar'} />}
|
||||
provider={provider as GlobalLLMProviderKey}
|
||||
showEndpoint={provider === ModelProvider.OpenAI}
|
||||
/>
|
||||
)}
|
||||
<Flexbox gap={12} width={'100%'}>
|
||||
<Button
|
||||
block
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
resend(id);
|
||||
deleteMessage(id);
|
||||
}}
|
||||
style={{ marginTop: 8 }}
|
||||
type={'primary'}
|
||||
>
|
||||
{t('unlock.confirm')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
deleteMessage(id);
|
||||
}}
|
||||
>
|
||||
{t('unlock.closeMessage')}
|
||||
</Button>
|
||||
</Flexbox>
|
||||
</Center>
|
||||
</LoadingContext>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { isDeprecatedEdition } from '@/const/version';
|
||||
import { LoadingContext } from '@/features/Conversation/Error/APIKeyForm/LoadingContext';
|
||||
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { keyVaultsConfigSelectors } from '@/store/user/selectors';
|
||||
@@ -11,7 +13,7 @@ export const useApiKey = (provider: string) => {
|
||||
keyVaultsConfigSelectors.getVaultByProvider(provider as any)(s)?.baseURL,
|
||||
s.updateKeyVaultConfig,
|
||||
]);
|
||||
|
||||
const { setLoading } = useContext(LoadingContext);
|
||||
const updateAiProviderConfig = useAiInfraStore((s) => s.updateAiProviderConfig);
|
||||
const data = useAiInfraStore(aiProviderSelectors.providerConfigById(provider), isEqual);
|
||||
|
||||
@@ -23,12 +25,14 @@ export const useApiKey = (provider: string) => {
|
||||
apiKey: data?.keyVaults.apiKey,
|
||||
baseURL: data?.keyVaults?.baseURL,
|
||||
setConfig: async (id: string, params: Record<string, string>) => {
|
||||
const next = { ...data?.keyVaults, ...params };
|
||||
if (isEqual(data?.keyVaults, next)) return;
|
||||
|
||||
setLoading(true);
|
||||
await updateAiProviderConfig(id, {
|
||||
keyVaults: {
|
||||
...data?.keyVaults,
|
||||
...params,
|
||||
},
|
||||
keyVaults: { ...data?.keyVaults, ...params },
|
||||
});
|
||||
setLoading(false);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user