@lobehub/chat 0.161.9 → 0.161.10

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/package.json +1 -1
  3. package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +5 -2
  4. package/src/app/(main)/settings/llm/components/ProviderModelList/CustomModelOption.tsx +6 -7
  5. package/src/app/(main)/settings/llm/components/ProviderModelList/{ModelConfigModal.tsx → ModelConfigModal/Form.tsx} +19 -63
  6. package/src/app/(main)/settings/llm/components/ProviderModelList/ModelConfigModal/index.tsx +78 -0
  7. package/src/app/(main)/settings/llm/components/ProviderModelList/Option.tsx +35 -11
  8. package/src/app/(main)/settings/llm/components/ProviderModelList/index.tsx +15 -18
  9. package/src/components/ModelProviderIcon/index.tsx +2 -2
  10. package/src/components/ModelSelect/index.tsx +5 -14
  11. package/src/features/User/UserPanel/PanelContent.tsx +1 -1
  12. package/src/hooks/useSyncData.ts +3 -1
  13. package/src/layout/GlobalProvider/StoreInitialization.tsx +17 -9
  14. package/src/layout/GlobalProvider/index.tsx +1 -1
  15. package/src/locales/default/components.ts +1 -0
  16. package/src/services/message/client.test.ts +0 -24
  17. package/src/services/message/client.ts +0 -5
  18. package/src/services/message/type.ts +0 -1
  19. package/src/services/user/client.test.ts +100 -0
  20. package/src/services/user/client.ts +16 -14
  21. package/src/services/user/index.ts +0 -2
  22. package/src/services/user/type.ts +2 -4
  23. package/src/store/user/initialState.ts +10 -1
  24. package/src/store/user/selectors.ts +3 -7
  25. package/src/store/user/slices/auth/action.test.ts +5 -87
  26. package/src/store/user/slices/auth/action.ts +3 -58
  27. package/src/store/user/slices/auth/initialState.ts +2 -1
  28. package/src/store/user/slices/common/action.test.ts +196 -20
  29. package/src/store/user/slices/common/action.ts +55 -26
  30. package/src/store/user/slices/common/initialState.ts +9 -0
  31. package/src/store/user/slices/modelList/action.test.ts +363 -0
  32. package/src/store/user/slices/{settings/actions/llm.ts → modelList/action.ts} +66 -60
  33. package/src/store/user/slices/modelList/initialState.ts +15 -0
  34. package/src/store/user/slices/modelList/selectors/index.ts +2 -0
  35. package/src/store/user/slices/{settings → modelList}/selectors/modelConfig.test.ts +3 -2
  36. package/src/store/user/slices/{settings → modelList}/selectors/modelConfig.ts +1 -1
  37. package/src/store/user/slices/{settings → modelList}/selectors/modelProvider.test.ts +7 -7
  38. package/src/store/user/slices/{settings → modelList}/selectors/modelProvider.ts +2 -4
  39. package/src/store/user/slices/preference/action.test.ts +0 -52
  40. package/src/store/user/slices/preference/action.ts +1 -17
  41. package/src/store/user/slices/preference/initialState.ts +0 -5
  42. package/src/store/user/slices/preference/selectors.test.ts +2 -2
  43. package/src/store/user/slices/preference/selectors.ts +1 -1
  44. package/src/store/user/slices/settings/{actions/general.ts → action.ts} +5 -5
  45. package/src/store/user/slices/settings/initialState.ts +0 -12
  46. package/src/store/user/slices/settings/selectors/index.ts +0 -3
  47. package/src/store/user/slices/sync/action.test.ts +19 -5
  48. package/src/store/user/slices/sync/action.ts +9 -6
  49. package/src/store/user/slices/{settings/selectors/sync.ts → sync/selectors.ts} +2 -2
  50. package/src/store/user/store.ts +5 -2
  51. package/src/types/serverConfig.ts +3 -1
  52. package/src/types/user/index.ts +13 -0
  53. package/src/utils/parseModels.test.ts +121 -1
  54. package/src/utils/parseModels.ts +9 -4
  55. package/src/store/user/slices/settings/actions/index.ts +0 -18
  56. package/src/store/user/slices/settings/actions/llm.test.ts +0 -136
  57. /package/src/app/(main)/settings/llm/components/ProviderModelList/{MaxTokenSlider.tsx → ModelConfigModal/MaxTokenSlider.tsx} +0 -0
  58. /package/src/store/user/slices/{settings → modelList}/reducers/customModelCard.test.ts +0 -0
  59. /package/src/store/user/slices/{settings → modelList}/reducers/customModelCard.ts +0 -0
  60. /package/src/store/user/slices/settings/{actions/general.test.ts → action.test.ts} +0 -0
  61. /package/src/store/user/slices/settings/selectors/__snapshots__/{selectors.test.ts.snap → settings.test.ts.snap} +0 -0
  62. /package/src/store/user/slices/settings/selectors/{selectors.test.ts → settings.test.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.161.10](https://github.com/lobehub/lobe-chat/compare/v0.161.9...v0.161.10)
6
+
7
+ <sup>Released on **2024-05-23**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Refactor user store and fix custom model list form.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Refactor user store and fix custom model list form, closes [#2620](https://github.com/lobehub/lobe-chat/issues/2620) ([81ea886](https://github.com/lobehub/lobe-chat/commit/81ea886))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 0.161.9](https://github.com/lobehub/lobe-chat/compare/v0.161.8...v0.161.9)
6
31
 
7
32
  <sup>Released on **2024-05-23**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.161.9",
3
+ "version": "0.161.10",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -50,6 +50,8 @@ interface ProviderConfigProps {
50
50
  canDeactivate?: boolean;
51
51
  checkModel?: string;
52
52
  checkerItem?: FormItemProps;
53
+ className?: string;
54
+ hideSwitch?: boolean;
53
55
  modelList?: {
54
56
  azureDeployName?: boolean;
55
57
  notFoundContent?: ReactNode;
@@ -81,11 +83,12 @@ const ProviderConfig = memo<ProviderConfigProps>(
81
83
  checkerItem,
82
84
  modelList,
83
85
  showBrowserRequest,
86
+ className,
84
87
  }) => {
85
88
  const { t } = useTranslation('setting');
86
89
  const { t: modelT } = useTranslation('modelProvider');
87
90
  const [form] = Form.useForm();
88
- const { styles } = useStyles();
91
+ const { cx, styles } = useStyles();
89
92
  const [
90
93
  toggleProviderEnabled,
91
94
  setSettings,
@@ -192,7 +195,7 @@ const ProviderConfig = memo<ProviderConfigProps>(
192
195
 
193
196
  return (
194
197
  <Form
195
- className={styles.form}
198
+ className={cx(styles.form, className)}
196
199
  form={form}
197
200
  items={[model]}
198
201
  onValuesChange={debounce(setSettings, 100)}
@@ -71,18 +71,17 @@ const CustomModelOption = memo<CustomModelOptionProps>(({ id, provider }) => {
71
71
  e.stopPropagation();
72
72
  e.preventDefault();
73
73
 
74
- const isConfirm = await modal.confirm({
74
+ await modal.confirm({
75
75
  centered: true,
76
76
  content: s('llm.customModelCards.confirmDelete'),
77
77
  okButtonProps: { danger: true },
78
+ onOk: async () => {
79
+ // delete model and deactivate id
80
+ await dispatchCustomModelCards(provider, { id, type: 'delete' });
81
+ await removeEnabledModels(provider, id);
82
+ },
78
83
  type: 'warning',
79
84
  });
80
-
81
- // delete model and deactive id
82
- if (isConfirm) {
83
- await dispatchCustomModelCards(provider, { id, type: 'delete' });
84
- await removeEnabledModels(provider, id);
85
- }
86
85
  }}
87
86
  title={t('delete')}
88
87
  />
@@ -1,71 +1,28 @@
1
- import { Modal } from '@lobehub/ui';
2
- import { Button, Checkbox, Form, Input } from 'antd';
3
- import isEqual from 'fast-deep-equal';
4
- import { memo } from 'react';
1
+ import { Checkbox, Form, FormInstance, Input } from 'antd';
2
+ import { memo, useEffect } from 'react';
5
3
  import { useTranslation } from 'react-i18next';
6
4
 
7
- import { useUserStore } from '@/store/user';
8
- import { modelConfigSelectors } from '@/store/user/selectors';
5
+ import { ChatModelCard } from '@/types/llm';
9
6
 
10
7
  import MaxTokenSlider from './MaxTokenSlider';
11
8
 
12
- interface ModelConfigModalProps {
13
- provider?: string;
9
+ interface ModelConfigFormProps {
10
+ initialValues?: ChatModelCard;
11
+ onFormInstanceReady: (instance: FormInstance) => void;
14
12
  showAzureDeployName?: boolean;
15
13
  }
16
- const ModelConfigModal = memo<ModelConfigModalProps>(({ showAzureDeployName, provider }) => {
17
- const [formInstance] = Form.useForm();
18
- const { t } = useTranslation('setting');
19
- const { t: tc } = useTranslation('common');
20
14
 
21
- const [open, id, editingProvider, dispatchCustomModelCards, toggleEditingCustomModelCard] =
22
- useUserStore((s) => [
23
- !!s.editingCustomCardModel && provider === s.editingCustomCardModel?.provider,
24
- s.editingCustomCardModel?.id,
25
- s.editingCustomCardModel?.provider,
26
- s.dispatchCustomModelCards,
27
- s.toggleEditingCustomModelCard,
28
- ]);
15
+ const ModelConfigForm = memo<ModelConfigFormProps>(
16
+ ({ showAzureDeployName, onFormInstanceReady, initialValues }) => {
17
+ const { t } = useTranslation('setting');
29
18
 
30
- const modelCard = useUserStore(
31
- modelConfigSelectors.getCustomModelCard({ id, provider: editingProvider }),
32
- isEqual,
33
- );
19
+ const [formInstance] = Form.useForm();
34
20
 
35
- const closeModal = () => {
36
- toggleEditingCustomModelCard(undefined);
37
- };
21
+ useEffect(() => {
22
+ onFormInstanceReady(formInstance);
23
+ }, []);
38
24
 
39
- return (
40
- <Modal
41
- destroyOnClose
42
- footer={[
43
- <Button key="cancel" onClick={closeModal}>
44
- {tc('cancel')}
45
- </Button>,
46
-
47
- <Button
48
- key="ok"
49
- onClick={() => {
50
- if (!editingProvider || !id) return;
51
- const data = formInstance.getFieldsValue();
52
-
53
- dispatchCustomModelCards(editingProvider as any, { id, type: 'update', value: data });
54
-
55
- closeModal();
56
- }}
57
- style={{ marginInlineStart: '16px' }}
58
- type="primary"
59
- >
60
- {tc('ok')}
61
- </Button>,
62
- ]}
63
- maskClosable
64
- onCancel={closeModal}
65
- open={open}
66
- title={t('llm.customModelCards.modelConfig.modalTitle')}
67
- zIndex={1051} // Select is 1050
68
- >
25
+ return (
69
26
  <div
70
27
  onClick={(e) => {
71
28
  e.stopPropagation();
@@ -77,9 +34,8 @@ const ModelConfigModal = memo<ModelConfigModalProps>(({ showAzureDeployName, pro
77
34
  <Form
78
35
  colon={false}
79
36
  form={formInstance}
80
- initialValues={modelCard}
37
+ initialValues={initialValues}
81
38
  labelCol={{ span: 4 }}
82
- preserve={false}
83
39
  style={{ marginTop: 16 }}
84
40
  wrapperCol={{ offset: 1, span: 18 }}
85
41
  >
@@ -136,7 +92,7 @@ const ModelConfigModal = memo<ModelConfigModalProps>(({ showAzureDeployName, pro
136
92
  </Form.Item>
137
93
  </Form>
138
94
  </div>
139
- </Modal>
140
- );
141
- });
142
- export default ModelConfigModal;
95
+ );
96
+ },
97
+ );
98
+ export default ModelConfigForm;
@@ -0,0 +1,78 @@
1
+ import { Modal } from '@lobehub/ui';
2
+ import { Button, FormInstance } from 'antd';
3
+ import isEqual from 'fast-deep-equal';
4
+ import { memo, useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { useUserStore } from '@/store/user';
8
+ import { modelConfigSelectors } from '@/store/user/slices/modelList/selectors';
9
+
10
+ import ModelConfigForm from './Form';
11
+
12
+ interface ModelConfigModalProps {
13
+ provider?: string;
14
+ showAzureDeployName?: boolean;
15
+ }
16
+
17
+ const ModelConfigModal = memo<ModelConfigModalProps>(({ showAzureDeployName, provider }) => {
18
+ const { t } = useTranslation('setting');
19
+ const { t: tc } = useTranslation('common');
20
+ const [formInstance, setFormInstance] = useState<FormInstance>();
21
+
22
+ const [open, id, editingProvider, dispatchCustomModelCards, toggleEditingCustomModelCard] =
23
+ useUserStore((s) => [
24
+ !!s.editingCustomCardModel && provider === s.editingCustomCardModel?.provider,
25
+ s.editingCustomCardModel?.id,
26
+ s.editingCustomCardModel?.provider,
27
+ s.dispatchCustomModelCards,
28
+ s.toggleEditingCustomModelCard,
29
+ ]);
30
+
31
+ const modelCard = useUserStore(
32
+ modelConfigSelectors.getCustomModelCard({ id, provider: editingProvider }),
33
+ isEqual,
34
+ );
35
+
36
+ const closeModal = () => {
37
+ toggleEditingCustomModelCard(undefined);
38
+ };
39
+
40
+ return (
41
+ <Modal
42
+ destroyOnClose
43
+ footer={[
44
+ <Button key="cancel" onClick={closeModal}>
45
+ {tc('cancel')}
46
+ </Button>,
47
+
48
+ <Button
49
+ key="ok"
50
+ onClick={() => {
51
+ if (!editingProvider || !id || !formInstance) return;
52
+ const data = formInstance.getFieldsValue();
53
+
54
+ dispatchCustomModelCards(editingProvider as any, { id, type: 'update', value: data });
55
+
56
+ closeModal();
57
+ }}
58
+ style={{ marginInlineStart: '16px' }}
59
+ type="primary"
60
+ >
61
+ {tc('ok')}
62
+ </Button>,
63
+ ]}
64
+ maskClosable
65
+ onCancel={closeModal}
66
+ open={open}
67
+ title={t('llm.customModelCards.modelConfig.modalTitle')}
68
+ zIndex={1251} // Select is 1150
69
+ >
70
+ <ModelConfigForm
71
+ initialValues={modelCard}
72
+ onFormInstanceReady={setFormInstance}
73
+ showAzureDeployName={showAzureDeployName}
74
+ />
75
+ </Modal>
76
+ );
77
+ });
78
+ export default ModelConfigModal;
@@ -1,6 +1,10 @@
1
+ import { ActionIcon, Tooltip } from '@lobehub/ui';
1
2
  import { Typography } from 'antd';
3
+ import { useTheme } from 'antd-style';
2
4
  import isEqual from 'fast-deep-equal';
5
+ import { Recycle } from 'lucide-react';
3
6
  import { memo } from 'react';
7
+ import { useTranslation } from 'react-i18next';
4
8
  import { Flexbox } from 'react-layout-kit';
5
9
 
6
10
  import ModelIcon from '@/components/ModelIcon';
@@ -16,25 +20,45 @@ interface OptionRenderProps {
16
20
  id: string;
17
21
  isAzure?: boolean;
18
22
  provider: GlobalLLMProviderKey;
23
+ removed?: boolean;
19
24
  }
20
- const OptionRender = memo<OptionRenderProps>(({ displayName, id, provider, isAzure }) => {
25
+ const OptionRender = memo<OptionRenderProps>(({ displayName, id, provider, isAzure, removed }) => {
21
26
  const model = useUserStore((s) => modelProviderSelectors.getModelCardById(id)(s), isEqual);
22
-
27
+ const { t } = useTranslation('components');
28
+ const theme = useTheme();
23
29
  // if there is isCustom, it means it is a user defined custom model
24
30
  if (model?.isCustom || isAzure) return <CustomModelOption id={id} provider={provider} />;
25
31
 
26
32
  return (
27
- <Flexbox align={'center'} gap={8} horizontal>
28
- <ModelIcon model={id} size={32} />
29
- <Flexbox>
30
- <Flexbox align={'center'} gap={8} horizontal>
31
- {displayName}
32
- <ModelInfoTags directionReverse placement={'top'} {...model!} />
33
+ <Flexbox
34
+ align={'center'}
35
+ gap={8}
36
+ horizontal
37
+ justify={'space-between'}
38
+ style={{ paddingInlineEnd: 8 }}
39
+ >
40
+ <Flexbox align={'center'} gap={8} horizontal>
41
+ <ModelIcon model={id} size={32} />
42
+ <Flexbox>
43
+ <Flexbox align={'center'} gap={8} horizontal>
44
+ {displayName}
45
+ <ModelInfoTags directionReverse placement={'top'} {...model!} />
46
+ </Flexbox>
47
+ <Typography.Text style={{ fontSize: 12 }} type={'secondary'}>
48
+ {id}
49
+ </Typography.Text>
33
50
  </Flexbox>
34
- <Typography.Text style={{ fontSize: 12 }} type={'secondary'}>
35
- {id}
36
- </Typography.Text>
37
51
  </Flexbox>
52
+ {removed && (
53
+ <Tooltip
54
+ overlayStyle={{ maxWidth: 300 }}
55
+ placement={'top'}
56
+ style={{ pointerEvents: 'none' }}
57
+ title={t('ModelSelect.removed')}
58
+ >
59
+ <ActionIcon icon={Recycle} style={{ color: theme.colorWarning }} />
60
+ </Tooltip>
61
+ )}
38
62
  </Flexbox>
39
63
  );
40
64
  });
@@ -51,10 +51,9 @@ const ProviderModelListSelect = memo<CustomModelSelectProps>(
51
51
  ({ showModelFetcher = false, provider, showAzureDeployName, notFoundContent, placeholder }) => {
52
52
  const { t } = useTranslation('common');
53
53
  const { t: transSetting } = useTranslation('setting');
54
- const [setModelProviderConfig, dispatchCustomModelCards] = useUserStore((s) => [
54
+ const [setModelProviderConfig, updateEnabledModels] = useUserStore((s) => [
55
55
  s.setModelProviderConfig,
56
- s.dispatchCustomModelCards,
57
- s.useFetchProviderModelList,
56
+ s.updateEnabledModels,
58
57
  ]);
59
58
 
60
59
  const chatModelCards = useUserStore(
@@ -94,21 +93,7 @@ const ProviderModelListSelect = memo<CustomModelSelectProps>(
94
93
  mode="tags"
95
94
  notFoundContent={notFoundContent}
96
95
  onChange={(value, options) => {
97
- setModelProviderConfig(provider, { enabledModels: value.filter(Boolean) });
98
-
99
- // if there is a new model, add it to `customModelCards`
100
- options.forEach((option: { label?: string; value?: string }, index: number) => {
101
- // if is a known model, it should have value
102
- // if is an unknown model, the option will be {}
103
- if (option.value) return;
104
-
105
- const modelId = value[index];
106
-
107
- dispatchCustomModelCards(provider, {
108
- modelCard: { id: modelId },
109
- type: 'add',
110
- });
111
- });
96
+ updateEnabledModels(provider, value, options as any[]);
112
97
  }}
113
98
  optionFilterProp="label"
114
99
  optionRender={({ label, value }) => {
@@ -123,6 +108,18 @@ const ProviderModelListSelect = memo<CustomModelSelectProps>(
123
108
  />
124
109
  );
125
110
 
111
+ if (enabledModels?.some((m) => value === m)) {
112
+ return (
113
+ <OptionRender
114
+ displayName={label as string}
115
+ id={value as string}
116
+ isAzure={showAzureDeployName}
117
+ provider={provider}
118
+ removed
119
+ />
120
+ );
121
+ }
122
+
126
123
  // model is defined by user in client
127
124
  return (
128
125
  <Flexbox align={'center'} gap={8} horizontal>
@@ -5,6 +5,7 @@ import {
5
5
  DeepSeek,
6
6
  Google,
7
7
  Groq,
8
+ LobeHub,
8
9
  Minimax,
9
10
  Mistral,
10
11
  Moonshot,
@@ -16,7 +17,6 @@ import {
16
17
  ZeroOne,
17
18
  Zhipu,
18
19
  } from '@lobehub/icons';
19
- import { Logo } from '@lobehub/ui';
20
20
  import { memo } from 'react';
21
21
  import { Center } from 'react-layout-kit';
22
22
 
@@ -29,7 +29,7 @@ interface ModelProviderIconProps {
29
29
  const ModelProviderIcon = memo<ModelProviderIconProps>(({ provider }) => {
30
30
  switch (provider) {
31
31
  case 'lobehub': {
32
- return <Logo size={20} />;
32
+ return <LobeHub size={20} />;
33
33
  }
34
34
 
35
35
  case ModelProvider.ZhiPu: {
@@ -79,10 +79,10 @@ export const ModelInfoTags = memo<ModelInfoTagsProps>(
79
79
  return (
80
80
  <Flexbox direction={directionReverse ? 'horizontal-reverse' : 'horizontal'} gap={4}>
81
81
  {model.files && (
82
- <Tooltip
82
+ <Tooltip
83
83
  overlayStyle={{ pointerEvents: 'none' }}
84
- placement={placement}
85
- title={t('ModelSelect.featureTag.file')}
84
+ placement={placement}
85
+ title={t('ModelSelect.featureTag.file')}
86
86
  >
87
87
  <div className={cx(styles.tag, styles.tagGreen)} style={{ cursor: 'pointer' }} title="">
88
88
  <Icon icon={LucidePaperclip} />
@@ -90,9 +90,9 @@ export const ModelInfoTags = memo<ModelInfoTagsProps>(
90
90
  </Tooltip>
91
91
  )}
92
92
  {model.vision && (
93
- <Tooltip
93
+ <Tooltip
94
94
  overlayStyle={{ pointerEvents: 'none' }}
95
- placement={placement}
95
+ placement={placement}
96
96
  title={t('ModelSelect.featureTag.vision')}
97
97
  >
98
98
  <div className={cx(styles.tag, styles.tagGreen)} style={{ cursor: 'pointer' }} title="">
@@ -128,15 +128,6 @@ export const ModelInfoTags = memo<ModelInfoTagsProps>(
128
128
  </Center>
129
129
  </Tooltip>
130
130
  )}
131
- {/*{model.isCustom && (*/}
132
- {/* <Tooltip*/}
133
- {/* overlayStyle={{ maxWidth: 300 }}*/}
134
- {/* placement={placement}*/}
135
- {/* title={t('ModelSelect.featureTag.custom')}*/}
136
- {/* >*/}
137
- {/* <Center className={styles.custom}>DIY</Center>*/}
138
- {/* </Tooltip>*/}
139
- {/*)}*/}
140
131
  </Flexbox>
141
132
  );
142
133
  },
@@ -22,7 +22,7 @@ const PanelContent = memo<{ closePopover: () => void }>(({ closePopover }) => {
22
22
  s.logout,
23
23
  s.openUserProfile,
24
24
  s.enableAuth(),
25
- s.enabledNextAuth(),
25
+ s.enabledNextAuth,
26
26
  ]);
27
27
  const { mainItems, logoutItems } = useMenu();
28
28
 
@@ -1,6 +1,7 @@
1
1
  import { useCallback } from 'react';
2
2
 
3
3
  import { useChatStore } from '@/store/chat';
4
+ import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
4
5
  import { useSessionStore } from '@/store/session';
5
6
  import { useUserStore } from '@/store/user';
6
7
  import { syncSettingsSelectors } from '@/store/user/selectors';
@@ -42,7 +43,8 @@ export const useEnabledDataSync = () => {
42
43
  s.useEnabledSync,
43
44
  ]);
44
45
 
46
+ const { enableWebrtc } = useServerConfigStore(featureFlagsSelectors);
45
47
  const syncEvent = useSyncEvent();
46
48
 
47
- useEnabledSync(userEnableSync, userId, syncEvent);
49
+ useEnabledSync(enableWebrtc, { onEvent: syncEvent, userEnableSync, userId });
48
50
  };
@@ -10,32 +10,40 @@ import { useIsMobile } from '@/hooks/useIsMobile';
10
10
  import { useEnabledDataSync } from '@/hooks/useSyncData';
11
11
  import { useAgentStore } from '@/store/agent';
12
12
  import { useGlobalStore } from '@/store/global';
13
+ import { useServerConfigStore } from '@/store/serverConfig';
13
14
  import { useUserStore } from '@/store/user';
15
+ import { authSelectors } from '@/store/user/selectors';
14
16
 
15
17
  const StoreInitialization = memo(() => {
16
- const [useFetchServerConfig, useFetchUserConfig, useInitPreference] = useUserStore((s) => [
17
- s.useFetchServerConfig,
18
- s.useFetchUserConfig,
19
- s.useInitPreference,
18
+ const router = useRouter();
19
+
20
+ const [useInitUserState, isLogin] = useUserStore((s) => [
21
+ s.useInitUserState,
22
+ authSelectors.isLogin(s),
20
23
  ]);
24
+
25
+ const { serverConfig } = useServerConfigStore();
26
+
21
27
  const useInitGlobalPreference = useGlobalStore((s) => s.useInitGlobalPreference);
22
28
 
23
29
  const useFetchDefaultAgentConfig = useAgentStore((s) => s.useFetchDefaultAgentConfig);
24
30
  // init the system preference
25
- useInitPreference();
26
31
  useInitGlobalPreference();
27
-
28
32
  useFetchDefaultAgentConfig();
29
33
 
30
- const { isLoading } = useFetchServerConfig();
31
- useFetchUserConfig(!isLoading);
34
+ useInitUserState(isLogin, serverConfig, {
35
+ onSuccess: (state) => {
36
+ if (state.isOnboard === false) {
37
+ router.push('/onboard');
38
+ }
39
+ },
40
+ });
32
41
 
33
42
  useEnabledDataSync();
34
43
 
35
44
  const useStoreUpdater = createStoreUpdater(useGlobalStore);
36
45
 
37
46
  const mobile = useIsMobile();
38
- const router = useRouter();
39
47
 
40
48
  useStoreUpdater('isMobile', mobile);
41
49
  useStoreUpdater('router', router);
@@ -58,13 +58,13 @@ const GlobalLayout = async ({ children }: GlobalLayoutProps) => {
58
58
  defaultNeutralColor={neutralColor?.value as any}
59
59
  defaultPrimaryColor={primaryColor?.value as any}
60
60
  >
61
- <StoreInitialization />
62
61
  <ServerConfigStoreProvider
63
62
  featureFlags={serverFeatureFlags}
64
63
  isMobile={isMobile}
65
64
  serverConfig={serverConfig}
66
65
  >
67
66
  {children}
67
+ <StoreInitialization />
68
68
  </ServerConfigStoreProvider>
69
69
  <DebugUI />
70
70
  </AppTheme>
@@ -7,6 +7,7 @@ export default {
7
7
  tokens: '该模型单个会话最多支持 {{tokens}} Tokens',
8
8
  vision: '该模型支持视觉识别',
9
9
  },
10
+ removed: '该模型不在列表中,若取消选中将会自动移除',
10
11
  },
11
12
  ModelSwitchPanel: {
12
13
  emptyModel: '没有启用的模型,请前往设置开启',
@@ -343,28 +343,4 @@ describe('MessageClientService', () => {
343
343
  expect(result).toBe(false);
344
344
  });
345
345
  });
346
-
347
- describe('messageCountToCheckTrace', () => {
348
- it('should return true if message count is greater than or equal to 4', async () => {
349
- // Setup
350
- (MessageModel.count as Mock).mockResolvedValue(5);
351
-
352
- // Execute
353
- const result = await messageService.messageCountToCheckTrace();
354
-
355
- // Assert
356
- expect(result).toBe(true);
357
- });
358
-
359
- it('should return false if message count is less than 4', async () => {
360
- // Setup
361
- (MessageModel.count as Mock).mockResolvedValue(3);
362
-
363
- // Execute
364
- const result = await messageService.messageCountToCheckTrace();
365
-
366
- // Assert
367
- expect(result).toBe(false);
368
- });
369
- });
370
346
  });
@@ -80,9 +80,4 @@ export class ClientService implements IMessageService {
80
80
  const number = await this.countMessages();
81
81
  return number > 0;
82
82
  }
83
-
84
- async messageCountToCheckTrace() {
85
- const number = await this.countMessages();
86
- return number >= 4;
87
- }
88
83
  }
@@ -43,5 +43,4 @@ export interface IMessageService {
43
43
  removeAllMessages(): Promise<any>;
44
44
 
45
45
  hasMessages(): Promise<boolean>;
46
- messageCountToCheckTrace(): Promise<boolean>;
47
46
  }