@lobehub/chat 1.134.1 → 1.134.3
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/.github/workflows/claude-translator.yml +1 -1
- package/.github/workflows/lock-closed-issues.yml +1 -1
- package/.github/workflows/test.yml +4 -4
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/packages/database/src/models/__tests__/aiModel.test.ts +9 -0
- package/packages/database/src/models/aiModel.ts +23 -11
- package/packages/database/src/repositories/aiInfra/index.ts +1 -1
- package/packages/model-bank/src/types/aiModel.ts +3 -0
- package/packages/model-runtime/src/providers/google/index.ts +4 -3
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/CreateNewModelModal/Form.tsx +38 -3
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/index.tsx +2 -1
- package/src/locales/default/modelProvider.ts +15 -0
- package/src/server/routers/lambda/aiModel.ts +4 -1
- package/src/store/aiInfra/slices/aiProvider/action.ts +4 -1
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
run: bun run --filter @lobechat/${{ matrix.package }} test:coverage
|
|
46
46
|
|
|
47
47
|
- name: Upload ${{ matrix.package }} coverage to Codecov
|
|
48
|
-
uses: codecov/codecov-action@
|
|
48
|
+
uses: codecov/codecov-action@v5
|
|
49
49
|
with:
|
|
50
50
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
51
51
|
files: ./packages/${{ matrix.package }}/coverage/lcov.info
|
|
@@ -80,7 +80,7 @@ jobs:
|
|
|
80
80
|
run: bun run --filter ${{ matrix.package }} test:coverage
|
|
81
81
|
|
|
82
82
|
- name: Upload ${{ matrix.package }} coverage to Codecov
|
|
83
|
-
uses: codecov/codecov-action@
|
|
83
|
+
uses: codecov/codecov-action@v5
|
|
84
84
|
with:
|
|
85
85
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
86
86
|
files: ./packages/${{ matrix.package }}/coverage/lcov.info
|
|
@@ -113,7 +113,7 @@ jobs:
|
|
|
113
113
|
run: bun run test-app:coverage
|
|
114
114
|
|
|
115
115
|
- name: Upload App Coverage to Codecov
|
|
116
|
-
uses: codecov/codecov-action@
|
|
116
|
+
uses: codecov/codecov-action@v5
|
|
117
117
|
with:
|
|
118
118
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
119
119
|
files: ./coverage/app/lcov.info
|
|
@@ -174,7 +174,7 @@ jobs:
|
|
|
174
174
|
APP_URL: https://home.com
|
|
175
175
|
|
|
176
176
|
- name: Upload Database coverage to Codecov
|
|
177
|
-
uses: codecov/codecov-action@
|
|
177
|
+
uses: codecov/codecov-action@v5
|
|
178
178
|
with:
|
|
179
179
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
180
180
|
files: ./packages/database/coverage/lcov.info
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 1.134.3](https://github.com/lobehub/lobe-chat/compare/v1.134.2...v1.134.3)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-10-05**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Type not preserved when model is sorted.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Type not preserved when model is sorted, closes [#9561](https://github.com/lobehub/lobe-chat/issues/9561) ([5fe2518](https://github.com/lobehub/lobe-chat/commit/5fe2518))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.134.2](https://github.com/lobehub/lobe-chat/compare/v1.134.1...v1.134.2)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2025-10-05**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **misc**: Allow switching model `type`.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **misc**: Allow switching model `type`, closes [#9529](https://github.com/lobehub/lobe-chat/issues/9529) ([9b62685](https://github.com/lobehub/lobe-chat/commit/9b62685))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 1.134.1](https://github.com/lobehub/lobe-chat/compare/v1.134.0...v1.134.1)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2025-10-05**</sup>
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"fixes": [
|
|
5
|
+
"Type not preserved when model is sorted."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2025-10-05",
|
|
9
|
+
"version": "1.134.3"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"improvements": [
|
|
14
|
+
"Allow switching model type."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"date": "2025-10-05",
|
|
18
|
+
"version": "1.134.2"
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"children": {
|
|
4
22
|
"improvements": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.134.
|
|
3
|
+
"version": "1.134.3",
|
|
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",
|
|
@@ -315,5 +315,14 @@ describe('AiModelModel', () => {
|
|
|
315
315
|
expect(models[0].id).toBe('model2');
|
|
316
316
|
expect(models[1].id).toBe('model1');
|
|
317
317
|
});
|
|
318
|
+
|
|
319
|
+
it('should preserve model type when inserting order records', async () => {
|
|
320
|
+
const sortMap = [{ id: 'image-model', sort: 0, type: 'image' as const }];
|
|
321
|
+
|
|
322
|
+
await aiProviderModel.updateModelsOrder('openai', sortMap);
|
|
323
|
+
|
|
324
|
+
const model = await aiProviderModel.findById('image-model');
|
|
325
|
+
expect(model?.type).toBe('image');
|
|
326
|
+
});
|
|
318
327
|
});
|
|
319
328
|
});
|
|
@@ -223,20 +223,32 @@ export class AiModelModel {
|
|
|
223
223
|
|
|
224
224
|
updateModelsOrder = async (providerId: string, sortMap: AiModelSortMap[]) => {
|
|
225
225
|
await this.db.transaction(async (tx) => {
|
|
226
|
-
const updates = sortMap.map(({ id, sort }) => {
|
|
226
|
+
const updates = sortMap.map(({ id, sort, type }) => {
|
|
227
|
+
const now = new Date();
|
|
228
|
+
const insertValues: typeof aiModels.$inferInsert = {
|
|
229
|
+
enabled: true,
|
|
230
|
+
id,
|
|
231
|
+
providerId,
|
|
232
|
+
sort,
|
|
233
|
+
// source: isBuiltin ? 'builtin' : 'custom',
|
|
234
|
+
updatedAt: now,
|
|
235
|
+
userId: this.userId,
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
if (type) insertValues.type = type;
|
|
239
|
+
|
|
240
|
+
const updateValues: Partial<typeof aiModels.$inferInsert> = {
|
|
241
|
+
sort,
|
|
242
|
+
updatedAt: now,
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
if (type) updateValues.type = type;
|
|
246
|
+
|
|
227
247
|
return tx
|
|
228
248
|
.insert(aiModels)
|
|
229
|
-
.values(
|
|
230
|
-
enabled: true,
|
|
231
|
-
id,
|
|
232
|
-
providerId,
|
|
233
|
-
sort,
|
|
234
|
-
// source: isBuiltin ? 'builtin' : 'custom',
|
|
235
|
-
updatedAt: new Date(),
|
|
236
|
-
userId: this.userId,
|
|
237
|
-
})
|
|
249
|
+
.values(insertValues)
|
|
238
250
|
.onConflictDoUpdate({
|
|
239
|
-
set:
|
|
251
|
+
set: updateValues,
|
|
240
252
|
target: [aiModels.id, aiModels.userId, aiModels.providerId],
|
|
241
253
|
});
|
|
242
254
|
});
|
|
@@ -327,6 +327,7 @@ export const CreateAiModelSchema = z.object({
|
|
|
327
327
|
id: z.string(),
|
|
328
328
|
providerId: z.string(),
|
|
329
329
|
releasedAt: z.string().optional(),
|
|
330
|
+
type: AiModelTypeSchema.optional(),
|
|
330
331
|
|
|
331
332
|
// checkModel: z.string().optional(),
|
|
332
333
|
// homeUrl: z.string().optional(),
|
|
@@ -362,6 +363,7 @@ export const UpdateAiModelSchema = z.object({
|
|
|
362
363
|
.optional(),
|
|
363
364
|
contextWindowTokens: z.number().nullable().optional(),
|
|
364
365
|
displayName: z.string().nullable().optional(),
|
|
366
|
+
type: AiModelTypeSchema.optional(),
|
|
365
367
|
});
|
|
366
368
|
|
|
367
369
|
export type UpdateAiModelParams = z.infer<typeof UpdateAiModelSchema>;
|
|
@@ -369,6 +371,7 @@ export type UpdateAiModelParams = z.infer<typeof UpdateAiModelSchema>;
|
|
|
369
371
|
export interface AiModelSortMap {
|
|
370
372
|
id: string;
|
|
371
373
|
sort: number;
|
|
374
|
+
type?: AiModelType;
|
|
372
375
|
}
|
|
373
376
|
|
|
374
377
|
export const ToggleAiModelEnableSchema = z.object({
|
|
@@ -75,9 +75,10 @@ const getThinkingModelCategory = (model?: string): ThinkingModelCategory => {
|
|
|
75
75
|
const normalized = model.toLowerCase();
|
|
76
76
|
|
|
77
77
|
if (normalized.includes('robotics-er-1.5-preview')) return 'robotics';
|
|
78
|
-
if (normalized.includes('-2.5-flash-lite')
|
|
79
|
-
|
|
80
|
-
if (normalized.includes('-2.5-
|
|
78
|
+
if (normalized.includes('-2.5-flash-lite') || normalized.includes('flash-lite-latest'))
|
|
79
|
+
return 'flashLite';
|
|
80
|
+
if (normalized.includes('-2.5-flash') || normalized.includes('flash-latest')) return 'flash';
|
|
81
|
+
if (normalized.includes('-2.5-pro') || normalized.includes('pro-latest')) return 'pro';
|
|
81
82
|
|
|
82
83
|
return 'other';
|
|
83
84
|
};
|
package/src/app/[variants]/(main)/settings/provider/features/ModelList/CreateNewModelModal/Form.tsx
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Input } from '@lobehub/ui';
|
|
2
|
-
import { Checkbox, Form, FormInstance } from 'antd';
|
|
3
|
-
import { memo, useEffect } from 'react';
|
|
2
|
+
import { Checkbox, Form, FormInstance, Select } from 'antd';
|
|
3
|
+
import { memo, useEffect, useMemo } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
import MaxTokenSlider from '@/components/MaxTokenSlider';
|
|
7
7
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
8
|
-
import { AiModelType } from '../../../../../../../../../packages/model-bank/src/types/aiModel';
|
|
9
8
|
import { ChatModelCard } from '@/types/llm';
|
|
10
9
|
|
|
10
|
+
import { AiModelType } from '../../../../../../../../../packages/model-bank/src/types/aiModel';
|
|
11
|
+
|
|
11
12
|
interface ModelConfigFormProps {
|
|
12
13
|
idEditable?: boolean;
|
|
13
14
|
initialValues?: ChatModelCard;
|
|
@@ -24,6 +25,30 @@ const ModelConfigForm = memo<ModelConfigFormProps>(
|
|
|
24
25
|
|
|
25
26
|
const isMobile = useIsMobile();
|
|
26
27
|
|
|
28
|
+
const modelTypeOptions = useMemo(
|
|
29
|
+
() =>
|
|
30
|
+
(
|
|
31
|
+
[
|
|
32
|
+
'chat',
|
|
33
|
+
'embedding',
|
|
34
|
+
'tts',
|
|
35
|
+
'stt',
|
|
36
|
+
'image',
|
|
37
|
+
// 'text2video',
|
|
38
|
+
// 'text2music',
|
|
39
|
+
'realtime',
|
|
40
|
+
] as AiModelType[]
|
|
41
|
+
).map((value) => {
|
|
42
|
+
const label = t(`providerModels.item.modelConfig.type.options.${value}`);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
label: label !== value ? `${label} (${value})` : label,
|
|
46
|
+
value,
|
|
47
|
+
};
|
|
48
|
+
}),
|
|
49
|
+
[t],
|
|
50
|
+
);
|
|
51
|
+
|
|
27
52
|
useEffect(() => {
|
|
28
53
|
onFormInstanceReady(formInstance);
|
|
29
54
|
}, []);
|
|
@@ -102,6 +127,16 @@ const ModelConfigForm = memo<ModelConfigFormProps>(
|
|
|
102
127
|
>
|
|
103
128
|
<Checkbox />
|
|
104
129
|
</Form.Item>
|
|
130
|
+
<Form.Item
|
|
131
|
+
extra={t('providerModels.item.modelConfig.type.extra')}
|
|
132
|
+
label={t('providerModels.item.modelConfig.type.title')}
|
|
133
|
+
name={'type'}
|
|
134
|
+
>
|
|
135
|
+
<Select
|
|
136
|
+
options={modelTypeOptions}
|
|
137
|
+
placeholder={t('providerModels.item.modelConfig.type.placeholder')}
|
|
138
|
+
/>
|
|
139
|
+
</Form.Item>
|
|
105
140
|
{/*<Form.Item*/}
|
|
106
141
|
{/* extra={t('providerModels.item.modelConfig.files.extra')}*/}
|
|
107
142
|
{/* label={t('providerModels.item.modelConfig.files.title')}*/}
|
package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/index.tsx
CHANGED
|
@@ -6,8 +6,8 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
8
|
import { useAiInfraStore } from '@/store/aiInfra';
|
|
9
|
-
import { AiProviderModelListItem } from '../../../../../../../../../packages/model-bank/src/types/aiModel';
|
|
10
9
|
|
|
10
|
+
import { AiProviderModelListItem } from '../../../../../../../../../packages/model-bank/src/types/aiModel';
|
|
11
11
|
import ListItem from './ListItem';
|
|
12
12
|
|
|
13
13
|
const useStyles = createStyles(({ css, token }) => ({
|
|
@@ -76,6 +76,7 @@ const SortModelModal = memo<SortModelModalProps>(({ open, onCancel, defaultItems
|
|
|
76
76
|
const sortMap = items.map((item, index) => ({
|
|
77
77
|
id: item.id,
|
|
78
78
|
sort: index,
|
|
79
|
+
type: item.type,
|
|
79
80
|
}));
|
|
80
81
|
|
|
81
82
|
setLoading(true);
|
|
@@ -299,6 +299,21 @@ export default {
|
|
|
299
299
|
title: '最大上下文窗口',
|
|
300
300
|
unlimited: '无限制',
|
|
301
301
|
},
|
|
302
|
+
type: {
|
|
303
|
+
extra: '不同模型类型拥有差异化的使用场景与能力',
|
|
304
|
+
options: {
|
|
305
|
+
chat: '对话',
|
|
306
|
+
embedding: '向量化',
|
|
307
|
+
image: '图片生成',
|
|
308
|
+
realtime: '实时对话',
|
|
309
|
+
stt: '语音转文本',
|
|
310
|
+
text2music: '文本转音乐',
|
|
311
|
+
text2video: '文本转视频',
|
|
312
|
+
tts: '语音合成',
|
|
313
|
+
},
|
|
314
|
+
placeholder: '请选择模型类型',
|
|
315
|
+
title: '模型类型',
|
|
316
|
+
},
|
|
302
317
|
vision: {
|
|
303
318
|
extra:
|
|
304
319
|
'此配置将仅开启应用中的图片上传配置,是否支持识别完全取决于模型本身,请自行测试该模型的视觉识别能力可用性',
|
|
@@ -7,13 +7,15 @@ import { authedProcedure, router } from '@/libs/trpc/lambda';
|
|
|
7
7
|
import { serverDatabase } from '@/libs/trpc/lambda/middleware';
|
|
8
8
|
import { getServerGlobalConfig } from '@/server/globalConfig';
|
|
9
9
|
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
|
10
|
+
import { ProviderConfig } from '@/types/user/settings';
|
|
11
|
+
|
|
10
12
|
import {
|
|
13
|
+
AiModelTypeSchema,
|
|
11
14
|
AiProviderModelListItem,
|
|
12
15
|
CreateAiModelSchema,
|
|
13
16
|
ToggleAiModelEnableSchema,
|
|
14
17
|
UpdateAiModelSchema,
|
|
15
18
|
} from '../../../../packages/model-bank/src/types/aiModel';
|
|
16
|
-
import { ProviderConfig } from '@/types/user/settings';
|
|
17
19
|
|
|
18
20
|
const aiModelProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
|
19
21
|
const { ctx } = opts;
|
|
@@ -121,6 +123,7 @@ export const aiModelRouter = router({
|
|
|
121
123
|
z.object({
|
|
122
124
|
id: z.string(),
|
|
123
125
|
sort: z.number(),
|
|
126
|
+
type: AiModelTypeSchema.optional(),
|
|
124
127
|
}),
|
|
125
128
|
),
|
|
126
129
|
}),
|
|
@@ -160,7 +160,10 @@ export const createAiProviderSlice: StateCreator<
|
|
|
160
160
|
await get().refreshAiProviderRuntimeState();
|
|
161
161
|
},
|
|
162
162
|
refreshAiProviderRuntimeState: async () => {
|
|
163
|
-
await
|
|
163
|
+
await Promise.all([
|
|
164
|
+
mutate([AiProviderSwrKey.fetchAiProviderRuntimeState, true]),
|
|
165
|
+
mutate([AiProviderSwrKey.fetchAiProviderRuntimeState, false]),
|
|
166
|
+
]);
|
|
164
167
|
},
|
|
165
168
|
removeAiProvider: async (id) => {
|
|
166
169
|
await aiProviderService.deleteAiProvider(id);
|