@lobehub/chat 0.161.22 → 0.161.24
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 +58 -0
- package/package.json +2 -2
- package/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +3 -3
- package/src/app/(main)/settings/common/features/Common.tsx +1 -1
- package/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesNeutral.tsx +5 -5
- package/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesPrimary.tsx +5 -5
- package/src/app/(main)/settings/common/features/Theme/index.tsx +5 -4
- package/src/app/(main)/settings/llm/Azure/index.tsx +4 -4
- package/src/app/(main)/settings/llm/Bedrock/index.tsx +4 -4
- package/src/app/(main)/settings/llm/Ollama/Checker.tsx +1 -1
- package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +5 -4
- package/src/app/(main)/settings/llm/const.ts +2 -1
- package/src/app/api/chat/[provider]/route.test.ts +2 -1
- package/src/app/api/chat/[provider]/route.ts +7 -8
- package/src/const/auth.ts +6 -0
- package/src/const/settings/common.ts +2 -2
- package/src/const/settings/index.ts +2 -1
- package/src/const/settings/llm.ts +0 -19
- package/src/database/client/core/db.ts +19 -0
- package/src/database/client/core/schemas.ts +3 -2
- package/src/database/client/models/__tests__/user.test.ts +5 -5
- package/src/database/client/models/user.ts +2 -3
- package/src/database/client/schemas/user.ts +10 -4
- package/src/features/AgentSetting/AgentMeta/index.tsx +3 -3
- package/src/features/AgentSetting/AgentTTS/index.tsx +2 -2
- package/src/features/ChatInput/STT/browser.tsx +2 -2
- package/src/features/ChatInput/STT/openai.tsx +2 -2
- package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +5 -5
- package/src/features/Conversation/Error/APIKeyForm/ProviderApiKeyForm.tsx +4 -4
- package/src/features/Conversation/Error/AccessCodeForm.tsx +4 -4
- package/src/features/Conversation/Extras/TTS/index.tsx +2 -2
- package/src/features/Conversation/Plugins/Render/MarkdownType/index.tsx +2 -2
- package/src/features/Conversation/components/ChatItem/index.tsx +2 -2
- package/src/features/PluginDevModal/LocalForm.tsx +2 -2
- package/src/features/PluginStore/index.tsx +6 -2
- package/src/features/User/UserPanel/LangButton.tsx +2 -2
- package/src/features/User/UserPanel/ThemeButton.tsx +2 -2
- package/src/hooks/_header.ts +6 -3
- package/src/hooks/useTTS.ts +2 -2
- package/src/layout/GlobalProvider/AppTheme.tsx +4 -4
- package/src/libs/agent-runtime/types/chat.ts +4 -0
- package/src/libs/agent-runtime/types/type.ts +3 -2
- package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.test.ts +10 -7
- package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +8 -5
- package/src/migrations/FromV6ToV7/fixtures/output-v7-from-v1.json +203 -0
- package/src/migrations/FromV6ToV7/fixtures/provider-input-v6.json +103 -0
- package/src/migrations/FromV6ToV7/fixtures/provider-output-v7.json +118 -0
- package/src/migrations/FromV6ToV7/index.ts +101 -0
- package/src/migrations/FromV6ToV7/migrations.test.ts +64 -0
- package/src/migrations/FromV6ToV7/types/v6.ts +61 -0
- package/src/migrations/FromV6ToV7/types/v7.ts +71 -0
- package/src/migrations/index.ts +9 -3
- package/src/services/__tests__/chat.test.ts +19 -19
- package/src/services/__tests__/share.test.ts +2 -2
- package/src/services/_auth.test.ts +10 -5
- package/src/services/_auth.ts +17 -8
- package/src/services/_header.ts +6 -3
- package/src/services/ollama.ts +3 -3
- package/src/services/user/client.test.ts +1 -1
- package/src/store/chat/slices/topic/action.test.ts +12 -6
- package/src/store/chat/slices/topic/action.ts +17 -18
- package/src/store/chat/slices/topic/initialState.ts +0 -2
- package/src/store/chat/slices/topic/selectors.test.ts +1 -1
- package/src/store/chat/slices/topic/selectors.ts +2 -1
- package/src/store/user/helpers.ts +3 -2
- package/src/store/user/selectors.ts +10 -2
- package/src/store/user/slices/common/action.test.ts +3 -3
- package/src/store/user/slices/common/action.ts +2 -2
- package/src/store/user/slices/modelList/action.test.ts +2 -2
- package/src/store/user/slices/modelList/action.ts +15 -3
- package/src/store/user/slices/modelList/selectors/index.ts +1 -0
- package/src/store/user/slices/modelList/selectors/keyVaults.ts +25 -0
- package/src/store/user/slices/modelList/selectors/modelConfig.test.ts +1 -1
- package/src/store/user/slices/modelList/selectors/modelConfig.ts +0 -5
- package/src/store/user/slices/settings/action.test.ts +14 -12
- package/src/store/user/slices/settings/action.ts +12 -6
- package/src/store/user/slices/settings/selectors/general.test.ts +45 -0
- package/src/store/user/slices/settings/selectors/general.ts +40 -0
- package/src/store/user/slices/settings/selectors/index.ts +1 -0
- package/src/store/user/slices/settings/selectors/settings.test.ts +0 -39
- package/src/store/user/slices/settings/selectors/settings.ts +6 -32
- package/src/types/user/settings/general.ts +1 -1
- package/src/types/user/settings/index.ts +7 -29
- package/src/types/user/settings/keyVaults.ts +36 -0
- package/src/types/user/settings/modelProvider.ts +4 -40
|
@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
11
11
|
|
|
12
12
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
13
13
|
import { useUserStore } from '@/store/user';
|
|
14
|
-
import {
|
|
14
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
15
15
|
|
|
16
16
|
import { useStore } from '../store';
|
|
17
17
|
import { SessionLoadingState } from '../store/initialState';
|
|
@@ -30,7 +30,7 @@ const AgentMeta = memo(() => {
|
|
|
30
30
|
s.autocompleteMeta,
|
|
31
31
|
s.autocompleteAllMeta,
|
|
32
32
|
]);
|
|
33
|
-
const locale = useUserStore(
|
|
33
|
+
const locale = useUserStore(userGeneralSettingsSelectors.currentLanguage);
|
|
34
34
|
const loading = useStore((s) => s.autocompleteLoading);
|
|
35
35
|
const meta = useStore((s) => s.meta, isEqual);
|
|
36
36
|
|
|
@@ -132,4 +132,4 @@ const AgentMeta = memo(() => {
|
|
|
132
132
|
return <Form items={[metaData]} itemsType={'group'} variant={'pure'} {...FORM_STYLE} />;
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
export default AgentMeta;
|
|
135
|
+
export default AgentMeta;
|
|
@@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
10
10
|
|
|
11
11
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
12
12
|
import { useUserStore } from '@/store/user';
|
|
13
|
-
import {
|
|
13
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
14
14
|
|
|
15
15
|
import { useStore } from '../store';
|
|
16
16
|
import { useAgentSyncSettings } from '../useSyncAgemtSettings';
|
|
@@ -24,7 +24,7 @@ const AgentTTS = memo(() => {
|
|
|
24
24
|
const { t } = useTranslation('setting');
|
|
25
25
|
const [form] = Form.useForm();
|
|
26
26
|
const voiceList = useUserStore((s) => {
|
|
27
|
-
const locale =
|
|
27
|
+
const locale = userGeneralSettingsSelectors.currentLanguage(s);
|
|
28
28
|
return (all?: boolean) => new VoiceList(all ? undefined : locale);
|
|
29
29
|
});
|
|
30
30
|
const [showAllLocaleVoice, ttsService, updateConfig] = useStore((s) => [
|
|
@@ -9,7 +9,7 @@ import { agentSelectors } from '@/store/agent/slices/chat';
|
|
|
9
9
|
import { useChatStore } from '@/store/chat';
|
|
10
10
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
11
11
|
import { useUserStore } from '@/store/user';
|
|
12
|
-
import { settingsSelectors } from '@/store/user/selectors';
|
|
12
|
+
import { settingsSelectors, userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
13
13
|
import { ChatMessageError } from '@/types/message';
|
|
14
14
|
import { getMessageError } from '@/utils/fetch';
|
|
15
15
|
|
|
@@ -22,7 +22,7 @@ interface STTConfig extends SWRConfiguration {
|
|
|
22
22
|
const useBrowserSTT = (config: STTConfig) => {
|
|
23
23
|
const ttsSettings = useUserStore(settingsSelectors.currentTTS, isEqual);
|
|
24
24
|
const ttsAgentSettings = useAgentStore(agentSelectors.currentAgentTTS, isEqual);
|
|
25
|
-
const locale = useUserStore(
|
|
25
|
+
const locale = useUserStore(userGeneralSettingsSelectors.currentLanguage);
|
|
26
26
|
|
|
27
27
|
const autoStop = ttsSettings.sttAutoStop;
|
|
28
28
|
const sttLocale =
|
|
@@ -12,7 +12,7 @@ import { agentSelectors } from '@/store/agent/selectors';
|
|
|
12
12
|
import { useChatStore } from '@/store/chat';
|
|
13
13
|
import { chatSelectors } from '@/store/chat/slices/message/selectors';
|
|
14
14
|
import { useUserStore } from '@/store/user';
|
|
15
|
-
import { settingsSelectors } from '@/store/user/selectors';
|
|
15
|
+
import { settingsSelectors, userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
16
16
|
import { ChatMessageError } from '@/types/message';
|
|
17
17
|
import { getMessageError } from '@/utils/fetch';
|
|
18
18
|
|
|
@@ -25,7 +25,7 @@ interface STTConfig extends SWRConfiguration {
|
|
|
25
25
|
const useOpenaiSTT = (config: STTConfig) => {
|
|
26
26
|
const ttsSettings = useUserStore(settingsSelectors.currentTTS, isEqual);
|
|
27
27
|
const ttsAgentSettings = useAgentStore(agentSelectors.currentAgentTTS, isEqual);
|
|
28
|
-
const locale = useUserStore(
|
|
28
|
+
const locale = useUserStore(userGeneralSettingsSelectors.currentLanguage);
|
|
29
29
|
|
|
30
30
|
const autoStop = ttsSettings.sttAutoStop;
|
|
31
31
|
const sttLocale =
|
|
@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
8
8
|
|
|
9
9
|
import { ModelProvider } from '@/libs/agent-runtime';
|
|
10
10
|
import { useUserStore } from '@/store/user';
|
|
11
|
-
import {
|
|
11
|
+
import { keyVaultsConfigSelectors } from '@/store/user/selectors';
|
|
12
12
|
|
|
13
13
|
import { FormAction } from '../style';
|
|
14
14
|
|
|
@@ -17,10 +17,10 @@ const BedrockForm = memo(() => {
|
|
|
17
17
|
const [showRegion, setShow] = useState(false);
|
|
18
18
|
|
|
19
19
|
const [accessKeyId, secretAccessKey, region, setConfig] = useUserStore((s) => [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
s.
|
|
20
|
+
keyVaultsConfigSelectors.bedrockConfig(s).accessKeyId,
|
|
21
|
+
keyVaultsConfigSelectors.bedrockConfig(s).secretAccessKey,
|
|
22
|
+
keyVaultsConfigSelectors.bedrockConfig(s).region,
|
|
23
|
+
s.updateKeyVaultConfig,
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
26
|
const theme = useTheme();
|
|
@@ -5,7 +5,7 @@ import { ReactNode, memo, useState } from 'react';
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import { useUserStore } from '@/store/user';
|
|
8
|
-
import {
|
|
8
|
+
import { keyVaultsConfigSelectors } from '@/store/user/selectors';
|
|
9
9
|
import { GlobalLLMProviderKey } from '@/types/user/settings';
|
|
10
10
|
|
|
11
11
|
import { FormAction } from '../style';
|
|
@@ -24,9 +24,9 @@ const ProviderApiKeyForm = memo<ProviderApiKeyFormProps>(
|
|
|
24
24
|
const [showProxy, setShow] = useState(false);
|
|
25
25
|
|
|
26
26
|
const [apiKey, proxyUrl, setConfig] = useUserStore((s) => [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
s.
|
|
27
|
+
keyVaultsConfigSelectors.getVaultByProvider(provider)(s)?.apiKey,
|
|
28
|
+
keyVaultsConfigSelectors.getVaultByProvider(provider)(s)?.baseURL,
|
|
29
|
+
s.updateKeyVaultConfig,
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
32
|
return (
|
|
@@ -15,9 +15,9 @@ interface AccessCodeFormProps {
|
|
|
15
15
|
|
|
16
16
|
const AccessCodeForm = memo<AccessCodeFormProps>(({ id }) => {
|
|
17
17
|
const { t } = useTranslation('error');
|
|
18
|
-
const [password,
|
|
19
|
-
settingsSelectors.
|
|
20
|
-
s.
|
|
18
|
+
const [password, updateKeyVaults] = useUserStore((s) => [
|
|
19
|
+
settingsSelectors.password(s),
|
|
20
|
+
s.updateKeyVaults,
|
|
21
21
|
]);
|
|
22
22
|
const [resend, deleteMessage] = useChatStore((s) => [s.regenerateMessage, s.deleteMessage]);
|
|
23
23
|
|
|
@@ -31,7 +31,7 @@ const AccessCodeForm = memo<AccessCodeFormProps>(({ id }) => {
|
|
|
31
31
|
<Input.Password
|
|
32
32
|
autoComplete={'new-password'}
|
|
33
33
|
onChange={(e) => {
|
|
34
|
-
|
|
34
|
+
updateKeyVaults({ password: e.target.value });
|
|
35
35
|
}}
|
|
36
36
|
placeholder={t('unlock.password.placeholder')}
|
|
37
37
|
type={'block'}
|
|
@@ -4,7 +4,7 @@ import { Md5 } from 'ts-md5';
|
|
|
4
4
|
import { useAgentStore } from '@/store/agent';
|
|
5
5
|
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
6
6
|
import { useUserStore } from '@/store/user';
|
|
7
|
-
import {
|
|
7
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
8
8
|
|
|
9
9
|
import FilePlayer from './FilePlayer';
|
|
10
10
|
import InitPlayer, { TTSProps } from './InitPlayer';
|
|
@@ -12,7 +12,7 @@ import InitPlayer, { TTSProps } from './InitPlayer';
|
|
|
12
12
|
const TTS = memo<TTSProps>(
|
|
13
13
|
(props) => {
|
|
14
14
|
const { file, voice, content, contentMd5 } = props;
|
|
15
|
-
const lang = useUserStore(
|
|
15
|
+
const lang = useUserStore(userGeneralSettingsSelectors.currentLanguage);
|
|
16
16
|
const currentVoice = useAgentStore(agentSelectors.currentAgentTTSVoice(lang));
|
|
17
17
|
|
|
18
18
|
const md5 = useMemo(() => Md5.hashStr(content).toString(), [content]);
|
|
@@ -2,7 +2,7 @@ import { Markdown } from '@lobehub/ui';
|
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { useUserStore } from '@/store/user';
|
|
5
|
-
import {
|
|
5
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
6
6
|
|
|
7
7
|
import Loading from '../Loading';
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ export interface PluginMarkdownTypeProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const PluginMarkdownType = memo<PluginMarkdownTypeProps>(({ content, loading }) => {
|
|
15
|
-
const fontSize = useUserStore(
|
|
15
|
+
const fontSize = useUserStore(userGeneralSettingsSelectors.fontSize);
|
|
16
16
|
if (loading) return <Loading />;
|
|
17
17
|
|
|
18
18
|
return (
|
|
@@ -11,7 +11,7 @@ import { chatSelectors } from '@/store/chat/selectors';
|
|
|
11
11
|
import { useSessionStore } from '@/store/session';
|
|
12
12
|
import { sessionMetaSelectors } from '@/store/session/selectors';
|
|
13
13
|
import { useUserStore } from '@/store/user';
|
|
14
|
-
import {
|
|
14
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
15
15
|
import { ChatMessage } from '@/types/message';
|
|
16
16
|
|
|
17
17
|
import ErrorMessageExtra, { getErrorAlertConfig } from '../../Error';
|
|
@@ -38,7 +38,7 @@ export interface ChatListItemProps {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
41
|
-
const fontSize = useUserStore(
|
|
41
|
+
const fontSize = useUserStore(userGeneralSettingsSelectors.fontSize);
|
|
42
42
|
const { t } = useTranslation('common');
|
|
43
43
|
const { styles, cx } = useStyles();
|
|
44
44
|
const [type = 'chat'] = useAgentStore((s) => {
|
|
@@ -7,13 +7,13 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
import { useToolStore } from '@/store/tool';
|
|
8
8
|
import { pluginSelectors } from '@/store/tool/selectors';
|
|
9
9
|
import { useUserStore } from '@/store/user';
|
|
10
|
-
import {
|
|
10
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
11
11
|
|
|
12
12
|
const EmojiPicker = dynamic(() => import('@lobehub/ui/es/EmojiPicker'), { ssr: false });
|
|
13
13
|
|
|
14
14
|
const LocalForm = memo<{ form: FormInstance; mode?: 'edit' | 'create' }>(({ form, mode }) => {
|
|
15
15
|
const isEditMode = mode === 'edit';
|
|
16
|
-
const locale = useUserStore(
|
|
16
|
+
const locale = useUserStore(userGeneralSettingsSelectors.currentLanguage);
|
|
17
17
|
const { t } = useTranslation('plugin');
|
|
18
18
|
|
|
19
19
|
const pluginIds = useToolStore(pluginSelectors.storeAndInstallPluginsIdList);
|
|
@@ -31,7 +31,11 @@ export const PluginStore = memo<PluginStoreProps>(({ setOpen, open }) => {
|
|
|
31
31
|
title={t('store.title')}
|
|
32
32
|
width={800}
|
|
33
33
|
>
|
|
34
|
-
<Flexbox
|
|
34
|
+
<Flexbox
|
|
35
|
+
gap={ mobile ? 8 : 16 }
|
|
36
|
+
style={{ maxHeight: mobile ? '-webkit-fill-available' : 'inherit' }}
|
|
37
|
+
width={'100%'}
|
|
38
|
+
>
|
|
35
39
|
<Segmented
|
|
36
40
|
block
|
|
37
41
|
onChange={(v) => {
|
|
@@ -50,4 +54,4 @@ export const PluginStore = memo<PluginStoreProps>(({ setOpen, open }) => {
|
|
|
50
54
|
);
|
|
51
55
|
});
|
|
52
56
|
|
|
53
|
-
export default PluginStore;
|
|
57
|
+
export default PluginStore;
|
|
@@ -8,12 +8,12 @@ import { useTranslation } from 'react-i18next';
|
|
|
8
8
|
import Menu, { type MenuProps } from '@/components/Menu';
|
|
9
9
|
import { localeOptions } from '@/locales/resources';
|
|
10
10
|
import { useUserStore } from '@/store/user';
|
|
11
|
-
import {
|
|
11
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
12
12
|
|
|
13
13
|
const LangButton = memo(() => {
|
|
14
14
|
const theme = useTheme();
|
|
15
15
|
const [language, switchLocale] = useUserStore((s) => [
|
|
16
|
-
|
|
16
|
+
userGeneralSettingsSelectors.language(s),
|
|
17
17
|
s.switchLocale,
|
|
18
18
|
]);
|
|
19
19
|
|
|
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
|
|
8
8
|
import Menu, { type MenuProps } from '@/components/Menu';
|
|
9
9
|
import { useUserStore } from '@/store/user';
|
|
10
|
-
import {
|
|
10
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
11
11
|
|
|
12
12
|
const themeIcons = {
|
|
13
13
|
auto: Monitor,
|
|
@@ -18,7 +18,7 @@ const themeIcons = {
|
|
|
18
18
|
const ThemeButton = memo(() => {
|
|
19
19
|
const theme = useTheme();
|
|
20
20
|
const [themeMode, switchThemeMode] = useUserStore((s) => [
|
|
21
|
-
|
|
21
|
+
userGeneralSettingsSelectors.currentThemeMode(s),
|
|
22
22
|
s.switchThemeMode,
|
|
23
23
|
]);
|
|
24
24
|
|
package/src/hooks/_header.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { LOBE_CHAT_ACCESS_CODE, OPENAI_API_KEY_HEADER_KEY, OPENAI_END_POINT } from '@/const/fetch';
|
|
2
2
|
import { useUserStore } from '@/store/user';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
keyVaultsConfigSelectors,
|
|
5
|
+
settingsSelectors,
|
|
6
|
+
} from '@/store/user/selectors';
|
|
4
7
|
|
|
5
8
|
// TODO: Need to be removed after tts refactor
|
|
6
9
|
// eslint-disable-next-line no-undef
|
|
7
10
|
export const createHeaderWithOpenAI = (header?: HeadersInit): HeadersInit => {
|
|
8
|
-
const openai =
|
|
11
|
+
const openai = keyVaultsConfigSelectors.openAIConfig(useUserStore.getState());
|
|
9
12
|
|
|
10
13
|
const apiKey = openai.apiKey || '';
|
|
11
|
-
const endpoint = openai.
|
|
14
|
+
const endpoint = openai.baseURL || '';
|
|
12
15
|
|
|
13
16
|
// eslint-disable-next-line no-undef
|
|
14
17
|
return {
|
package/src/hooks/useTTS.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { API_ENDPOINTS } from '@/services/_url';
|
|
|
14
14
|
import { useAgentStore } from '@/store/agent';
|
|
15
15
|
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
16
16
|
import { useUserStore } from '@/store/user';
|
|
17
|
-
import { settingsSelectors } from '@/store/user/selectors';
|
|
17
|
+
import { settingsSelectors, userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
18
18
|
import { TTSServer } from '@/types/agent';
|
|
19
19
|
|
|
20
20
|
interface TTSConfig extends TTSOptions {
|
|
@@ -26,7 +26,7 @@ interface TTSConfig extends TTSOptions {
|
|
|
26
26
|
export const useTTS = (content: string, config?: TTSConfig) => {
|
|
27
27
|
const ttsSettings = useUserStore(settingsSelectors.currentTTS, isEqual);
|
|
28
28
|
const ttsAgentSettings = useAgentStore(agentSelectors.currentAgentTTS, isEqual);
|
|
29
|
-
const lang = useUserStore(
|
|
29
|
+
const lang = useUserStore(userGeneralSettingsSelectors.currentLanguage);
|
|
30
30
|
const voice = useAgentStore(agentSelectors.currentAgentTTSVoice(lang));
|
|
31
31
|
let useSelectedTTS;
|
|
32
32
|
let options: any = {};
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
LOBE_THEME_PRIMARY_COLOR,
|
|
15
15
|
} from '@/const/theme';
|
|
16
16
|
import { useUserStore } from '@/store/user';
|
|
17
|
-
import {
|
|
17
|
+
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
18
18
|
import { GlobalStyle } from '@/styles';
|
|
19
19
|
import { setCookie } from '@/utils/cookie';
|
|
20
20
|
|
|
@@ -86,11 +86,11 @@ const AppTheme = memo<AppThemeProps>(
|
|
|
86
86
|
// console.debug('server:appearance', defaultAppearance);
|
|
87
87
|
// console.debug('server:primaryColor', defaultPrimaryColor);
|
|
88
88
|
// console.debug('server:neutralColor', defaultNeutralColor);
|
|
89
|
-
const themeMode = useUserStore(
|
|
89
|
+
const themeMode = useUserStore(userGeneralSettingsSelectors.currentThemeMode);
|
|
90
90
|
const { styles, cx } = useStyles();
|
|
91
91
|
const [primaryColor, neutralColor] = useUserStore((s) => [
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
userGeneralSettingsSelectors.primaryColor(s),
|
|
93
|
+
userGeneralSettingsSelectors.neutralColor(s),
|
|
94
94
|
]);
|
|
95
95
|
|
|
96
96
|
useEffect(() => {
|
|
@@ -95,6 +95,10 @@ export interface ChatCompetitionOptions {
|
|
|
95
95
|
callback?: ChatStreamCallbacks;
|
|
96
96
|
headers?: Record<string, any>;
|
|
97
97
|
signal?: AbortSignal;
|
|
98
|
+
/**
|
|
99
|
+
* userId for the chat completion
|
|
100
|
+
*/
|
|
101
|
+
user?: string;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
export interface ChatCompletionFunctions {
|
|
@@ -25,7 +25,6 @@ export enum ModelProvider {
|
|
|
25
25
|
Anthropic = 'anthropic',
|
|
26
26
|
Azure = 'azure',
|
|
27
27
|
Bedrock = 'bedrock',
|
|
28
|
-
ChatGLM = 'chatglm',
|
|
29
28
|
DeepSeek = 'deepseek',
|
|
30
29
|
Google = 'google',
|
|
31
30
|
Groq = 'groq',
|
|
@@ -37,7 +36,9 @@ export enum ModelProvider {
|
|
|
37
36
|
OpenRouter = 'openrouter',
|
|
38
37
|
Perplexity = 'perplexity',
|
|
39
38
|
TogetherAI = 'togetherai',
|
|
40
|
-
Tongyi = 'tongyi',
|
|
39
|
+
// Tongyi = 'tongyi',
|
|
41
40
|
ZeroOne = 'zeroone',
|
|
42
41
|
ZhiPu = 'zhipu',
|
|
43
42
|
}
|
|
43
|
+
|
|
44
|
+
export type ModelProviderKey = Lowercase<keyof typeof ModelProvider>;
|
|
@@ -195,18 +195,21 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
195
195
|
});
|
|
196
196
|
|
|
197
197
|
describe('handlePayload option', () => {
|
|
198
|
-
it('should
|
|
198
|
+
it('should add user in payload correctly', async () => {
|
|
199
199
|
const mockCreateMethod = vi.spyOn(instance['client'].chat.completions, 'create');
|
|
200
200
|
|
|
201
|
-
await instance.chat(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
201
|
+
await instance.chat(
|
|
202
|
+
{
|
|
203
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
204
|
+
model: 'mistralai/mistral-7b-instruct:free',
|
|
205
|
+
temperature: 0,
|
|
206
|
+
},
|
|
207
|
+
{ user: 'abc' },
|
|
208
|
+
);
|
|
206
209
|
|
|
207
210
|
expect(mockCreateMethod).toHaveBeenCalledWith(
|
|
208
211
|
expect.objectContaining({
|
|
209
|
-
|
|
212
|
+
user: 'abc',
|
|
210
213
|
}),
|
|
211
214
|
expect.anything(),
|
|
212
215
|
);
|
|
@@ -79,11 +79,14 @@ export const LobeOpenAICompatibleFactory = ({
|
|
|
79
79
|
stream: payload.stream ?? true,
|
|
80
80
|
} as OpenAI.ChatCompletionCreateParamsStreaming);
|
|
81
81
|
|
|
82
|
-
const response = await this.client.chat.completions.create(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
const response = await this.client.chat.completions.create(
|
|
83
|
+
{ ...postPayload, user: options?.user },
|
|
84
|
+
{
|
|
85
|
+
// https://github.com/lobehub/lobe-chat/pull/318
|
|
86
|
+
headers: { Accept: '*/*' },
|
|
87
|
+
signal: options?.signal,
|
|
88
|
+
},
|
|
89
|
+
);
|
|
87
90
|
|
|
88
91
|
if (postPayload.stream) {
|
|
89
92
|
const [prod, useForDebug] = response.tee();
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
{
|
|
2
|
+
"exportType": "sessions",
|
|
3
|
+
"state": {
|
|
4
|
+
"sessions": [
|
|
5
|
+
{
|
|
6
|
+
"config": {
|
|
7
|
+
"displayMode": "chat",
|
|
8
|
+
"historyCount": 1,
|
|
9
|
+
"model": "gpt-3.5-turbo",
|
|
10
|
+
"params": {
|
|
11
|
+
"frequency_penalty": 0,
|
|
12
|
+
"presence_penalty": 0,
|
|
13
|
+
"temperature": 0.6,
|
|
14
|
+
"top_p": 1,
|
|
15
|
+
"max_tokens": 2200
|
|
16
|
+
},
|
|
17
|
+
"plugins": [],
|
|
18
|
+
"systemRole": "你是一名 Postgresql 的数据库专家。用户是一名数据库小白,你需要使用简单直白的方式告诉用户如何使用 ostgresql 和它相应的 orm 工具 primsa",
|
|
19
|
+
"enableCompressThreshold": false,
|
|
20
|
+
"enableMaxTokens": false,
|
|
21
|
+
"inputTemplate": ""
|
|
22
|
+
},
|
|
23
|
+
"createdAt": 1698463356269,
|
|
24
|
+
"id": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
25
|
+
"meta": {
|
|
26
|
+
"avatar": "🐘",
|
|
27
|
+
"backgroundColor": "rgba(0,0,0,0)",
|
|
28
|
+
"title": "Postgresql 指南",
|
|
29
|
+
"description": "PostgreSQL 数据库和 Prisma ORM 工具的简单使用指南",
|
|
30
|
+
"tags": ["数据库", "PostgreSQL", "教程", "ORM", "Prisma"]
|
|
31
|
+
},
|
|
32
|
+
"type": "agent",
|
|
33
|
+
"updatedAt": 1698463356269,
|
|
34
|
+
"group": "default",
|
|
35
|
+
"pinned": true
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"topics": [
|
|
39
|
+
{
|
|
40
|
+
"createdAt": 1698463911747,
|
|
41
|
+
"id": "CZg3IEdy",
|
|
42
|
+
"title": "Prisma中的cuid函数作用是什么",
|
|
43
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
44
|
+
"updatedAt": 1698463915716
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"createdAt": 1698754463117,
|
|
48
|
+
"id": "MNWhBEh5",
|
|
49
|
+
"title": "启动 PostgreSQL Docker 镜像方法",
|
|
50
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
51
|
+
"updatedAt": 1698754464867
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"messages": [
|
|
55
|
+
{
|
|
56
|
+
"content": "是的,你可以使用 Prisma 来自定义生成 `id` 的逻辑,例如使用 `nanoid` 库来生成唯一标识符。\n\n首先,你需要在项目中安装 `nanoid` 库:\n\n```\nnpm install nanoid\n```\n\n然后,你可以在 Prisma 的模型定义中使用 `@default` 指令,并提供一个自定义的默认值函数来生成 `id`。\n\n```prisma\nmodel Message {\n id String @id @default(dbgenerated(\"nanoid(10)\"))\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n```\n\n在上述模型定义中,我们使用 `dbgenerated` 指令来定义一个自定义的默认值函数。函数 `nanoid(10)` 会生成一个长度为 10 的唯一标识符。\n\n请注意,使用自定义的 `id` 生成逻辑可能会对数据库性能产生一些影响,因为每次创建新记录时都需要执行自定义函数。因此,请确保你的自定义逻辑是高效的,并在实际使用中进行测试和评估性能。",
|
|
57
|
+
"createdAt": 1698463981313,
|
|
58
|
+
"id": "n2Tsl3Dm",
|
|
59
|
+
"meta": {},
|
|
60
|
+
"parentId": "JSZaJOGj",
|
|
61
|
+
"role": "assistant",
|
|
62
|
+
"updatedAt": 1698464004494,
|
|
63
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
64
|
+
"topicId": "CZg3IEdy",
|
|
65
|
+
"fromModel": "gpt-3.5-turbo"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"content": "如何指定 自定义函数的引入位置?",
|
|
69
|
+
"createdAt": 1698464173224,
|
|
70
|
+
"id": "xPft8Msa",
|
|
71
|
+
"meta": {},
|
|
72
|
+
"role": "user",
|
|
73
|
+
"updatedAt": 1698464173226,
|
|
74
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
75
|
+
"topicId": "CZg3IEdy"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"content": "在 Prisma 中,你可以通过在 `schema.prisma` 文件的顶部使用 `generator` 块来指定自定义函数的引入位置。\n\n例如,假设你想使用 `nanoid` 库来生成自定义的 `id`,你可以按照以下方式配置:\n\n```prisma\ngenerator client {\n provider = \"prisma-client-js\"\n output = \"./node_modules/@prisma/client\"\n}\n\ngenerator dbgenerated {\n provider = \"prisma-dbgenerator\"\n output = \"./node_modules/@prisma/client\"\n binaryTargets = [\"native\"]\n previewFeatures = [\"nativeTypes\"]\n config = {\n \"generator\": {\n \"dbgenerated\": {\n \"output\": \"./src/db/generated\",\n \"provider\": \"./src/db/generated/provider.js\"\n }\n }\n }\n}\n```\n\n在上述配置中,我们定义了两个生成器。`client` 生成器用于生成 Prisma 客户端代码,而 `dbgenerated` 生成器用于生成数据库相关的代码。\n\n注意到 `dbgenerated` 生成器的 `config` 部分中有一个 `provider` 字段,它指定了自定义函数的引入位置。在这个示例中,我们将自定义函数放在 `./src/db/generated/provider.js` 文件中。\n\n你可以根据你的项目结构和需要来调整路径和文件名,确保指定的 `provider` 路径正确引入了自定义函数。",
|
|
79
|
+
"createdAt": 1698464173228,
|
|
80
|
+
"id": "jZc2KKRs",
|
|
81
|
+
"meta": {},
|
|
82
|
+
"parentId": "xPft8Msa",
|
|
83
|
+
"role": "assistant",
|
|
84
|
+
"updatedAt": 1698464181896,
|
|
85
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
86
|
+
"topicId": "CZg3IEdy",
|
|
87
|
+
"fromModel": "gpt-3.5-turbo"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"content": "如何启动一个 postgres Docker 镜像?",
|
|
91
|
+
"createdAt": 1698754460196,
|
|
92
|
+
"id": "LjG9XSuq",
|
|
93
|
+
"meta": {},
|
|
94
|
+
"role": "user",
|
|
95
|
+
"updatedAt": 1698754463118,
|
|
96
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
97
|
+
"topicId": "MNWhBEh5"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"content": "要启动一个 PostgreSQL Docker 镜像,你可以按照以下步骤操作:\n\n1. 首先,确保你已经安装了 Docker,可以在终端中运行 `docker --version` 来检查。\n\n2. 在终端中运行以下命令以下载并启动一个 PostgreSQL 镜像:\n\n ```shell\n docker run --name my-postgres -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres\n ```\n\n 这将从 Docker Hub 下载 PostgreSQL 镜像",
|
|
101
|
+
"createdAt": 1698754479751,
|
|
102
|
+
"id": "CL7E1Mc5",
|
|
103
|
+
"meta": {},
|
|
104
|
+
"parentId": "LjG9XSuq",
|
|
105
|
+
"role": "assistant",
|
|
106
|
+
"updatedAt": 1698754507690,
|
|
107
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
108
|
+
"topicId": "MNWhBEh5",
|
|
109
|
+
"fromModel": "gpt-3.5-turbo"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"content": "如何指定本地存储的目录到 /www/database/postgres",
|
|
113
|
+
"createdAt": 1698754591763,
|
|
114
|
+
"id": "UIvHZr7m",
|
|
115
|
+
"meta": {},
|
|
116
|
+
"role": "user",
|
|
117
|
+
"updatedAt": 1698754591764,
|
|
118
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
119
|
+
"topicId": "MNWhBEh5"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"content": "要将本地存储的目录映射到容器内的 `/var/lib/postgresql/data` 目录,你可以使用 Docker 的 `-v` 参数。\n\n以下是示例命令:\n\n```shell\ndocker run --name my-postgres -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -v /www/database/postgres:/var/lib/postgresql/data -d postgres\n```\n\n在这个命令中,我们使用了 `-v` 参数来指定本地目录 `/www/database/postgres` 映射到容器内的 `/var/lib/postgresql/data` 目录。这样,所有的 PostgreSQL 数据将会保存在本地指定的目录中。",
|
|
123
|
+
"createdAt": 1698754591765,
|
|
124
|
+
"id": "XLJOK44r",
|
|
125
|
+
"meta": {},
|
|
126
|
+
"parentId": "UIvHZr7m",
|
|
127
|
+
"role": "assistant",
|
|
128
|
+
"updatedAt": 1698754609275,
|
|
129
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
130
|
+
"topicId": "MNWhBEh5",
|
|
131
|
+
"fromModel": "gpt-3.5-turbo"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"content": "docker run --name postgres -e POSTGRES_PASSWORD=DSLapHYdzNrai5j6 -p 33300:5432 -v /www/database/postgres:/var/lib/postgresql/data -d postgres",
|
|
135
|
+
"createdAt": 1698754700529,
|
|
136
|
+
"id": "W3J6jQjm",
|
|
137
|
+
"meta": {},
|
|
138
|
+
"role": "user",
|
|
139
|
+
"updatedAt": 1698754700530,
|
|
140
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
141
|
+
"topicId": "MNWhBEh5"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"content": "如何启动 pgadmin",
|
|
145
|
+
"createdAt": 1698755749886,
|
|
146
|
+
"id": "L7mq0ehV",
|
|
147
|
+
"meta": {},
|
|
148
|
+
"role": "user",
|
|
149
|
+
"updatedAt": 1698755749888,
|
|
150
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
151
|
+
"topicId": "MNWhBEh5"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"content": "要启动 pgAdmin,你可以按照以下步骤操作:\n\n1. 首先,确保你已经安装了 Docker,并且已经成功启动了 PostgreSQL Docker 容器。\n\n2. 在终端中运行以下命令以启动 pgAdmin Docker 容器:\n\n ```shell\n docker run --name my-pgadmin -p 5050:80 -e PGADMIN_DEFAULT_EMAIL=myemail@example.com -e PGADMIN_DEFAULT_PASSWORD=mypassword -d dpage/pgadmin4\n ```\n\n 在这个命令中,我们使用了 `-p` 参数来将容器的端口 80 映射到本地的端口 5050。你可以根据需要修改这个端口映射。\n\n 我们还使用了 `-e` 参数来设置 pgAdmin 的默认登录邮箱和密码。你可以根据需要修改这些值。\n\n3. 在浏览器中访问 `http://localhost:5050`,你将看到 pgAdmin 的登录界面。\n\n4. 使用在上一步中设置的邮箱和密码进行登录。\n\n5. 在 pgAdmin 中,你可以添加一个新的服务器连接,以连接到运行在 Docker 容器中的 PostgreSQL 数据库。要添加一个新的服务器连接,你需要提供以下信息:\n\n - 主机名/地址:使用 Docker 容器的 IP 地址或者 `localhost`。\n - 端口:使用 Docker 容器中 PostgreSQL 的映射端口,例如 33300。\n - 用户名和密码:使用在启动 PostgreSQL 容器时设置的用户名和密码。\n\n 完成上述信息的填写后,点击保存并连接到 PostgreSQL 服务器。\n\n现在,你已经成功启动了 pgAdmin 并连接到了你的 PostgreSQL 数据库。你可以使用 pgAdmin 来管理和操作你的数据库。",
|
|
155
|
+
"createdAt": 1698755749889,
|
|
156
|
+
"id": "d5XTX9EQ",
|
|
157
|
+
"meta": {},
|
|
158
|
+
"parentId": "L7mq0ehV",
|
|
159
|
+
"role": "assistant",
|
|
160
|
+
"updatedAt": 1698755786183,
|
|
161
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
162
|
+
"topicId": "MNWhBEh5",
|
|
163
|
+
"fromModel": "gpt-3.5-turbo"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"content": "abcabc",
|
|
167
|
+
"createdAt": 1690650544852,
|
|
168
|
+
"id": "KPPDiRyW",
|
|
169
|
+
"meta": {},
|
|
170
|
+
"parentId": "42k72jMi",
|
|
171
|
+
"role": "function",
|
|
172
|
+
"updatedAt": 1690650572399,
|
|
173
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
174
|
+
|
|
175
|
+
"fromModel": "gpt-3.5-turbo-16k",
|
|
176
|
+
"plugin": {
|
|
177
|
+
"apiName": "websiteCrawler",
|
|
178
|
+
"arguments": "{\n \"url\": \"https://mp.weixin.qq.com/s?__biz=MjM5MTA1MjAxMQ==&mid=2651264337&idx=1&sn=d7d9126578c74c912e1f0d42cb5629da&chksm=bd48ccd58a3f45c3f2cbc7d7b732c820b9e7cd6b547c06acc8170b233710b5fb5ed62f5fd94d&mpshare=1&scene=1&srcid=07294Mpw7C6JCLgtagL1cBDR&sharer_sharetime=1690622712877&sharer_shareid=0358058a42fc25387d28337fc3d22c3c#rd\"\n}",
|
|
179
|
+
"identifier": "websiteCrawler",
|
|
180
|
+
"type": "default"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"content": "bbbbb",
|
|
185
|
+
"createdAt": 1700065743405,
|
|
186
|
+
"id": "9cRjevRQ",
|
|
187
|
+
"meta": {},
|
|
188
|
+
"parentId": "3nDXtEKv",
|
|
189
|
+
"role": "function",
|
|
190
|
+
"sessionId": "06cc3e20-e870-4099-a619-c07a849d742d",
|
|
191
|
+
"updatedAt": 1700065751861,
|
|
192
|
+
"fromModel": "gpt-3.5-turbo-16k",
|
|
193
|
+
"plugin": {
|
|
194
|
+
"apiName": "getWebsiteContent",
|
|
195
|
+
"arguments": "{\n \"url\": \"https://nodejs.org/api/packages.html#dual-package-hazard\"\n}",
|
|
196
|
+
"identifier": "website-crawler",
|
|
197
|
+
"type": "default"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
"version": 7
|
|
203
|
+
}
|