@lobehub/chat 0.141.2 → 0.142.1
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/.env.example +6 -0
- package/CHANGELOG.md +42 -0
- package/Dockerfile +3 -0
- package/README.md +14 -14
- package/README.zh-CN.md +16 -15
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +10 -0
- package/docs/usage/features/multi-ai-providers.zh-CN.mdx +1 -0
- package/docs/usage/providers/ollama/qwen.mdx +47 -0
- package/docs/usage/providers/ollama/qwen.zh-CN.mdx +45 -0
- package/locales/ar/common.json +1 -0
- package/locales/ar/error.json +7 -1
- package/locales/ar/setting.json +8 -0
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/error.json +7 -1
- package/locales/de-DE/setting.json +8 -0
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/error.json +7 -1
- package/locales/en-US/setting.json +8 -0
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/error.json +7 -1
- package/locales/es-ES/setting.json +8 -0
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/error.json +7 -1
- package/locales/fr-FR/setting.json +8 -0
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/error.json +7 -1
- package/locales/it-IT/setting.json +30 -24
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/error.json +7 -1
- package/locales/ja-JP/setting.json +30 -24
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/error.json +7 -1
- package/locales/ko-KR/setting.json +8 -0
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/error.json +7 -1
- package/locales/nl-NL/setting.json +30 -24
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/error.json +7 -1
- package/locales/pl-PL/setting.json +8 -0
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/error.json +7 -1
- package/locales/pt-BR/setting.json +8 -0
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/error.json +7 -1
- package/locales/ru-RU/setting.json +8 -0
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/error.json +7 -1
- package/locales/tr-TR/setting.json +8 -0
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/error.json +7 -1
- package/locales/vi-VN/setting.json +8 -0
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/error.json +7 -1
- package/locales/zh-CN/setting.json +8 -0
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/error.json +7 -1
- package/locales/zh-TW/setting.json +8 -0
- package/package.json +1 -1
- package/src/app/api/chat/[provider]/agentRuntime.ts +15 -2
- package/src/app/api/config/route.ts +2 -0
- package/src/app/api/errorResponse.ts +3 -0
- package/src/app/layout.tsx +13 -25
- package/src/app/settings/common/Theme.tsx +1 -1
- package/src/app/settings/llm/Google/index.tsx +10 -3
- package/src/app/settings/llm/ZeroOne/index.tsx +52 -0
- package/src/app/settings/llm/index.tsx +2 -0
- package/src/components/ModelIcon/index.tsx +2 -0
- package/src/components/ModelProviderIcon/index.tsx +5 -0
- package/src/components/ModelTag/ModelIcon.tsx +2 -0
- package/src/config/modelProviders/index.ts +3 -0
- package/src/config/modelProviders/zeroone.ts +28 -0
- package/src/config/server/provider.ts +10 -2
- package/src/const/settings.ts +4 -0
- package/src/features/Conversation/Error/APIKeyForm/ZeroOne.tsx +60 -0
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +6 -1
- package/src/features/Conversation/Error/index.tsx +1 -0
- package/src/features/DebugUI/index.tsx +2 -0
- package/src/layout/{GlobalLayout → GlobalProvider}/AppTheme.tsx +28 -3
- package/src/layout/{GlobalLayout → GlobalProvider}/Locale.tsx +16 -26
- package/src/layout/{GlobalLayout → GlobalProvider}/StoreHydration.tsx +2 -0
- package/src/layout/GlobalProvider/index.tsx +62 -0
- package/src/libs/agent-runtime/error.ts +4 -1
- package/src/libs/agent-runtime/index.ts +1 -0
- package/src/libs/agent-runtime/types/type.ts +1 -0
- package/src/libs/agent-runtime/zeroone/index.ts +78 -0
- package/src/locales/default/common.ts +1 -0
- package/src/locales/default/error.ts +8 -1
- package/src/locales/default/setting.ts +8 -0
- package/src/services/_auth.ts +5 -1
- package/src/store/global/slices/common/action.test.ts +2 -2
- package/src/store/global/slices/common/action.ts +1 -1
- package/src/store/global/slices/settings/selectors/modelProvider.ts +11 -2
- package/src/types/settings/modelProvider.ts +7 -0
- package/src/utils/locale.ts +16 -0
- package/src/layout/GlobalLayout/index.tsx +0 -75
- /package/src/{app → layout/GlobalProvider}/StyleRegistry.tsx +0 -0
- /package/src/utils/{switchLang.ts → client/switchLang.ts} +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ZeroOne } from '@lobehub/icons';
|
|
2
|
+
import { Input } from 'antd';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
|
|
6
|
+
import { ModelProvider } from '@/libs/agent-runtime';
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
|
+
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
9
|
+
|
|
10
|
+
import { FormAction } from '../style';
|
|
11
|
+
|
|
12
|
+
const ZeroOneForm = memo(() => {
|
|
13
|
+
const { t } = useTranslation('error');
|
|
14
|
+
// const [showProxy, setShow] = useState(false);
|
|
15
|
+
|
|
16
|
+
const [apiKey, setConfig] = useGlobalStore((s) => [
|
|
17
|
+
modelProviderSelectors.zerooneAPIKey(s),
|
|
18
|
+
s.setModelProviderConfig,
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<FormAction
|
|
23
|
+
avatar={<ZeroOne size={56} />}
|
|
24
|
+
description={t('unlock.apikey.ZeroOne.description')}
|
|
25
|
+
title={t('unlock.apikey.ZeroOne.title')}
|
|
26
|
+
>
|
|
27
|
+
<Input.Password
|
|
28
|
+
autoComplete={'new-password'}
|
|
29
|
+
onChange={(e) => {
|
|
30
|
+
setConfig(ModelProvider.ZeroOne, { apiKey: e.target.value });
|
|
31
|
+
}}
|
|
32
|
+
placeholder={'*********************************'}
|
|
33
|
+
type={'block'}
|
|
34
|
+
value={apiKey}
|
|
35
|
+
/>
|
|
36
|
+
{/*{showProxy ? (*/}
|
|
37
|
+
{/* <Input*/}
|
|
38
|
+
{/* onChange={(e) => {*/}
|
|
39
|
+
{/* setConfig({ endpoint: e.target.value });*/}
|
|
40
|
+
{/* }}*/}
|
|
41
|
+
{/* placeholder={'https://api.openai.com/v1'}*/}
|
|
42
|
+
{/* type={'block'}*/}
|
|
43
|
+
{/* value={proxyUrl}*/}
|
|
44
|
+
{/* />*/}
|
|
45
|
+
{/*) : (*/}
|
|
46
|
+
{/* <Button*/}
|
|
47
|
+
{/* icon={<Icon icon={Network} />}*/}
|
|
48
|
+
{/* onClick={() => {*/}
|
|
49
|
+
{/* setShow(true);*/}
|
|
50
|
+
{/* }}*/}
|
|
51
|
+
{/* type={'text'}*/}
|
|
52
|
+
{/* >*/}
|
|
53
|
+
{/* {t('unlock.apikey.addProxyUrl')}*/}
|
|
54
|
+
{/* </Button>*/}
|
|
55
|
+
{/*)}*/}
|
|
56
|
+
</FormAction>
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export default ZeroOneForm;
|
|
@@ -15,6 +15,7 @@ import MoonshotForm from './Moonshot';
|
|
|
15
15
|
import OpenAIForm from './OpenAI';
|
|
16
16
|
import OpenRouterForm from './OpenRouter';
|
|
17
17
|
import PerplexityForm from './Perplexity';
|
|
18
|
+
import ZeroOneForm from './ZeroOne';
|
|
18
19
|
import ZhipuForm from './Zhipu';
|
|
19
20
|
|
|
20
21
|
interface APIKeyFormProps {
|
|
@@ -60,11 +61,15 @@ const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
|
|
|
60
61
|
case ModelProvider.Groq: {
|
|
61
62
|
return <GroqForm />;
|
|
62
63
|
}
|
|
63
|
-
|
|
64
|
+
|
|
64
65
|
case ModelProvider.OpenRouter: {
|
|
65
66
|
return <OpenRouterForm />;
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
case ModelProvider.ZeroOne: {
|
|
70
|
+
return <ZeroOneForm />;
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
default:
|
|
69
74
|
case ModelProvider.OpenAI: {
|
|
70
75
|
return <OpenAIForm />;
|
|
@@ -76,6 +76,7 @@ const ErrorMessageExtra = memo<{ data: ChatMessage }>(({ data }) => {
|
|
|
76
76
|
case AgentRuntimeErrorType.InvalidAnthropicAPIKey:
|
|
77
77
|
case AgentRuntimeErrorType.InvalidGroqAPIKey:
|
|
78
78
|
case AgentRuntimeErrorType.InvalidOpenRouterAPIKey:
|
|
79
|
+
case AgentRuntimeErrorType.InvalidZeroOneAPIKey:
|
|
79
80
|
case AgentRuntimeErrorType.NoOpenAIAPIKey: {
|
|
80
81
|
return <InvalidAPIKey id={data.id} provider={data.error?.body?.provider} />;
|
|
81
82
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
1
3
|
import { ConfigProvider, NeutralColors, PrimaryColors, ThemeProvider } from '@lobehub/ui';
|
|
2
|
-
import {
|
|
4
|
+
import { App } from 'antd';
|
|
5
|
+
import { ThemeAppearance, createStyles } from 'antd-style';
|
|
6
|
+
import 'antd/dist/reset.css';
|
|
3
7
|
import Image from 'next/image';
|
|
4
|
-
import { ReactNode, memo, useEffect } from 'react';
|
|
8
|
+
import { PropsWithChildren, ReactNode, memo, useEffect } from 'react';
|
|
5
9
|
|
|
6
10
|
import {
|
|
7
11
|
LOBE_THEME_APPEARANCE,
|
|
@@ -13,6 +17,25 @@ import { settingsSelectors } from '@/store/global/selectors';
|
|
|
13
17
|
import { GlobalStyle } from '@/styles';
|
|
14
18
|
import { setCookie } from '@/utils/cookie';
|
|
15
19
|
|
|
20
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
21
|
+
bg: css`
|
|
22
|
+
overflow-y: hidden;
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
align-items: center;
|
|
26
|
+
|
|
27
|
+
height: 100%;
|
|
28
|
+
|
|
29
|
+
background: ${token.colorBgLayout};
|
|
30
|
+
`,
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
const Container = memo<PropsWithChildren>(({ children }) => {
|
|
34
|
+
const { styles } = useStyles();
|
|
35
|
+
|
|
36
|
+
return <App className={styles.bg}>{children}</App>;
|
|
37
|
+
});
|
|
38
|
+
|
|
16
39
|
export interface AppThemeProps {
|
|
17
40
|
children?: ReactNode;
|
|
18
41
|
defaultAppearance?: ThemeAppearance;
|
|
@@ -53,7 +76,9 @@ const AppTheme = memo<AppThemeProps>(
|
|
|
53
76
|
themeMode={themeMode}
|
|
54
77
|
>
|
|
55
78
|
<GlobalStyle />
|
|
56
|
-
<ConfigProvider config={{ imgAs: Image } as any}>
|
|
79
|
+
<ConfigProvider config={{ imgAs: Image } as any}>
|
|
80
|
+
<Container>{children}</Container>
|
|
81
|
+
</ConfigProvider>
|
|
57
82
|
</ThemeProvider>
|
|
58
83
|
);
|
|
59
84
|
},
|
|
@@ -1,39 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
1
3
|
import { ConfigProvider } from 'antd';
|
|
2
4
|
import { PropsWithChildren, memo, useEffect, useState } from 'react';
|
|
3
5
|
import { isRtlLang } from 'rtl-detect';
|
|
4
|
-
import useSWR from 'swr';
|
|
5
6
|
|
|
6
7
|
import { createI18nNext } from '@/locales/create';
|
|
7
|
-
import { normalizeLocale } from '@/locales/resources';
|
|
8
8
|
import { isOnServerSide } from '@/utils/env';
|
|
9
|
-
|
|
10
|
-
const getAntdLocale = async (lang?: string) => {
|
|
11
|
-
let normalLang = normalizeLocale(lang);
|
|
12
|
-
|
|
13
|
-
// due to antd only have ar-EG locale, we need to convert ar to ar-EG
|
|
14
|
-
// refs: https://ant.design/docs/react/i18n
|
|
15
|
-
|
|
16
|
-
// And we don't want to handle it in `normalizeLocale` function
|
|
17
|
-
// because of other locale files are all `ar` not `ar-EG`
|
|
18
|
-
if (normalLang === 'ar') normalLang = 'ar-EG';
|
|
19
|
-
|
|
20
|
-
const { default: locale } = await import(`antd/locale/${normalLang.replace('-', '_')}.js`);
|
|
21
|
-
|
|
22
|
-
return locale;
|
|
23
|
-
};
|
|
9
|
+
import { getAntdLocale } from '@/utils/locale';
|
|
24
10
|
|
|
25
11
|
interface LocaleLayoutProps extends PropsWithChildren {
|
|
12
|
+
antdLocale?: any;
|
|
26
13
|
defaultLang?: string;
|
|
27
14
|
}
|
|
28
15
|
|
|
29
|
-
const Locale = memo<LocaleLayoutProps>(({ children, defaultLang }) => {
|
|
16
|
+
const Locale = memo<LocaleLayoutProps>(({ children, defaultLang, antdLocale }) => {
|
|
30
17
|
const [i18n] = useState(createI18nNext(defaultLang));
|
|
31
18
|
const [lang, setLang] = useState(defaultLang);
|
|
32
|
-
|
|
33
|
-
const { data: locale } = useSWR(['antd-locale', lang], ([, key]) => getAntdLocale(key), {
|
|
34
|
-
dedupingInterval: 0,
|
|
35
|
-
revalidateOnFocus: false,
|
|
36
|
-
});
|
|
19
|
+
const [locale, setLocale] = useState(antdLocale);
|
|
37
20
|
|
|
38
21
|
// if run on server side, init i18n instance everytime
|
|
39
22
|
if (isOnServerSide) {
|
|
@@ -49,15 +32,20 @@ const Locale = memo<LocaleLayoutProps>(({ children, defaultLang }) => {
|
|
|
49
32
|
|
|
50
33
|
// handle i18n instance language change
|
|
51
34
|
useEffect(() => {
|
|
52
|
-
const handleLang = (
|
|
53
|
-
setLang(
|
|
35
|
+
const handleLang = async (lng: string) => {
|
|
36
|
+
setLang(lng);
|
|
37
|
+
|
|
38
|
+
if (lang === lng) return;
|
|
39
|
+
|
|
40
|
+
const newLocale = await getAntdLocale(lng);
|
|
41
|
+
setLocale(newLocale);
|
|
54
42
|
};
|
|
55
43
|
|
|
56
44
|
i18n.instance.on('languageChanged', handleLang);
|
|
57
45
|
return () => {
|
|
58
46
|
i18n.instance.off('languageChanged', handleLang);
|
|
59
47
|
};
|
|
60
|
-
}, [i18n]);
|
|
48
|
+
}, [i18n, lang]);
|
|
61
49
|
|
|
62
50
|
// detect document direction
|
|
63
51
|
const documentDir = isRtlLang(lang!) ? 'rtl' : 'ltr';
|
|
@@ -69,4 +57,6 @@ const Locale = memo<LocaleLayoutProps>(({ children, defaultLang }) => {
|
|
|
69
57
|
);
|
|
70
58
|
});
|
|
71
59
|
|
|
60
|
+
Locale.displayName = 'Locale';
|
|
61
|
+
|
|
72
62
|
export default Locale;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import dynamic from 'next/dynamic';
|
|
2
|
+
import { cookies } from 'next/headers';
|
|
3
|
+
import { FC, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
import { getClientConfig } from '@/config/client';
|
|
6
|
+
import { LOBE_LOCALE_COOKIE } from '@/const/locale';
|
|
7
|
+
import {
|
|
8
|
+
LOBE_THEME_APPEARANCE,
|
|
9
|
+
LOBE_THEME_NEUTRAL_COLOR,
|
|
10
|
+
LOBE_THEME_PRIMARY_COLOR,
|
|
11
|
+
} from '@/const/theme';
|
|
12
|
+
import { getAntdLocale } from '@/utils/locale';
|
|
13
|
+
|
|
14
|
+
import AppTheme from './AppTheme';
|
|
15
|
+
import Locale from './Locale';
|
|
16
|
+
import StoreHydration from './StoreHydration';
|
|
17
|
+
import StyleRegistry from './StyleRegistry';
|
|
18
|
+
|
|
19
|
+
let DebugUI: FC = () => null;
|
|
20
|
+
|
|
21
|
+
// we need use Constant Folding to remove code below in production
|
|
22
|
+
// refs: https://webpack.js.org/plugins/internal-plugins/#constplugin
|
|
23
|
+
if (process.env.NODE_ENV === 'development') {
|
|
24
|
+
// eslint-disable-next-line unicorn/no-lonely-if
|
|
25
|
+
if (getClientConfig().DEBUG_MODE) {
|
|
26
|
+
DebugUI = dynamic(() => import('@/features/DebugUI'), { ssr: false }) as FC;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface GlobalLayoutProps {
|
|
31
|
+
children: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const GlobalLayout = async ({ children }: GlobalLayoutProps) => {
|
|
35
|
+
// get default theme config to use with ssr
|
|
36
|
+
const cookieStore = cookies();
|
|
37
|
+
const appearance = cookieStore.get(LOBE_THEME_APPEARANCE);
|
|
38
|
+
const neutralColor = cookieStore.get(LOBE_THEME_NEUTRAL_COLOR);
|
|
39
|
+
const primaryColor = cookieStore.get(LOBE_THEME_PRIMARY_COLOR);
|
|
40
|
+
|
|
41
|
+
// get default locale config to use with ssr
|
|
42
|
+
const defaultLang = cookieStore.get(LOBE_LOCALE_COOKIE);
|
|
43
|
+
const antdLocale = await getAntdLocale(defaultLang?.value);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<StyleRegistry>
|
|
47
|
+
<AppTheme
|
|
48
|
+
defaultAppearance={appearance?.value}
|
|
49
|
+
defaultNeutralColor={neutralColor?.value as any}
|
|
50
|
+
defaultPrimaryColor={primaryColor?.value as any}
|
|
51
|
+
>
|
|
52
|
+
<Locale antdLocale={antdLocale} defaultLang={defaultLang?.value}>
|
|
53
|
+
<StoreHydration />
|
|
54
|
+
{children}
|
|
55
|
+
<DebugUI />
|
|
56
|
+
</Locale>
|
|
57
|
+
</AppTheme>
|
|
58
|
+
</StyleRegistry>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default GlobalLayout;
|
|
@@ -37,7 +37,10 @@ export const AgentRuntimeErrorType = {
|
|
|
37
37
|
|
|
38
38
|
InvalidGroqAPIKey: 'InvalidGroqAPIKey',
|
|
39
39
|
GroqBizError: 'GroqBizError',
|
|
40
|
-
|
|
40
|
+
|
|
41
|
+
InvalidZeroOneAPIKey: 'InvalidZeroOneAPIKey',
|
|
42
|
+
ZeroOneBizError: 'ZeroOneBizError',
|
|
43
|
+
|
|
41
44
|
InvalidOpenRouterAPIKey: 'InvalidOpenRouterAPIKey',
|
|
42
45
|
OpenRouterBizError: 'OpenRouterBizError',
|
|
43
46
|
} as const;
|
|
@@ -13,4 +13,5 @@ export { LobeOpenRouterAI } from './openrouter';
|
|
|
13
13
|
export { LobePerplexityAI } from './perplexity';
|
|
14
14
|
export * from './types';
|
|
15
15
|
export { AgentRuntimeError } from './utils/createError';
|
|
16
|
+
export { LobeZeroOneAI } from './zeroone';
|
|
16
17
|
export { LobeZhipuAI } from './zhipu';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { OpenAIStream, StreamingTextResponse } from 'ai';
|
|
2
|
+
import OpenAI, { ClientOptions } from 'openai';
|
|
3
|
+
|
|
4
|
+
import { LobeRuntimeAI } from '../BaseAI';
|
|
5
|
+
import { AgentRuntimeErrorType } from '../error';
|
|
6
|
+
import { ChatCompetitionOptions, ChatStreamPayload, ModelProvider } from '../types';
|
|
7
|
+
import { AgentRuntimeError } from '../utils/createError';
|
|
8
|
+
import { debugStream } from '../utils/debugStream';
|
|
9
|
+
import { desensitizeUrl } from '../utils/desensitizeUrl';
|
|
10
|
+
import { handleOpenAIError } from '../utils/handleOpenAIError';
|
|
11
|
+
|
|
12
|
+
const DEFAULT_BASE_URL = 'https://api.lingyiwanwu.com/v1';
|
|
13
|
+
|
|
14
|
+
export class LobeZeroOneAI implements LobeRuntimeAI {
|
|
15
|
+
private client: OpenAI;
|
|
16
|
+
|
|
17
|
+
baseURL: string;
|
|
18
|
+
|
|
19
|
+
constructor({ apiKey, baseURL = DEFAULT_BASE_URL, ...res }: ClientOptions) {
|
|
20
|
+
if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidZeroOneAPIKey);
|
|
21
|
+
|
|
22
|
+
this.client = new OpenAI({ apiKey, baseURL, ...res });
|
|
23
|
+
this.baseURL = this.client.baseURL;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) {
|
|
27
|
+
try {
|
|
28
|
+
const response = await this.client.chat.completions.create(
|
|
29
|
+
payload as unknown as OpenAI.ChatCompletionCreateParamsStreaming
|
|
30
|
+
);
|
|
31
|
+
const [prod, debug] = response.tee();
|
|
32
|
+
|
|
33
|
+
if (process.env.DEBUG_ZEROONE_CHAT_COMPLETION === '1') {
|
|
34
|
+
debugStream(debug.toReadableStream()).catch(console.error);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return new StreamingTextResponse(OpenAIStream(prod, options?.callback), {
|
|
38
|
+
headers: options?.headers,
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
let desensitizedEndpoint = this.baseURL;
|
|
42
|
+
|
|
43
|
+
if (this.baseURL !== DEFAULT_BASE_URL) {
|
|
44
|
+
desensitizedEndpoint = desensitizeUrl(this.baseURL);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if ('status' in (error as any)) {
|
|
48
|
+
switch ((error as Response).status) {
|
|
49
|
+
case 401: {
|
|
50
|
+
throw AgentRuntimeError.chat({
|
|
51
|
+
endpoint: desensitizedEndpoint,
|
|
52
|
+
error: error as any,
|
|
53
|
+
errorType: AgentRuntimeErrorType.InvalidZeroOneAPIKey,
|
|
54
|
+
provider: ModelProvider.ZeroOne,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
default: {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { errorResult, RuntimeError } = handleOpenAIError(error);
|
|
65
|
+
|
|
66
|
+
const errorType = RuntimeError || AgentRuntimeErrorType.ZeroOneBizError;
|
|
67
|
+
|
|
68
|
+
throw AgentRuntimeError.chat({
|
|
69
|
+
endpoint: desensitizedEndpoint,
|
|
70
|
+
error: errorResult,
|
|
71
|
+
errorType,
|
|
72
|
+
provider: ModelProvider.ZeroOne,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default LobeZeroOneAI;
|
|
@@ -84,10 +84,13 @@ export default {
|
|
|
84
84
|
|
|
85
85
|
InvalidGroqAPIKey: 'Groq API Key 不正确或为空,请检查 Groq API Key 后重试',
|
|
86
86
|
GroqBizError: '请求 Groq 服务出错,请根据以下信息排查或重试',
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
InvalidOpenRouterAPIKey: 'OpenRouter API Key 不正确或为空,请检查 OpenRouter API Key 后重试',
|
|
89
89
|
OpenRouterBizError: '请求 OpenRouter AI 服务出错,请根据以下信息排查或重试',
|
|
90
90
|
|
|
91
|
+
ZeroOneBizError: '请求零一万物服务出错,请根据以下信息排查或重试',
|
|
92
|
+
InvalidZeroOneAPIKey: '零一万物 API Key 不正确或为空,请检查零一万物 API Key 后重试',
|
|
93
|
+
|
|
91
94
|
InvalidOllamaArgs: 'Ollama 配置不正确,请检查 Ollama 配置后重试',
|
|
92
95
|
OllamaBizError: '请求 Ollama 服务出错,请根据以下信息排查或重试',
|
|
93
96
|
OllamaServiceUnavailable: '未检测到 Ollama 服务,请检查是否正常启动',
|
|
@@ -142,6 +145,10 @@ export default {
|
|
|
142
145
|
description: '输入你的 Perplexity API Key 即可开始会话。应用不会记录你的 API Key',
|
|
143
146
|
title: '使用自定义 Perplexity API Key',
|
|
144
147
|
},
|
|
148
|
+
ZeroOne: {
|
|
149
|
+
description: '输入你的零一万物 API Key 即可开始会话。应用不会记录你的 API Key',
|
|
150
|
+
title: '使用自定义零一万物 API Key',
|
|
151
|
+
},
|
|
145
152
|
Zhipu: {
|
|
146
153
|
description: '输入你的 Zhipu API Key 即可开始会话。应用不会记录你的 API Key',
|
|
147
154
|
title: '使用自定义 Zhipu API Key',
|
|
@@ -202,6 +202,14 @@ export default {
|
|
|
202
202
|
title: 'API Key',
|
|
203
203
|
},
|
|
204
204
|
},
|
|
205
|
+
ZeroOne: {
|
|
206
|
+
title: '01.AI 零一万物',
|
|
207
|
+
token: {
|
|
208
|
+
desc: '填入来自 01.AI 零一万物的 API Key',
|
|
209
|
+
placeholder: '01.AI 零一万物 API Key',
|
|
210
|
+
title: 'API Key',
|
|
211
|
+
}
|
|
212
|
+
},
|
|
205
213
|
Zhipu: {
|
|
206
214
|
title: '智谱',
|
|
207
215
|
token: {
|
package/src/services/_auth.ts
CHANGED
|
@@ -65,11 +65,15 @@ export const getProviderAuthPayload = (provider: string) => {
|
|
|
65
65
|
case ModelProvider.Groq: {
|
|
66
66
|
return { apiKey: modelProviderSelectors.groqAPIKey(useGlobalStore.getState()) };
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
case ModelProvider.OpenRouter: {
|
|
70
70
|
return { apiKey: modelProviderSelectors.openrouterAPIKey(useGlobalStore.getState()) };
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
case ModelProvider.ZeroOne: {
|
|
74
|
+
return { apiKey: modelProviderSelectors.zerooneAPIKey(useGlobalStore.getState()) };
|
|
75
|
+
}
|
|
76
|
+
|
|
73
77
|
default:
|
|
74
78
|
case ModelProvider.OpenAI: {
|
|
75
79
|
const openai = modelProviderSelectors.openAIConfig(useGlobalStore.getState());
|
|
@@ -7,11 +7,11 @@ import { globalService } from '@/services/global';
|
|
|
7
7
|
import { userService } from '@/services/user';
|
|
8
8
|
import { useGlobalStore } from '@/store/global';
|
|
9
9
|
import { GlobalServerConfig } from '@/types/settings';
|
|
10
|
-
import { switchLang } from '@/utils/switchLang';
|
|
10
|
+
import { switchLang } from '@/utils/client/switchLang';
|
|
11
11
|
|
|
12
12
|
vi.mock('zustand/traditional');
|
|
13
13
|
|
|
14
|
-
vi.mock('@/utils/switchLang', () => ({
|
|
14
|
+
vi.mock('@/utils/client/switchLang', () => ({
|
|
15
15
|
switchLang: vi.fn(),
|
|
16
16
|
}));
|
|
17
17
|
|
|
@@ -12,10 +12,10 @@ import { UserConfig, userService } from '@/services/user';
|
|
|
12
12
|
import type { GlobalStore } from '@/store/global';
|
|
13
13
|
import type { GlobalServerConfig, GlobalSettings } from '@/types/settings';
|
|
14
14
|
import { OnSyncEvent, PeerSyncStatus } from '@/types/sync';
|
|
15
|
+
import { switchLang } from '@/utils/client/switchLang';
|
|
15
16
|
import { merge } from '@/utils/merge';
|
|
16
17
|
import { browserInfo } from '@/utils/platform';
|
|
17
18
|
import { setNamespace } from '@/utils/storeDebug';
|
|
18
|
-
import { switchLang } from '@/utils/switchLang';
|
|
19
19
|
|
|
20
20
|
import { preferenceSelectors } from '../preference/selectors';
|
|
21
21
|
import { settingsSelectors, syncSettingsSelectors } from '../settings/selectors';
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
OpenAIProvider,
|
|
13
13
|
OpenRouterProvider,
|
|
14
14
|
PerplexityProvider,
|
|
15
|
+
ZeroOneProvider,
|
|
15
16
|
ZhiPuProvider,
|
|
16
17
|
} from '@/config/modelProviders';
|
|
17
18
|
import { ChatModelCard, ModelProviderCard } from '@/types/llm';
|
|
@@ -66,6 +67,9 @@ const groqAPIKey = (s: GlobalStore) => modelProvider(s).groq.apiKey;
|
|
|
66
67
|
const enableOpenrouter = (s: GlobalStore) => modelProvider(s).openrouter.enabled;
|
|
67
68
|
const openrouterAPIKey = (s: GlobalStore) => modelProvider(s).openrouter.apiKey;
|
|
68
69
|
|
|
70
|
+
const enableZeroone = (s: GlobalStore) => modelProvider(s).zeroone.enabled;
|
|
71
|
+
const zerooneAPIKey = (s: GlobalStore) => modelProvider(s).zeroone.apiKey;
|
|
72
|
+
|
|
69
73
|
// const azureModelList = (s: GlobalStore): ModelProviderCard => {
|
|
70
74
|
// const azure = azureConfig(s);
|
|
71
75
|
// return {
|
|
@@ -165,7 +169,8 @@ const modelSelectList = (s: GlobalStore): ModelProviderCard[] => {
|
|
|
165
169
|
{ ...GroqProvider, enabled: enableGroq(s) },
|
|
166
170
|
{ ...ZhiPuProvider, enabled: enableZhipu(s) },
|
|
167
171
|
{ ...MoonshotProvider, enabled: enableMoonshot(s) },
|
|
168
|
-
{ ...OpenRouterProvider, chatModels: openrouterChatModels, enabled: enableOpenrouter(s)}
|
|
172
|
+
{ ...OpenRouterProvider, chatModels: openrouterChatModels, enabled: enableOpenrouter(s)},
|
|
173
|
+
{ ...ZeroOneProvider, enabled: enableZeroone(s) }
|
|
169
174
|
];
|
|
170
175
|
};
|
|
171
176
|
|
|
@@ -252,8 +257,12 @@ export const modelProviderSelectors = {
|
|
|
252
257
|
// Groq
|
|
253
258
|
enableGroq,
|
|
254
259
|
groqAPIKey,
|
|
255
|
-
|
|
260
|
+
|
|
256
261
|
// OpenRouter
|
|
257
262
|
enableOpenrouter,
|
|
258
263
|
openrouterAPIKey,
|
|
264
|
+
|
|
265
|
+
// ZeroOne 零一万物
|
|
266
|
+
enableZeroone,
|
|
267
|
+
zerooneAPIKey,
|
|
259
268
|
};
|
|
@@ -82,6 +82,12 @@ export interface OpenRouterConfig {
|
|
|
82
82
|
enabled?: boolean;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
export interface ZeroOneConfig {
|
|
86
|
+
apiKey?: string;
|
|
87
|
+
customModelName?: string;
|
|
88
|
+
enabled?: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
export interface GlobalLLMConfig {
|
|
86
92
|
anthropic: AnthropicConfig;
|
|
87
93
|
azure: AzureOpenAIConfig;
|
|
@@ -94,6 +100,7 @@ export interface GlobalLLMConfig {
|
|
|
94
100
|
openAI: OpenAIConfig;
|
|
95
101
|
openrouter: OpenRouterConfig;
|
|
96
102
|
perplexity: PerplexityConfig;
|
|
103
|
+
zeroone: ZeroOneConfig;
|
|
97
104
|
zhipu: ZhiPuConfig;
|
|
98
105
|
}
|
|
99
106
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { normalizeLocale } from '@/locales/resources';
|
|
2
|
+
|
|
3
|
+
export const getAntdLocale = async (lang?: string) => {
|
|
4
|
+
let normalLang = normalizeLocale(lang);
|
|
5
|
+
|
|
6
|
+
// due to antd only have ar-EG locale, we need to convert ar to ar-EG
|
|
7
|
+
// refs: https://ant.design/docs/react/i18n
|
|
8
|
+
|
|
9
|
+
// And we don't want to handle it in `normalizeLocale` function
|
|
10
|
+
// because of other locale files are all `ar` not `ar-EG`
|
|
11
|
+
if (normalLang === 'ar') normalLang = 'ar-EG';
|
|
12
|
+
|
|
13
|
+
const { default: locale } = await import(`antd/locale/${normalLang.replace('-', '_')}.js`);
|
|
14
|
+
|
|
15
|
+
return locale;
|
|
16
|
+
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { App } from 'antd';
|
|
4
|
-
import { createStyles } from 'antd-style';
|
|
5
|
-
import 'antd/dist/reset.css';
|
|
6
|
-
import { SessionProvider } from 'next-auth/react';
|
|
7
|
-
import dynamic from 'next/dynamic';
|
|
8
|
-
import { FC, PropsWithChildren, memo } from 'react';
|
|
9
|
-
|
|
10
|
-
import { getClientConfig } from '@/config/client';
|
|
11
|
-
import { API_ENDPOINTS } from '@/services/_url';
|
|
12
|
-
|
|
13
|
-
import AppTheme, { AppThemeProps } from './AppTheme';
|
|
14
|
-
import Locale from './Locale';
|
|
15
|
-
import StoreHydration from './StoreHydration';
|
|
16
|
-
|
|
17
|
-
let DebugUI: FC = () => null;
|
|
18
|
-
|
|
19
|
-
// we need use Constant Folding to remove code below in production
|
|
20
|
-
// refs: https://webpack.js.org/plugins/internal-plugins/#constplugin
|
|
21
|
-
if (process.env.NODE_ENV === 'development') {
|
|
22
|
-
// eslint-disable-next-line unicorn/no-lonely-if
|
|
23
|
-
if (getClientConfig().DEBUG_MODE) {
|
|
24
|
-
DebugUI = dynamic(() => import('@/features/DebugUI'), { ssr: false }) as FC;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const useStyles = createStyles(({ css, token }) => ({
|
|
29
|
-
bg: css`
|
|
30
|
-
overflow-y: hidden;
|
|
31
|
-
display: flex;
|
|
32
|
-
flex-direction: column;
|
|
33
|
-
align-items: center;
|
|
34
|
-
|
|
35
|
-
height: 100%;
|
|
36
|
-
|
|
37
|
-
background: ${token.colorBgLayout};
|
|
38
|
-
`,
|
|
39
|
-
}));
|
|
40
|
-
|
|
41
|
-
const Container = memo<PropsWithChildren>(({ children }) => {
|
|
42
|
-
const { styles } = useStyles();
|
|
43
|
-
|
|
44
|
-
return <App className={styles.bg}>{children}</App>;
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
interface GlobalLayoutProps extends AppThemeProps {
|
|
48
|
-
defaultLang?: string;
|
|
49
|
-
enableOAuthSSO?: boolean;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const GlobalLayout = ({
|
|
53
|
-
children,
|
|
54
|
-
defaultLang,
|
|
55
|
-
enableOAuthSSO = false,
|
|
56
|
-
...theme
|
|
57
|
-
}: GlobalLayoutProps) => {
|
|
58
|
-
const content = (
|
|
59
|
-
<AppTheme {...theme}>
|
|
60
|
-
<Locale defaultLang={defaultLang}>
|
|
61
|
-
<StoreHydration />
|
|
62
|
-
<Container>{children}</Container>
|
|
63
|
-
<DebugUI />
|
|
64
|
-
</Locale>
|
|
65
|
-
</AppTheme>
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
return enableOAuthSSO ? (
|
|
69
|
-
<SessionProvider basePath={API_ENDPOINTS.oauth}>{content}</SessionProvider>
|
|
70
|
-
) : (
|
|
71
|
-
content
|
|
72
|
-
);
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export default GlobalLayout;
|
|
File without changes
|
|
File without changes
|