@lobehub/chat 0.56.0 → 0.58.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 +71 -0
- package/package.json +2 -2
- package/src/components/SafeSpacing/index.tsx +27 -0
- package/src/const/fetch.ts +2 -0
- package/src/const/layoutTokens.ts +2 -0
- package/src/features/AgentSetting/AgentPlugin/index.tsx +107 -60
- package/src/features/AvatarWithUpload/index.tsx +4 -3
- package/src/features/MobileTabBar/index.tsx +60 -0
- package/src/features/PluginSettings/PluginSettingRender.tsx +65 -0
- package/src/features/PluginSettings/index.tsx +65 -0
- package/src/features/SideBar/TopActions.tsx +1 -1
- package/src/layout/AppMobileLayout.tsx +76 -0
- package/src/locales/default/common.ts +3 -1
- package/src/locales/default/error.ts +30 -2
- package/src/locales/default/setting.ts +1 -0
- package/src/pages/api/auth.ts +2 -2
- package/src/pages/api/error.ts +3 -3
- package/src/pages/api/openai.ts +3 -3
- package/src/pages/chat/SessionList/Header.tsx +26 -2
- package/src/pages/chat/SessionList/List/Item/index.tsx +2 -2
- package/src/pages/chat/SessionList/index.tsx +10 -1
- package/src/pages/chat/[id]/index.page.tsx +19 -7
- package/src/pages/chat/[id]/mobile.tsx +31 -0
- package/src/pages/chat/[id]/setting/Header.tsx +25 -2
- package/src/pages/chat/[id]/setting/index.page.tsx +33 -16
- package/src/pages/chat/[id]/setting/mobile.tsx +11 -0
- package/src/pages/chat/features/Conversation/ChatList/Error/Plugin/PluginError.tsx +28 -0
- package/src/pages/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx +61 -0
- package/src/pages/chat/features/Conversation/ChatList/Error/index.tsx +42 -0
- package/src/pages/chat/features/Conversation/ChatList/index.tsx +2 -15
- package/src/pages/chat/features/Conversation/index.tsx +5 -5
- package/src/pages/chat/features/Header/Mobile.tsx +47 -0
- package/src/pages/chat/features/Header/PC.tsx +101 -0
- package/src/pages/chat/features/Header/index.tsx +7 -93
- package/src/pages/chat/features/Sidebar/Header.tsx +6 -4
- package/src/pages/chat/features/Sidebar/Mobile.tsx +36 -0
- package/src/pages/chat/features/Sidebar/SystemRole.tsx +2 -2
- package/src/pages/chat/features/Sidebar/index.tsx +33 -15
- package/src/pages/chat/index.page.tsx +14 -8
- package/src/pages/chat/layout.tsx +12 -8
- package/src/pages/chat/mobile.tsx +25 -0
- package/src/pages/settings/index.page.tsx +40 -8
- package/src/pages/settings/layout.tsx +5 -27
- package/src/pages/settings/mobile.tsx +20 -0
- package/src/pages/welcome/Banner/Hero.tsx +3 -5
- package/src/pages/welcome/Banner/index.tsx +5 -5
- package/src/pages/welcome/index.page.tsx +13 -4
- package/src/pages/welcome/mobile.tsx +20 -0
- package/src/pages/welcome/style.ts +2 -2
- package/src/services/plugin.ts +11 -14
- package/src/services/pluginMarket.ts +10 -0
- package/src/store/global/initialState.ts +2 -0
- package/src/store/global/selectors.ts +2 -2
- package/src/store/global/slices/common.ts +7 -0
- package/src/store/global/store.ts +7 -0
- package/src/store/plugin/action.ts +13 -2
- package/src/store/plugin/initialState.ts +3 -0
- package/src/store/plugin/selectors.ts +4 -0
- package/src/store/plugin/store.ts +2 -1
- package/src/store/session/slices/chat/actions/message.ts +11 -2
- package/src/types/fetch.ts +18 -14
- package/src/utils/fetch.ts +24 -18
- package/src/components/HeaderSpacing/index.tsx +0 -9
|
@@ -21,12 +21,10 @@ const Hero = memo<{ width: number }>(({ width }) => {
|
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
23
|
<>
|
|
24
|
-
<LogoThree
|
|
25
|
-
size={size.logo}
|
|
26
|
-
style={{ marginBottom: -size.logo / 40, marginTop: -size.logo / 5 }}
|
|
27
|
-
/>
|
|
24
|
+
<LogoThree size={size.logo} style={{ marginTop: -size.logo / 5 }} />
|
|
28
25
|
<div className={styles.title} style={{ fontSize: size.title }}>
|
|
29
|
-
|
|
26
|
+
<span style={mobile ? { fontSize: '1.2em' } : {}}>LobeChat</span>
|
|
27
|
+
{mobile ? <br /> : ' '}
|
|
30
28
|
{t('slogan.title')}
|
|
31
29
|
</div>
|
|
32
30
|
<div className={styles.desc} style={{ fontSize: size.desc }}>
|
|
@@ -13,7 +13,7 @@ import { useImportConfig } from '@/hooks/useImportConfig';
|
|
|
13
13
|
import { useStyles } from '../style';
|
|
14
14
|
import Hero from './Hero';
|
|
15
15
|
|
|
16
|
-
const Banner = memo(() => {
|
|
16
|
+
const Banner = memo<{ mobile?: boolean }>(() => {
|
|
17
17
|
const { importConfig } = useImportConfig();
|
|
18
18
|
const ref = useRef(null);
|
|
19
19
|
const domSize = useSize(ref);
|
|
@@ -28,12 +28,15 @@ const Banner = memo(() => {
|
|
|
28
28
|
}, []);
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
|
-
<Flexbox height={'80vh'} style={{
|
|
31
|
+
<Flexbox height={'80vh'} style={{ paddingTop: '10vh' }}>
|
|
32
32
|
<GridShowcase>
|
|
33
33
|
<div className={styles.container} ref={ref}>
|
|
34
34
|
<Hero width={width} />
|
|
35
35
|
</div>
|
|
36
36
|
<Flexbox gap={16} horizontal style={{ marginTop: 16 }}>
|
|
37
|
+
<Upload maxCount={1} onChange={handleImport} showUploadList={false}>
|
|
38
|
+
<Button size={'large'}>{t('button.import')}</Button>
|
|
39
|
+
</Upload>
|
|
37
40
|
<Link href={'/chat'}>
|
|
38
41
|
<Button size={'large'} type={'primary'}>
|
|
39
42
|
<Flexbox align={'center'} gap={4} horizontal>
|
|
@@ -42,9 +45,6 @@ const Banner = memo(() => {
|
|
|
42
45
|
</Flexbox>
|
|
43
46
|
</Button>
|
|
44
47
|
</Link>
|
|
45
|
-
<Upload maxCount={1} onChange={handleImport} showUploadList={false}>
|
|
46
|
-
<Button size={'large'}>{t('button.import')}</Button>
|
|
47
|
-
</Upload>
|
|
48
48
|
</Flexbox>
|
|
49
49
|
</GridShowcase>
|
|
50
50
|
{/*TODO:暂时隐藏,待模板完成后再补回*/}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useResponsive } from 'antd-style';
|
|
1
2
|
import Head from 'next/head';
|
|
2
3
|
import { memo } from 'react';
|
|
3
4
|
import { useTranslation } from 'react-i18next';
|
|
@@ -7,8 +8,10 @@ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
|
7
8
|
import Banner from './Banner';
|
|
8
9
|
import Footer from './Footer';
|
|
9
10
|
import Layout from './layout';
|
|
11
|
+
import Mobile from './mobile';
|
|
10
12
|
|
|
11
13
|
const Welcome = memo(() => {
|
|
14
|
+
const { mobile } = useResponsive();
|
|
12
15
|
const { t } = useTranslation('welcome');
|
|
13
16
|
const pageTitle = genSiteHeadTitle(t('header'));
|
|
14
17
|
|
|
@@ -17,10 +20,16 @@ const Welcome = memo(() => {
|
|
|
17
20
|
<Head>
|
|
18
21
|
<title>{pageTitle}</title>
|
|
19
22
|
</Head>
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
{mobile ? (
|
|
24
|
+
<Mobile>
|
|
25
|
+
<Banner />
|
|
26
|
+
</Mobile>
|
|
27
|
+
) : (
|
|
28
|
+
<Layout>
|
|
29
|
+
<Banner />
|
|
30
|
+
<Footer />
|
|
31
|
+
</Layout>
|
|
32
|
+
)}
|
|
24
33
|
</>
|
|
25
34
|
);
|
|
26
35
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Logo, MobileNavBar } from '@lobehub/ui';
|
|
2
|
+
import { useTheme } from 'antd-style';
|
|
3
|
+
import { PropsWithChildren, memo } from 'react';
|
|
4
|
+
|
|
5
|
+
import AppMobileLayout from '../../layout/AppMobileLayout';
|
|
6
|
+
|
|
7
|
+
const WelcomeLayout = memo<PropsWithChildren>(({ children }) => {
|
|
8
|
+
const theme = useTheme();
|
|
9
|
+
return (
|
|
10
|
+
<AppMobileLayout
|
|
11
|
+
navBar={<MobileNavBar center={<Logo type={'text'} />} />}
|
|
12
|
+
showTabBar
|
|
13
|
+
style={{ background: theme.colorBgContainer }}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</AppMobileLayout>
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default WelcomeLayout;
|
|
@@ -41,9 +41,9 @@ export const useStyles = createStyles(({ css, token, stylish, cx }) => {
|
|
|
41
41
|
padding: 16px;
|
|
42
42
|
`,
|
|
43
43
|
title: css`
|
|
44
|
-
margin-bottom: 0.
|
|
44
|
+
margin-bottom: 0.25em;
|
|
45
45
|
font-weight: 800;
|
|
46
|
-
line-height: 1.
|
|
46
|
+
line-height: 1.4;
|
|
47
47
|
text-align: center;
|
|
48
48
|
`,
|
|
49
49
|
view: cx(
|
package/src/services/plugin.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { LOBE_PLUGIN_SETTINGS } from '@/const/fetch';
|
|
4
|
+
import { usePluginStore } from '@/store/plugin';
|
|
5
|
+
import { getMessageError } from '@/utils/fetch';
|
|
6
6
|
|
|
7
7
|
import { URLS } from './url';
|
|
8
8
|
|
|
@@ -12,30 +12,27 @@ interface FetchChatModelOptions {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* 请求插件结果´
|
|
16
16
|
*/
|
|
17
17
|
export const fetchPlugin = async (
|
|
18
18
|
params: PluginRequestPayload,
|
|
19
19
|
options?: FetchChatModelOptions,
|
|
20
20
|
) => {
|
|
21
|
+
const settings = usePluginStore.getState().pluginsSettings?.[params.identifier];
|
|
22
|
+
|
|
21
23
|
const res = await fetch(URLS.plugins, {
|
|
22
24
|
body: JSON.stringify(params),
|
|
23
25
|
headers: {
|
|
24
26
|
'Content-Type': 'application/json',
|
|
25
|
-
[
|
|
27
|
+
[LOBE_PLUGIN_SETTINGS]: JSON.stringify(settings) || '',
|
|
26
28
|
},
|
|
27
29
|
method: 'POST',
|
|
28
30
|
signal: options?.signal,
|
|
29
31
|
});
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw await getMessageError(res);
|
|
35
|
+
}
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
* 请求插件列表
|
|
36
|
-
*/
|
|
37
|
-
export const getPluginList = async () => {
|
|
38
|
-
const res = await fetch(PLUGINS_INDEX_URL);
|
|
39
|
-
|
|
40
|
-
return res.json();
|
|
37
|
+
return await res.text();
|
|
41
38
|
};
|
|
@@ -25,6 +25,7 @@ export interface GlobalState {
|
|
|
25
25
|
export interface GlobalPreference {
|
|
26
26
|
guide?: Guide;
|
|
27
27
|
inputHeight: number;
|
|
28
|
+
mobileShowTopic?: boolean;
|
|
28
29
|
sessionsWidth: number;
|
|
29
30
|
showChatSideBar?: boolean;
|
|
30
31
|
showSessionPanel?: boolean;
|
|
@@ -34,6 +35,7 @@ export const initialState: GlobalState = {
|
|
|
34
35
|
preference: {
|
|
35
36
|
guide: {},
|
|
36
37
|
inputHeight: 200,
|
|
38
|
+
mobileShowTopic: false,
|
|
37
39
|
sessionsWidth: 320,
|
|
38
40
|
showChatSideBar: true,
|
|
39
41
|
showSessionPanel: true,
|
|
@@ -11,10 +11,10 @@ const currentSettings = (s: GlobalStore) => merge({}, DEFAULT_SETTINGS, s.settin
|
|
|
11
11
|
const currentDefaultAgent = (s: GlobalStore) => merge({}, DEFAULT_AGENT, s.settings.defaultAgent);
|
|
12
12
|
|
|
13
13
|
const currentAgentConfig = (s: GlobalStore) =>
|
|
14
|
-
merge({}, DEFAULT_AGENT_CONFIG, s.
|
|
14
|
+
merge({}, DEFAULT_AGENT_CONFIG, currentDefaultAgent(s).config);
|
|
15
15
|
|
|
16
16
|
const currentAgentMeta = (s: GlobalStore) =>
|
|
17
|
-
merge({}, DEFAULT_AGENT_META, s.
|
|
17
|
+
merge({}, DEFAULT_AGENT_META, currentDefaultAgent(s).meta);
|
|
18
18
|
|
|
19
19
|
export const exportSettings = (s: GlobalStore) => {
|
|
20
20
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -19,6 +19,7 @@ export interface CommonAction {
|
|
|
19
19
|
*/
|
|
20
20
|
switchSideBar: (key: SidebarTabKey) => void;
|
|
21
21
|
toggleChatSideBar: (visible?: boolean) => void;
|
|
22
|
+
toggleMobileTopic: (visible?: boolean) => void;
|
|
22
23
|
updateGuideState: (guide: Partial<Guide>) => void;
|
|
23
24
|
updatePreference: (preference: Partial<GlobalPreference>, action?: string) => void;
|
|
24
25
|
}
|
|
@@ -38,6 +39,12 @@ export const createCommonSlice: StateCreator<
|
|
|
38
39
|
|
|
39
40
|
get().updatePreference({ showChatSideBar }, t('toggleAgentPanel', newValue) as string);
|
|
40
41
|
},
|
|
42
|
+
toggleMobileTopic: (newValue) => {
|
|
43
|
+
const mobileShowTopic =
|
|
44
|
+
typeof newValue === 'boolean' ? newValue : !get().preference.mobileShowTopic;
|
|
45
|
+
|
|
46
|
+
get().updatePreference({ mobileShowTopic }, t('toggleMobileTopic', newValue) as string);
|
|
47
|
+
},
|
|
41
48
|
updateGuideState: (guide) => {
|
|
42
49
|
const { updatePreference } = get();
|
|
43
50
|
const nextGuide = merge({}, get().preference.guide, guide);
|
|
@@ -3,6 +3,7 @@ import { shallow } from 'zustand/shallow';
|
|
|
3
3
|
import { createWithEqualityFn } from 'zustand/traditional';
|
|
4
4
|
import { StateCreator } from 'zustand/vanilla';
|
|
5
5
|
|
|
6
|
+
import { DEFAULT_AGENT } from '@/const/settings';
|
|
6
7
|
import { isDev } from '@/utils/env';
|
|
7
8
|
|
|
8
9
|
import { type GlobalState, initialState } from './initialState';
|
|
@@ -25,6 +26,12 @@ const createStore: StateCreator<GlobalStore, [['zustand/devtools', never]]> = (.
|
|
|
25
26
|
type GlobalPersist = Pick<GlobalStore, 'preference' | 'settings'>;
|
|
26
27
|
|
|
27
28
|
const persistOptions: PersistOptions<GlobalStore, GlobalPersist> = {
|
|
29
|
+
merge: (persistedState, currentState) => {
|
|
30
|
+
if (!(persistedState as GlobalPersist).settings.defaultAgent) {
|
|
31
|
+
currentState.settings.defaultAgent = DEFAULT_AGENT;
|
|
32
|
+
}
|
|
33
|
+
return currentState;
|
|
34
|
+
},
|
|
28
35
|
name: 'LOBE_SETTINGS',
|
|
29
36
|
partialize: (s) => ({
|
|
30
37
|
preference: s.preference,
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
} from '@lobehub/chat-plugin-sdk';
|
|
6
6
|
import { message } from 'antd';
|
|
7
7
|
import { produce } from 'immer';
|
|
8
|
-
import { uniq } from 'lodash-es';
|
|
8
|
+
import { merge, uniq } from 'lodash-es';
|
|
9
9
|
import useSWR, { SWRResponse } from 'swr';
|
|
10
10
|
import { StateCreator } from 'zustand/vanilla';
|
|
11
11
|
|
|
12
|
-
import { getPluginList } from '@/services/
|
|
12
|
+
import { getPluginList } from '@/services/pluginMarket';
|
|
13
13
|
import { pluginSelectors } from '@/store/plugin/selectors';
|
|
14
14
|
import { LobeSessions } from '@/types/session';
|
|
15
15
|
import { setNamespace } from '@/utils/storeDebug';
|
|
@@ -27,6 +27,7 @@ export interface PluginAction {
|
|
|
27
27
|
dispatchPluginManifest: (payload: PluginDispatch) => void;
|
|
28
28
|
fetchPluginManifest: (name: string) => Promise<void>;
|
|
29
29
|
updateManifestLoadingState: (key: string, value: boolean | undefined) => void;
|
|
30
|
+
updatePluginSettings: <T>(id: string, settings: Partial<T>) => void;
|
|
30
31
|
useFetchPluginList: () => SWRResponse<LobeChatPluginsMarketIndex>;
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -112,6 +113,16 @@ export const createPluginSlice: StateCreator<
|
|
|
112
113
|
t('updateManifestLoadingState'),
|
|
113
114
|
);
|
|
114
115
|
},
|
|
116
|
+
|
|
117
|
+
updatePluginSettings: (id, settings) => {
|
|
118
|
+
set(
|
|
119
|
+
produce((draft) => {
|
|
120
|
+
draft.pluginsSettings[id] = merge({}, draft.pluginsSettings[id], settings);
|
|
121
|
+
}),
|
|
122
|
+
false,
|
|
123
|
+
t('updatePluginSettings'),
|
|
124
|
+
);
|
|
125
|
+
},
|
|
115
126
|
useFetchPluginList: () =>
|
|
116
127
|
useSWR<LobeChatPluginsMarketIndex>('fetchPluginList', getPluginList, {
|
|
117
128
|
onSuccess: (pluginMarketIndex) => {
|
|
@@ -3,12 +3,14 @@ import { LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk';
|
|
|
3
3
|
import { PluginManifestMap } from '@/types/plugin';
|
|
4
4
|
|
|
5
5
|
export type PluginManifestLoadingState = Record<string, boolean>;
|
|
6
|
+
export type PluginsSettings = Record<string, any>;
|
|
6
7
|
|
|
7
8
|
export interface PluginStoreState {
|
|
8
9
|
manifestPrepared: boolean;
|
|
9
10
|
pluginList: LobeChatPluginMeta[];
|
|
10
11
|
pluginManifestLoading: PluginManifestLoadingState;
|
|
11
12
|
pluginManifestMap: PluginManifestMap;
|
|
13
|
+
pluginsSettings: PluginsSettings;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export const initialState: PluginStoreState = {
|
|
@@ -16,4 +18,5 @@ export const initialState: PluginStoreState = {
|
|
|
16
18
|
pluginList: [],
|
|
17
19
|
pluginManifestLoading: {},
|
|
18
20
|
pluginManifestMap: {},
|
|
21
|
+
pluginsSettings: {},
|
|
19
22
|
};
|
|
@@ -25,7 +25,11 @@ const enabledSchema =
|
|
|
25
25
|
const getPluginMetaById = (id: string) => (s: PluginStoreState) =>
|
|
26
26
|
s.pluginList?.find((p) => p.identifier === id);
|
|
27
27
|
|
|
28
|
+
const getPluginManifestSettingsById = (id: string) => (s: PluginStoreState) =>
|
|
29
|
+
s.pluginManifestMap[id];
|
|
30
|
+
|
|
28
31
|
export const pluginSelectors = {
|
|
29
32
|
enabledSchema,
|
|
33
|
+
getPluginManifestSettingsById,
|
|
30
34
|
getPluginMetaById,
|
|
31
35
|
};
|
|
@@ -19,7 +19,7 @@ const createStore: StateCreator<PluginStore, [['zustand/devtools', never]]> = (.
|
|
|
19
19
|
|
|
20
20
|
// =============== persist 本地缓存中间件配置 ============ //
|
|
21
21
|
|
|
22
|
-
type SessionPersist = Pick<PluginStore, 'pluginList' | 'pluginManifestMap'>;
|
|
22
|
+
type SessionPersist = Pick<PluginStore, 'pluginList' | 'pluginManifestMap' | 'pluginsSettings'>;
|
|
23
23
|
|
|
24
24
|
const storeName = 'LOBE_PLUGIN';
|
|
25
25
|
|
|
@@ -29,6 +29,7 @@ const persistOptions: PersistOptions<PluginStore, SessionPersist> = {
|
|
|
29
29
|
partialize: (s) => ({
|
|
30
30
|
pluginList: s.pluginList,
|
|
31
31
|
pluginManifestMap: s.pluginManifestMap,
|
|
32
|
+
pluginsSettings: s.pluginsSettings,
|
|
32
33
|
}),
|
|
33
34
|
|
|
34
35
|
// 手动控制 Hydration ,避免 ssr 报错
|
|
@@ -346,9 +346,18 @@ export const chatMessage: StateCreator<
|
|
|
346
346
|
dispatchMessage({ id, key: 'name', type: 'updateMessage', value: payload.identifier });
|
|
347
347
|
dispatchMessage({ id, key: 'plugin', type: 'updateMessage', value: payload });
|
|
348
348
|
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
let data: string;
|
|
350
|
+
try {
|
|
351
|
+
const abortController = toggleChatLoading(true, id);
|
|
352
|
+
data = await fetchPlugin(payload, { signal: abortController?.signal });
|
|
353
|
+
} catch (error) {
|
|
354
|
+
dispatchMessage({ id, key: 'error', type: 'updateMessage', value: error });
|
|
355
|
+
|
|
356
|
+
data = '';
|
|
357
|
+
}
|
|
351
358
|
toggleChatLoading(false);
|
|
359
|
+
// 如果报错则结束了
|
|
360
|
+
if (!data) return;
|
|
352
361
|
|
|
353
362
|
dispatchMessage({ id, key: 'content', type: 'updateMessage', value: data });
|
|
354
363
|
|
package/src/types/fetch.ts
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
|
2
|
+
export const ChatErrorType = {
|
|
2
3
|
// ******* 业务错误语义 ******* //
|
|
3
4
|
|
|
4
5
|
// 密码无效
|
|
5
|
-
InvalidAccessCode
|
|
6
|
+
InvalidAccessCode: 'InvalidAccessCode',
|
|
6
7
|
// OpenAI 返回的业务错误
|
|
7
|
-
OpenAIBizError
|
|
8
|
+
OpenAIBizError: 'OpenAIBizError',
|
|
8
9
|
|
|
9
10
|
// ******* 客户端错误 ******* //
|
|
10
|
-
BadRequest
|
|
11
|
-
Unauthorized
|
|
12
|
-
Forbidden
|
|
13
|
-
ContentNotFound
|
|
14
|
-
MethodNotAllowed
|
|
15
|
-
TooManyRequests
|
|
11
|
+
BadRequest: 400,
|
|
12
|
+
Unauthorized: 401,
|
|
13
|
+
Forbidden: 403,
|
|
14
|
+
ContentNotFound: 404, // 没找到接口
|
|
15
|
+
MethodNotAllowed: 405, // 不支持
|
|
16
|
+
TooManyRequests: 429,
|
|
16
17
|
|
|
17
18
|
// ******* 服务端错误 ******* //
|
|
18
|
-
InternalServerError
|
|
19
|
-
BadGateway
|
|
20
|
-
ServiceUnavailable
|
|
21
|
-
GatewayTimeout
|
|
22
|
-
}
|
|
19
|
+
InternalServerError: 500,
|
|
20
|
+
BadGateway: 502,
|
|
21
|
+
ServiceUnavailable: 503,
|
|
22
|
+
GatewayTimeout: 504,
|
|
23
|
+
} as const;
|
|
24
|
+
/* eslint-enable */
|
|
25
|
+
|
|
26
|
+
export type ErrorType = (typeof ChatErrorType)[keyof typeof ChatErrorType];
|
|
23
27
|
|
|
24
28
|
export interface ErrorResponse {
|
|
25
29
|
body: any;
|
package/src/utils/fetch.ts
CHANGED
|
@@ -2,7 +2,29 @@ import { t } from 'i18next';
|
|
|
2
2
|
|
|
3
3
|
import { fetchChatModel } from '@/services/chatModel';
|
|
4
4
|
import { ChatMessageError } from '@/types/chatMessage';
|
|
5
|
-
import { ErrorResponse } from '@/types/fetch';
|
|
5
|
+
import { ErrorResponse, ErrorType } from '@/types/fetch';
|
|
6
|
+
|
|
7
|
+
export const getMessageError = async (response: Response) => {
|
|
8
|
+
let chatMessageError: ChatMessageError;
|
|
9
|
+
|
|
10
|
+
// 尝试取一波业务错误语义
|
|
11
|
+
try {
|
|
12
|
+
const data = (await response.json()) as ErrorResponse;
|
|
13
|
+
chatMessageError = {
|
|
14
|
+
body: data.body,
|
|
15
|
+
message: t(`response.${data.errorType}`),
|
|
16
|
+
type: data.errorType,
|
|
17
|
+
};
|
|
18
|
+
} catch {
|
|
19
|
+
// 如果无法正常返回,说明是常规报错
|
|
20
|
+
chatMessageError = {
|
|
21
|
+
message: t(`response.${response.status}`),
|
|
22
|
+
type: response.status as ErrorType,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return chatMessageError;
|
|
27
|
+
};
|
|
6
28
|
|
|
7
29
|
export interface FetchSSEOptions {
|
|
8
30
|
onErrorHandle?: (error: ChatMessageError) => void;
|
|
@@ -19,23 +41,7 @@ export const fetchSSE = async (fetchFn: () => Promise<Response>, options: FetchS
|
|
|
19
41
|
|
|
20
42
|
// 如果不 ok 说明有请求错误
|
|
21
43
|
if (!response.ok) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// 尝试取一波业务错误语义
|
|
25
|
-
try {
|
|
26
|
-
const data = (await response.json()) as ErrorResponse;
|
|
27
|
-
chatMessageError = {
|
|
28
|
-
body: data.body,
|
|
29
|
-
message: t(`response.${data.errorType}`),
|
|
30
|
-
type: data.errorType,
|
|
31
|
-
};
|
|
32
|
-
} catch {
|
|
33
|
-
// 如果无法正常返回,说明是常规报错
|
|
34
|
-
chatMessageError = {
|
|
35
|
-
message: t(`response.${response.status}`),
|
|
36
|
-
type: response.status,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
44
|
+
const chatMessageError = await getMessageError(response);
|
|
39
45
|
|
|
40
46
|
options.onErrorHandle?.(chatMessageError);
|
|
41
47
|
return;
|