Skip to content

Commit

Permalink
✨ feat: 完成 ai provider 部分的新增、menu 列表、卡片列表与开启关闭,支持 model 开关,并优化列表展示,支持…
Browse files Browse the repository at this point in the history
… model 拉取。完成 ai models 新增和修改逻辑、排序完整实现,优化开关体验
  • Loading branch information
arvinxx committed Dec 31, 2024
1 parent 21b6610 commit 4f02822
Show file tree
Hide file tree
Showing 139 changed files with 18,932 additions and 49 deletions.
1 change: 0 additions & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const nextConfig: NextConfig = {
'@icons-pack/react-simple-icons',
'@lobehub/ui',
'gpt-tokenizer',
'chroma-js',
],
webVitalsAttribution: ['CLS', 'LCP'],
},
Expand Down
31 changes: 22 additions & 9 deletions src/app/(main)/settings/hooks/useCategory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';

import type { MenuProps } from '@/components/Menu';
import { isDeprecatedEdition } from '@/const/version';
import { SettingsTabs } from '@/store/global/initialState';
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';

Expand Down Expand Up @@ -50,15 +51,27 @@ export const useCategory = () => {
</Link>
),
},
showLLM && {
icon: <Icon icon={Brain} />,
key: SettingsTabs.LLM,
label: (
<Link href={'/settings/llm'} onClick={(e) => e.preventDefault()}>
{t('tab.llm')}
</Link>
),
},
showLLM &&
// TODO: Remove /llm when v2.0
isDeprecatedEdition
? {
icon: <Icon icon={Brain} />,
key: SettingsTabs.LLM,
label: (
<Link href={'/settings/llm'} onClick={(e) => e.preventDefault()}>
{t('tab.llm')}
</Link>
),
}
: {
icon: <Icon icon={Brain} />,
key: SettingsTabs.Provider,
label: (
<Link href={'/settings/provider'} onClick={(e) => e.preventDefault()}>
{t('tab.provider')}
</Link>
),
},

enableSTT && {
icon: <Icon icon={Mic2} />,
Expand Down
18 changes: 18 additions & 0 deletions src/app/(main)/settings/provider/(detail)/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';

import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import ModelList from '../../features/ModelList';
import ProviderConfig, { ProviderConfigProps } from '../../features/ProviderConfig';

const ProviderDetail = memo<ProviderConfigProps>((card) => {
return (
<Flexbox gap={24} paddingBlock={8}>
<ProviderConfig {...card} />
<ModelList id={card.id} {...card.modelList} />
</Flexbox>
);
});

export default ProviderDetail;
91 changes: 91 additions & 0 deletions src/app/(main)/settings/provider/(detail)/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import Ai21Provider from '@/config/modelProviders/ai21';
import Ai360Provider from '@/config/modelProviders/ai360';
import AnthropicProvider from '@/config/modelProviders/anthropic';
import BaichuanProvider from '@/config/modelProviders/baichuan';
import DeepSeekProvider from '@/config/modelProviders/deepseek';
import FireworksAIProvider from '@/config/modelProviders/fireworksai';
import GiteeAIProvider from '@/config/modelProviders/giteeai';
import GoogleProvider from '@/config/modelProviders/google';
import GroqProvider from '@/config/modelProviders/groq';
import HigressProvider from '@/config/modelProviders/higress';
import HunyuanProvider from '@/config/modelProviders/hunyuan';
import InternLMProvider from '@/config/modelProviders/internlm';
import MinimaxProvider from '@/config/modelProviders/minimax';
import MistralProvider from '@/config/modelProviders/mistral';
import MoonshotProvider from '@/config/modelProviders/moonshot';
import NovitaProvider from '@/config/modelProviders/novita';
import OpenRouterProvider from '@/config/modelProviders/openrouter';
import PerplexityProvider from '@/config/modelProviders/perplexity';
import QwenProvider from '@/config/modelProviders/qwen';
import SiliconCloudProvider from '@/config/modelProviders/siliconcloud';
import SparkProvider from '@/config/modelProviders/spark';
import StepfunProvider from '@/config/modelProviders/stepfun';
import TaichuProvider from '@/config/modelProviders/taichu';
import TogetherAIProvider from '@/config/modelProviders/togetherai';
import UpstageProvider from '@/config/modelProviders/upstage';
import XAIProvider from '@/config/modelProviders/xai';
import ZeroOneProvider from '@/config/modelProviders/zeroone';
import ZhiPuProvider from '@/config/modelProviders/zhipu';
import { isServerMode } from '@/const/version';
import { serverDB } from '@/database/server';
import { AiProviderModel } from '@/database/server/models/aiProvider';
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
import { PagePropsWithId } from '@/types/next';
import { getUserAuth } from '@/utils/server/auth';

import ProviderDetail from './index';

const DEFAULT_MODEL_PROVIDER_LIST = [
AnthropicProvider,
GoogleProvider,
DeepSeekProvider,
OpenRouterProvider,
NovitaProvider,
TogetherAIProvider,
FireworksAIProvider,
GroqProvider,
PerplexityProvider,
MistralProvider,
Ai21Provider,
UpstageProvider,
XAIProvider,
QwenProvider,
HunyuanProvider,
SparkProvider,
ZhiPuProvider,
ZeroOneProvider,
StepfunProvider,
MoonshotProvider,
BaichuanProvider,
MinimaxProvider,
Ai360Provider,
TaichuProvider,
InternLMProvider,
SiliconCloudProvider,
HigressProvider,
GiteeAIProvider,
];

const Page = async (props: PagePropsWithId) => {
const params = await props.params;

const builtinProviderCard = DEFAULT_MODEL_PROVIDER_LIST.find((v) => v.id === params.id);
if (!!builtinProviderCard) return <ProviderDetail {...builtinProviderCard} />;

if (isServerMode) {
const { userId } = await getUserAuth();

const aiProviderModel = new AiProviderModel(serverDB, userId!);

const userCard = await aiProviderModel.getAiProviderById(
params.id,
KeyVaultsGateKeeper.getUserKeyVaults,
);

if (userCard) return <ProviderDetail {...userCard} />;
}

return <div>not found</div>;
};

export default Page;
119 changes: 119 additions & 0 deletions src/app/(main)/settings/provider/(detail)/azure/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
'use client';

import { Markdown } from '@lobehub/ui';
import { AutoComplete, Input } from 'antd';
import { createStyles } from 'antd-style';
import { useTranslation } from 'react-i18next';

import { AzureProviderCard } from '@/config/modelProviders';
import { ModelProvider } from '@/libs/agent-runtime';
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
import { useUserStore } from '@/store/user';
import { modelProviderSelectors } from '@/store/user/selectors';

import { KeyVaultsConfigKey, LLMProviderApiTokenKey, LLMProviderBaseUrlKey } from '../../const';
import { SkeletonInput } from '../../features/ProviderConfig';
import { ProviderItem } from '../../type';
import ProviderDetail from '../[id]';

const useStyles = createStyles(({ css, token }) => ({
markdown: css`
p {
color: ${token.colorTextDescription} !important;
}
`,
tip: css`
font-size: 12px;
color: ${token.colorTextDescription};
`,
}));

const providerKey = ModelProvider.Azure;

const useProviderCard = (): ProviderItem => {
const { t } = useTranslation('modelProvider');
const { styles } = useStyles();

// Get the first model card's deployment name as the check model
const checkModel = useUserStore((s) => {
const chatModelCards = modelProviderSelectors.getModelCardsById(providerKey)(s);

if (chatModelCards.length > 0) {
return chatModelCards[0].deploymentName;
}

return 'gpt-35-turbo';
});

const isLoading = useAiInfraStore(aiProviderSelectors.isAiProviderConfigLoading(providerKey));

return {
...AzureProviderCard,
apiKeyItems: [
{
children: isLoading ? (
<SkeletonInput />
) : (
<Input.Password
autoComplete={'new-password'}
placeholder={t('azure.token.placeholder')}
/>
),
desc: t('azure.token.desc'),
label: t('azure.token.title'),
name: [KeyVaultsConfigKey, LLMProviderApiTokenKey],
},
{
children: isLoading ? (
<SkeletonInput />
) : (
<Input allowClear placeholder={t('azure.endpoint.placeholder')} />
),
desc: t('azure.endpoint.desc'),
label: t('azure.endpoint.title'),
name: [KeyVaultsConfigKey, LLMProviderBaseUrlKey],
},
{
children: isLoading ? (
<SkeletonInput />
) : (
<AutoComplete
options={[
'2024-06-01',
'2024-02-01',
'2024-05-01-preview',
'2024-04-01-preview',
'2024-03-01-preview',
'2024-02-15-preview',
'2023-10-01-preview',
'2023-06-01-preview',
'2023-05-15',
].map((i) => ({ label: i, value: i }))}
placeholder={'20XX-XX-XX'}
/>
),
desc: (
<Markdown className={styles.markdown} fontSize={12} variant={'chat'}>
{t('azure.azureApiVersion.desc')}
</Markdown>
),
label: t('azure.azureApiVersion.title'),
name: [KeyVaultsConfigKey, 'apiVersion'],
},
],
checkModel,
modelList: {
azureDeployName: true,
notFoundContent: t('azure.empty'),
placeholder: t('azure.modelListPlaceholder'),
},
};
};

const Page = () => {
const card = useProviderCard();

return <ProviderDetail {...card} />;
};

export default Page;
91 changes: 91 additions & 0 deletions src/app/(main)/settings/provider/(detail)/bedrock/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use client';

import { Input, Select } from 'antd';
import { useTranslation } from 'react-i18next';

import { BedrockProviderCard } from '@/config/modelProviders';
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
import { GlobalLLMProviderKey } from '@/types/user/settings';

import { KeyVaultsConfigKey } from '../../const';
import { SkeletonInput } from '../../features/ProviderConfig';
import { ProviderItem } from '../../type';
import ProviderDetail from '../[id]';

const providerKey: GlobalLLMProviderKey = 'bedrock';

const useBedrockCard = (): ProviderItem => {
const { t } = useTranslation('modelProvider');

const isLoading = useAiInfraStore(aiProviderSelectors.isAiProviderConfigLoading(providerKey));

return {
...BedrockProviderCard,
apiKeyItems: [
{
children: isLoading ? (
<SkeletonInput />
) : (
<Input.Password
autoComplete={'new-password'}
placeholder={t(`${providerKey}.accessKeyId.placeholder`)}
/>
),
desc: t(`${providerKey}.accessKeyId.desc`),
label: t(`${providerKey}.accessKeyId.title`),
name: [KeyVaultsConfigKey, 'accessKeyId'],
},
{
children: isLoading ? (
<SkeletonInput />
) : (
<Input.Password
autoComplete={'new-password'}
placeholder={t(`${providerKey}.secretAccessKey.placeholder`)}
/>
),
desc: t(`${providerKey}.secretAccessKey.desc`),
label: t(`${providerKey}.secretAccessKey.title`),
name: [KeyVaultsConfigKey, 'secretAccessKey'],
},
{
children: isLoading ? (
<SkeletonInput />
) : (
<Input.Password
autoComplete={'new-password'}
placeholder={t(`${providerKey}.sessionToken.placeholder`)}
/>
),
desc: t(`${providerKey}.sessionToken.desc`),
label: t(`${providerKey}.sessionToken.title`),
name: [KeyVaultsConfigKey, 'sessionToken'],
},
{
children: isLoading ? (
<SkeletonInput />
) : (
<Select
allowClear
options={['us-east-1', 'us-west-2', 'ap-southeast-1'].map((i) => ({
label: i,
value: i,
}))}
placeholder={'us-east-1'}
/>
),
desc: t(`${providerKey}.region.desc`),
label: t(`${providerKey}.region.title`),
name: [KeyVaultsConfigKey, 'region'],
},
],
};
};

const Page = () => {
const card = useBedrockCard();

return <ProviderDetail {...card} />;
};

export default Page;
Loading

0 comments on commit 4f02822

Please sign in to comment.