@lobehub/chat 1.2.0 → 1.3.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 CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 1.3.0](https://github.com/lobehub/lobe-chat/compare/v1.2.0...v1.3.0)
6
+
7
+ <sup>Released on **2023-07-18**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Implement settings and configuration functionality.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Implement settings and configuration functionality ([496c2d9](https://github.com/lobehub/lobe-chat/commit/496c2d9))
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 1.2.0](https://github.com/lobehub/lobe-chat/compare/v1.1.0...v1.2.0)
6
31
 
7
32
  <sup>Released on **2023-07-18**</sup>
@@ -20,60 +20,68 @@
20
20
  "desc": "When the uncompressed chat history exceeds this value, it will be compressed",
21
21
  "title": "Chat History Compression Threshold"
22
22
  },
23
+ "enableCompressThreshold": {
24
+ "title": "Enable Chat History Compression Threshold"
25
+ },
26
+ "enableHistoryCount": {
27
+ "title": "Enable History Message Count Limit"
28
+ },
23
29
  "historyCount": {
24
- "desc": "Number of chat history messages carried in each request",
30
+ "desc": "Number of history messages to include in each request",
25
31
  "title": "History Message Count"
26
32
  },
27
33
  "inputTemplate": {
28
34
  "desc": "The latest user message will be filled into this template",
29
35
  "title": "User Input Preprocessing"
30
36
  },
31
- "maxTokens": {
32
- "desc": "Maximum number of tokens used for each interaction",
33
- "title": "Reply Limit (max_tokens)"
34
- },
35
- "sendKey": {
36
- "title": "Send Key"
37
- },
38
37
  "title": "Chat Settings"
39
38
  },
40
39
  "settingModel": {
40
+ "enableMaxTokens": {
41
+ "title": "Enable Single Reply Limit"
42
+ },
41
43
  "frequencyPenalty": {
42
44
  "desc": "The higher the value, the more likely it is to reduce repeated words",
43
- "title": "Frequency Penalty (frequency_penalty)"
45
+ "title": "Frequency Penalty"
46
+ },
47
+ "maxTokens": {
48
+ "desc": "Maximum number of tokens used in a single interaction",
49
+ "title": "Single Reply Limit"
44
50
  },
45
51
  "model": {
52
+ "desc": "ChatGPT Model",
46
53
  "title": "Model"
47
54
  },
48
55
  "presencePenalty": {
49
56
  "desc": "The higher the value, the more likely it is to expand to new topics",
50
- "title": "Topic Freshness (presence_penalty)"
57
+ "title": "Topic Freshness"
51
58
  },
52
59
  "temperature": {
53
60
  "desc": "The higher the value, the more random the reply",
54
- "title": "Randomness (temperature)"
61
+ "title": "Randomness"
55
62
  },
56
63
  "title": "Model Settings",
57
64
  "topP": {
58
65
  "desc": "Similar to randomness, but do not change together with randomness",
59
- "title": "Nucleus Sampling (top_p)"
66
+ "title": "Top-p Sampling"
60
67
  }
61
68
  },
62
69
  "settingOpenAI": {
63
70
  "endpoint": {
64
71
  "desc": "Must include http(s)://, in addition to the default address",
65
- "title": "API Endpoint"
72
+ "placeholder": "https://api.openai.com/v1",
73
+ "title": "API Proxy Endpoint"
66
74
  },
67
75
  "title": "OpenAI Settings",
68
76
  "token": {
69
- "desc": "Use your own Key to bypass password access restrictions",
77
+ "desc": "Use your own OpenAI Key",
70
78
  "placeholder": "OpenAI API Key",
71
79
  "title": "API Key"
72
80
  }
73
81
  },
74
82
  "settingSystem": {
75
83
  "accessCode": {
76
- "desc": "Encryption access has been enabled by the administrator",
84
+ "desc": "Encryption access is enabled by the administrator",
77
85
  "placeholder": "Please enter the access password",
78
86
  "title": "Access Password"
79
87
  },
@@ -91,7 +99,7 @@
91
99
  "title": "Language Settings"
92
100
  },
93
101
  "neutralColor": {
94
- "desc": "Custom grayscale for different color tendencies",
102
+ "desc": "Custom grayscale for different color biases",
95
103
  "title": "Neutral Color"
96
104
  },
97
105
  "primaryColor": {
@@ -20,6 +20,12 @@
20
20
  "desc": "当未压缩的历史消息超过该值时,将进行压缩",
21
21
  "title": "历史消息长度压缩阈值"
22
22
  },
23
+ "enableCompressThreshold": {
24
+ "title": "是否开启历史消息长度压缩阈值"
25
+ },
26
+ "enableHistoryCount": {
27
+ "title": "是否开启携带的历史消息数限制"
28
+ },
23
29
  "historyCount": {
24
30
  "desc": "每次请求携带的历史消息数",
25
31
  "title": "附带历史消息数"
@@ -28,45 +34,47 @@
28
34
  "desc": "用户最新的一条消息会填充到此模板",
29
35
  "title": "用户输入预处理"
30
36
  },
31
- "maxTokens": {
32
- "desc": "单次交互所用的最大 Token 数",
33
- "title": "单次回复限制 (max_tokens)"
34
- },
35
- "sendKey": {
36
- "title": "发送键"
37
- },
38
37
  "title": "聊天设置"
39
38
  },
40
39
  "settingModel": {
40
+ "enableMaxTokens": {
41
+ "title": "开启单次回复限制"
42
+ },
41
43
  "frequencyPenalty": {
42
44
  "desc": "值越大,越有可能降低重复字词",
43
- "title": "频率惩罚度 (frequency_penalty)"
45
+ "title": "频率惩罚度"
46
+ },
47
+ "maxTokens": {
48
+ "desc": "单次交互所用的最大 Token 数",
49
+ "title": "单次回复限制"
44
50
  },
45
51
  "model": {
52
+ "desc": "ChatGPT 模型",
46
53
  "title": "模型"
47
54
  },
48
55
  "presencePenalty": {
49
56
  "desc": "值越大,越有可能扩展到新话题",
50
- "title": "话题新鲜度 (presence_penalty)"
57
+ "title": "话题新鲜度"
51
58
  },
52
59
  "temperature": {
53
60
  "desc": "值越大,回复越随机",
54
- "title": "随机性 (temperature)"
61
+ "title": "随机性"
55
62
  },
56
63
  "title": "模型设置",
57
64
  "topP": {
58
65
  "desc": "与随机性类似,但不要和随机性一起更改",
59
- "title": "核采样 (top_p)"
66
+ "title": "核采样"
60
67
  }
61
68
  },
62
69
  "settingOpenAI": {
63
70
  "endpoint": {
64
71
  "desc": "除默认地址外,必须包含 http(s)://",
65
- "title": "接口地址"
72
+ "placeholder": "https://api.openai.com/v1",
73
+ "title": "接口代理地址"
66
74
  },
67
75
  "title": "OpenAI 设置",
68
76
  "token": {
69
- "desc": "使用自己的 Key 可绕过密码访问限制",
77
+ "desc": "使用自己的 OpenAI Key",
70
78
  "placeholder": "OpenAI API Key",
71
79
  "title": "API Key"
72
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -20,6 +20,12 @@ export default {
20
20
  desc: '当未压缩的历史消息超过该值时,将进行压缩',
21
21
  title: '历史消息长度压缩阈值',
22
22
  },
23
+ enableCompressThreshold: {
24
+ title: '是否开启历史消息长度压缩阈值',
25
+ },
26
+ enableHistoryCount: {
27
+ title: '是否开启携带的历史消息数限制',
28
+ },
23
29
  historyCount: {
24
30
  desc: '每次请求携带的历史消息数',
25
31
  title: '附带历史消息数',
@@ -28,45 +34,47 @@ export default {
28
34
  desc: '用户最新的一条消息会填充到此模板',
29
35
  title: '用户输入预处理',
30
36
  },
31
- maxTokens: {
32
- desc: '单次交互所用的最大 Token 数',
33
- title: '单次回复限制 (max_tokens)',
34
- },
35
- sendKey: {
36
- title: '发送键',
37
- },
38
37
  title: '聊天设置',
39
38
  },
40
39
  settingModel: {
40
+ enableMaxTokens: {
41
+ title: '开启单次回复限制',
42
+ },
41
43
  frequencyPenalty: {
42
44
  desc: '值越大,越有可能降低重复字词',
43
- title: '频率惩罚度 (frequency_penalty)',
45
+ title: '频率惩罚度',
46
+ },
47
+ maxTokens: {
48
+ desc: '单次交互所用的最大 Token 数',
49
+ title: '单次回复限制',
44
50
  },
45
51
  model: {
52
+ desc: 'ChatGPT 模型',
46
53
  title: '模型',
47
54
  },
48
55
  presencePenalty: {
49
56
  desc: '值越大,越有可能扩展到新话题',
50
- title: '话题新鲜度 (presence_penalty)',
57
+ title: '话题新鲜度',
51
58
  },
52
59
  temperature: {
53
60
  desc: '值越大,回复越随机',
54
- title: '随机性 (temperature)',
61
+ title: '随机性',
55
62
  },
56
63
  title: '模型设置',
57
64
  topP: {
58
65
  desc: '与随机性类似,但不要和随机性一起更改',
59
- title: '核采样 (top_p)',
66
+ title: '核采样',
60
67
  },
61
68
  },
62
69
  settingOpenAI: {
63
70
  endpoint: {
64
71
  desc: '除默认地址外,必须包含 http(s)://',
65
- title: '接口地址',
72
+ placeholder: 'https://api.openai.com/v1',
73
+ title: '接口代理地址',
66
74
  },
67
75
  title: 'OpenAI 设置',
68
76
  token: {
69
- desc: '使用自己的 Key 可绕过密码访问限制',
77
+ desc: '使用自己的 OpenAI Key',
70
78
  placeholder: 'OpenAI API Key',
71
79
  title: 'API Key',
72
80
  },
@@ -1,7 +1,9 @@
1
1
  import common from '../../../locales/en_US/common.json';
2
+ import setting from '../../../locales/en_US/setting.json';
2
3
 
3
4
  const resources = {
4
5
  common,
6
+ setting,
5
7
  } as const;
6
8
 
7
9
  export default resources;
@@ -1,16 +1,19 @@
1
1
  import { Form, type ItemGroup, ThemeSwitch } from '@lobehub/ui';
2
- import { Select, Slider } from 'antd';
2
+ import { Form as AntForm, Button, Input, Popconfirm, Select, Switch } from 'antd';
3
3
  import isEqual from 'fast-deep-equal';
4
4
  import { debounce } from 'lodash-es';
5
- import { Palette } from 'lucide-react';
6
- import { memo, useMemo } from 'react';
5
+ import { AppWindow, Bot, MessagesSquare, Palette, Webhook } from 'lucide-react';
6
+ import { memo, useCallback, useMemo } from 'react';
7
7
  import { useTranslation } from 'react-i18next';
8
8
  import { shallow } from 'zustand/shallow';
9
9
 
10
10
  import AvatarWithUpload from '@/features/AvatarWithUpload';
11
11
  import { options } from '@/locales/options';
12
+ import SliderWithInput from '@/pages/setting/SliderWithInput';
12
13
  import { settingsSelectors, useSettings } from '@/store/settings';
14
+ import { DEFAULT_SETTINGS } from '@/store/settings/initialState';
13
15
  import { ConfigKeys } from '@/types/exportConfig';
16
+ import { LanguageModel } from '@/types/llm';
14
17
 
15
18
  import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from './ThemeSwatches';
16
19
 
@@ -21,13 +24,27 @@ type SettingItemGroup = ItemGroup & {
21
24
  };
22
25
 
23
26
  const SettingForm = memo(() => {
27
+ const { t } = useTranslation('setting');
28
+ const [form] = AntForm.useForm();
24
29
  const settings = useSettings(settingsSelectors.currentSettings, isEqual);
25
- const { setThemeMode, setSettings } = useSettings(
26
- (s) => ({ setSettings: s.setSettings, setThemeMode: s.setThemeMode }),
30
+ const { setThemeMode, setSettings, resetSettings } = useSettings(
31
+ (s) => ({
32
+ resetSettings: s.resetSettings,
33
+ setSettings: s.setSettings,
34
+ setThemeMode: s.setThemeMode,
35
+ }),
27
36
  shallow,
28
37
  );
29
38
 
30
- const { t } = useTranslation('setting');
39
+ const handleReset = useCallback(() => {
40
+ resetSettings();
41
+ form.setFieldsValue(DEFAULT_SETTINGS);
42
+ }, []);
43
+
44
+ const handleClear = useCallback(() => {
45
+ handleReset();
46
+ // TODO: 删除聊天记录
47
+ }, []);
31
48
 
32
49
  const theme: SettingItemGroup = useMemo(
33
50
  () => ({
@@ -58,7 +75,7 @@ const SettingForm = memo(() => {
58
75
  name: 'language',
59
76
  },
60
77
  {
61
- children: <Slider max={18} min={12} />,
78
+ children: <SliderWithInput max={18} min={12} />,
62
79
  desc: t('settingTheme.fontSize.desc'),
63
80
  label: t('settingTheme.fontSize.title'),
64
81
  name: 'fontSize',
@@ -82,11 +99,197 @@ const SettingForm = memo(() => {
82
99
  [settings],
83
100
  );
84
101
 
102
+ const OpenAI: SettingItemGroup = useMemo(
103
+ () => ({
104
+ children: [
105
+ {
106
+ children: <Input.Password placeholder={t('settingOpenAI.token.placeholder')} />,
107
+ desc: t('settingOpenAI.token.desc'),
108
+ label: t('settingOpenAI.token.title'),
109
+ name: 'token',
110
+ },
111
+ {
112
+ children: <Input placeholder={t('settingOpenAI.endpoint.placeholder')} />,
113
+ desc: t('settingOpenAI.endpoint.desc'),
114
+
115
+ label: t('settingOpenAI.endpoint.title'),
116
+
117
+ name: 'endpoint',
118
+ },
119
+ ],
120
+ icon: Webhook,
121
+ title: t('settingOpenAI.title'),
122
+ }),
123
+ [settings],
124
+ );
125
+
126
+ const Chat: SettingItemGroup = useMemo(
127
+ () => ({
128
+ children: [
129
+ {
130
+ children: <Switch />,
131
+ label: t('settingChat.enableHistoryCount.title'),
132
+ minWidth: undefined,
133
+ name: 'enableHistoryCount',
134
+ valuePropName: 'checked',
135
+ },
136
+ {
137
+ children: <SliderWithInput max={32} min={0} />,
138
+ desc: t('settingChat.historyCount.desc'),
139
+ hidden: !settings.enableHistoryCount,
140
+ label: t('settingChat.historyCount.title'),
141
+ name: 'historyCount',
142
+ },
143
+ {
144
+ children: <Switch />,
145
+ label: t('settingChat.enableCompressThreshold.title'),
146
+ minWidth: undefined,
147
+ name: 'enableCompressThreshold',
148
+ valuePropName: 'checked',
149
+ },
150
+ {
151
+ children: <SliderWithInput max={32} min={0} />,
152
+ desc: t('settingChat.compressThreshold.desc'),
153
+ hidden: !settings.enableCompressThreshold,
154
+ label: t('settingChat.compressThreshold.title'),
155
+ name: 'compressThreshold',
156
+ },
157
+ ],
158
+ icon: MessagesSquare,
159
+ title: t('settingChat.title'),
160
+ }),
161
+ [settings],
162
+ );
163
+
164
+ const Model: SettingItemGroup = useMemo(
165
+ () => ({
166
+ children: [
167
+ {
168
+ children: (
169
+ <Select
170
+ options={Object.values(LanguageModel).map((value) => ({
171
+ label: value,
172
+ value,
173
+ }))}
174
+ />
175
+ ),
176
+ desc: t('settingModel.model.desc'),
177
+ label: t('settingModel.model.title'),
178
+ name: 'model',
179
+ tag: 'model',
180
+ },
181
+ {
182
+ children: <SliderWithInput max={1} min={0} step={0.1} />,
183
+ desc: t('settingModel.temperature.desc'),
184
+ label: t('settingModel.temperature.title'),
185
+ name: 'temperature',
186
+ tag: 'temperature',
187
+ },
188
+ {
189
+ children: <SliderWithInput max={1} min={0} step={0.1} />,
190
+ desc: t('settingModel.topP.desc'),
191
+ label: t('settingModel.topP.title'),
192
+ name: 'topP',
193
+ tag: 'top_p',
194
+ },
195
+ {
196
+ children: <SliderWithInput max={2} min={-2} step={0.1} />,
197
+ desc: t('settingModel.presencePenalty.desc'),
198
+ label: t('settingModel.presencePenalty.title'),
199
+ name: 'presencePenalty',
200
+ tag: 'presence_penalty',
201
+ },
202
+ {
203
+ children: <SliderWithInput max={2} min={-2} step={0.1} />,
204
+ desc: t('settingModel.frequencyPenalty.desc'),
205
+ label: t('settingModel.frequencyPenalty.title'),
206
+ name: 'frequencyPenalty',
207
+ tag: 'frequency_penalty',
208
+ },
209
+ {
210
+ children: <Switch />,
211
+ label: t('settingModel.enableMaxTokens.title'),
212
+ minWidth: undefined,
213
+ name: 'enableMaxTokens',
214
+ valuePropName: 'checked',
215
+ },
216
+ {
217
+ children: <SliderWithInput max={32_000} min={0} step={100} />,
218
+ desc: t('settingModel.maxTokens.desc'),
219
+ hidden: !settings.enableMaxTokens,
220
+ label: t('settingModel.maxTokens.title'),
221
+ name: 'maxTokens',
222
+ tag: 'max_tokens',
223
+ },
224
+ ],
225
+ icon: Bot,
226
+ title: t('settingModel.title'),
227
+ }),
228
+ [settings],
229
+ );
230
+
231
+ const System: SettingItemGroup = useMemo(
232
+ () => ({
233
+ children: [
234
+ {
235
+ children: <Input.Password placeholder={t('settingSystem.accessCode.placeholder')} />,
236
+ desc: t('settingSystem.accessCode.desc'),
237
+ label: t('settingSystem.accessCode.title'),
238
+ name: 'accessCode',
239
+ },
240
+ {
241
+ children: (
242
+ <Popconfirm
243
+ arrow={false}
244
+ cancelText={t('cancel', { ns: 'common' })}
245
+ okButtonProps={{ danger: true }}
246
+ okText={t('ok', { ns: 'common' })}
247
+ onConfirm={handleReset}
248
+ title={t('danger.reset.confirm')}
249
+ >
250
+ <Button danger type="primary">
251
+ {t('danger.reset.action')}
252
+ </Button>
253
+ </Popconfirm>
254
+ ),
255
+ desc: t('danger.reset.title'),
256
+ label: t('danger.reset.desc'),
257
+ minWidth: undefined,
258
+ },
259
+ {
260
+ children: (
261
+ <Popconfirm
262
+ arrow={false}
263
+ cancelText={t('cancel', { ns: 'common' })}
264
+ okButtonProps={{ danger: true }}
265
+ okText={t('ok', { ns: 'common' })}
266
+ onConfirm={handleClear}
267
+ title={t('danger.clear.confirm')}
268
+ >
269
+ <Button danger type="primary">
270
+ {t('danger.clear.action')}
271
+ </Button>
272
+ </Popconfirm>
273
+ ),
274
+ desc: t('danger.clear.title'),
275
+ label: t('danger.clear.desc'),
276
+ minWidth: undefined,
277
+ },
278
+ ],
279
+ icon: AppWindow,
280
+ title: t('settingSystem.title'),
281
+ }),
282
+ [settings],
283
+ );
284
+
285
+ const items = useMemo(() => [theme, OpenAI, Chat, Model, System], [settings]);
286
+
85
287
  return (
86
288
  <Form
289
+ form={form}
87
290
  initialValues={settings}
88
- itemMinWidth="min(30%,200px)"
89
- items={[theme]}
291
+ itemMinWidth="max(30%,240px)"
292
+ items={items}
90
293
  onValuesChange={debounce(setSettings, 100)}
91
294
  style={{ maxWidth: 1024, width: '100%' }}
92
295
  />
@@ -0,0 +1,34 @@
1
+ import { InputNumber, Slider } from 'antd';
2
+ import { SliderSingleProps } from 'antd/es/slider';
3
+ import { memo } from 'react';
4
+ import { Flexbox } from 'react-layout-kit';
5
+
6
+ const SliderWithInput = memo<SliderSingleProps>(
7
+ ({ step, value, onChange, max, min, defaultValue, ...props }) => {
8
+ return (
9
+ <Flexbox direction={'horizontal'} gap={8}>
10
+ <Slider
11
+ defaultValue={defaultValue}
12
+ max={max}
13
+ min={min}
14
+ onChange={onChange}
15
+ step={step}
16
+ style={{ flex: 1 }}
17
+ value={value}
18
+ {...props}
19
+ />
20
+ <InputNumber
21
+ defaultValue={defaultValue}
22
+ max={max}
23
+ min={min}
24
+ onChange={onChange as any}
25
+ step={Number(step)}
26
+ style={{ flex: 1, maxWidth: 64 }}
27
+ value={value}
28
+ />
29
+ </Flexbox>
30
+ );
31
+ },
32
+ );
33
+
34
+ export default SliderWithInput;
@@ -24,12 +24,12 @@ const SettingLayout = memo(() => {
24
24
  <Head>
25
25
  <title>{pageTitle}</title>
26
26
  </Head>
27
- <Flexbox horizontal width={'100%'}>
27
+ <Flexbox height={'100vh'} horizontal width={'100%'}>
28
28
  <SideBar />
29
29
  <Sessions />
30
30
  <Flexbox flex={1}>
31
31
  <Header />
32
- <Flexbox align={'center'} padding={24}>
32
+ <Flexbox align={'center'} flex={1} padding={24} style={{ overflow: 'auto' }}>
33
33
  <SettingForm />
34
34
  </Flexbox>
35
35
  </Flexbox>
@@ -1,16 +1,16 @@
1
1
  import { ThemeMode } from 'antd-style';
2
- import { merge } from 'lodash-es';
3
2
  import type { StateCreator } from 'zustand/vanilla';
4
3
 
5
4
  import type { ConfigSettings } from '@/types/exportConfig';
6
5
 
7
6
  import type { SidebarTabKey } from './initialState';
8
- import { GlobalSettingsState } from './initialState';
7
+ import { DEFAULT_SETTINGS, GlobalSettingsState } from './initialState';
9
8
  import type { SettingsStore } from './store';
10
9
 
11
10
  export interface SettingsAction {
11
+ resetSettings: () => void;
12
12
  setGlobalSettings: (settings: GlobalSettingsState) => void;
13
- setSettings: (settings: { [keys in keyof ConfigSettings]?: any }) => void;
13
+ setSettings: (settings: Partial<ConfigSettings>) => void;
14
14
  setThemeMode: (themeMode: ThemeMode) => void;
15
15
  switchSideBar: (key: SidebarTabKey) => void;
16
16
  }
@@ -21,11 +21,15 @@ export const createSettings: StateCreator<
21
21
  [],
22
22
  SettingsAction
23
23
  > = (set, get) => ({
24
+ resetSettings: () => {
25
+ set({ settings: DEFAULT_SETTINGS });
26
+ },
24
27
  setGlobalSettings: (settings) => {
25
28
  set({ ...settings });
26
29
  },
27
30
  setSettings: (settings) => {
28
- set({ settings: merge(get().settings, settings) });
31
+ const oldSetting = get().settings;
32
+ set({ settings: { ...oldSetting, ...settings } });
29
33
  },
30
34
  setThemeMode: (themeMode) => {
31
35
  get().setSettings({ themeMode });
@@ -2,12 +2,26 @@ import type { ConfigSettings } from '@/types/exportConfig';
2
2
 
3
3
  export type SidebarTabKey = 'chat' | 'market';
4
4
  export const DEFAULT_SETTINGS: ConfigSettings = {
5
+ accessCode: '',
5
6
  avatar: '',
7
+ compressThreshold: 24,
8
+ enableCompressThreshold: true,
9
+ enableHistoryCount: true,
10
+ enableMaxTokens: true,
11
+ endpoint: '',
6
12
  fontSize: 14,
13
+ frequencyPenalty: 0,
14
+ historyCount: 24,
7
15
  language: 'zh-CN',
16
+ maxTokens: 2000,
17
+ model: 'gpt-3.5-turbo',
8
18
  neutralColor: '',
19
+ presencePenalty: 0,
9
20
  primaryColor: '',
21
+ temperature: 0.5,
10
22
  themeMode: 'auto',
23
+ token: '',
24
+ topP: 1,
11
25
  };
12
26
 
13
27
  export interface GlobalSettingsState {
@@ -1,10 +1,10 @@
1
- import { merge } from 'lodash-es';
1
+ import { defaults } from 'lodash-es';
2
2
 
3
3
  import { DEFAULT_SETTINGS } from '@/store/settings/initialState';
4
4
 
5
5
  import { SettingsStore } from './store';
6
6
 
7
- const currentSettings = (s: SettingsStore) => merge(DEFAULT_SETTINGS, s.settings);
7
+ const currentSettings = (s: SettingsStore) => defaults(s.settings, DEFAULT_SETTINGS);
8
8
 
9
9
  const selecThemeMode = (s: SettingsStore) => ({
10
10
  setThemeMode: s.setThemeMode,
@@ -16,7 +16,7 @@ export default (token: Theme) => css`
16
16
  background: ${token.colorPrimary} !important;
17
17
  }
18
18
 
19
- .ant-btn-primary {
19
+ .ant-btn-primary:not(.ant-btn-dangerous) {
20
20
  color: ${readableColor(token.colorPrimary)};
21
21
  background: ${token.colorPrimary};
22
22
 
@@ -7,12 +7,26 @@ import { Locales } from './locale';
7
7
  * 配置设置
8
8
  */
9
9
  export interface ConfigSettings {
10
- avatar?: string;
10
+ accessCode: string;
11
+ avatar: string;
12
+ compressThreshold: number;
13
+ enableCompressThreshold: boolean;
14
+ enableHistoryCount: boolean;
15
+ enableMaxTokens: boolean;
16
+ endpoint: string;
11
17
  fontSize: number;
18
+ frequencyPenalty: number;
19
+ historyCount: number;
12
20
  language: Locales;
13
- neutralColor?: NeutralColors | '';
14
- primaryColor?: PrimaryColors | '';
21
+ maxTokens: number;
22
+ model: string;
23
+ neutralColor: NeutralColors | '';
24
+ presencePenalty: number;
25
+ primaryColor: PrimaryColors | '';
26
+ temperature: number;
15
27
  themeMode: ThemeMode;
28
+ token: string;
29
+ topP: number;
16
30
  }
17
31
 
18
32
  export type ConfigKeys = keyof ConfigSettings;
@@ -2,7 +2,7 @@ import { DefaultResources } from '@/types/locale';
2
2
 
3
3
  declare module 'i18next' {
4
4
  interface CustomTypeOptions {
5
- defaultNS: 'common';
5
+ defaultNS: ['common', 'setting'];
6
6
  resources: DefaultResources;
7
7
  }
8
8
  }