@lobehub/chat 1.31.5 → 1.31.7

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 (61) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/Dockerfile +3 -1
  3. package/Dockerfile.database +3 -1
  4. package/docs/usage/providers/cloudflare.mdx +82 -0
  5. package/docs/usage/providers/cloudflare.zh-CN.mdx +79 -0
  6. package/locales/ar/models.json +39 -7
  7. package/locales/ar/providers.json +4 -0
  8. package/locales/bg-BG/models.json +38 -6
  9. package/locales/bg-BG/providers.json +4 -0
  10. package/locales/de-DE/models.json +39 -7
  11. package/locales/de-DE/providers.json +4 -0
  12. package/locales/en-US/models.json +38 -6
  13. package/locales/en-US/providers.json +4 -0
  14. package/locales/es-ES/models.json +38 -6
  15. package/locales/es-ES/providers.json +4 -0
  16. package/locales/fa-IR/modelProvider.json +12 -0
  17. package/locales/fa-IR/models.json +39 -7
  18. package/locales/fa-IR/providers.json +4 -0
  19. package/locales/fr-FR/models.json +38 -6
  20. package/locales/fr-FR/providers.json +4 -0
  21. package/locales/it-IT/models.json +38 -6
  22. package/locales/it-IT/providers.json +4 -0
  23. package/locales/ja-JP/models.json +39 -7
  24. package/locales/ja-JP/providers.json +4 -0
  25. package/locales/ko-KR/models.json +38 -6
  26. package/locales/ko-KR/providers.json +4 -0
  27. package/locales/nl-NL/models.json +38 -6
  28. package/locales/nl-NL/providers.json +4 -0
  29. package/locales/pl-PL/models.json +37 -5
  30. package/locales/pl-PL/providers.json +4 -0
  31. package/locales/pt-BR/models.json +38 -6
  32. package/locales/pt-BR/providers.json +4 -0
  33. package/locales/ru-RU/models.json +38 -6
  34. package/locales/ru-RU/providers.json +4 -0
  35. package/locales/tr-TR/models.json +39 -7
  36. package/locales/tr-TR/providers.json +4 -0
  37. package/locales/vi-VN/models.json +37 -5
  38. package/locales/vi-VN/providers.json +4 -0
  39. package/locales/zh-CN/modelProvider.json +1 -1
  40. package/locales/zh-CN/models.json +37 -5
  41. package/locales/zh-CN/providers.json +4 -0
  42. package/locales/zh-TW/models.json +38 -6
  43. package/locales/zh-TW/providers.json +4 -0
  44. package/package.json +1 -1
  45. package/src/app/(main)/chat/(workspace)/@conversation/default.tsx +2 -2
  46. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Header/index.tsx +6 -1
  47. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +63 -43
  48. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx +19 -1
  49. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/Content.tsx +35 -0
  50. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/index.tsx +28 -0
  51. package/src/config/llm.ts +0 -66
  52. package/src/config/modelProviders/cloudflare.ts +1 -0
  53. package/src/features/ChatInput/ActionBar/config.ts +1 -20
  54. package/src/features/ChatInput/ActionBar/index.tsx +25 -28
  55. package/src/features/ChatInput/types.ts +1 -0
  56. package/src/features/Conversation/components/ChatItem/index.tsx +1 -1
  57. package/src/features/Conversation/components/VirtualizedList/index.tsx +13 -28
  58. package/src/features/Conversation/index.ts +2 -0
  59. package/src/server/globalConfig/genServerLLMConfig.test.ts +5 -1
  60. package/src/server/globalConfig/genServerLLMConfig.ts +3 -2
  61. package/src/features/Conversation/index.tsx +0 -30
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+
3
+ import isEqual from 'fast-deep-equal';
4
+ import React, { memo } from 'react';
5
+
6
+ import { WELCOME_GUIDE_CHAT_ID } from '@/const/session';
7
+ import { VirtualizedList } from '@/features/Conversation';
8
+ import { useChatStore } from '@/store/chat';
9
+ import { chatSelectors } from '@/store/chat/selectors';
10
+ import { useSessionStore } from '@/store/session';
11
+
12
+ interface ListProps {
13
+ mobile?: boolean;
14
+ }
15
+
16
+ const Content = memo<ListProps>(({ mobile }) => {
17
+ const [activeTopicId, useFetchMessages] = useChatStore((s) => [
18
+ s.activeTopicId,
19
+ s.useFetchMessages,
20
+ ]);
21
+
22
+ const [sessionId] = useSessionStore((s) => [s.activeId]);
23
+ useFetchMessages(sessionId, activeTopicId);
24
+
25
+ const data = useChatStore((s) => {
26
+ const showInboxWelcome = chatSelectors.showInboxWelcome(s);
27
+ if (showInboxWelcome) return [WELCOME_GUIDE_CHAT_ID];
28
+
29
+ return chatSelectors.currentChatIDsWithGuideMessage(s);
30
+ }, isEqual);
31
+
32
+ return <VirtualizedList dataSource={data} mobile={mobile} />;
33
+ });
34
+
35
+ export default Content;
@@ -0,0 +1,28 @@
1
+ import { Suspense, lazy } from 'react';
2
+ import { Flexbox } from 'react-layout-kit';
3
+
4
+ import { SkeletonList } from '@/features/Conversation';
5
+
6
+ const Content = lazy(() => import('./Content'));
7
+
8
+ interface ChatListProps {
9
+ mobile?: boolean;
10
+ }
11
+
12
+ const ChatList = ({ mobile }: ChatListProps) => (
13
+ <Flexbox
14
+ flex={1}
15
+ style={{
16
+ overflowX: 'hidden',
17
+ overflowY: 'auto',
18
+ position: 'relative',
19
+ }}
20
+ width={'100%'}
21
+ >
22
+ <Suspense fallback={<SkeletonList mobile={mobile} />}>
23
+ <Content mobile={mobile} />
24
+ </Suspense>
25
+ </Flexbox>
26
+ );
27
+
28
+ export default ChatList;
package/src/config/llm.ts CHANGED
@@ -10,77 +10,60 @@ export const getLLMConfig = () => {
10
10
  ENABLED_OPENAI: z.boolean(),
11
11
  OPENAI_API_KEY: z.string().optional(),
12
12
  OPENAI_PROXY_URL: z.string().optional(),
13
- OPENAI_MODEL_LIST: z.string().optional(),
14
13
 
15
14
  ENABLED_AZURE_OPENAI: z.boolean(),
16
15
  AZURE_API_KEY: z.string().optional(),
17
16
  AZURE_API_VERSION: z.string().optional(),
18
17
  AZURE_ENDPOINT: z.string().optional(),
19
- AZURE_MODEL_LIST: z.string().optional(),
20
18
 
21
19
  ENABLED_ZHIPU: z.boolean(),
22
20
  ZHIPU_API_KEY: z.string().optional(),
23
- ZHIPU_MODEL_LIST: z.string().optional(),
24
21
 
25
22
  ENABLED_DEEPSEEK: z.boolean(),
26
23
  DEEPSEEK_API_KEY: z.string().optional(),
27
- DEEPSEEK_MODEL_LIST: z.string().optional(),
28
24
 
29
25
  ENABLED_GOOGLE: z.boolean(),
30
26
  GOOGLE_API_KEY: z.string().optional(),
31
27
  GOOGLE_PROXY_URL: z.string().optional(),
32
- GOOGLE_MODEL_LIST: z.string().optional(),
33
28
 
34
29
  ENABLED_MOONSHOT: z.boolean(),
35
30
  MOONSHOT_API_KEY: z.string().optional(),
36
- MOONSHOT_MODEL_LIST: z.string().optional(),
37
31
  MOONSHOT_PROXY_URL: z.string().optional(),
38
32
 
39
33
  ENABLED_PERPLEXITY: z.boolean(),
40
34
  PERPLEXITY_API_KEY: z.string().optional(),
41
- PERPLEXITY_MODEL_LIST: z.string().optional(),
42
35
  PERPLEXITY_PROXY_URL: z.string().optional(),
43
36
 
44
37
  ENABLED_ANTHROPIC: z.boolean(),
45
38
  ANTHROPIC_API_KEY: z.string().optional(),
46
- ANTHROPIC_MODEL_LIST: z.string().optional(),
47
39
  ANTHROPIC_PROXY_URL: z.string().optional(),
48
40
 
49
41
  ENABLED_MINIMAX: z.boolean(),
50
- MINIMAX_MODEL_LIST: z.string().optional(),
51
42
  MINIMAX_API_KEY: z.string().optional(),
52
43
 
53
44
  ENABLED_MISTRAL: z.boolean(),
54
45
  MISTRAL_API_KEY: z.string().optional(),
55
- MISTRAL_MODEL_LIST: z.string().optional(),
56
46
 
57
47
  ENABLED_GROQ: z.boolean(),
58
48
  GROQ_API_KEY: z.string().optional(),
59
- GROQ_MODEL_LIST: z.string().optional(),
60
49
  GROQ_PROXY_URL: z.string().optional(),
61
50
 
62
51
  ENABLED_GITHUB: z.boolean(),
63
52
  GITHUB_TOKEN: z.string().optional(),
64
- GITHUB_MODEL_LIST: z.string().optional(),
65
53
 
66
54
  ENABLED_OPENROUTER: z.boolean(),
67
55
  OPENROUTER_API_KEY: z.string().optional(),
68
- OPENROUTER_MODEL_LIST: z.string().optional(),
69
56
 
70
57
  ENABLED_ZEROONE: z.boolean(),
71
58
  ZEROONE_API_KEY: z.string().optional(),
72
- ZEROONE_MODEL_LIST: z.string().optional(),
73
59
 
74
60
  ENABLED_TOGETHERAI: z.boolean(),
75
61
  TOGETHERAI_API_KEY: z.string().optional(),
76
- TOGETHERAI_MODEL_LIST: z.string().optional(),
77
62
 
78
63
  ENABLED_FIREWORKSAI: z.boolean(),
79
64
  FIREWORKSAI_API_KEY: z.string().optional(),
80
- FIREWORKSAI_MODEL_LIST: z.string().optional(),
81
65
 
82
66
  ENABLED_AWS_BEDROCK: z.boolean(),
83
- AWS_BEDROCK_MODEL_LIST: z.string().optional(),
84
67
  AWS_REGION: z.string().optional(),
85
68
  AWS_ACCESS_KEY_ID: z.string().optional(),
86
69
  AWS_SECRET_ACCESS_KEY: z.string().optional(),
@@ -89,31 +72,24 @@ export const getLLMConfig = () => {
89
72
  ENABLED_WENXIN: z.boolean(),
90
73
  WENXIN_ACCESS_KEY: z.string().optional(),
91
74
  WENXIN_SECRET_KEY: z.string().optional(),
92
- WENXIN_MODEL_LIST: z.string().optional(),
93
75
 
94
76
  ENABLED_OLLAMA: z.boolean(),
95
77
  OLLAMA_PROXY_URL: z.string().optional(),
96
- OLLAMA_MODEL_LIST: z.string().optional(),
97
78
 
98
79
  ENABLED_QWEN: z.boolean(),
99
80
  QWEN_API_KEY: z.string().optional(),
100
- QWEN_MODEL_LIST: z.string().optional(),
101
81
 
102
82
  ENABLED_STEPFUN: z.boolean(),
103
83
  STEPFUN_API_KEY: z.string().optional(),
104
- STEPFUN_MODEL_LIST: z.string().optional(),
105
84
 
106
85
  ENABLED_NOVITA: z.boolean(),
107
86
  NOVITA_API_KEY: z.string().optional(),
108
- NOVITA_MODEL_LIST: z.string().optional(),
109
87
 
110
88
  ENABLED_BAICHUAN: z.boolean(),
111
89
  BAICHUAN_API_KEY: z.string().optional(),
112
- BAICHUAN_MODEL_LIST: z.string().optional(),
113
90
 
114
91
  ENABLED_TAICHU: z.boolean(),
115
92
  TAICHU_API_KEY: z.string().optional(),
116
- TAICHU_MODEL_LIST: z.string().optional(),
117
93
 
118
94
  ENABLED_CLOUDFLARE: z.boolean(),
119
95
  CLOUDFLARE_API_KEY: z.string().optional(),
@@ -121,42 +97,33 @@ export const getLLMConfig = () => {
121
97
 
122
98
  ENABLED_AI360: z.boolean(),
123
99
  AI360_API_KEY: z.string().optional(),
124
- AI360_MODEL_LIST: z.string().optional(),
125
100
 
126
101
  ENABLED_SILICONCLOUD: z.boolean(),
127
102
  SILICONCLOUD_API_KEY: z.string().optional(),
128
- SILICONCLOUD_MODEL_LIST: z.string().optional(),
129
103
  SILICONCLOUD_PROXY_URL: z.string().optional(),
130
104
 
131
105
  ENABLED_UPSTAGE: z.boolean(),
132
106
  UPSTAGE_API_KEY: z.string().optional(),
133
- UPSTAGE_MODEL_LIST: z.string().optional(),
134
107
 
135
108
  ENABLED_SPARK: z.boolean(),
136
109
  SPARK_API_KEY: z.string().optional(),
137
- SPARK_MODEL_LIST: z.string().optional(),
138
110
 
139
111
  ENABLED_AI21: z.boolean(),
140
112
  AI21_API_KEY: z.string().optional(),
141
- AI21_MODEL_LIST: z.string().optional(),
142
113
 
143
114
  ENABLED_HUNYUAN: z.boolean(),
144
115
  HUNYUAN_API_KEY: z.string().optional(),
145
- HUNYUAN_MODEL_LIST: z.string().optional(),
146
116
 
147
117
  ENABLED_HUGGINGFACE: z.boolean(),
148
118
  HUGGINGFACE_API_KEY: z.string().optional(),
149
119
  HUGGINGFACE_PROXY_URL: z.string().optional(),
150
- HUGGINGFACE_MODEL_LIST: z.string().optional(),
151
120
 
152
121
  ENABLED_SENSENOVA: z.boolean(),
153
122
  SENSENOVA_ACCESS_KEY_ID: z.string().optional(),
154
123
  SENSENOVA_ACCESS_KEY_SECRET: z.string().optional(),
155
- SENSENOVA_MODEL_LIST: z.string().optional(),
156
124
 
157
125
  ENABLED_XAI: z.boolean(),
158
126
  XAI_API_KEY: z.string().optional(),
159
- XAI_MODEL_LIST: z.string().optional(),
160
127
  },
161
128
  runtimeEnv: {
162
129
  API_KEY_SELECT_MODE: process.env.API_KEY_SELECT_MODE,
@@ -164,77 +131,60 @@ export const getLLMConfig = () => {
164
131
  ENABLED_OPENAI: process.env.ENABLED_OPENAI !== '0',
165
132
  OPENAI_API_KEY: process.env.OPENAI_API_KEY,
166
133
  OPENAI_PROXY_URL: process.env.OPENAI_PROXY_URL,
167
- OPENAI_MODEL_LIST: process.env.OPENAI_MODEL_LIST,
168
134
 
169
135
  ENABLED_AZURE_OPENAI: !!process.env.AZURE_API_KEY,
170
136
  AZURE_API_KEY: process.env.AZURE_API_KEY,
171
137
  AZURE_API_VERSION: process.env.AZURE_API_VERSION,
172
138
  AZURE_ENDPOINT: process.env.AZURE_ENDPOINT,
173
- AZURE_MODEL_LIST: process.env.AZURE_MODEL_LIST,
174
139
 
175
140
  ENABLED_ZHIPU: !!process.env.ZHIPU_API_KEY,
176
141
  ZHIPU_API_KEY: process.env.ZHIPU_API_KEY,
177
- ZHIPU_MODEL_LIST: process.env.ZHIPU_MODEL_LIST,
178
142
 
179
143
  ENABLED_DEEPSEEK: !!process.env.DEEPSEEK_API_KEY,
180
144
  DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY,
181
- DEEPSEEK_MODEL_LIST: process.env.DEEPSEEK_MODEL_LIST,
182
145
 
183
146
  ENABLED_GOOGLE: !!process.env.GOOGLE_API_KEY,
184
147
  GOOGLE_API_KEY: process.env.GOOGLE_API_KEY,
185
148
  GOOGLE_PROXY_URL: process.env.GOOGLE_PROXY_URL,
186
- GOOGLE_MODEL_LIST: process.env.GOOGLE_MODEL_LIST,
187
149
 
188
150
  ENABLED_PERPLEXITY: !!process.env.PERPLEXITY_API_KEY,
189
151
  PERPLEXITY_API_KEY: process.env.PERPLEXITY_API_KEY,
190
- PERPLEXITY_MODEL_LIST: process.env.PERPLEXITY_MODEL_LIST,
191
152
  PERPLEXITY_PROXY_URL: process.env.PERPLEXITY_PROXY_URL,
192
153
 
193
154
  ENABLED_ANTHROPIC: !!process.env.ANTHROPIC_API_KEY,
194
155
  ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
195
- ANTHROPIC_MODEL_LIST: process.env.ANTHROPIC_MODEL_LIST,
196
156
  ANTHROPIC_PROXY_URL: process.env.ANTHROPIC_PROXY_URL,
197
157
 
198
158
  ENABLED_MINIMAX: !!process.env.MINIMAX_API_KEY,
199
159
  MINIMAX_API_KEY: process.env.MINIMAX_API_KEY,
200
- MINIMAX_MODEL_LIST: process.env.MINIMAX_MODEL_LIST,
201
160
 
202
161
  ENABLED_MISTRAL: !!process.env.MISTRAL_API_KEY,
203
162
  MISTRAL_API_KEY: process.env.MISTRAL_API_KEY,
204
- MISTRAL_MODEL_LIST: process.env.MISTRAL_MODEL_LIST,
205
163
 
206
164
  ENABLED_OPENROUTER: !!process.env.OPENROUTER_API_KEY,
207
165
  OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY,
208
- OPENROUTER_MODEL_LIST: process.env.OPENROUTER_MODEL_LIST,
209
166
 
210
167
  ENABLED_TOGETHERAI: !!process.env.TOGETHERAI_API_KEY,
211
168
  TOGETHERAI_API_KEY: process.env.TOGETHERAI_API_KEY,
212
- TOGETHERAI_MODEL_LIST: process.env.TOGETHERAI_MODEL_LIST,
213
169
 
214
170
  ENABLED_FIREWORKSAI: !!process.env.FIREWORKSAI_API_KEY,
215
171
  FIREWORKSAI_API_KEY: process.env.FIREWORKSAI_API_KEY,
216
- FIREWORKSAI_MODEL_LIST: process.env.FIREWORKSAI_MODEL_LIST,
217
172
 
218
173
  ENABLED_MOONSHOT: !!process.env.MOONSHOT_API_KEY,
219
174
  MOONSHOT_API_KEY: process.env.MOONSHOT_API_KEY,
220
- MOONSHOT_MODEL_LIST: process.env.MOONSHOT_MODEL_LIST,
221
175
  MOONSHOT_PROXY_URL: process.env.MOONSHOT_PROXY_URL,
222
176
 
223
177
  ENABLED_GROQ: !!process.env.GROQ_API_KEY,
224
178
  GROQ_API_KEY: process.env.GROQ_API_KEY,
225
- GROQ_MODEL_LIST: process.env.GROQ_MODEL_LIST,
226
179
  GROQ_PROXY_URL: process.env.GROQ_PROXY_URL,
227
180
 
228
181
  ENABLED_GITHUB: !!process.env.GITHUB_TOKEN,
229
182
  GITHUB_TOKEN: process.env.GITHUB_TOKEN,
230
- GITHUB_MODEL_LIST: process.env.GITHUB_MODEL_LIST,
231
183
 
232
184
  ENABLED_ZEROONE: !!process.env.ZEROONE_API_KEY,
233
185
  ZEROONE_API_KEY: process.env.ZEROONE_API_KEY,
234
- ZEROONE_MODEL_LIST: process.env.ZEROONE_MODEL_LIST,
235
186
 
236
187
  ENABLED_AWS_BEDROCK: process.env.ENABLED_AWS_BEDROCK === '1',
237
- AWS_BEDROCK_MODEL_LIST: process.env.AWS_BEDROCK_MODEL_LIST,
238
188
  AWS_REGION: process.env.AWS_REGION,
239
189
  AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
240
190
  AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
@@ -243,31 +193,24 @@ export const getLLMConfig = () => {
243
193
  ENABLED_WENXIN: !!process.env.WENXIN_ACCESS_KEY && !!process.env.WENXIN_SECRET_KEY,
244
194
  WENXIN_ACCESS_KEY: process.env.WENXIN_ACCESS_KEY,
245
195
  WENXIN_SECRET_KEY: process.env.WENXIN_SECRET_KEY,
246
- WENXIN_MODEL_LIST: process.env.WENXIN_MODEL_LIST,
247
196
 
248
197
  ENABLED_OLLAMA: process.env.ENABLED_OLLAMA !== '0',
249
198
  OLLAMA_PROXY_URL: process.env.OLLAMA_PROXY_URL || '',
250
- OLLAMA_MODEL_LIST: process.env.OLLAMA_MODEL_LIST,
251
199
 
252
200
  ENABLED_QWEN: !!process.env.QWEN_API_KEY,
253
201
  QWEN_API_KEY: process.env.QWEN_API_KEY,
254
- QWEN_MODEL_LIST: process.env.QWEN_MODEL_LIST,
255
202
 
256
203
  ENABLED_STEPFUN: !!process.env.STEPFUN_API_KEY,
257
204
  STEPFUN_API_KEY: process.env.STEPFUN_API_KEY,
258
- STEPFUN_MODEL_LIST: process.env.STEPFUN_MODEL_LIST,
259
205
 
260
206
  ENABLED_NOVITA: !!process.env.NOVITA_API_KEY,
261
207
  NOVITA_API_KEY: process.env.NOVITA_API_KEY,
262
- NOVITA_MODEL_LIST: process.env.NOVITA_MODEL_LIST,
263
208
 
264
209
  ENABLED_BAICHUAN: !!process.env.BAICHUAN_API_KEY,
265
210
  BAICHUAN_API_KEY: process.env.BAICHUAN_API_KEY,
266
- BAICHUAN_MODEL_LIST: process.env.BAICHUAN_MODEL_LIST,
267
211
 
268
212
  ENABLED_TAICHU: !!process.env.TAICHU_API_KEY,
269
213
  TAICHU_API_KEY: process.env.TAICHU_API_KEY,
270
- TAICHU_MODEL_LIST: process.env.TAICHU_MODEL_LIST,
271
214
 
272
215
  ENABLED_CLOUDFLARE:
273
216
  !!process.env.CLOUDFLARE_API_KEY && !!process.env.CLOUDFLARE_BASE_URL_OR_ACCOUNT_ID,
@@ -276,42 +219,33 @@ export const getLLMConfig = () => {
276
219
 
277
220
  ENABLED_AI360: !!process.env.AI360_API_KEY,
278
221
  AI360_API_KEY: process.env.AI360_API_KEY,
279
- AI360_MODEL_LIST: process.env.AI360_MODEL_LIST,
280
222
 
281
223
  ENABLED_SILICONCLOUD: !!process.env.SILICONCLOUD_API_KEY,
282
224
  SILICONCLOUD_API_KEY: process.env.SILICONCLOUD_API_KEY,
283
- SILICONCLOUD_MODEL_LIST: process.env.SILICONCLOUD_MODEL_LIST,
284
225
  SILICONCLOUD_PROXY_URL: process.env.SILICONCLOUD_PROXY_URL,
285
226
 
286
227
  ENABLED_UPSTAGE: !!process.env.UPSTAGE_API_KEY,
287
228
  UPSTAGE_API_KEY: process.env.UPSTAGE_API_KEY,
288
- UPSTAGE_MODEL_LIST: process.env.UPSTAGE_MODEL_LIST,
289
229
 
290
230
  ENABLED_SPARK: !!process.env.SPARK_API_KEY,
291
231
  SPARK_API_KEY: process.env.SPARK_API_KEY,
292
- SPARK_MODEL_LIST: process.env.SPARK_MODEL_LIST,
293
232
 
294
233
  ENABLED_AI21: !!process.env.AI21_API_KEY,
295
234
  AI21_API_KEY: process.env.AI21_API_KEY,
296
- AI21_MODEL_LIST: process.env.AI21_MODEL_LIST,
297
235
 
298
236
  ENABLED_HUNYUAN: !!process.env.HUNYUAN_API_KEY,
299
237
  HUNYUAN_API_KEY: process.env.HUNYUAN_API_KEY,
300
- HUNYUAN_MODEL_LIST: process.env.HUNYUAN_MODEL_LIST,
301
238
 
302
239
  ENABLED_HUGGINGFACE: !!process.env.HUGGINGFACE_API_KEY,
303
240
  HUGGINGFACE_API_KEY: process.env.HUGGINGFACE_API_KEY,
304
241
  HUGGINGFACE_PROXY_URL: process.env.HUGGINGFACE_PROXY_URL,
305
- HUGGINGFACE_MODEL_LIST: process.env.HUGGINGFACE_MODEL_LIST,
306
242
 
307
243
  ENABLED_SENSENOVA: !!process.env.SENSENOVA_ACCESS_KEY_ID && !!process.env.SENSENOVA_ACCESS_KEY_SECRET,
308
244
  SENSENOVA_ACCESS_KEY_ID: process.env.SENSENOVA_ACCESS_KEY_ID,
309
245
  SENSENOVA_ACCESS_KEY_SECRET: process.env.SENSENOVA_ACCESS_KEY_SECRET,
310
- SENSENOVA_MODEL_LIST: process.env.SENSENOVA_MODEL_LIST,
311
246
 
312
247
  ENABLED_XAI: !!process.env.XAI_API_KEY,
313
248
  XAI_API_KEY: process.env.XAI_API_KEY,
314
- XAI_MODEL_LIST: process.env.XAI_MODEL_LIST,
315
249
  },
316
250
  });
317
251
  };
@@ -78,6 +78,7 @@ const Cloudflare: ModelProviderCard = {
78
78
  },
79
79
  ],
80
80
  checkModel: '@hf/meta-llama/meta-llama-3-8b-instruct',
81
+ disableBrowserRequest: true,
81
82
  id: 'cloudflare',
82
83
  modelList: {
83
84
  showModelFetcher: true,
@@ -20,23 +20,4 @@ export const actionMap = {
20
20
  tools: Tools,
21
21
  } as const;
22
22
 
23
- type ActionMap = typeof actionMap;
24
-
25
- export type ActionKeys = keyof ActionMap;
26
-
27
- type getActionList = (mobile?: boolean) => ActionKeys[];
28
-
29
- // we can make these action lists configurable in the future
30
- export const getLeftActionList: getActionList = (mobile) =>
31
- [
32
- 'model',
33
- 'fileUpload',
34
- 'knowledgeBase',
35
- 'temperature',
36
- 'history',
37
- !mobile && 'stt',
38
- 'tools',
39
- 'token',
40
- ].filter(Boolean) as ActionKeys[];
41
-
42
- export const getRightActionList: getActionList = () => ['clear'].filter(Boolean) as ActionKeys[];
23
+ export type ActionKeys = keyof typeof actionMap;
@@ -1,7 +1,7 @@
1
1
  import { ChatInputActionBar } from '@lobehub/ui';
2
- import { ReactNode, memo, useMemo } from 'react';
2
+ import { ReactNode, memo } from 'react';
3
3
 
4
- import { ActionKeys, actionMap, getLeftActionList, getRightActionList } from './config';
4
+ import { ActionKeys, actionMap } from './config';
5
5
 
6
6
  const RenderActionList = ({ dataSource }: { dataSource: ActionKeys[] }) => (
7
7
  <>
@@ -13,10 +13,11 @@ const RenderActionList = ({ dataSource }: { dataSource: ActionKeys[] }) => (
13
13
  );
14
14
 
15
15
  export interface ActionBarProps {
16
+ leftActions: ActionKeys[];
16
17
  leftAreaEndRender?: ReactNode;
17
18
  leftAreaStartRender?: ReactNode;
18
- mobile?: boolean;
19
19
  padding?: number | string;
20
+ rightActions: ActionKeys[];
20
21
  rightAreaEndRender?: ReactNode;
21
22
  rightAreaStartRender?: ReactNode;
22
23
  }
@@ -24,35 +25,31 @@ export interface ActionBarProps {
24
25
  const ActionBar = memo<ActionBarProps>(
25
26
  ({
26
27
  padding = '0 16px',
27
- mobile,
28
28
  rightAreaStartRender,
29
29
  rightAreaEndRender,
30
30
  leftAreaStartRender,
31
31
  leftAreaEndRender,
32
- }) => {
33
- const leftActionList = useMemo(() => getLeftActionList(mobile), [mobile]);
34
- const rightActionList = useMemo(() => getRightActionList(mobile), [mobile]);
35
-
36
- return (
37
- <ChatInputActionBar
38
- leftAddons={
39
- <>
40
- {leftAreaStartRender}
41
- <RenderActionList dataSource={leftActionList} />
42
- {leftAreaEndRender}
43
- </>
44
- }
45
- padding={padding}
46
- rightAddons={
47
- <>
48
- {rightAreaStartRender}
49
- <RenderActionList dataSource={rightActionList} />
50
- {rightAreaEndRender}
51
- </>
52
- }
53
- />
54
- );
55
- },
32
+ leftActions,
33
+ rightActions,
34
+ }) => (
35
+ <ChatInputActionBar
36
+ leftAddons={
37
+ <>
38
+ {leftAreaStartRender}
39
+ <RenderActionList dataSource={leftActions} />
40
+ {leftAreaEndRender}
41
+ </>
42
+ }
43
+ padding={padding}
44
+ rightAddons={
45
+ <>
46
+ {rightAreaStartRender}
47
+ <RenderActionList dataSource={rightActions} />
48
+ {rightAreaEndRender}
49
+ </>
50
+ }
51
+ />
52
+ ),
56
53
  );
57
54
 
58
55
  export default ActionBar;
@@ -0,0 +1 @@
1
+ export type { ActionKeys } from './ActionBar/config';
@@ -166,7 +166,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
166
166
  return (
167
167
  item && (
168
168
  <>
169
- {enableHistoryDivider && <History />}
169
+ {enableHistoryDivider && <History />}
170
170
  <ChatItem
171
171
  actions={
172
172
  <ActionsBar
@@ -2,7 +2,6 @@
2
2
 
3
3
  import { Icon } from '@lobehub/ui';
4
4
  import { useTheme } from 'antd-style';
5
- import isEqual from 'fast-deep-equal';
6
5
  import { Loader2Icon } from 'lucide-react';
7
6
  import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
8
7
  import { Center, Flexbox } from 'react-layout-kit';
@@ -12,7 +11,6 @@ import { WELCOME_GUIDE_CHAT_ID } from '@/const/session';
12
11
  import { isServerMode } from '@/const/version';
13
12
  import { useChatStore } from '@/store/chat';
14
13
  import { chatSelectors } from '@/store/chat/selectors';
15
- import { useSessionStore } from '@/store/session';
16
14
 
17
15
  import AutoScroll from '../AutoScroll';
18
16
  import Item from '../ChatItem';
@@ -20,33 +18,20 @@ import InboxWelcome from '../InboxWelcome';
20
18
  import SkeletonList from '../SkeletonList';
21
19
 
22
20
  interface VirtualizedListProps {
21
+ dataSource: string[];
23
22
  mobile?: boolean;
24
23
  }
25
- const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
24
+
25
+ const VirtualizedList = memo<VirtualizedListProps>(({ mobile, dataSource }) => {
26
26
  const virtuosoRef = useRef<VirtuosoHandle>(null);
27
27
  const [atBottom, setAtBottom] = useState(true);
28
28
  const [isScrolling, setIsScrolling] = useState(false);
29
29
 
30
30
  const [id] = useChatStore((s) => [chatSelectors.currentChatKey(s)]);
31
-
32
- const [activeTopicId, useFetchMessages, isFirstLoading, isCurrentChatLoaded] = useChatStore(
33
- (s) => [
34
- s.activeTopicId,
35
- s.useFetchMessages,
36
- chatSelectors.currentChatLoadingState(s),
37
- chatSelectors.isCurrentChatLoaded(s),
38
- ],
39
- );
40
-
41
- const [sessionId] = useSessionStore((s) => [s.activeId]);
42
- useFetchMessages(sessionId, activeTopicId);
43
-
44
- const data = useChatStore((s) => {
45
- const showInboxWelcome = chatSelectors.showInboxWelcome(s);
46
- return showInboxWelcome
47
- ? [WELCOME_GUIDE_CHAT_ID]
48
- : chatSelectors.currentChatIDsWithGuideMessage(s);
49
- }, isEqual);
31
+ const [isFirstLoading, isCurrentChatLoaded] = useChatStore((s) => [
32
+ chatSelectors.currentChatLoadingState(s),
33
+ chatSelectors.isCurrentChatLoaded(s),
34
+ ]);
50
35
 
51
36
  useEffect(() => {
52
37
  if (virtuosoRef.current) {
@@ -54,13 +39,13 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
54
39
  }
55
40
  }, [id]);
56
41
 
57
- const prevDataLengthRef = useRef(data.length);
42
+ const prevDataLengthRef = useRef(dataSource.length);
58
43
 
59
44
  const getFollowOutput = useCallback(() => {
60
- const newFollowOutput = data.length > prevDataLengthRef.current ? 'auto' : false;
61
- prevDataLengthRef.current = data.length;
45
+ const newFollowOutput = dataSource.length > prevDataLengthRef.current ? 'auto' : false;
46
+ prevDataLengthRef.current = dataSource.length;
62
47
  return newFollowOutput;
63
- }, [data.length]);
48
+ }, [dataSource.length]);
64
49
 
65
50
  const theme = useTheme();
66
51
  // overscan should be 3 times the height of the window
@@ -100,10 +85,10 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
100
85
  atBottomStateChange={setAtBottom}
101
86
  atBottomThreshold={50 * (mobile ? 2 : 1)}
102
87
  computeItemKey={(_, item) => item}
103
- data={data}
88
+ data={dataSource}
104
89
  followOutput={getFollowOutput}
105
90
  increaseViewportBy={overscan}
106
- initialTopMostItemIndex={data?.length - 1}
91
+ initialTopMostItemIndex={dataSource?.length - 1}
107
92
  isScrolling={setIsScrolling}
108
93
  itemContent={itemContent}
109
94
  overscan={overscan}
@@ -0,0 +1,2 @@
1
+ export { default as SkeletonList } from './components/SkeletonList';
2
+ export { default as VirtualizedList } from './components/VirtualizedList';
@@ -53,6 +53,10 @@ vi.mock('@/utils/parseModels', () => ({
53
53
 
54
54
  describe('genServerLLMConfig', () => {
55
55
  it('should generate correct LLM config for Azure, Bedrock, and Ollama', () => {
56
+ vi.stubEnv('AZURE_MODEL_LIST', 'azureModels');
57
+ vi.stubEnv('AWS_BEDROCK_MODEL_LIST', 'bedrockModels');
58
+ vi.stubEnv('OLLAMA_MODEL_LIST', 'ollamaModels');
59
+
56
60
  const specificConfig = {
57
61
  azure: {
58
62
  enabledKey: 'ENABLED_AZURE_OPENAI',
@@ -67,7 +71,7 @@ describe('genServerLLMConfig', () => {
67
71
  },
68
72
  };
69
73
  const config = genServerLLMConfig(specificConfig);
70
-
74
+
71
75
  expect(config.azure).toEqual({
72
76
  enabled: true,
73
77
  enabledModels: ['azureModels_withDeployment'],
@@ -14,16 +14,17 @@ export const genServerLLMConfig = (specificConfig: Record<any, any>) => {
14
14
  const providerUpperCase = provider.toUpperCase();
15
15
  const providerCard = ProviderCards[`${provider}ProviderCard` as keyof typeof ProviderCards] as ModelProviderCard;
16
16
  const providerConfig = specificConfig[provider as keyof typeof specificConfig] || {};
17
+ const providerModelList = process.env[providerConfig.modelListKey ?? `${providerUpperCase}_MODEL_LIST`];
17
18
 
18
19
  config[provider] = {
19
20
  enabled: llmConfig[providerConfig.enabledKey || `ENABLED_${providerUpperCase}`],
20
21
  enabledModels: extractEnabledModels(
21
- llmConfig[providerConfig.modelListKey || `${providerUpperCase}_MODEL_LIST`],
22
+ providerModelList,
22
23
  providerConfig.withDeploymentName || false,
23
24
  ),
24
25
  serverModelCards: transformToChatModelCards({
25
26
  defaultChatModels: (providerCard as ModelProviderCard)?.chatModels || [],
26
- modelString: llmConfig[providerConfig.modelListKey || `${providerUpperCase}_MODEL_LIST`],
27
+ modelString: providerModelList,
27
28
  withDeploymentName: providerConfig.withDeploymentName || false,
28
29
  }),
29
30
  ...(providerConfig.fetchOnClient !== undefined && { fetchOnClient: providerConfig.fetchOnClient }),
@@ -1,30 +0,0 @@
1
- import { Suspense, lazy } from 'react';
2
- import { Flexbox } from 'react-layout-kit';
3
-
4
- import SkeletonList from './components/SkeletonList';
5
-
6
- const ChatList = lazy(() => import('./components/VirtualizedList'));
7
-
8
- interface ConversationProps {
9
- mobile?: boolean;
10
- }
11
-
12
- const Conversation = ({ mobile }: ConversationProps) => {
13
- return (
14
- <Flexbox
15
- flex={1}
16
- style={{
17
- overflowX: 'hidden',
18
- overflowY: 'auto',
19
- position: 'relative',
20
- }}
21
- width={'100%'}
22
- >
23
- <Suspense fallback={<SkeletonList mobile={mobile} />}>
24
- <ChatList mobile={mobile} />
25
- </Suspense>
26
- </Flexbox>
27
- );
28
- };
29
-
30
- export default Conversation;