@lobehub/chat 0.126.5 → 0.127.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.
Files changed (118) hide show
  1. package/.env.example +8 -0
  2. package/CHANGELOG.md +50 -0
  3. package/Dockerfile +3 -0
  4. package/docs/Deployment/Environment-Variable.md +10 -0
  5. package/docs/Deployment/Environment-Variable.zh-CN.md +10 -0
  6. package/locales/ar/common.json +1 -0
  7. package/locales/ar/error.json +2 -0
  8. package/locales/ar/setting.json +16 -0
  9. package/locales/de-DE/common.json +1 -0
  10. package/locales/de-DE/error.json +2 -0
  11. package/locales/de-DE/setting.json +16 -0
  12. package/locales/en-US/common.json +1 -0
  13. package/locales/en-US/error.json +2 -0
  14. package/locales/en-US/setting.json +16 -0
  15. package/locales/es-ES/common.json +1 -0
  16. package/locales/es-ES/error.json +2 -0
  17. package/locales/es-ES/setting.json +16 -0
  18. package/locales/fr-FR/common.json +1 -0
  19. package/locales/fr-FR/error.json +2 -0
  20. package/locales/fr-FR/setting.json +16 -0
  21. package/locales/it-IT/common.json +1 -0
  22. package/locales/it-IT/error.json +2 -0
  23. package/locales/it-IT/setting.json +16 -0
  24. package/locales/ja-JP/common.json +1 -0
  25. package/locales/ja-JP/error.json +2 -0
  26. package/locales/ja-JP/setting.json +16 -0
  27. package/locales/ko-KR/common.json +1 -0
  28. package/locales/ko-KR/error.json +2 -0
  29. package/locales/ko-KR/setting.json +16 -0
  30. package/locales/nl-NL/common.json +1 -0
  31. package/locales/nl-NL/error.json +2 -0
  32. package/locales/nl-NL/setting.json +16 -0
  33. package/locales/pl-PL/common.json +1 -0
  34. package/locales/pl-PL/error.json +2 -0
  35. package/locales/pl-PL/setting.json +16 -0
  36. package/locales/pt-BR/common.json +1 -0
  37. package/locales/pt-BR/error.json +2 -0
  38. package/locales/pt-BR/setting.json +16 -0
  39. package/locales/ru-RU/common.json +1 -0
  40. package/locales/ru-RU/error.json +2 -0
  41. package/locales/ru-RU/setting.json +16 -0
  42. package/locales/tr-TR/common.json +1 -0
  43. package/locales/tr-TR/error.json +2 -0
  44. package/locales/tr-TR/setting.json +16 -0
  45. package/locales/vi-VN/common.json +1 -0
  46. package/locales/vi-VN/error.json +2 -0
  47. package/locales/vi-VN/setting.json +16 -0
  48. package/locales/zh-CN/common.json +1 -0
  49. package/locales/zh-CN/error.json +2 -0
  50. package/locales/zh-CN/setting.json +16 -0
  51. package/locales/zh-TW/common.json +1 -0
  52. package/locales/zh-TW/error.json +2 -0
  53. package/locales/zh-TW/setting.json +16 -0
  54. package/package.json +1 -1
  55. package/src/app/api/chat/[provider]/agentRuntime.ts +14 -0
  56. package/src/app/api/config/route.ts +2 -0
  57. package/src/app/api/errorResponse.ts +3 -0
  58. package/src/app/chat/features/ChatHeader/SettingButton.tsx +1 -2
  59. package/src/app/settings/(desktop)/features/Header.tsx +3 -4
  60. package/src/app/settings/(desktop)/features/SideBar.tsx +42 -0
  61. package/src/app/settings/(desktop)/index.tsx +4 -3
  62. package/src/app/settings/(desktop)/layout.desktop.tsx +14 -6
  63. package/src/app/settings/(desktop)/layout.responsive.tsx +4 -4
  64. package/src/app/settings/(mobile)/features/ExtraList.tsx +7 -5
  65. package/src/app/settings/(mobile)/features/Header/index.tsx +8 -5
  66. package/src/app/settings/(mobile)/index.tsx +1 -3
  67. package/src/app/settings/(mobile)/layout.mobile.tsx +8 -4
  68. package/src/app/settings/(mobile)/mobile/index.tsx +3 -5
  69. package/src/app/settings/agent/Agent.tsx +0 -4
  70. package/src/app/settings/agent/layout.tsx +9 -1
  71. package/src/app/settings/agent/page.tsx +17 -2
  72. package/src/app/settings/common/index.tsx +0 -3
  73. package/src/app/settings/common/layout.tsx +9 -1
  74. package/src/app/settings/features/SettingList/Item.tsx +50 -0
  75. package/src/app/settings/features/{SideBar/List.tsx → SettingList/index.tsx} +14 -15
  76. package/src/app/settings/layout.server.tsx +10 -3
  77. package/src/app/settings/llm/Azure/index.tsx +78 -106
  78. package/src/app/settings/llm/Bedrock/index.tsx +60 -89
  79. package/src/app/settings/llm/Google/index.tsx +26 -55
  80. package/src/app/settings/llm/Moonshot/index.tsx +29 -54
  81. package/src/app/settings/llm/Ollama/index.tsx +55 -0
  82. package/src/app/settings/llm/OpenAI/index.tsx +91 -107
  83. package/src/app/settings/llm/Zhipu/index.tsx +29 -54
  84. package/src/app/settings/llm/components/ProviderConfig/index.tsx +58 -0
  85. package/src/app/settings/llm/index.tsx +42 -0
  86. package/src/app/settings/llm/layout.tsx +9 -1
  87. package/src/app/settings/llm/page.tsx +6 -39
  88. package/src/app/settings/tts/layout.tsx +9 -1
  89. package/src/app/settings/tts/page.tsx +17 -2
  90. package/src/components/ModelProviderIcon/index.tsx +5 -1
  91. package/src/config/modelProviders/index.ts +3 -0
  92. package/src/config/modelProviders/ollama.ts +117 -0
  93. package/src/config/server/provider.ts +6 -0
  94. package/src/const/settings.ts +5 -0
  95. package/src/features/SideBar/BottomActions.tsx +1 -2
  96. package/src/layout/ResponsiveLayout.client.tsx +7 -7
  97. package/src/layout/ResponsiveLayout.server.tsx +6 -6
  98. package/src/libs/agent-runtime/error.ts +3 -0
  99. package/src/libs/agent-runtime/index.ts +1 -0
  100. package/src/libs/agent-runtime/ollama/index.ts +80 -0
  101. package/src/libs/agent-runtime/types/type.ts +1 -0
  102. package/src/locales/default/common.ts +1 -0
  103. package/src/locales/default/error.ts +3 -0
  104. package/src/locales/default/setting.ts +16 -0
  105. package/src/services/_auth.test.ts +132 -0
  106. package/src/services/_auth.ts +9 -1
  107. package/src/store/global/slices/common/initialState.ts +0 -2
  108. package/src/store/global/slices/settings/action.test.ts +0 -13
  109. package/src/store/global/slices/settings/action.ts +0 -5
  110. package/src/store/global/slices/settings/selectors/modelProvider.ts +31 -2
  111. package/src/types/settings/modelProvider.ts +8 -0
  112. package/src/app/settings/agent/index.tsx +0 -21
  113. package/src/app/settings/features/SideBar/Item.tsx +0 -44
  114. package/src/app/settings/features/SideBar/index.tsx +0 -42
  115. package/src/app/settings/tts/index.tsx +0 -21
  116. package/src/store/global/hooks/useSwitchSettingsOnInit.ts +0 -12
  117. /package/src/app/settings/llm/{Checker.tsx → components/Checker.tsx} +0 -0
  118. /package/src/app/settings/llm/{useSyncSettings.ts → components/ProviderConfig/useSyncSettings.ts} +0 -0
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+ import { memo } from 'react';
5
+ import { Trans, useTranslation } from 'react-i18next';
6
+
7
+ import PageTitle from '@/components/PageTitle';
8
+ import { MORE_MODEL_PROVIDER_REQUEST_URL } from '@/const/url';
9
+
10
+ import Footer from '../features/Footer';
11
+ import Bedrock from './Bedrock';
12
+ import Google from './Google';
13
+ import Moonshot from './Moonshot';
14
+ import Ollama from './Ollama';
15
+ import OpenAI from './OpenAI';
16
+ import Zhipu from './Zhipu';
17
+
18
+ export default memo<{ showOllama: boolean }>(({ showOllama }) => {
19
+ const { t } = useTranslation('setting');
20
+
21
+ return (
22
+ <>
23
+ <PageTitle title={t('tab.llm')} />
24
+ <OpenAI />
25
+ {/*<AzureOpenAI />*/}
26
+ <Zhipu />
27
+ <Moonshot />
28
+ <Google />
29
+ <Bedrock />
30
+ {showOllama && <Ollama />}
31
+ <Footer>
32
+ <Trans i18nKey="llm.waitingForMore" ns={'setting'}>
33
+ 更多模型正在
34
+ <Link aria-label={'todo'} href={MORE_MODEL_PROVIDER_REQUEST_URL} target="_blank">
35
+ 计划接入
36
+ </Link>
37
+ 中 ,敬请期待 ✨
38
+ </Trans>
39
+ </Footer>
40
+ </>
41
+ );
42
+ });
@@ -1 +1,9 @@
1
- export { default } from '../layout.server';
1
+ import { PropsWithChildren } from 'react';
2
+
3
+ import { SettingsTabs } from '@/store/global/initialState';
4
+
5
+ import SettingLayout from '../layout.server';
6
+
7
+ export default ({ children }: PropsWithChildren) => {
8
+ return <SettingLayout activeTab={SettingsTabs.LLM}>{children}</SettingLayout>;
9
+ };
@@ -1,42 +1,9 @@
1
- 'use client';
1
+ import { getServerConfig } from '@/config/server';
2
2
 
3
- import Link from 'next/link';
4
- import { memo } from 'react';
5
- import { Trans, useTranslation } from 'react-i18next';
3
+ import Page from './index';
6
4
 
7
- import Footer from '@/app/settings/features/Footer';
8
- import PageTitle from '@/components/PageTitle';
9
- import { MORE_MODEL_PROVIDER_REQUEST_URL } from '@/const/url';
10
- import { useSwitchSideBarOnInit } from '@/store/global/hooks/useSwitchSettingsOnInit';
11
- import { SettingsTabs } from '@/store/global/initialState';
5
+ export default () => {
6
+ const { ENABLE_OLLAMA } = getServerConfig();
12
7
 
13
- import Bedrock from './Bedrock';
14
- import Google from './Google';
15
- import Moonshot from './Moonshot';
16
- import OpenAI from './OpenAI';
17
- import Zhipu from './Zhipu';
18
-
19
- export default memo(() => {
20
- useSwitchSideBarOnInit(SettingsTabs.LLM);
21
- const { t } = useTranslation('setting');
22
- return (
23
- <>
24
- <PageTitle title={t('tab.llm')} />
25
- <OpenAI />
26
- {/*<AzureOpenAI />*/}
27
- <Zhipu />
28
- <Moonshot />
29
- <Google />
30
- <Bedrock />
31
- <Footer>
32
- <Trans i18nKey="llm.waitingForMore" ns={'setting'}>
33
- 更多模型正在
34
- <Link aria-label={'todo'} href={MORE_MODEL_PROVIDER_REQUEST_URL} target="_blank">
35
- 计划接入
36
- </Link>
37
- 中 ,敬请期待 ✨
38
- </Trans>
39
- </Footer>
40
- </>
41
- );
42
- });
8
+ return <Page showOllama={ENABLE_OLLAMA} />;
9
+ };
@@ -1 +1,9 @@
1
- export { default } from '../layout.server';
1
+ import { PropsWithChildren } from 'react';
2
+
3
+ import { SettingsTabs } from '@/store/global/initialState';
4
+
5
+ import SettingLayout from '../layout.server';
6
+
7
+ export default ({ children }: PropsWithChildren) => {
8
+ return <SettingLayout activeTab={SettingsTabs.TTS}>{children}</SettingLayout>;
9
+ };
@@ -1,3 +1,18 @@
1
- import Index from './index';
1
+ 'use client';
2
2
 
3
- export default () => <Index />;
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import PageTitle from '@/components/PageTitle';
7
+
8
+ import TTS from './TTS';
9
+
10
+ export default memo(() => {
11
+ const { t } = useTranslation('setting');
12
+ return (
13
+ <>
14
+ <PageTitle title={t('tab.llm')} />
15
+ <TTS />
16
+ </>
17
+ );
18
+ });
@@ -1,4 +1,4 @@
1
- import { Azure, Bedrock, Google, Moonshot, OpenAI, Zhipu } from '@lobehub/icons';
1
+ import { Azure, Bedrock, Google, Moonshot, Ollama, OpenAI, Zhipu } from '@lobehub/icons';
2
2
  import { memo } from 'react';
3
3
  import { Center } from 'react-layout-kit';
4
4
 
@@ -42,6 +42,10 @@ const ModelProviderIcon = memo<ModelProviderIconProps>(({ provider }) => {
42
42
  return <OpenAI size={20} />;
43
43
  }
44
44
 
45
+ case ModelProvider.Ollama: {
46
+ return <Ollama size={20} />;
47
+ }
48
+
45
49
  default: {
46
50
  return null;
47
51
  }
@@ -3,6 +3,7 @@ import { ChatModelCard } from '@/types/llm';
3
3
  import BedrockProvider from './bedrock';
4
4
  import GoogleProvider from './google';
5
5
  import MoonshotProvider from './moonshot';
6
+ import OllamaProvider from './ollama';
6
7
  import OpenAIProvider from './openai';
7
8
  import ZhiPuProvider from './zhipu';
8
9
 
@@ -12,10 +13,12 @@ export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [
12
13
  BedrockProvider.chatModels,
13
14
  GoogleProvider.chatModels,
14
15
  MoonshotProvider.chatModels,
16
+ OllamaProvider.chatModels,
15
17
  ].flat();
16
18
 
17
19
  export { default as BedrockProvider } from './bedrock';
18
20
  export { default as GoogleProvider } from './google';
19
21
  export { default as MoonshotProvider } from './moonshot';
22
+ export { default as OllamaProvider } from './ollama';
20
23
  export { default as OpenAIProvider } from './openai';
21
24
  export { default as ZhiPuProvider } from './zhipu';
@@ -0,0 +1,117 @@
1
+ import { ModelProviderCard } from '@/types/llm';
2
+
3
+ const Ollama: ModelProviderCard = {
4
+ chatModels: [
5
+ {
6
+ displayName: 'Llama2 Chat 7B',
7
+ functionCall: false,
8
+ id: 'llama2',
9
+ tokens: 4000,
10
+ vision: false,
11
+ },
12
+ {
13
+ displayName: 'Llama2 Chat 13B',
14
+ functionCall: false,
15
+ hidden: true,
16
+ id: 'llama2:13b',
17
+ tokens: 4000,
18
+ vision: false,
19
+ },
20
+ {
21
+ displayName: 'Llama2 Chat 70B',
22
+ functionCall: false,
23
+ hidden: true,
24
+ id: 'llama2:70b',
25
+ tokens: 4000,
26
+ vision: false,
27
+ },
28
+ {
29
+ displayName: 'Code Llama 7B',
30
+ functionCall: false,
31
+ id: 'codellama',
32
+ tokens: 16_000,
33
+ vision: false,
34
+ },
35
+ {
36
+ displayName: 'Code Llama 34B',
37
+ functionCall: false,
38
+ hidden: true,
39
+ id: 'codellama:34b',
40
+ tokens: 16_000,
41
+ vision: false,
42
+ },
43
+ {
44
+ displayName: 'Code Llama 70B',
45
+ functionCall: false,
46
+ hidden: true,
47
+ id: 'codellama:70b',
48
+ tokens: 16_000,
49
+ vision: false,
50
+ },
51
+ {
52
+ displayName: 'Code Llama 7B (Python)',
53
+ functionCall: false,
54
+ hidden: true,
55
+ id: 'codellama:python',
56
+ tokens: 16_000,
57
+ vision: false,
58
+ },
59
+ {
60
+ displayName: 'Mistral',
61
+ functionCall: false,
62
+ id: 'mistral',
63
+ tokens: 4800,
64
+ vision: false,
65
+ },
66
+ {
67
+ displayName: 'Qwen Chat 7B',
68
+ functionCall: false,
69
+ id: 'qwen:7b-chat',
70
+ tokens: 32_768,
71
+ vision: false,
72
+ },
73
+ {
74
+ displayName: 'Qwen Chat 14B',
75
+ functionCall: false,
76
+ hidden: true,
77
+ id: 'qwen:14b-chat',
78
+ tokens: 32_768,
79
+ vision: false,
80
+ },
81
+ {
82
+ displayName: 'Qwen Chat 70B',
83
+ functionCall: false,
84
+ hidden: true,
85
+ id: 'qwen:70b-chat',
86
+ tokens: 32_768,
87
+ vision: false,
88
+ },
89
+ {
90
+ displayName: 'LLaVA 7B',
91
+ functionCall: false,
92
+ hidden: true,
93
+ id: 'llava',
94
+ tokens: 4000,
95
+ vision: false,
96
+ },
97
+ {
98
+ displayName: 'LLaVA 13B',
99
+ functionCall: false,
100
+ hidden: true,
101
+ id: 'llava:13b',
102
+ tokens: 4000,
103
+ vision: false,
104
+ },
105
+ {
106
+ displayName: 'LLaVA 34B',
107
+ functionCall: false,
108
+ hidden: true,
109
+ id: 'llava:34b',
110
+ tokens: 4000,
111
+ vision: false,
112
+ },
113
+ ],
114
+ id: 'ollama',
115
+ };
116
+
117
+ export default Ollama;
@@ -33,6 +33,9 @@ declare global {
33
33
  AWS_ACCESS_KEY_ID?: string;
34
34
  AWS_SECRET_ACCESS_KEY?: string;
35
35
 
36
+ // Ollama Provider;
37
+ OLLAMA_PROXY_URL?: string;
38
+
36
39
  DEBUG_CHAT_COMPLETION?: string;
37
40
  }
38
41
  }
@@ -83,6 +86,9 @@ export const getProviderConfig = () => {
83
86
  AZURE_ENDPOINT: process.env.AZURE_ENDPOINT,
84
87
  USE_AZURE_OPENAI: process.env.USE_AZURE_OPENAI === '1',
85
88
 
89
+ ENABLE_OLLAMA: !!process.env.OLLAMA_PROXY_URL,
90
+ OLLAMA_PROXY_URL: process.env.OLLAMA_PROXY_URL || '',
91
+
86
92
  DEBUG_CHAT_COMPLETION: process.env.DEBUG_CHAT_COMPLETION === '1',
87
93
  };
88
94
  };
@@ -66,8 +66,13 @@ export const DEFAULT_LLM_CONFIG: GlobalLLMConfig = {
66
66
  apiKey: '',
67
67
  enabled: false,
68
68
  },
69
+ ollama: {
70
+ enabled: false,
71
+ endpoint: '',
72
+ },
69
73
  openAI: {
70
74
  OPENAI_API_KEY: '',
75
+ enabled: true,
71
76
  models: [],
72
77
  },
73
78
  zhipu: {
@@ -20,7 +20,7 @@ import { ABOUT, CHANGELOG, DISCORD, FEEDBACK, GITHUB, WIKI } from '@/const/url';
20
20
  import DataImporter from '@/features/DataImporter';
21
21
  import { configService } from '@/services/config';
22
22
  import { GlobalStore, useGlobalStore } from '@/store/global';
23
- import { SettingsTabs, SidebarTabKey } from '@/store/global/initialState';
23
+ import { SidebarTabKey } from '@/store/global/initialState';
24
24
 
25
25
  export interface BottomActionProps {
26
26
  setTab: GlobalStore['switchSideBar'];
@@ -115,7 +115,6 @@ const BottomActions = memo<BottomActionProps>(({ tab, setTab }) => {
115
115
  onClick: () => {
116
116
  setTab(SidebarTabKey.Setting);
117
117
  useGlobalStore.setState({
118
- settingsTab: SettingsTabs.Common,
119
118
  sidebarKey: SidebarTabKey.Setting,
120
119
  });
121
120
  router.push('/settings/common');
@@ -1,26 +1,26 @@
1
1
  'use client';
2
2
 
3
- import { PropsWithChildren, ReactNode, Suspense } from 'react';
3
+ import { ReactNode, Suspense } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
6
  import FullscreenLoading from '@/components/FullscreenLoading';
7
7
  import { useIsMobile } from '@/hooks/useIsMobile';
8
8
 
9
- interface ServerResponsiveLayoutProps {
10
- Desktop: (props: PropsWithChildren) => ReactNode;
11
- Mobile: (props: PropsWithChildren) => ReactNode;
9
+ interface ServerResponsiveLayoutProps extends Record<string, any> {
10
+ Desktop: (props: any) => ReactNode;
11
+ Mobile: (props: any) => ReactNode;
12
12
  children?: ReactNode;
13
13
  }
14
- const ResponsiveLayout = ({ children, Desktop, Mobile }: ServerResponsiveLayoutProps) => {
14
+ const ResponsiveLayout = ({ children, Desktop, Mobile, ...res }: ServerResponsiveLayoutProps) => {
15
15
  const { t } = useTranslation();
16
16
  const mobile = useIsMobile();
17
17
 
18
18
  return mobile ? (
19
19
  <Suspense fallback={<FullscreenLoading title={t('layoutInitializing', { ns: 'common' })} />}>
20
- <Mobile>{children}</Mobile>
20
+ <Mobile {...res}>{children}</Mobile>
21
21
  </Suspense>
22
22
  ) : (
23
- <Desktop>{children}</Desktop>
23
+ <Desktop {...res}>{children}</Desktop>
24
24
  );
25
25
  };
26
26
 
@@ -1,16 +1,16 @@
1
- import { PropsWithChildren, ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
 
3
3
  import { isMobileDevice } from '@/utils/responsive';
4
4
 
5
- interface ServerResponsiveLayoutProps {
6
- Desktop: (props: PropsWithChildren) => ReactNode;
7
- Mobile: (props: PropsWithChildren) => ReactNode;
5
+ interface ServerResponsiveLayoutProps extends Record<string, any> {
6
+ Desktop: (props: any) => ReactNode;
7
+ Mobile: (props: any) => ReactNode;
8
8
  children?: ReactNode;
9
9
  }
10
- const ResponsiveLayout = ({ children, Desktop, Mobile }: ServerResponsiveLayoutProps) => {
10
+ const ResponsiveLayout = ({ children, Desktop, Mobile, ...res }: ServerResponsiveLayoutProps) => {
11
11
  const mobile = isMobileDevice();
12
12
 
13
- return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
13
+ return mobile ? <Mobile {...res}>{children}</Mobile> : <Desktop {...res}>{children}</Desktop>;
14
14
  };
15
15
 
16
16
  export default ResponsiveLayout;
@@ -22,6 +22,9 @@ export const AgentRuntimeErrorType = {
22
22
 
23
23
  InvalidMoonshotAPIKey: 'InvalidMoonshotAPIKey',
24
24
  MoonshotBizError: 'MoonshotBizError',
25
+
26
+ InvalidOllamaArgs: 'InvalidOllamaArgs',
27
+ OllamaBizError: 'OllamaBizError',
25
28
  } as const;
26
29
 
27
30
  export type ILobeAgentRuntimeErrorType =
@@ -4,6 +4,7 @@ export { LobeBedrockAI } from './bedrock';
4
4
  export * from './error';
5
5
  export { LobeGoogleAI } from './google';
6
6
  export { LobeMoonshotAI } from './moonshot';
7
+ export { LobeOllamaAI } from './ollama';
7
8
  export { LobeOpenAI } from './openai';
8
9
  export * from './types';
9
10
  export { AgentRuntimeError } from './utils/createError';
@@ -0,0 +1,80 @@
1
+ import { OpenAIStream, StreamingTextResponse } from 'ai';
2
+ import OpenAI from 'openai';
3
+
4
+ import { LobeRuntimeAI } from '../BaseAI';
5
+ import { AgentRuntimeErrorType } from '../error';
6
+ import { ChatStreamPayload, ModelProvider } from '../types';
7
+ import { AgentRuntimeError } from '../utils/createError';
8
+ import { debugStream } from '../utils/debugStream';
9
+ import { desensitizeUrl } from '../utils/desensitizeUrl';
10
+ import { DEBUG_CHAT_COMPLETION } from '../utils/env';
11
+ import { handleOpenAIError } from '../utils/handleOpenAIError';
12
+
13
+ const DEFAULT_BASE_URL = 'http://127.0.0.1:11434/v1';
14
+
15
+ export class LobeOllamaAI implements LobeRuntimeAI {
16
+ private _llm: OpenAI;
17
+
18
+ baseURL: string;
19
+
20
+ constructor(baseURL: string = DEFAULT_BASE_URL) {
21
+ if (!baseURL) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidOllamaArgs);
22
+
23
+ this._llm = new OpenAI({ apiKey: 'ollama', baseURL });
24
+ this.baseURL = baseURL;
25
+ }
26
+
27
+ async chat(payload: ChatStreamPayload) {
28
+ try {
29
+ const response = await this._llm.chat.completions.create(
30
+ payload as unknown as OpenAI.ChatCompletionCreateParamsStreaming,
31
+ );
32
+
33
+ const stream = OpenAIStream(response);
34
+
35
+ const [debug, returnStream] = stream.tee();
36
+
37
+ if (DEBUG_CHAT_COMPLETION) {
38
+ debugStream(debug).catch(console.error);
39
+ }
40
+
41
+ return new StreamingTextResponse(returnStream);
42
+ } catch (error) {
43
+ let desensitizedEndpoint = this.baseURL;
44
+
45
+ if (this.baseURL !== DEFAULT_BASE_URL) {
46
+ desensitizedEndpoint = desensitizeUrl(this.baseURL);
47
+ }
48
+
49
+ if ('status' in (error as any)) {
50
+ switch ((error as Response).status) {
51
+ case 401: {
52
+ throw AgentRuntimeError.chat({
53
+ endpoint: desensitizedEndpoint,
54
+ error: error as any,
55
+ errorType: AgentRuntimeErrorType.InvalidOllamaArgs,
56
+ provider: ModelProvider.Ollama,
57
+ });
58
+ }
59
+
60
+ default: {
61
+ break;
62
+ }
63
+ }
64
+ }
65
+
66
+ const { errorResult, RuntimeError } = handleOpenAIError(error);
67
+
68
+ const errorType = RuntimeError || AgentRuntimeErrorType.OllamaBizError;
69
+
70
+ throw AgentRuntimeError.chat({
71
+ endpoint: desensitizedEndpoint,
72
+ error: errorResult,
73
+ errorType,
74
+ provider: ModelProvider.Ollama,
75
+ });
76
+ }
77
+ }
78
+ }
79
+
80
+ export default LobeOllamaAI;
@@ -29,6 +29,7 @@ export enum ModelProvider {
29
29
  Google = 'google',
30
30
  Mistral = 'mistral',
31
31
  Moonshot = 'moonshot',
32
+ Ollama = 'ollama',
32
33
  OpenAI = 'openai',
33
34
  Tongyi = 'tongyi',
34
35
  ZhiPu = 'zhipu',
@@ -103,6 +103,7 @@ export default {
103
103
  bedrock: 'AWS Bedrock',
104
104
  google: 'Google',
105
105
  moonshot: 'Moonshot AI',
106
+ ollama: 'Ollama',
106
107
  oneapi: 'One API',
107
108
  openai: 'OpenAI',
108
109
  zhipu: '智谱AI',
@@ -73,6 +73,9 @@ export default {
73
73
  InvalidAzureAPIKey: 'Azure API Key 不正确或为空,请检查 Azure API Key 后重试',
74
74
  AzureBizError: '请求 Azure AI 服务出错,请根据以下信息排查或重试',
75
75
 
76
+ InvalidOllamaArgs: 'Ollama 配置不正确,请检查 Ollama 配置后重试',
77
+ OllamaBizError: '请求 Ollama 服务出错,请根据以下信息排查或重试',
78
+
76
79
  AgentRuntimeError: 'Lobe 语言模型运行时执行出错,请根据以下信息排查或重试',
77
80
  /* eslint-enable */
78
81
  },
@@ -85,6 +85,22 @@ export default {
85
85
  title: 'API Key',
86
86
  },
87
87
  },
88
+ Ollama: {
89
+ checker: {
90
+ desc: '测试代理地址是否正确填写',
91
+ },
92
+ customModelName: {
93
+ desc: '增加自定义模型,多个模型使用逗号(,)隔开',
94
+ placeholder: 'vicuna,llava,codellama,llama2:13b-text',
95
+ title: '自定义模型名称',
96
+ },
97
+ endpoint: {
98
+ desc: '填入 Ollama 接口代理地址,本地未额外指定可留空',
99
+ placeholder: 'http://127.0.0.1:11434/v1',
100
+ title: '接口代理地址',
101
+ },
102
+ title: 'Ollama',
103
+ },
88
104
  OpenAI: {
89
105
  azureApiVersion: {
90
106
  desc: 'Azure 的 API 版本,遵循 YYYY-MM-DD 格式,查阅[最新版本](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)',