@lobehub/chat 1.62.10 → 1.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/changelog/v1.json +24 -0
- package/docs/self-hosting/environment-variables/model-provider.mdx +18 -0
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +18 -0
- package/docs/self-hosting/server-database/sealos.mdx +5 -1
- package/locales/ar/chat.json +26 -0
- package/locales/ar/models.json +21 -0
- package/locales/bg-BG/chat.json +26 -0
- package/locales/bg-BG/models.json +21 -0
- package/locales/de-DE/chat.json +26 -0
- package/locales/de-DE/models.json +21 -0
- package/locales/en-US/chat.json +26 -0
- package/locales/en-US/models.json +21 -0
- package/locales/es-ES/chat.json +26 -0
- package/locales/es-ES/models.json +21 -0
- package/locales/fa-IR/chat.json +26 -0
- package/locales/fa-IR/models.json +21 -0
- package/locales/fr-FR/chat.json +26 -0
- package/locales/fr-FR/models.json +21 -0
- package/locales/it-IT/chat.json +26 -0
- package/locales/it-IT/models.json +21 -0
- package/locales/ja-JP/chat.json +26 -0
- package/locales/ja-JP/models.json +21 -0
- package/locales/ko-KR/chat.json +26 -0
- package/locales/ko-KR/models.json +21 -0
- package/locales/nl-NL/chat.json +26 -0
- package/locales/nl-NL/models.json +21 -0
- package/locales/pl-PL/chat.json +26 -0
- package/locales/pl-PL/models.json +21 -0
- package/locales/pt-BR/chat.json +26 -0
- package/locales/pt-BR/models.json +21 -0
- package/locales/ru-RU/chat.json +26 -0
- package/locales/ru-RU/models.json +21 -0
- package/locales/tr-TR/chat.json +26 -0
- package/locales/tr-TR/models.json +21 -0
- package/locales/vi-VN/chat.json +26 -0
- package/locales/vi-VN/models.json +21 -0
- package/locales/zh-CN/chat.json +27 -1
- package/locales/zh-CN/models.json +25 -4
- package/locales/zh-TW/chat.json +26 -0
- package/locales/zh-TW/models.json +21 -0
- package/package.json +3 -3
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +1 -0
- package/src/config/aiModels/google.ts +8 -0
- package/src/config/aiModels/groq.ts +111 -95
- package/src/config/aiModels/hunyuan.ts +36 -4
- package/src/config/aiModels/internlm.ts +4 -5
- package/src/config/aiModels/jina.ts +3 -0
- package/src/config/aiModels/mistral.ts +35 -21
- package/src/config/aiModels/novita.ts +293 -32
- package/src/config/aiModels/perplexity.ts +14 -2
- package/src/config/aiModels/qwen.ts +91 -37
- package/src/config/aiModels/sensenova.ts +70 -17
- package/src/config/aiModels/siliconcloud.ts +5 -3
- package/src/config/aiModels/stepfun.ts +19 -0
- package/src/config/aiModels/taichu.ts +4 -2
- package/src/config/aiModels/upstage.ts +24 -11
- package/src/config/modelProviders/openrouter.ts +1 -0
- package/src/config/modelProviders/qwen.ts +2 -1
- package/src/config/modelProviders/volcengine.ts +4 -1
- package/src/const/settings/agent.ts +1 -0
- package/src/database/repositories/aiInfra/index.test.ts +2 -5
- package/src/database/repositories/aiInfra/index.ts +6 -2
- package/src/database/schemas/message.ts +2 -1
- package/src/database/server/models/aiModel.ts +1 -1
- package/src/database/server/models/aiProvider.ts +6 -1
- package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +38 -0
- package/src/features/ChatInput/ActionBar/Model/ExtendControls.tsx +40 -0
- package/src/features/ChatInput/ActionBar/Model/index.tsx +132 -0
- package/src/features/ChatInput/ActionBar/Params/index.tsx +2 -2
- package/src/features/ChatInput/ActionBar/Search/ExaIcon.tsx +15 -0
- package/src/features/ChatInput/ActionBar/Search/ModelBuiltinSearch.tsx +68 -0
- package/src/features/ChatInput/ActionBar/Search/SwitchPanel.tsx +167 -0
- package/src/features/ChatInput/ActionBar/Search/index.tsx +76 -0
- package/src/features/ChatInput/ActionBar/config.ts +4 -2
- package/src/features/Conversation/Messages/Assistant/SearchGrounding.tsx +153 -0
- package/src/features/Conversation/Messages/Assistant/index.tsx +7 -1
- package/src/features/ModelSelect/index.tsx +1 -1
- package/src/features/ModelSwitchPanel/index.tsx +2 -3
- package/src/hooks/useEnabledChatModels.ts +1 -1
- package/src/libs/agent-runtime/azureai/index.ts +21 -2
- package/src/libs/agent-runtime/google/index.test.ts +142 -36
- package/src/libs/agent-runtime/google/index.ts +26 -51
- package/src/libs/agent-runtime/novita/__snapshots__/index.test.ts.snap +3 -3
- package/src/libs/agent-runtime/openrouter/__snapshots__/index.test.ts.snap +3 -3
- package/src/libs/agent-runtime/openrouter/index.ts +20 -20
- package/src/libs/agent-runtime/perplexity/index.test.ts +2 -2
- package/src/libs/agent-runtime/qwen/index.ts +38 -55
- package/src/libs/agent-runtime/types/chat.ts +6 -2
- package/src/libs/agent-runtime/utils/streams/google-ai.ts +29 -4
- package/src/libs/agent-runtime/utils/streams/openai.ts +1 -1
- package/src/libs/agent-runtime/utils/streams/protocol.ts +1 -1
- package/src/locales/default/chat.ts +28 -0
- package/src/services/chat.ts +10 -0
- package/src/store/agent/slices/chat/__snapshots__/selectors.test.ts.snap +1 -0
- package/src/store/agent/slices/chat/selectors.ts +6 -0
- package/src/store/aiInfra/slices/aiModel/selectors.ts +36 -0
- package/src/store/aiInfra/slices/aiProvider/initialState.ts +2 -2
- package/src/store/aiInfra/slices/aiProvider/selectors.ts +14 -0
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +15 -5
- package/src/store/chat/slices/message/action.ts +1 -1
- package/src/store/user/slices/modelList/selectors/modelProvider.ts +1 -1
- package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +1 -0
- package/src/types/agent/index.ts +4 -0
- package/src/types/aiModel.ts +35 -8
- package/src/types/aiProvider.ts +7 -10
- package/src/types/message/base.ts +2 -5
- package/src/types/message/chat.ts +5 -3
- package/src/types/openai/chat.ts +5 -0
- package/src/types/search.ts +29 -0
- package/src/utils/fetch/fetchSSE.ts +11 -11
- package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +0 -20
@@ -153,7 +153,8 @@ const Qwen: ModelProviderCard = {
|
|
153
153
|
},
|
154
154
|
{
|
155
155
|
contextWindowTokens: 32_768,
|
156
|
-
description:
|
156
|
+
description:
|
157
|
+
'QVQ模型是由 Qwen 团队开发的实验性研究模型,专注于提升视觉推理能力,尤其在数学推理领域。',
|
157
158
|
displayName: 'QVQ 72B Preview',
|
158
159
|
id: 'qvq-72b-preview',
|
159
160
|
pricing: {
|
@@ -7,9 +7,12 @@ const Doubao: ModelProviderCard = {
|
|
7
7
|
'字节跳动推出的大模型服务的开发平台,提供功能丰富、安全以及具备价格竞争力的模型调用服务,同时提供模型数据、精调、推理、评测等端到端功能,全方位保障您的 AI 应用开发落地。',
|
8
8
|
id: 'volcengine',
|
9
9
|
modelsUrl: 'https://www.volcengine.com/docs/82379/1330310',
|
10
|
-
name: '
|
10
|
+
name: 'Volcengine',
|
11
11
|
settings: {
|
12
12
|
disableBrowserRequest: true, // CORS error
|
13
|
+
proxyUrl: {
|
14
|
+
placeholder: 'https://ark.cn-beijing.volces.com/api/v3',
|
15
|
+
},
|
13
16
|
sdkType: 'openai',
|
14
17
|
showDeployName: true,
|
15
18
|
smoothing: {
|
@@ -2,14 +2,11 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
3
3
|
import { DEFAULT_MODEL_PROVIDER_LIST } from '@/config/modelProviders';
|
4
4
|
import { clientDB, initializeDB } from '@/database/client/db';
|
5
|
-
import {
|
6
|
-
import { LobeChatDatabase } from '@/database/type';
|
7
|
-
import { AiProviderModelListItem } from '@/types/aiModel';
|
5
|
+
import { AiProviderModelListItem, EnabledAiModel } from '@/types/aiModel';
|
8
6
|
import {
|
9
7
|
AiProviderDetailItem,
|
10
8
|
AiProviderListItem,
|
11
9
|
AiProviderRuntimeConfig,
|
12
|
-
EnabledAiModel,
|
13
10
|
EnabledProvider,
|
14
11
|
} from '@/types/aiProvider';
|
15
12
|
|
@@ -286,7 +283,7 @@ describe('AiInfraRepos', () => {
|
|
286
283
|
expect(result).toEqual(
|
287
284
|
expect.arrayContaining([
|
288
285
|
expect.objectContaining({ id: 'taichu_llm' }),
|
289
|
-
expect.objectContaining({ id: '
|
286
|
+
expect.objectContaining({ id: 'taichu_vl' }),
|
290
287
|
]),
|
291
288
|
);
|
292
289
|
});
|
@@ -5,12 +5,16 @@ import { DEFAULT_MODEL_PROVIDER_LIST } from '@/config/modelProviders';
|
|
5
5
|
import { AiModelModel } from '@/database/server/models/aiModel';
|
6
6
|
import { AiProviderModel } from '@/database/server/models/aiProvider';
|
7
7
|
import { LobeChatDatabase } from '@/database/type';
|
8
|
-
import {
|
8
|
+
import {
|
9
|
+
AIChatModelCard,
|
10
|
+
AiModelSourceEnum,
|
11
|
+
AiProviderModelListItem,
|
12
|
+
EnabledAiModel,
|
13
|
+
} from '@/types/aiModel';
|
9
14
|
import {
|
10
15
|
AiProviderDetailItem,
|
11
16
|
AiProviderListItem,
|
12
17
|
AiProviderRuntimeState,
|
13
|
-
EnabledAiModel,
|
14
18
|
EnabledProvider,
|
15
19
|
} from '@/types/aiProvider';
|
16
20
|
import { ProviderConfig } from '@/types/user/settings';
|
@@ -13,7 +13,8 @@ import {
|
|
13
13
|
import { createSelectSchema } from 'drizzle-zod';
|
14
14
|
|
15
15
|
import { idGenerator } from '@/database/utils/idGenerator';
|
16
|
-
import {
|
16
|
+
import { ModelReasoning } from '@/types/message';
|
17
|
+
import { GroundingSearch } from '@/types/search';
|
17
18
|
|
18
19
|
import { timestamps } from './_helpers';
|
19
20
|
import { agents } from './agent';
|
@@ -5,9 +5,9 @@ import {
|
|
5
5
|
AiModelSortMap,
|
6
6
|
AiModelSourceEnum,
|
7
7
|
AiProviderModelListItem,
|
8
|
+
EnabledAiModel,
|
8
9
|
ToggleAiModelEnableParams,
|
9
10
|
} from '@/types/aiModel';
|
10
|
-
import { EnabledAiModel } from '@/types/aiProvider';
|
11
11
|
|
12
12
|
import { AiModelSelectItem, NewAiModelItem, aiModels } from '../../schemas';
|
13
13
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { and, asc, desc, eq } from 'drizzle-orm/expressions';
|
2
2
|
import { isEmpty } from 'lodash-es';
|
3
3
|
|
4
|
+
import { DEFAULT_MODEL_PROVIDER_LIST } from '@/config/modelProviders';
|
4
5
|
import { LobeChatDatabase } from '@/database/type';
|
5
6
|
import { ModelProvider } from '@/libs/agent-runtime';
|
6
7
|
import {
|
@@ -10,6 +11,7 @@ import {
|
|
10
11
|
CreateAiProviderParams,
|
11
12
|
UpdateAiProviderConfigParams,
|
12
13
|
} from '@/types/aiProvider';
|
14
|
+
import { merge } from '@/utils/merge';
|
13
15
|
|
14
16
|
import { AiProviderSelectItem, aiModels, aiProviders } from '../../schemas';
|
15
17
|
|
@@ -238,10 +240,13 @@ export class AiProviderModel {
|
|
238
240
|
let runtimeConfig: Record<string, AiProviderRuntimeConfig> = {};
|
239
241
|
|
240
242
|
for (const item of result) {
|
243
|
+
const builtin = DEFAULT_MODEL_PROVIDER_LIST.find((provider) => provider.id === item.id);
|
244
|
+
|
245
|
+
const userSettings = item.settings || {};
|
241
246
|
runtimeConfig[item.id] = {
|
242
247
|
fetchOnClient: typeof item.fetchOnClient === 'boolean' ? item.fetchOnClient : undefined,
|
243
248
|
keyVaults: !!item.keyVaults ? await decrypt(item.keyVaults) : {},
|
244
|
-
settings:
|
249
|
+
settings: !!builtin ? merge(builtin.settings, userSettings) : userSettings,
|
245
250
|
};
|
246
251
|
}
|
247
252
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { Form } from '@lobehub/ui';
|
2
|
+
import { Switch } from 'antd';
|
3
|
+
import { memo } from 'react';
|
4
|
+
|
5
|
+
import { useAgentStore } from '@/store/agent';
|
6
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
7
|
+
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
8
|
+
|
9
|
+
const ControlsForm = memo(() => {
|
10
|
+
const [model, provider] = useAgentStore((s) => [
|
11
|
+
agentSelectors.currentAgentModel(s),
|
12
|
+
agentSelectors.currentAgentModelProvider(s),
|
13
|
+
]);
|
14
|
+
const modelExtendControls = useAiInfraStore(
|
15
|
+
aiModelSelectors.modelExtendControls(model, provider),
|
16
|
+
);
|
17
|
+
|
18
|
+
return (
|
19
|
+
<Form
|
20
|
+
itemMinWidth={200}
|
21
|
+
items={modelExtendControls!.map((item: any) => ({
|
22
|
+
children: <Switch />,
|
23
|
+
label: item.key,
|
24
|
+
minWidth: undefined,
|
25
|
+
name: item.key,
|
26
|
+
}))}
|
27
|
+
itemsType={'flat'}
|
28
|
+
onValuesChange={(_, values) => {
|
29
|
+
console.log(values);
|
30
|
+
}}
|
31
|
+
size={'small'}
|
32
|
+
style={{ fontSize: 12 }}
|
33
|
+
variant={'pure'}
|
34
|
+
/>
|
35
|
+
);
|
36
|
+
});
|
37
|
+
|
38
|
+
export default ControlsForm;
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
2
|
+
import { Popover } from 'antd';
|
3
|
+
import { Settings2Icon } from 'lucide-react';
|
4
|
+
import { memo } from 'react';
|
5
|
+
import { useTranslation } from 'react-i18next';
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
7
|
+
|
8
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
9
|
+
|
10
|
+
import ControlsForm from './ControlsForm';
|
11
|
+
|
12
|
+
const ExtendControls = memo(() => {
|
13
|
+
const { t } = useTranslation('chat');
|
14
|
+
|
15
|
+
const isMobile = useIsMobile();
|
16
|
+
return (
|
17
|
+
<Flexbox style={{ marginInlineStart: -4 }}>
|
18
|
+
<Popover
|
19
|
+
arrow={false}
|
20
|
+
content={<ControlsForm />}
|
21
|
+
open
|
22
|
+
styles={{
|
23
|
+
body: {
|
24
|
+
minWidth: isMobile ? undefined : 250,
|
25
|
+
width: isMobile ? '100vw' : undefined,
|
26
|
+
},
|
27
|
+
}}
|
28
|
+
>
|
29
|
+
<ActionIcon
|
30
|
+
icon={Settings2Icon}
|
31
|
+
placement={'bottom'}
|
32
|
+
style={{ borderRadius: 20 }}
|
33
|
+
title={t('extendControls.title')}
|
34
|
+
/>
|
35
|
+
</Popover>
|
36
|
+
</Flexbox>
|
37
|
+
);
|
38
|
+
});
|
39
|
+
|
40
|
+
export default ExtendControls;
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import { ModelIcon } from '@lobehub/icons';
|
2
|
+
import { ActionIcon, Tooltip } from '@lobehub/ui';
|
3
|
+
import { Popover } from 'antd';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { Brain, Settings2Icon } from 'lucide-react';
|
6
|
+
import { memo } from 'react';
|
7
|
+
import { useTranslation } from 'react-i18next';
|
8
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
9
|
+
|
10
|
+
import ModelSwitchPanel from '@/features/ModelSwitchPanel';
|
11
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
12
|
+
import { useAgentStore } from '@/store/agent';
|
13
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
14
|
+
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
15
|
+
|
16
|
+
import ControlsForm from './ControlsForm';
|
17
|
+
|
18
|
+
const useStyles = createStyles(({ css, token, isDarkMode, cx }) => ({
|
19
|
+
container: css`
|
20
|
+
border-radius: 20px;
|
21
|
+
background: ${isDarkMode ? token.colorFillSecondary : token.colorFillTertiary};
|
22
|
+
`,
|
23
|
+
icon: cx(
|
24
|
+
'model-switch',
|
25
|
+
css`
|
26
|
+
transition: scale 400ms cubic-bezier(0.215, 0.61, 0.355, 1);
|
27
|
+
`,
|
28
|
+
),
|
29
|
+
model: css`
|
30
|
+
cursor: pointer;
|
31
|
+
border-radius: 8px;
|
32
|
+
|
33
|
+
:hover {
|
34
|
+
background: ${token.colorFillSecondary};
|
35
|
+
}
|
36
|
+
|
37
|
+
:active {
|
38
|
+
.model-switch {
|
39
|
+
scale: 0.8;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
`,
|
43
|
+
modelWithControl: css`
|
44
|
+
border-radius: 20px;
|
45
|
+
|
46
|
+
:hover {
|
47
|
+
background: ${token.colorFillTertiary};
|
48
|
+
}
|
49
|
+
`,
|
50
|
+
|
51
|
+
video: css`
|
52
|
+
overflow: hidden;
|
53
|
+
border-radius: 8px;
|
54
|
+
`,
|
55
|
+
}));
|
56
|
+
|
57
|
+
const ModelSwitch = memo(() => {
|
58
|
+
const { t } = useTranslation('chat');
|
59
|
+
const { styles, cx } = useStyles();
|
60
|
+
const [model, provider, isLoading] = useAgentStore((s) => [
|
61
|
+
agentSelectors.currentAgentModel(s),
|
62
|
+
agentSelectors.currentAgentModelProvider(s),
|
63
|
+
agentSelectors.isAgentConfigLoading(s),
|
64
|
+
]);
|
65
|
+
|
66
|
+
const isModelHasExtendControls = useAiInfraStore(
|
67
|
+
aiModelSelectors.isModelHasExtendControls(model, provider),
|
68
|
+
);
|
69
|
+
|
70
|
+
const isMobile = useIsMobile();
|
71
|
+
|
72
|
+
if (isLoading)
|
73
|
+
return (
|
74
|
+
<ActionIcon
|
75
|
+
icon={Brain}
|
76
|
+
placement={'bottom'}
|
77
|
+
style={{
|
78
|
+
cursor: 'not-allowed',
|
79
|
+
}}
|
80
|
+
title={t('ModelSwitch.title')}
|
81
|
+
/>
|
82
|
+
);
|
83
|
+
|
84
|
+
return (
|
85
|
+
<Flexbox
|
86
|
+
align={'center'}
|
87
|
+
className={isModelHasExtendControls ? styles.container : ''}
|
88
|
+
horizontal
|
89
|
+
>
|
90
|
+
<ModelSwitchPanel>
|
91
|
+
<Center
|
92
|
+
className={cx(styles.model, isModelHasExtendControls && styles.modelWithControl)}
|
93
|
+
height={36}
|
94
|
+
width={36}
|
95
|
+
>
|
96
|
+
<Tooltip placement={'bottom'} title={[provider, model].join(' / ')}>
|
97
|
+
<div className={styles.icon}>
|
98
|
+
<ModelIcon model={model} size={22} />
|
99
|
+
</div>
|
100
|
+
</Tooltip>
|
101
|
+
</Center>
|
102
|
+
</ModelSwitchPanel>
|
103
|
+
|
104
|
+
{isModelHasExtendControls && (
|
105
|
+
<Flexbox style={{ marginInlineStart: -4 }}>
|
106
|
+
<Popover
|
107
|
+
arrow={false}
|
108
|
+
content={<ControlsForm />}
|
109
|
+
open
|
110
|
+
styles={{
|
111
|
+
body: {
|
112
|
+
minWidth: isMobile ? undefined : 200,
|
113
|
+
width: isMobile ? '100vw' : undefined,
|
114
|
+
},
|
115
|
+
}}
|
116
|
+
>
|
117
|
+
<ActionIcon
|
118
|
+
icon={Settings2Icon}
|
119
|
+
placement={'bottom'}
|
120
|
+
style={{ borderRadius: 20 }}
|
121
|
+
title={t('extendControls.title')}
|
122
|
+
/>
|
123
|
+
</Popover>
|
124
|
+
</Flexbox>
|
125
|
+
)}
|
126
|
+
</Flexbox>
|
127
|
+
);
|
128
|
+
});
|
129
|
+
|
130
|
+
ModelSwitch.displayName = 'ModelSwitch';
|
131
|
+
|
132
|
+
export default ModelSwitch;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { ActionIcon } from '@lobehub/ui';
|
2
2
|
import { Popover } from 'antd';
|
3
3
|
import { useTheme } from 'antd-style';
|
4
|
-
import {
|
4
|
+
import { SlidersHorizontal } from 'lucide-react';
|
5
5
|
import { memo, useState } from 'react';
|
6
6
|
import { useTranslation } from 'react-i18next';
|
7
7
|
import { Flexbox } from 'react-layout-kit';
|
@@ -41,7 +41,7 @@ const Params = memo(() => {
|
|
41
41
|
trigger={'click'}
|
42
42
|
>
|
43
43
|
<ActionIcon
|
44
|
-
icon={
|
44
|
+
icon={SlidersHorizontal}
|
45
45
|
placement={'bottom'}
|
46
46
|
title={popoverOpen ? undefined : t('settingModel.params.title')}
|
47
47
|
/>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
const ExaIcon = () => {
|
2
|
+
return (
|
3
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
4
|
+
<rect fill="white" height="24" width="24" />
|
5
|
+
<path
|
6
|
+
clipRule="evenodd"
|
7
|
+
d="M4 2H20V3.49254L13.1718 12L20 20.5075V22H4V2ZM12.1006 10.6234L17.6493 3.49254H6.5519L12.1006 10.6234ZM5.80014 5.27954V11.2537H10.4488L5.80014 5.27954ZM10.4488 12.7463H5.80014V18.7205L10.4488 12.7463ZM6.5519 20.5075L12.1006 13.3766L17.6493 20.5075H6.5519Z"
|
8
|
+
fill="#1F40ED"
|
9
|
+
fillRule="evenodd"
|
10
|
+
/>
|
11
|
+
</svg>
|
12
|
+
);
|
13
|
+
};
|
14
|
+
|
15
|
+
export default ExaIcon;
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import { Google } from '@lobehub/icons';
|
2
|
+
import { Icon } from '@lobehub/ui';
|
3
|
+
import { Switch } from 'antd';
|
4
|
+
import { Search } from 'lucide-react';
|
5
|
+
import { memo, useState } from 'react';
|
6
|
+
import { useTranslation } from 'react-i18next';
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
8
|
+
|
9
|
+
import { useAgentStore } from '@/store/agent';
|
10
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
11
|
+
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
12
|
+
|
13
|
+
import ExaIcon from './ExaIcon';
|
14
|
+
|
15
|
+
interface SearchEngineIconProps {
|
16
|
+
icon?: string;
|
17
|
+
}
|
18
|
+
|
19
|
+
const SearchEngineIcon = ({ icon }: SearchEngineIconProps) => {
|
20
|
+
switch (icon) {
|
21
|
+
case 'google': {
|
22
|
+
return <Google.Color />;
|
23
|
+
}
|
24
|
+
|
25
|
+
case 'exa': {
|
26
|
+
return <ExaIcon />;
|
27
|
+
}
|
28
|
+
|
29
|
+
default: {
|
30
|
+
return <Icon icon={Search} size={{ fontSize: 16 }} />;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
};
|
34
|
+
|
35
|
+
const ModelBuiltinSearch = memo(() => {
|
36
|
+
const { t } = useTranslation('chat');
|
37
|
+
const [model, provider, checked, updateAgentChatConfig] = useAgentStore((s) => [
|
38
|
+
agentSelectors.currentAgentModel(s),
|
39
|
+
agentSelectors.currentAgentModelProvider(s),
|
40
|
+
agentSelectors.currentAgentChatConfig(s).useModelBuiltinSearch,
|
41
|
+
s.updateAgentChatConfig,
|
42
|
+
]);
|
43
|
+
|
44
|
+
const [isLoading, setLoading] = useState(false);
|
45
|
+
const modelCard = useAiInfraStore(aiModelSelectors.getEnabledModelById(model, provider));
|
46
|
+
|
47
|
+
return (
|
48
|
+
<Flexbox
|
49
|
+
align={'center'}
|
50
|
+
horizontal
|
51
|
+
justify={'space-between'}
|
52
|
+
onClick={async () => {
|
53
|
+
setLoading(true);
|
54
|
+
await updateAgentChatConfig({ useModelBuiltinSearch: !checked });
|
55
|
+
setLoading(false);
|
56
|
+
}}
|
57
|
+
padding={'8px 12px'}
|
58
|
+
style={{ cursor: 'pointer', userSelect: 'none' }}
|
59
|
+
>
|
60
|
+
<Flexbox align={'center'} gap={4} horizontal>
|
61
|
+
<SearchEngineIcon icon={modelCard?.settings?.searchProvider} />
|
62
|
+
{t('search.mode.useModelBuiltin')}
|
63
|
+
</Flexbox>
|
64
|
+
<Switch checked={checked} loading={isLoading} size={'small'} />
|
65
|
+
</Flexbox>
|
66
|
+
);
|
67
|
+
});
|
68
|
+
export default ModelBuiltinSearch;
|
@@ -0,0 +1,167 @@
|
|
1
|
+
import { DisconnectOutlined } from '@ant-design/icons';
|
2
|
+
import { Icon } from '@lobehub/ui';
|
3
|
+
import { Divider, Typography } from 'antd';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { CheckIcon, SparklesIcon } from 'lucide-react';
|
6
|
+
import { ReactNode, memo } from 'react';
|
7
|
+
import { useTranslation } from 'react-i18next';
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
9
|
+
|
10
|
+
import { useAgentStore } from '@/store/agent';
|
11
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
12
|
+
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
13
|
+
import { SearchMode } from '@/types/search';
|
14
|
+
|
15
|
+
import ModelBuiltinSearch from './ModelBuiltinSearch';
|
16
|
+
|
17
|
+
const { Text } = Typography;
|
18
|
+
|
19
|
+
interface NetworkOption {
|
20
|
+
description: string;
|
21
|
+
disable?: boolean;
|
22
|
+
icon: ReactNode;
|
23
|
+
label: string;
|
24
|
+
value: SearchMode;
|
25
|
+
}
|
26
|
+
|
27
|
+
const useStyles = createStyles(({ css, token }) => ({
|
28
|
+
check: css`
|
29
|
+
margin-inline-start: 12px;
|
30
|
+
font-size: 16px;
|
31
|
+
color: ${token.colorPrimary};
|
32
|
+
`,
|
33
|
+
content: css`
|
34
|
+
flex: 1;
|
35
|
+
width: 230px;
|
36
|
+
`,
|
37
|
+
description: css`
|
38
|
+
font-size: 12px;
|
39
|
+
color: ${token.colorTextSecondary};
|
40
|
+
`,
|
41
|
+
disable: css`
|
42
|
+
cursor: not-allowed;
|
43
|
+
opacity: 0.45;
|
44
|
+
`,
|
45
|
+
iconWrapper: css`
|
46
|
+
display: flex;
|
47
|
+
flex-shrink: 0;
|
48
|
+
align-items: center;
|
49
|
+
justify-content: center;
|
50
|
+
|
51
|
+
width: 32px;
|
52
|
+
height: 32px;
|
53
|
+
border-radius: 8px;
|
54
|
+
|
55
|
+
font-size: 16px;
|
56
|
+
|
57
|
+
background: ${token.colorFillQuaternary};
|
58
|
+
`,
|
59
|
+
option: css`
|
60
|
+
cursor: pointer;
|
61
|
+
|
62
|
+
align-items: center;
|
63
|
+
|
64
|
+
width: 100%;
|
65
|
+
padding-block: 8px;
|
66
|
+
padding-inline: 12px;
|
67
|
+
border-radius: 8px;
|
68
|
+
|
69
|
+
transition: background-color 0.2s;
|
70
|
+
|
71
|
+
&:hover {
|
72
|
+
background: ${token.colorFillTertiary};
|
73
|
+
}
|
74
|
+
`,
|
75
|
+
title: css`
|
76
|
+
margin-block-end: 2px;
|
77
|
+
font-size: 14px;
|
78
|
+
font-weight: 500;
|
79
|
+
color: ${token.colorText};
|
80
|
+
`,
|
81
|
+
}));
|
82
|
+
|
83
|
+
const Item = memo<NetworkOption>(({ value, description, icon, label, disable }) => {
|
84
|
+
const { t } = useTranslation('chat');
|
85
|
+
const { styles } = useStyles();
|
86
|
+
const [mode, updateAgentChatConfig] = useAgentStore((s) => [
|
87
|
+
agentSelectors.agentSearchMode(s),
|
88
|
+
s.updateAgentChatConfig,
|
89
|
+
]);
|
90
|
+
|
91
|
+
return (
|
92
|
+
<Flexbox
|
93
|
+
className={styles.option}
|
94
|
+
gap={24}
|
95
|
+
horizontal
|
96
|
+
key={value}
|
97
|
+
onClick={() => updateAgentChatConfig({ searchMode: value })}
|
98
|
+
>
|
99
|
+
<Flexbox className={disable ? styles.disable : ''} gap={8} horizontal>
|
100
|
+
<div className={styles.iconWrapper}>{icon}</div>
|
101
|
+
<div className={styles.content}>
|
102
|
+
<div className={styles.title}>{label}</div>
|
103
|
+
<Text className={styles.description} type="secondary">
|
104
|
+
{disable ? t('search.mode.disable') : description}
|
105
|
+
</Text>
|
106
|
+
</div>
|
107
|
+
</Flexbox>
|
108
|
+
{mode === value && <Icon className={styles.check} icon={CheckIcon} />}
|
109
|
+
</Flexbox>
|
110
|
+
);
|
111
|
+
});
|
112
|
+
|
113
|
+
interface AINetworkSettingsProps {
|
114
|
+
providerSearch?: boolean;
|
115
|
+
}
|
116
|
+
const AINetworkSettings = memo<AINetworkSettingsProps>(() => {
|
117
|
+
const { t } = useTranslation('chat');
|
118
|
+
const [model, provider] = useAgentStore((s) => [
|
119
|
+
agentSelectors.currentAgentModel(s),
|
120
|
+
agentSelectors.currentAgentModelProvider(s),
|
121
|
+
]);
|
122
|
+
|
123
|
+
const supportFC = useAiInfraStore(aiModelSelectors.isModelSupportToolUse(model, provider));
|
124
|
+
const isModelHasBuiltinSearchConfig = useAiInfraStore(
|
125
|
+
aiModelSelectors.isModelHasBuiltinSearchConfig(model, provider),
|
126
|
+
);
|
127
|
+
|
128
|
+
const options: NetworkOption[] = [
|
129
|
+
{
|
130
|
+
description: t('search.mode.off.desc'),
|
131
|
+
icon: <DisconnectOutlined />,
|
132
|
+
label: t('search.mode.off.title'),
|
133
|
+
value: 'off',
|
134
|
+
},
|
135
|
+
// 等应用层联网功能做好以后再开启
|
136
|
+
// {
|
137
|
+
// description: t('search.mode.on.desc'),
|
138
|
+
// icon: <WifiOutlined />,
|
139
|
+
// label: t('search.mode.on.title'),
|
140
|
+
// value: 'on',
|
141
|
+
// },
|
142
|
+
{
|
143
|
+
description: t('search.mode.auto.desc'),
|
144
|
+
disable: !supportFC,
|
145
|
+
icon: <Icon icon={SparklesIcon} />,
|
146
|
+
label: t('search.mode.auto.title'),
|
147
|
+
value: 'auto',
|
148
|
+
},
|
149
|
+
];
|
150
|
+
|
151
|
+
return (
|
152
|
+
<Flexbox gap={8}>
|
153
|
+
{options.map((option) => (
|
154
|
+
<Item {...option} key={option.value} />
|
155
|
+
))}
|
156
|
+
|
157
|
+
{isModelHasBuiltinSearchConfig && (
|
158
|
+
<>
|
159
|
+
<Divider style={{ margin: 0, paddingInline: 12 }} />
|
160
|
+
<ModelBuiltinSearch />
|
161
|
+
</>
|
162
|
+
)}
|
163
|
+
</Flexbox>
|
164
|
+
);
|
165
|
+
});
|
166
|
+
|
167
|
+
export default AINetworkSettings;
|