@lobehub/chat 0.160.5 → 0.160.6
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 +40 -0
- package/locales/ar/error.json +2 -0
- package/locales/bg-BG/error.json +2 -0
- package/locales/de-DE/error.json +2 -0
- package/locales/en-US/error.json +2 -0
- package/locales/es-ES/error.json +2 -0
- package/locales/fr-FR/error.json +2 -0
- package/locales/it-IT/error.json +2 -0
- package/locales/ja-JP/error.json +2 -0
- package/locales/ko-KR/error.json +2 -0
- package/locales/nl-NL/error.json +2 -0
- package/locales/pl-PL/error.json +2 -0
- package/locales/pt-BR/error.json +2 -0
- package/locales/ru-RU/error.json +2 -0
- package/locales/tr-TR/error.json +2 -0
- package/locales/vi-VN/error.json +2 -0
- package/locales/zh-CN/error.json +2 -0
- package/locales/zh-TW/error.json +2 -0
- package/package.json +2 -2
- package/src/app/(loading)/Redirect.tsx +8 -0
- package/src/app/(main)/chat/(workspace)/features/TelemetryNotification.tsx +42 -75
- package/src/app/(main)/market/_layout/Desktop/index.tsx +24 -20
- package/src/app/(main)/settings/llm/Azure/index.tsx +1 -0
- package/src/app/(main)/settings/llm/OpenAI/index.tsx +0 -1
- package/src/app/trpc/edge/[trpc]/route.ts +1 -1
- package/src/components/FetchErrorNotification/Description.tsx +48 -0
- package/src/components/FetchErrorNotification/index.tsx +15 -0
- package/src/components/ModelProviderIcon/index.tsx +6 -1
- package/src/components/Notification/index.tsx +95 -0
- package/src/config/server/provider.ts +1 -0
- package/src/database/client/models/__tests__/message.test.ts +2 -2
- package/src/database/client/models/message.ts +2 -2
- package/src/features/User/UserAvatar.tsx +4 -3
- package/src/locales/default/error.ts +3 -1
- package/src/middleware.ts +10 -1
- package/src/server/globalConfig/index.ts +2 -0
- package/src/server/routers/edge/config/__snapshots__/index.test.ts.snap +1 -0
- package/src/services/file/type.ts +2 -3
- package/src/services/message/client.test.ts +151 -23
- package/src/services/message/client.ts +9 -5
- package/src/services/message/type.ts +10 -3
- package/src/services/upload.ts +4 -4
- package/src/services/user/client.ts +17 -1
- package/src/services/user/type.ts +14 -0
- package/src/store/chat/slices/enchance/action.test.ts +4 -3
- package/src/store/chat/slices/enchance/action.ts +3 -2
- package/src/store/chat/slices/plugin/action.test.ts +3 -5
- package/src/store/chat/slices/plugin/action.ts +1 -1
- package/src/store/market/action.ts +7 -0
- package/src/store/user/slices/auth/selectors.ts +1 -1
- package/src/store/user/slices/preference/action.test.ts +4 -9
- package/src/store/user/slices/preference/action.ts +17 -20
- package/src/store/user/slices/settings/selectors/modelConfig.test.ts +29 -1
- package/src/store/user/slices/settings/selectors/modelConfig.ts +1 -1
- package/src/tools/dalle/Render/Item/Error.tsx +1 -1
- package/src/types/files.ts +33 -0
- /package/src/types/{user.ts → user/index.ts} +0 -0
|
@@ -43,5 +43,5 @@ const isLogin = (s: UserStore) => {
|
|
|
43
43
|
export const authSelectors = {
|
|
44
44
|
isLogin,
|
|
45
45
|
isLoginWithAuth: (s: UserStore) => s.isSignedIn,
|
|
46
|
-
isLoginWithClerk: (s: UserStore) => s.isSignedIn && enableClerk,
|
|
46
|
+
isLoginWithClerk: (s: UserStore): boolean => (s.isSignedIn && enableClerk) || false,
|
|
47
47
|
};
|
|
@@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
3
3
|
import { withSWR } from '~test-utils';
|
|
4
4
|
|
|
5
5
|
import { DEFAULT_PREFERENCE } from '@/const/user';
|
|
6
|
+
import { userService } from '@/services/user';
|
|
6
7
|
import { useUserStore } from '@/store/user';
|
|
7
8
|
import { UserGuide, UserPreference } from '@/types/user';
|
|
8
9
|
|
|
@@ -44,9 +45,7 @@ describe('createPreferenceSlice', () => {
|
|
|
44
45
|
it('should return false when userId is empty', async () => {
|
|
45
46
|
const { result } = renderHook(() => useUserStore());
|
|
46
47
|
|
|
47
|
-
vi.spyOn(
|
|
48
|
-
{} as any,
|
|
49
|
-
);
|
|
48
|
+
vi.spyOn(userService, 'getPreference').mockResolvedValueOnce({} as any);
|
|
50
49
|
|
|
51
50
|
const { result: prefernce } = renderHook(() => result.current.useInitPreference(), {
|
|
52
51
|
wrapper: withSWR,
|
|
@@ -60,9 +59,7 @@ describe('createPreferenceSlice', () => {
|
|
|
60
59
|
it('should return default preference when local storage is empty', async () => {
|
|
61
60
|
const { result } = renderHook(() => useUserStore());
|
|
62
61
|
|
|
63
|
-
vi.spyOn(
|
|
64
|
-
{} as any,
|
|
65
|
-
);
|
|
62
|
+
vi.spyOn(userService, 'getPreference').mockResolvedValueOnce({} as any);
|
|
66
63
|
|
|
67
64
|
renderHook(() => result.current.useInitPreference(), {
|
|
68
65
|
wrapper: withSWR,
|
|
@@ -82,9 +79,7 @@ describe('createPreferenceSlice', () => {
|
|
|
82
79
|
guide: { topic: false, moveSettingsToAvatar: true },
|
|
83
80
|
};
|
|
84
81
|
|
|
85
|
-
vi.spyOn(
|
|
86
|
-
savedPreference,
|
|
87
|
-
);
|
|
82
|
+
vi.spyOn(userService, 'getPreference').mockResolvedValueOnce(savedPreference);
|
|
88
83
|
|
|
89
84
|
const { result: prefernce } = renderHook(() => result.current.useInitPreference(), {
|
|
90
85
|
wrapper: withSWR,
|
|
@@ -3,6 +3,7 @@ import type { StateCreator } from 'zustand/vanilla';
|
|
|
3
3
|
|
|
4
4
|
import { DEFAULT_PREFERENCE } from '@/const/user';
|
|
5
5
|
import { useClientDataSWR } from '@/libs/swr';
|
|
6
|
+
import { userService } from '@/services/user';
|
|
6
7
|
import type { UserStore } from '@/store/user';
|
|
7
8
|
import { UserGuide, UserPreference } from '@/types/user';
|
|
8
9
|
import { merge } from '@/utils/merge';
|
|
@@ -11,8 +12,8 @@ import { setNamespace } from '@/utils/storeDebug';
|
|
|
11
12
|
const n = setNamespace('preference');
|
|
12
13
|
|
|
13
14
|
export interface PreferenceAction {
|
|
14
|
-
updateGuideState: (guide: Partial<UserGuide>) => void
|
|
15
|
-
updatePreference: (preference: Partial<UserPreference>, action?: any) => void
|
|
15
|
+
updateGuideState: (guide: Partial<UserGuide>) => Promise<void>;
|
|
16
|
+
updatePreference: (preference: Partial<UserPreference>, action?: any) => Promise<void>;
|
|
16
17
|
useInitPreference: () => SWRResponse;
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -22,33 +23,29 @@ export const createPreferenceSlice: StateCreator<
|
|
|
22
23
|
[],
|
|
23
24
|
PreferenceAction
|
|
24
25
|
> = (set, get) => ({
|
|
25
|
-
updateGuideState: (guide) => {
|
|
26
|
+
updateGuideState: async (guide) => {
|
|
26
27
|
const { updatePreference } = get();
|
|
27
28
|
const nextGuide = merge(get().preference.guide, guide);
|
|
28
|
-
updatePreference({ guide: nextGuide });
|
|
29
|
+
await updatePreference({ guide: nextGuide });
|
|
29
30
|
},
|
|
30
|
-
updatePreference: (preference, action) => {
|
|
31
|
+
updatePreference: async (preference, action) => {
|
|
31
32
|
const nextPreference = merge(get().preference, preference);
|
|
32
33
|
|
|
33
34
|
set({ preference: nextPreference }, false, action || n('updatePreference'));
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
await userService.updatePreference(nextPreference);
|
|
36
37
|
},
|
|
37
38
|
|
|
38
39
|
useInitPreference: () =>
|
|
39
|
-
useClientDataSWR<UserPreference>(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
false,
|
|
49
|
-
n('initPreference'),
|
|
50
|
-
);
|
|
51
|
-
},
|
|
40
|
+
useClientDataSWR<UserPreference>('initUserPreference', userService.getPreference, {
|
|
41
|
+
onSuccess: (preference) => {
|
|
42
|
+
const isEmpty = Object.keys(preference).length === 0;
|
|
43
|
+
|
|
44
|
+
set(
|
|
45
|
+
{ isPreferenceInit: true, preference: isEmpty ? DEFAULT_PREFERENCE : preference },
|
|
46
|
+
false,
|
|
47
|
+
n('initPreference'),
|
|
48
|
+
);
|
|
52
49
|
},
|
|
53
|
-
),
|
|
50
|
+
}),
|
|
54
51
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
+
import { UserStore } from '@/store/user';
|
|
3
4
|
import { merge } from '@/utils/merge';
|
|
4
5
|
|
|
5
|
-
import { UserStore, useUserStore } from '../../../store';
|
|
6
6
|
import { UserSettingsState, initialSettingsState } from '../initialState';
|
|
7
7
|
import { modelConfigSelectors } from './modelConfig';
|
|
8
8
|
|
|
@@ -33,6 +33,34 @@ describe('modelConfigSelectors', () => {
|
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
+
describe('isProviderFetchOnClient', () => {
|
|
37
|
+
it('client fetch should disabled on default', () => {
|
|
38
|
+
const s = merge(initialSettingsState, {
|
|
39
|
+
settings: {
|
|
40
|
+
languageModel: {
|
|
41
|
+
azure: {
|
|
42
|
+
endpoint: 'endpoint',
|
|
43
|
+
apiKey: 'apikey',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
} as UserSettingsState) as unknown as UserStore;
|
|
48
|
+
|
|
49
|
+
expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('client fetch should enabled if user set it enabled', () => {
|
|
53
|
+
const s = merge(initialSettingsState, {
|
|
54
|
+
settings: {
|
|
55
|
+
languageModel: {
|
|
56
|
+
azure: { fetchOnClient: true },
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
} as UserSettingsState) as unknown as UserStore;
|
|
60
|
+
expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
36
64
|
describe('getCustomModelCardById', () => {
|
|
37
65
|
it('should return the custom model card with the given id and provider', () => {
|
|
38
66
|
const s = merge(initialSettingsState, {
|
|
@@ -13,7 +13,7 @@ const isProviderFetchOnClient = (provider: GlobalLLMProviderKey | string) => (s:
|
|
|
13
13
|
const config = getProviderConfigById(provider)(s);
|
|
14
14
|
if (typeof config?.fetchOnClient !== 'undefined') return config?.fetchOnClient;
|
|
15
15
|
|
|
16
|
-
return
|
|
16
|
+
return false;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const getCustomModelCard =
|
|
@@ -28,7 +28,7 @@ const Error = memo<ErrorProps>(({ messageId, index }) => {
|
|
|
28
28
|
<Alert
|
|
29
29
|
extra={
|
|
30
30
|
<Highlighter copyButtonSize={'small'} language={'json'}>
|
|
31
|
-
{JSON.stringify(error
|
|
31
|
+
{JSON.stringify(error?.body || error, null, 2)}
|
|
32
32
|
</Highlighter>
|
|
33
33
|
}
|
|
34
34
|
extraDefaultExpand
|
package/src/types/files.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
1
3
|
export interface FilePreview {
|
|
2
4
|
base64Url?: string;
|
|
3
5
|
data?: ArrayBuffer;
|
|
@@ -6,3 +8,34 @@ export interface FilePreview {
|
|
|
6
8
|
saveMode: 'local' | 'url';
|
|
7
9
|
url: string;
|
|
8
10
|
}
|
|
11
|
+
|
|
12
|
+
export const UploadFileSchema = z.object({
|
|
13
|
+
data: z.instanceof(ArrayBuffer).optional(),
|
|
14
|
+
/**
|
|
15
|
+
* file type
|
|
16
|
+
* @example 'image/png'
|
|
17
|
+
*/
|
|
18
|
+
fileType: z.string(),
|
|
19
|
+
metadata: z.any().optional(),
|
|
20
|
+
/**
|
|
21
|
+
* file name
|
|
22
|
+
* @example 'test.png'
|
|
23
|
+
*/
|
|
24
|
+
name: z.string(),
|
|
25
|
+
/**
|
|
26
|
+
* the mode database save the file
|
|
27
|
+
* local mean save the raw file into data
|
|
28
|
+
* url mean upload the file to a cdn and then save the url
|
|
29
|
+
*/
|
|
30
|
+
saveMode: z.enum(['local', 'url']),
|
|
31
|
+
/**
|
|
32
|
+
* file size
|
|
33
|
+
*/
|
|
34
|
+
size: z.number(),
|
|
35
|
+
/**
|
|
36
|
+
* file url if saveMode is url
|
|
37
|
+
*/
|
|
38
|
+
url: z.string().optional(),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export type UploadFileParams = z.infer<typeof UploadFileSchema>;
|
|
File without changes
|