@lobehub/chat 0.137.0 → 0.138.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 +11 -5
- package/CHANGELOG.md +50 -0
- package/docs/self-hosting/environment-variables/model-provider.mdx +9 -2
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +9 -2
- package/locales/ar/common.json +1 -0
- package/locales/ar/error.json +6 -0
- package/locales/ar/setting.json +8 -0
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/error.json +6 -0
- package/locales/de-DE/setting.json +8 -0
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/error.json +6 -0
- package/locales/en-US/setting.json +8 -0
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/error.json +6 -0
- package/locales/es-ES/setting.json +8 -0
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/error.json +6 -0
- package/locales/fr-FR/setting.json +8 -0
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/error.json +6 -0
- package/locales/it-IT/setting.json +8 -0
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/error.json +6 -0
- package/locales/ja-JP/setting.json +8 -0
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/error.json +6 -0
- package/locales/ko-KR/setting.json +8 -0
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/error.json +6 -0
- package/locales/nl-NL/setting.json +8 -0
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/error.json +6 -0
- package/locales/pl-PL/setting.json +8 -0
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/error.json +6 -0
- package/locales/pt-BR/setting.json +8 -0
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/error.json +6 -0
- package/locales/ru-RU/setting.json +8 -0
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/error.json +6 -0
- package/locales/tr-TR/setting.json +8 -0
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/error.json +6 -0
- package/locales/vi-VN/setting.json +8 -0
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/error.json +6 -0
- package/locales/zh-CN/setting.json +8 -0
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/error.json +6 -0
- 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/settings/llm/Groq/index.tsx +47 -0
- package/src/app/settings/llm/index.tsx +2 -0
- package/src/components/ModelProviderIcon/index.tsx +5 -0
- package/src/config/modelProviders/groq.ts +24 -0
- package/src/config/modelProviders/index.ts +3 -0
- package/src/config/server/provider.ts +11 -3
- package/src/const/settings.ts +4 -0
- package/src/const/url.ts +1 -1
- package/src/features/Conversation/Error/APIKeyForm/Groq.tsx +60 -0
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +5 -0
- package/src/features/Conversation/Error/index.tsx +1 -0
- package/src/features/Conversation/components/ChatItem/index.tsx +2 -1
- package/src/libs/agent-runtime/error.ts +3 -0
- package/src/libs/agent-runtime/groq/index.ts +78 -0
- package/src/libs/agent-runtime/index.ts +1 -0
- package/src/libs/agent-runtime/types/type.ts +1 -0
- package/src/locales/default/common.ts +1 -0
- package/src/locales/default/error.ts +7 -0
- package/src/locales/default/setting.ts +8 -0
- package/src/services/_auth.ts +5 -1
- package/src/store/global/slices/settings/selectors/modelProvider.ts +14 -5
- package/src/types/settings/modelProvider.ts +6 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Groq } 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 GroqForm = memo(() => {
|
|
13
|
+
const { t } = useTranslation('error');
|
|
14
|
+
// const [showProxy, setShow] = useState(false);
|
|
15
|
+
|
|
16
|
+
const [apiKey, setConfig] = useGlobalStore((s) => [
|
|
17
|
+
modelProviderSelectors.groqAPIKey(s),
|
|
18
|
+
s.setModelProviderConfig,
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<FormAction
|
|
23
|
+
avatar={<Groq size={56} />}
|
|
24
|
+
description={t('unlock.apikey.Groq.description')}
|
|
25
|
+
title={t('unlock.apikey.Groq.title')}
|
|
26
|
+
>
|
|
27
|
+
<Input.Password
|
|
28
|
+
autoComplete={'new-password'}
|
|
29
|
+
onChange={(e) => {
|
|
30
|
+
setConfig(ModelProvider.Groq, { 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 GroqForm;
|
|
@@ -9,6 +9,7 @@ import { useChatStore } from '@/store/chat';
|
|
|
9
9
|
import AnthropicForm from './Anthropic';
|
|
10
10
|
import BedrockForm from './Bedrock';
|
|
11
11
|
import GoogleForm from './Google';
|
|
12
|
+
import GroqForm from './Groq';
|
|
12
13
|
import MistralForm from './Mistral';
|
|
13
14
|
import MoonshotForm from './Moonshot';
|
|
14
15
|
import OpenAIForm from './OpenAI';
|
|
@@ -55,6 +56,10 @@ const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
|
|
|
55
56
|
return <AnthropicForm />;
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
case ModelProvider.Groq: {
|
|
60
|
+
return <GroqForm />;
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
default:
|
|
59
64
|
case ModelProvider.OpenAI: {
|
|
60
65
|
return <OpenAIForm />;
|
|
@@ -74,6 +74,7 @@ const ErrorMessageExtra = memo<{ data: ChatMessage }>(({ data }) => {
|
|
|
74
74
|
case AgentRuntimeErrorType.InvalidGoogleAPIKey:
|
|
75
75
|
case AgentRuntimeErrorType.InvalidPerplexityAPIKey:
|
|
76
76
|
case AgentRuntimeErrorType.InvalidAnthropicAPIKey:
|
|
77
|
+
case AgentRuntimeErrorType.InvalidGroqAPIKey:
|
|
77
78
|
case AgentRuntimeErrorType.NoOpenAIAPIKey: {
|
|
78
79
|
return <InvalidAPIKey id={data.id} provider={data.error?.body?.provider} />;
|
|
79
80
|
}
|
|
@@ -81,13 +81,14 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
|
81
81
|
[item?.role],
|
|
82
82
|
);
|
|
83
83
|
|
|
84
|
+
const { t: errorT } = useTranslation('error');
|
|
84
85
|
const error = useMemo<AlertProps | undefined>(() => {
|
|
85
86
|
if (!item?.error) return;
|
|
86
87
|
const messageError = item.error;
|
|
87
88
|
|
|
88
89
|
const alertConfig = getErrorAlertConfig(messageError.type);
|
|
89
90
|
|
|
90
|
-
return { message:
|
|
91
|
+
return { message: errorT(`response.${messageError.type}` as any), ...alertConfig };
|
|
91
92
|
}, [item?.error]);
|
|
92
93
|
|
|
93
94
|
const enableHistoryDivider = useSessionStore((s) => {
|
|
@@ -34,6 +34,9 @@ export const AgentRuntimeErrorType = {
|
|
|
34
34
|
|
|
35
35
|
InvalidAnthropicAPIKey: 'InvalidAnthropicAPIKey',
|
|
36
36
|
AnthropicBizError: 'AnthropicBizError',
|
|
37
|
+
|
|
38
|
+
InvalidGroqAPIKey: 'InvalidGroqAPIKey',
|
|
39
|
+
GroqBizError: 'GroqBizError',
|
|
37
40
|
} as const;
|
|
38
41
|
|
|
39
42
|
export type ILobeAgentRuntimeErrorType =
|
|
@@ -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.groq.com/openai/v1';
|
|
13
|
+
|
|
14
|
+
export class LobeGroq 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.InvalidGroqAPIKey);
|
|
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_GROQ_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.InvalidGroqAPIKey,
|
|
54
|
+
provider: ModelProvider.Groq,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
default: {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { errorResult, RuntimeError } = handleOpenAIError(error);
|
|
65
|
+
|
|
66
|
+
const errorType = RuntimeError || AgentRuntimeErrorType.GroqBizError;
|
|
67
|
+
|
|
68
|
+
throw AgentRuntimeError.chat({
|
|
69
|
+
endpoint: desensitizedEndpoint,
|
|
70
|
+
error: errorResult,
|
|
71
|
+
errorType,
|
|
72
|
+
provider: ModelProvider.Groq,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default LobeGroq;
|
|
@@ -4,6 +4,7 @@ export * from './BaseAI';
|
|
|
4
4
|
export { LobeBedrockAI } from './bedrock';
|
|
5
5
|
export * from './error';
|
|
6
6
|
export { LobeGoogleAI } from './google';
|
|
7
|
+
export { LobeGroq } from './groq';
|
|
7
8
|
export { LobeMistralAI } from './mistral';
|
|
8
9
|
export { LobeMoonshotAI } from './moonshot';
|
|
9
10
|
export { LobeOllamaAI } from './ollama';
|
|
@@ -82,6 +82,9 @@ export default {
|
|
|
82
82
|
InvalidAnthropicAPIKey: 'Anthropic API Key 不正确或为空,请检查 Anthropic API Key 后重试',
|
|
83
83
|
AnthropicBizError: '请求 Anthropic AI 服务出错,请根据以下信息排查或重试',
|
|
84
84
|
|
|
85
|
+
InvalidGroqAPIKey: 'Groq API Key 不正确或为空,请检查 Groq API Key 后重试',
|
|
86
|
+
GroqBizError: '请求 Groq 服务出错,请根据以下信息排查或重试',
|
|
87
|
+
|
|
85
88
|
InvalidOllamaArgs: 'Ollama 配置不正确,请检查 Ollama 配置后重试',
|
|
86
89
|
OllamaBizError: '请求 Ollama 服务出错,请根据以下信息排查或重试',
|
|
87
90
|
OllamaServiceUnavailable: '未检测到 Ollama 服务,请检查是否正常启动',
|
|
@@ -111,6 +114,10 @@ export default {
|
|
|
111
114
|
description: '输入你的 Google API Key 即可开始会话。应用不会记录你的 API Key',
|
|
112
115
|
title: '使用自定义 Google API Key',
|
|
113
116
|
},
|
|
117
|
+
Groq: {
|
|
118
|
+
description: '输入你的 Groq API Key 即可开始会话。应用不会记录你的 API Key',
|
|
119
|
+
title: '使用自定义 Groq API Key',
|
|
120
|
+
},
|
|
114
121
|
Mistral: {
|
|
115
122
|
description: '输入你的 Mistral AI API Key 即可开始会话。应用不会记录你的 API Key',
|
|
116
123
|
title: '使用自定义 Mistral AI API Key',
|
|
@@ -100,6 +100,14 @@ export default {
|
|
|
100
100
|
title: 'API Key',
|
|
101
101
|
},
|
|
102
102
|
},
|
|
103
|
+
Groq: {
|
|
104
|
+
title: 'Groq',
|
|
105
|
+
token: {
|
|
106
|
+
desc: '填入来自 Groq 的 API Key',
|
|
107
|
+
placeholder: 'Groq API Key',
|
|
108
|
+
title: 'API Key',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
103
111
|
Mistral: {
|
|
104
112
|
title: 'Mistral AI',
|
|
105
113
|
token: {
|
package/src/services/_auth.ts
CHANGED
|
@@ -57,11 +57,15 @@ export const getProviderAuthPayload = (provider: string) => {
|
|
|
57
57
|
const endpoint = modelProviderSelectors.anthropicProxyUrl(useGlobalStore.getState());
|
|
58
58
|
return { apiKey, endpoint };
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
case ModelProvider.Mistral: {
|
|
62
62
|
return { apiKey: modelProviderSelectors.mistralAPIKey(useGlobalStore.getState()) };
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
case ModelProvider.Groq: {
|
|
66
|
+
return { apiKey: modelProviderSelectors.groqAPIKey(useGlobalStore.getState()) };
|
|
67
|
+
}
|
|
68
|
+
|
|
65
69
|
default:
|
|
66
70
|
case ModelProvider.OpenAI: {
|
|
67
71
|
const openai = modelProviderSelectors.openAIConfig(useGlobalStore.getState());
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
AnthropicProvider,
|
|
5
5
|
BedrockProvider,
|
|
6
6
|
GoogleProvider,
|
|
7
|
+
GroqProvider,
|
|
7
8
|
LOBE_DEFAULT_MODEL_LIST,
|
|
8
9
|
MistralProvider,
|
|
9
10
|
MoonshotProvider,
|
|
@@ -58,6 +59,9 @@ const enableAnthropic = (s: GlobalStore) => modelProvider(s).anthropic.enabled;
|
|
|
58
59
|
const anthropicAPIKey = (s: GlobalStore) => modelProvider(s).anthropic.apiKey;
|
|
59
60
|
const anthropicProxyUrl = (s: GlobalStore) => modelProvider(s).anthropic.endpoint;
|
|
60
61
|
|
|
62
|
+
const enableGroq = (s: GlobalStore) => modelProvider(s).groq.enabled;
|
|
63
|
+
const groqAPIKey = (s: GlobalStore) => modelProvider(s).groq.apiKey;
|
|
64
|
+
|
|
61
65
|
// const azureModelList = (s: GlobalStore): ModelProviderCard => {
|
|
62
66
|
// const azure = azureConfig(s);
|
|
63
67
|
// return {
|
|
@@ -143,14 +147,15 @@ const modelSelectList = (s: GlobalStore): ModelProviderCard[] => {
|
|
|
143
147
|
chatModels: openaiChatModels,
|
|
144
148
|
},
|
|
145
149
|
// { ...azureModelList(s), enabled: enableAzure(s) },
|
|
146
|
-
{ ...
|
|
147
|
-
{ ...
|
|
150
|
+
{ ...OllamaProvider, chatModels: ollamaChatModels, enabled: enableOllama(s) },
|
|
151
|
+
{ ...AnthropicProvider, enabled: enableAnthropic(s) },
|
|
148
152
|
{ ...GoogleProvider, enabled: enableGoogle(s) },
|
|
149
153
|
{ ...BedrockProvider, enabled: enableBedrock(s) },
|
|
150
|
-
{ ...OllamaProvider, chatModels: ollamaChatModels, enabled: enableOllama(s) },
|
|
151
154
|
{ ...PerplexityProvider, enabled: enablePerplexity(s) },
|
|
152
|
-
{ ...AnthropicProvider, enabled: enableAnthropic(s) },
|
|
153
155
|
{ ...MistralProvider, enabled: enableMistral(s) },
|
|
156
|
+
{ ...GroqProvider, enabled: enableGroq(s) },
|
|
157
|
+
{ ...ZhiPuProvider, enabled: enableZhipu(s) },
|
|
158
|
+
{ ...MoonshotProvider, enabled: enableMoonshot(s) },
|
|
154
159
|
];
|
|
155
160
|
};
|
|
156
161
|
|
|
@@ -229,8 +234,12 @@ export const modelProviderSelectors = {
|
|
|
229
234
|
enableAnthropic,
|
|
230
235
|
anthropicAPIKey,
|
|
231
236
|
anthropicProxyUrl,
|
|
232
|
-
|
|
237
|
+
|
|
233
238
|
// Mistral
|
|
234
239
|
enableMistral,
|
|
235
240
|
mistralAPIKey,
|
|
241
|
+
|
|
242
|
+
// Groq
|
|
243
|
+
enableGroq,
|
|
244
|
+
groqAPIKey,
|
|
236
245
|
};
|
|
@@ -71,11 +71,17 @@ export interface MistralConfig {
|
|
|
71
71
|
enabled: boolean;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
export interface GroqConfig {
|
|
75
|
+
apiKey?: string;
|
|
76
|
+
enabled: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
74
79
|
export interface GlobalLLMConfig {
|
|
75
80
|
anthropic: AnthropicConfig;
|
|
76
81
|
azure: AzureOpenAIConfig;
|
|
77
82
|
bedrock: AWSBedrockConfig;
|
|
78
83
|
google: GoogleConfig;
|
|
84
|
+
groq: GroqConfig;
|
|
79
85
|
mistral: MistralConfig;
|
|
80
86
|
moonshot: MoonshotConfig;
|
|
81
87
|
ollama: OllamaConfig;
|