@lobehub/chat 1.39.1 → 1.39.3

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 (54) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/Dockerfile +1 -1
  3. package/Dockerfile.database +1 -1
  4. package/changelog/v1.json +18 -0
  5. package/package.json +1 -1
  6. package/src/app/(main)/(mobile)/me/(home)/loading.tsx +1 -1
  7. package/src/app/(main)/(mobile)/me/data/loading.tsx +1 -1
  8. package/src/app/(main)/(mobile)/me/profile/loading.tsx +1 -1
  9. package/src/app/(main)/(mobile)/me/settings/loading.tsx +1 -1
  10. package/src/app/(main)/chat/(workspace)/@portal/default.tsx +1 -1
  11. package/src/app/(main)/chat/(workspace)/@portal/loading.tsx +1 -1
  12. package/src/app/(main)/chat/@session/default.tsx +3 -2
  13. package/src/app/(main)/chat/loading.tsx +1 -1
  14. package/src/app/(main)/chat/settings/loading.tsx +1 -1
  15. package/src/app/(main)/discover/loading.tsx +1 -1
  16. package/src/app/(main)/files/loading.tsx +2 -22
  17. package/src/app/(main)/profile/loading.tsx +1 -1
  18. package/src/app/(main)/repos/[id]/evals/dataset/page.tsx +1 -1
  19. package/src/app/(main)/repos/[id]/evals/evaluation/page.tsx +1 -1
  20. package/src/app/(main)/settings/@category/default.tsx +6 -2
  21. package/src/app/(main)/settings/_layout/Desktop/SideBar.tsx +1 -1
  22. package/src/app/(main)/settings/llm/ProviderList/providers.tsx +2 -4
  23. package/src/app/(main)/settings/loading.tsx +2 -8
  24. package/src/app/loading/Client/Content.tsx +1 -1
  25. package/src/app/loading/Server/Content.tsx +1 -1
  26. package/src/components/Loading/BrandTextLoading/LobeChatText/SVG.tsx +44 -0
  27. package/src/components/Loading/BrandTextLoading/LobeChatText/index.tsx +6 -0
  28. package/src/components/Loading/BrandTextLoading/LobeChatText/style.css +32 -0
  29. package/src/components/Loading/BrandTextLoading/index.tsx +11 -0
  30. package/src/components/{SkeletonLoading → Loading/SkeletonLoading}/index.tsx +1 -1
  31. package/src/config/llm.ts +3 -6
  32. package/src/const/auth.ts +0 -3
  33. package/src/features/Conversation/Error/APIKeyForm/index.tsx +0 -3
  34. package/src/features/FileViewer/Renderer/TXT/index.tsx +1 -1
  35. package/src/features/Portal/FilePreview/Body/index.tsx +1 -1
  36. package/src/features/Portal/Home/Body/Files/FileList/index.tsx +1 -1
  37. package/src/features/Setting/Footer.tsx +3 -1
  38. package/src/features/Setting/SettingContainer.tsx +1 -0
  39. package/src/libs/agent-runtime/AgentRuntime.ts +1 -1
  40. package/src/libs/agent-runtime/index.ts +0 -1
  41. package/src/libs/agent-runtime/sensenova/index.test.ts +78 -148
  42. package/src/libs/agent-runtime/sensenova/index.ts +23 -98
  43. package/src/locales/default/modelProvider.ts +0 -17
  44. package/src/server/modules/AgentRuntime/index.ts +0 -15
  45. package/src/services/_auth.ts +0 -14
  46. package/src/store/user/slices/modelList/selectors/keyVaults.ts +0 -2
  47. package/src/store/user/slices/modelList/selectors/modelConfig.ts +0 -2
  48. package/src/types/user/settings/keyVaults.ts +1 -6
  49. package/src/app/(main)/settings/llm/ProviderList/SenseNova/index.tsx +0 -44
  50. package/src/features/Conversation/Error/APIKeyForm/SenseNova.tsx +0 -49
  51. package/src/libs/agent-runtime/sensenova/authToken.test.ts +0 -18
  52. package/src/libs/agent-runtime/sensenova/authToken.ts +0 -27
  53. /package/src/components/{CircleLoading → Loading/CircleLoading}/index.tsx +0 -0
  54. /package/src/components/{FullscreenLoading → Loading/FullscreenLoading}/index.tsx +0 -0
@@ -1,142 +1,49 @@
1
1
  // @vitest-environment node
2
- import { OpenAI } from 'openai';
2
+ import OpenAI from 'openai';
3
3
  import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
4
 
5
- import { ChatStreamCallbacks, LobeOpenAI } from '@/libs/agent-runtime';
6
- import * as debugStreamModule from '@/libs/agent-runtime/utils/debugStream';
5
+ import { LobeOpenAICompatibleRuntime } from '@/libs/agent-runtime';
6
+ import { ModelProvider } from '@/libs/agent-runtime';
7
+ import { AgentRuntimeErrorType } from '@/libs/agent-runtime';
7
8
 
8
- import * as authTokenModule from './authToken';
9
+ import * as debugStreamModule from '../utils/debugStream';
9
10
  import { LobeSenseNovaAI } from './index';
10
11
 
11
- const bizErrorType = 'ProviderBizError';
12
- const invalidErrorType = 'InvalidProviderAPIKey';
12
+ const provider = ModelProvider.SenseNova;
13
+ const defaultBaseURL = 'https://api.sensenova.cn/compatible-mode/v1';
14
+ const bizErrorType = AgentRuntimeErrorType.ProviderBizError;
15
+ const invalidErrorType = AgentRuntimeErrorType.InvalidProviderAPIKey;
13
16
 
14
- // Mock相关依赖
15
- vi.mock('./authToken');
17
+ // Mock the console.error to avoid polluting test output
18
+ vi.spyOn(console, 'error').mockImplementation(() => {});
16
19
 
17
- describe('LobeSenseNovaAI', () => {
18
- beforeEach(() => {
19
- // Mock generateApiToken
20
- vi.spyOn(authTokenModule, 'generateApiToken').mockResolvedValue('mocked_token');
21
- });
20
+ let instance: LobeOpenAICompatibleRuntime;
22
21
 
23
- afterEach(() => {
24
- vi.restoreAllMocks();
25
- });
22
+ beforeEach(() => {
23
+ instance = new LobeSenseNovaAI({ apiKey: 'test' });
26
24
 
27
- describe('fromAPIKey', () => {
28
- it('should correctly initialize with an API key', async () => {
29
- const lobeSenseNovaAI = await LobeSenseNovaAI.fromAPIKey({ apiKey: 'test_api_key' });
30
- expect(lobeSenseNovaAI).toBeInstanceOf(LobeSenseNovaAI);
31
- expect(lobeSenseNovaAI.baseURL).toEqual('https://api.sensenova.cn/compatible-mode/v1');
32
- });
25
+ // 使用 vi.spyOn 来模拟 chat.completions.create 方法
26
+ vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
27
+ new ReadableStream() as any,
28
+ );
29
+ });
33
30
 
34
- it('should throw an error if API key is invalid', async () => {
35
- vi.spyOn(authTokenModule, 'generateApiToken').mockRejectedValue(new Error('Invalid API Key'));
36
- try {
37
- await LobeSenseNovaAI.fromAPIKey({ apiKey: 'asd' });
38
- } catch (e) {
39
- expect(e).toEqual({ errorType: invalidErrorType });
40
- }
31
+ afterEach(() => {
32
+ vi.clearAllMocks();
33
+ });
34
+
35
+ describe('LobeSenseNovaAI', () => {
36
+ describe('init', () => {
37
+ it('should correctly initialize with an API key', async () => {
38
+ const instance = new LobeSenseNovaAI({ apiKey: 'test_api_key' });
39
+ expect(instance).toBeInstanceOf(LobeSenseNovaAI);
40
+ expect(instance.baseURL).toEqual(defaultBaseURL);
41
41
  });
42
42
  });
43
43
 
44
44
  describe('chat', () => {
45
- let instance: LobeSenseNovaAI;
46
-
47
- beforeEach(async () => {
48
- instance = await LobeSenseNovaAI.fromAPIKey({
49
- apiKey: 'test_api_key',
50
- });
51
-
52
- // Mock chat.completions.create
53
- vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
54
- new ReadableStream() as any,
55
- );
56
- });
57
-
58
- it('should return a StreamingTextResponse on successful API call', async () => {
59
- const result = await instance.chat({
60
- messages: [{ content: 'Hello', role: 'user' }],
61
- model: 'SenseChat',
62
- temperature: 0,
63
- });
64
- expect(result).toBeInstanceOf(Response);
65
- });
66
-
67
- it('should handle callback and headers correctly', async () => {
68
- // 模拟 chat.completions.create 方法返回一个可读流
69
- const mockCreateMethod = vi
70
- .spyOn(instance['client'].chat.completions, 'create')
71
- .mockResolvedValue(
72
- new ReadableStream({
73
- start(controller) {
74
- controller.enqueue({
75
- id: 'chatcmpl-8xDx5AETP8mESQN7UB30GxTN2H1SO',
76
- object: 'chat.completion.chunk',
77
- created: 1709125675,
78
- model: 'gpt-3.5-turbo-0125',
79
- system_fingerprint: 'fp_86156a94a0',
80
- choices: [
81
- { index: 0, delta: { content: 'hello' }, logprobs: null, finish_reason: null },
82
- ],
83
- });
84
- controller.close();
85
- },
86
- }) as any,
87
- );
88
-
89
- // 准备 callback 和 headers
90
- const mockCallback: ChatStreamCallbacks = {
91
- onStart: vi.fn(),
92
- onToken: vi.fn(),
93
- };
94
- const mockHeaders = { 'Custom-Header': 'TestValue' };
95
-
96
- // 执行测试
97
- const result = await instance.chat(
98
- {
99
- messages: [{ content: 'Hello', role: 'user' }],
100
- model: 'SenseChat',
101
- temperature: 0,
102
- },
103
- { callback: mockCallback, headers: mockHeaders },
104
- );
105
-
106
- // 验证 callback 被调用
107
- await result.text(); // 确保流被消费
108
-
109
- // 验证 headers 被正确传递
110
- expect(result.headers.get('Custom-Header')).toEqual('TestValue');
111
-
112
- // 清理
113
- mockCreateMethod.mockRestore();
114
- });
115
-
116
- it('should transform messages correctly', async () => {
117
- const spyOn = vi.spyOn(instance['client'].chat.completions, 'create');
118
-
119
- await instance.chat({
120
- frequency_penalty: 0,
121
- messages: [
122
- { content: 'Hello', role: 'user' },
123
- { content: [{ type: 'text', text: 'Hello again' }], role: 'user' },
124
- ],
125
- model: 'SenseChat',
126
- temperature: 0,
127
- top_p: 1,
128
- });
129
-
130
- const calledWithParams = spyOn.mock.calls[0][0];
131
-
132
- expect(calledWithParams.frequency_penalty).toBeUndefined(); // frequency_penalty 0 should be undefined
133
- expect(calledWithParams.messages[1].content).toEqual([{ type: 'text', text: 'Hello again' }]);
134
- expect(calledWithParams.temperature).toBeUndefined(); // temperature 0 should be undefined
135
- expect(calledWithParams.top_p).toBeUndefined(); // top_p 1 should be undefined
136
- });
137
-
138
45
  describe('Error', () => {
139
- it('should return SenseNovaAIBizError with an openai error response when OpenAI.APIError is thrown', async () => {
46
+ it('should return QwenBizError with an openai error response when OpenAI.APIError is thrown', async () => {
140
47
  // Arrange
141
48
  const apiError = new OpenAI.APIError(
142
49
  400,
@@ -156,31 +63,31 @@ describe('LobeSenseNovaAI', () => {
156
63
  try {
157
64
  await instance.chat({
158
65
  messages: [{ content: 'Hello', role: 'user' }],
159
- model: 'SenseChat',
160
- temperature: 0,
66
+ model: 'max-32k',
67
+ temperature: 0.999,
161
68
  });
162
69
  } catch (e) {
163
70
  expect(e).toEqual({
164
- endpoint: 'https://api.sensenova.cn/compatible-mode/v1',
71
+ endpoint: defaultBaseURL,
165
72
  error: {
166
73
  error: { message: 'Bad Request' },
167
74
  status: 400,
168
75
  },
169
76
  errorType: bizErrorType,
170
- provider: 'sensenova',
77
+ provider,
171
78
  });
172
79
  }
173
80
  });
174
81
 
175
- it('should throw AgentRuntimeError with NoOpenAIAPIKey if no apiKey is provided', async () => {
82
+ it('should throw AgentRuntimeError with InvalidQwenAPIKey if no apiKey is provided', async () => {
176
83
  try {
177
- await LobeSenseNovaAI.fromAPIKey({ apiKey: '' });
84
+ new LobeSenseNovaAI({});
178
85
  } catch (e) {
179
86
  expect(e).toEqual({ errorType: invalidErrorType });
180
87
  }
181
88
  });
182
89
 
183
- it('should return OpenAIBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
90
+ it('should return QwenBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
184
91
  // Arrange
185
92
  const errorInfo = {
186
93
  stack: 'abc',
@@ -196,23 +103,23 @@ describe('LobeSenseNovaAI', () => {
196
103
  try {
197
104
  await instance.chat({
198
105
  messages: [{ content: 'Hello', role: 'user' }],
199
- model: 'SenseChat',
200
- temperature: 0.2,
106
+ model: 'max-32k',
107
+ temperature: 0.999,
201
108
  });
202
109
  } catch (e) {
203
110
  expect(e).toEqual({
204
- endpoint: 'https://api.sensenova.cn/compatible-mode/v1',
111
+ endpoint: defaultBaseURL,
205
112
  error: {
206
113
  cause: { message: 'api is undefined' },
207
114
  stack: 'abc',
208
115
  },
209
116
  errorType: bizErrorType,
210
- provider: 'sensenova',
117
+ provider,
211
118
  });
212
119
  }
213
120
  });
214
121
 
215
- it('should return OpenAIBizError with an cause response with desensitize Url', async () => {
122
+ it('should return QwenBizError with an cause response with desensitize Url', async () => {
216
123
  // Arrange
217
124
  const errorInfo = {
218
125
  stack: 'abc',
@@ -220,10 +127,10 @@ describe('LobeSenseNovaAI', () => {
220
127
  };
221
128
  const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
222
129
 
223
- instance = await LobeSenseNovaAI.fromAPIKey({
130
+ instance = new LobeSenseNovaAI({
224
131
  apiKey: 'test',
225
132
 
226
- baseURL: 'https://abc.com/v2',
133
+ baseURL: 'https://api.abc.com/v1',
227
134
  });
228
135
 
229
136
  vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
@@ -232,18 +139,40 @@ describe('LobeSenseNovaAI', () => {
232
139
  try {
233
140
  await instance.chat({
234
141
  messages: [{ content: 'Hello', role: 'user' }],
235
- model: 'gpt-3.5-turbo',
236
- temperature: 0,
142
+ model: 'max-32k',
143
+ temperature: 0.999,
237
144
  });
238
145
  } catch (e) {
239
146
  expect(e).toEqual({
240
- endpoint: 'https://***.com/v2',
147
+ endpoint: 'https://api.***.com/v1',
241
148
  error: {
242
149
  cause: { message: 'api is undefined' },
243
150
  stack: 'abc',
244
151
  },
245
152
  errorType: bizErrorType,
246
- provider: 'sensenova',
153
+ provider,
154
+ });
155
+ }
156
+ });
157
+
158
+ it('should throw an InvalidQwenAPIKey error type on 401 status code', async () => {
159
+ // Mock the API call to simulate a 401 error
160
+ const error = new Error('InvalidApiKey') as any;
161
+ error.status = 401;
162
+ vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error);
163
+
164
+ try {
165
+ await instance.chat({
166
+ messages: [{ content: 'Hello', role: 'user' }],
167
+ model: 'max-32k',
168
+ temperature: 0.999,
169
+ });
170
+ } catch (e) {
171
+ expect(e).toEqual({
172
+ endpoint: defaultBaseURL,
173
+ error: new Error('InvalidApiKey'),
174
+ errorType: invalidErrorType,
175
+ provider,
247
176
  });
248
177
  }
249
178
  });
@@ -258,14 +187,14 @@ describe('LobeSenseNovaAI', () => {
258
187
  try {
259
188
  await instance.chat({
260
189
  messages: [{ content: 'Hello', role: 'user' }],
261
- model: 'SenseChat',
262
- temperature: 0,
190
+ model: 'max-32k',
191
+ temperature: 0.999,
263
192
  });
264
193
  } catch (e) {
265
194
  expect(e).toEqual({
266
- endpoint: 'https://api.sensenova.cn/compatible-mode/v1',
195
+ endpoint: defaultBaseURL,
267
196
  errorType: 'AgentRuntimeError',
268
- provider: 'sensenova',
197
+ provider,
269
198
  error: {
270
199
  name: genericError.name,
271
200
  cause: genericError.cause,
@@ -278,7 +207,7 @@ describe('LobeSenseNovaAI', () => {
278
207
  });
279
208
 
280
209
  describe('DEBUG', () => {
281
- it('should call debugStream and return StreamingTextResponse when DEBUG_OPENAI_CHAT_COMPLETION is 1', async () => {
210
+ it('should call debugStream and return StreamingTextResponse when DEBUG_SENSENOVA_CHAT_COMPLETION is 1', async () => {
282
211
  // Arrange
283
212
  const mockProdStream = new ReadableStream() as any; // 模拟的 prod 流
284
213
  const mockDebugStream = new ReadableStream({
@@ -306,8 +235,9 @@ describe('LobeSenseNovaAI', () => {
306
235
  // 假设的测试函数调用,你可能需要根据实际情况调整
307
236
  await instance.chat({
308
237
  messages: [{ content: 'Hello', role: 'user' }],
309
- model: 'SenseChat',
310
- temperature: 0,
238
+ model: 'max-32k',
239
+ stream: true,
240
+ temperature: 0.999,
311
241
  });
312
242
 
313
243
  // 验证 debugStream 被调用
@@ -1,98 +1,23 @@
1
- import OpenAI, { ClientOptions } from 'openai';
2
-
3
- import { LobeRuntimeAI } from '../BaseAI';
4
- import { AgentRuntimeErrorType } from '../error';
5
- import { ChatCompetitionOptions, ChatStreamPayload, ModelProvider } from '../types';
6
- import { AgentRuntimeError } from '../utils/createError';
7
- import { debugStream } from '../utils/debugStream';
8
- import { desensitizeUrl } from '../utils/desensitizeUrl';
9
- import { handleOpenAIError } from '../utils/handleOpenAIError';
10
- import { convertOpenAIMessages } from '../utils/openaiHelpers';
11
- import { StreamingResponse } from '../utils/response';
12
- import { OpenAIStream } from '../utils/streams';
13
- import { generateApiToken } from './authToken';
14
-
15
- const DEFAULT_BASE_URL = 'https://api.sensenova.cn/compatible-mode/v1';
16
-
17
- export class LobeSenseNovaAI implements LobeRuntimeAI {
18
- private client: OpenAI;
19
-
20
- baseURL: string;
21
-
22
- constructor(oai: OpenAI) {
23
- this.client = oai;
24
- this.baseURL = this.client.baseURL;
25
- }
26
-
27
- static async fromAPIKey({ apiKey, baseURL = DEFAULT_BASE_URL, ...res }: ClientOptions = {}) {
28
- const invalidSenseNovaAPIKey = AgentRuntimeError.createError(
29
- AgentRuntimeErrorType.InvalidProviderAPIKey,
30
- );
31
-
32
- if (!apiKey) throw invalidSenseNovaAPIKey;
33
-
34
- let token: string;
35
-
36
- try {
37
- token = await generateApiToken(apiKey);
38
- } catch {
39
- throw invalidSenseNovaAPIKey;
40
- }
41
-
42
- const header = { Authorization: `Bearer ${token}` };
43
-
44
- const llm = new OpenAI({ apiKey, baseURL, defaultHeaders: header, ...res });
45
-
46
- return new LobeSenseNovaAI(llm);
47
- }
48
-
49
- async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) {
50
- try {
51
- const params = await this.buildCompletionsParams(payload);
52
-
53
- const response = await this.client.chat.completions.create(
54
- params as unknown as OpenAI.ChatCompletionCreateParamsStreaming,
55
- );
56
-
57
- const [prod, debug] = response.tee();
58
-
59
- if (process.env.DEBUG_SENSENOVA_CHAT_COMPLETION === '1') {
60
- debugStream(debug.toReadableStream()).catch(console.error);
61
- }
62
-
63
- return StreamingResponse(OpenAIStream(prod), {
64
- headers: options?.headers,
65
- });
66
- } catch (error) {
67
- const { errorResult, RuntimeError } = handleOpenAIError(error);
68
-
69
- const errorType = RuntimeError || AgentRuntimeErrorType.ProviderBizError;
70
- let desensitizedEndpoint = this.baseURL;
71
-
72
- if (this.baseURL !== DEFAULT_BASE_URL) {
73
- desensitizedEndpoint = desensitizeUrl(this.baseURL);
74
- }
75
- throw AgentRuntimeError.chat({
76
- endpoint: desensitizedEndpoint,
77
- error: errorResult,
78
- errorType,
79
- provider: ModelProvider.SenseNova,
80
- });
81
- }
82
- }
83
-
84
- private async buildCompletionsParams(payload: ChatStreamPayload) {
85
- const { frequency_penalty, messages, temperature, top_p, ...params } = payload;
86
-
87
- return {
88
- messages: await convertOpenAIMessages(messages as any),
89
- ...params,
90
- frequency_penalty: (frequency_penalty !== undefined && frequency_penalty > 0 && frequency_penalty <= 2) ? frequency_penalty : undefined,
91
- stream: true,
92
- temperature: (temperature !== undefined && temperature > 0 && temperature <= 2) ? temperature : undefined,
93
- top_p: (top_p !== undefined && top_p > 0 && top_p < 1) ? top_p : undefined,
94
- };
95
- }
96
- }
97
-
98
- export default LobeSenseNovaAI;
1
+ import { ModelProvider } from '../types';
2
+ import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
3
+
4
+ export const LobeSenseNovaAI = LobeOpenAICompatibleFactory({
5
+ baseURL: 'https://api.sensenova.cn/compatible-mode/v1',
6
+ chatCompletion: {
7
+ handlePayload: (payload) => {
8
+ const { frequency_penalty, temperature, top_p, ...rest } = payload;
9
+
10
+ return {
11
+ ...rest,
12
+ frequency_penalty: (frequency_penalty !== undefined && frequency_penalty > 0 && frequency_penalty <= 2) ? frequency_penalty : undefined,
13
+ stream: true,
14
+ temperature: (temperature !== undefined && temperature > 0 && temperature <= 2) ? temperature : undefined,
15
+ top_p: (top_p !== undefined && top_p > 0 && top_p < 1) ? top_p : undefined,
16
+ } as any;
17
+ },
18
+ },
19
+ debug: {
20
+ chatCompletion: () => process.env.DEBUG_SENSENOVA_CHAT_COMPLETION === '1',
21
+ },
22
+ provider: ModelProvider.SenseNova,
23
+ });
@@ -134,23 +134,6 @@ export default {
134
134
  title: '下载指定的 Ollama 模型',
135
135
  },
136
136
  },
137
- sensenova: {
138
- sensenovaAccessKeyID: {
139
- desc: '填入 SenseNova Access Key ID',
140
- placeholder: 'SenseNova Access Key ID',
141
- title: 'Access Key ID',
142
- },
143
- sensenovaAccessKeySecret: {
144
- desc: '填入 SenseNova Access Key Secret',
145
- placeholder: 'SenseNova Access Key Secret',
146
- title: 'Access Key Secret',
147
- },
148
- unlock: {
149
- description:
150
- '输入你的 Access Key ID / Access Key Secret 即可开始会话。应用不会记录你的鉴权配置',
151
- title: '使用自定义 SenseNova 鉴权信息',
152
- },
153
- },
154
137
  wenxin: {
155
138
  accessKey: {
156
139
  desc: '填入百度千帆平台的 Access Key',
@@ -100,21 +100,6 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
100
100
 
101
101
  return { apiKey };
102
102
  }
103
-
104
- case ModelProvider.SenseNova: {
105
- const { SENSENOVA_ACCESS_KEY_ID, SENSENOVA_ACCESS_KEY_SECRET } = llmConfig;
106
-
107
- const sensenovaAccessKeyID = apiKeyManager.pick(
108
- payload?.sensenovaAccessKeyID || SENSENOVA_ACCESS_KEY_ID,
109
- );
110
- const sensenovaAccessKeySecret = apiKeyManager.pick(
111
- payload?.sensenovaAccessKeySecret || SENSENOVA_ACCESS_KEY_SECRET,
112
- );
113
-
114
- const apiKey = sensenovaAccessKeyID + ':' + sensenovaAccessKeySecret;
115
-
116
- return { apiKey };
117
- }
118
103
  }
119
104
  };
120
105
 
@@ -25,20 +25,6 @@ export const getProviderAuthPayload = (provider: string) => {
25
25
  };
26
26
  }
27
27
 
28
- case ModelProvider.SenseNova: {
29
- const { sensenovaAccessKeyID, sensenovaAccessKeySecret } = keyVaultsConfigSelectors.sensenovaConfig(
30
- useUserStore.getState(),
31
- );
32
-
33
- const apiKey = (sensenovaAccessKeyID || '') + ':' + (sensenovaAccessKeySecret || '')
34
-
35
- return {
36
- apiKey,
37
- sensenovaAccessKeyID: sensenovaAccessKeyID,
38
- sensenovaAccessKeySecret: sensenovaAccessKeySecret,
39
- };
40
- }
41
-
42
28
  case ModelProvider.Wenxin: {
43
29
  const { secretKey, accessKey } = keyVaultsConfigSelectors.wenxinConfig(
44
30
  useUserStore.getState(),
@@ -16,7 +16,6 @@ const openAIConfig = (s: UserStore) => keyVaultsSettings(s).openai || {};
16
16
  const bedrockConfig = (s: UserStore) => keyVaultsSettings(s).bedrock || {};
17
17
  const wenxinConfig = (s: UserStore) => keyVaultsSettings(s).wenxin || {};
18
18
  const ollamaConfig = (s: UserStore) => keyVaultsSettings(s).ollama || {};
19
- const sensenovaConfig = (s: UserStore) => keyVaultsSettings(s).sensenova || {};
20
19
  const azureConfig = (s: UserStore) => keyVaultsSettings(s).azure || {};
21
20
  const cloudflareConfig = (s: UserStore) => keyVaultsSettings(s).cloudflare || {};
22
21
  const getVaultByProvider = (provider: GlobalLLMProviderKey) => (s: UserStore) =>
@@ -46,6 +45,5 @@ export const keyVaultsConfigSelectors = {
46
45
  ollamaConfig,
47
46
  openAIConfig,
48
47
  password,
49
- sensenovaConfig,
50
48
  wenxinConfig,
51
49
  };
@@ -70,7 +70,6 @@ const bedrockConfig = (s: UserStore) => currentLLMSettings(s).bedrock;
70
70
  const ollamaConfig = (s: UserStore) => currentLLMSettings(s).ollama;
71
71
  const azureConfig = (s: UserStore) => currentLLMSettings(s).azure;
72
72
  const cloudflareConfig = (s: UserStore) => currentLLMSettings(s).cloudflare;
73
- const sensenovaConfig = (s: UserStore) => currentLLMSettings(s).sensenova;
74
73
 
75
74
  const isAzureEnabled = (s: UserStore) => currentLLMSettings(s).azure.enabled;
76
75
 
@@ -89,5 +88,4 @@ export const modelConfigSelectors = {
89
88
 
90
89
  ollamaConfig,
91
90
  openAIConfig,
92
- sensenovaConfig,
93
91
  };
@@ -21,11 +21,6 @@ export interface CloudflareKeyVault {
21
21
  baseURLOrAccountID?: string;
22
22
  }
23
23
 
24
- export interface SenseNovaKeyVault {
25
- sensenovaAccessKeyID?: string;
26
- sensenovaAccessKeySecret?: string;
27
- }
28
-
29
24
  export interface WenxinKeyVault {
30
25
  accessKey?: string;
31
26
  secretKey?: string;
@@ -60,7 +55,7 @@ export interface UserKeyVaults {
60
55
  password?: string;
61
56
  perplexity?: OpenAICompatibleKeyVault;
62
57
  qwen?: OpenAICompatibleKeyVault;
63
- sensenova?: SenseNovaKeyVault;
58
+ sensenova?: OpenAICompatibleKeyVault;
64
59
  siliconcloud?: OpenAICompatibleKeyVault;
65
60
  spark?: OpenAICompatibleKeyVault;
66
61
  stepfun?: OpenAICompatibleKeyVault;
@@ -1,44 +0,0 @@
1
- 'use client';
2
-
3
- import { Input } from 'antd';
4
- import { useTranslation } from 'react-i18next';
5
-
6
- import { SenseNovaProviderCard } from '@/config/modelProviders';
7
- import { GlobalLLMProviderKey } from '@/types/user/settings';
8
-
9
- import { KeyVaultsConfigKey } from '../../const';
10
- import { ProviderItem } from '../../type';
11
-
12
- const providerKey: GlobalLLMProviderKey = 'sensenova';
13
-
14
- export const useSenseNovaProvider = (): ProviderItem => {
15
- const { t } = useTranslation('modelProvider');
16
-
17
- return {
18
- ...SenseNovaProviderCard,
19
- apiKeyItems: [
20
- {
21
- children: (
22
- <Input.Password
23
- autoComplete={'new-password'}
24
- placeholder={t(`${providerKey}.sensenovaAccessKeyID.placeholder`)}
25
- />
26
- ),
27
- desc: t(`${providerKey}.sensenovaAccessKeyID.desc`),
28
- label: t(`${providerKey}.sensenovaAccessKeyID.title`),
29
- name: [KeyVaultsConfigKey, providerKey, 'sensenovaAccessKeyID'],
30
- },
31
- {
32
- children: (
33
- <Input.Password
34
- autoComplete={'new-password'}
35
- placeholder={t(`${providerKey}.sensenovaAccessKeySecret.placeholder`)}
36
- />
37
- ),
38
- desc: t(`${providerKey}.sensenovaAccessKeySecret.desc`),
39
- label: t(`${providerKey}.sensenovaAccessKeySecret.title`),
40
- name: [KeyVaultsConfigKey, providerKey, 'sensenovaAccessKeySecret'],
41
- },
42
- ],
43
- };
44
- };
@@ -1,49 +0,0 @@
1
- import { SenseNova } 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 { useUserStore } from '@/store/user';
8
- import { keyVaultsConfigSelectors } from '@/store/user/selectors';
9
-
10
- import { FormAction } from '../style';
11
-
12
- const SenseNovaForm = memo(() => {
13
- const { t } = useTranslation('modelProvider');
14
-
15
- const [sensenovaAccessKeyID, sensenovaAccessKeySecret, setConfig] = useUserStore((s) => [
16
- keyVaultsConfigSelectors.sensenovaConfig(s).sensenovaAccessKeyID,
17
- keyVaultsConfigSelectors.sensenovaConfig(s).sensenovaAccessKeySecret,
18
- s.updateKeyVaultConfig,
19
- ]);
20
-
21
- return (
22
- <FormAction
23
- avatar={<SenseNova color={SenseNova.colorPrimary} size={56} />}
24
- description={t('sensenova.unlock.description')}
25
- title={t('sensenova.unlock.title')}
26
- >
27
- <Input.Password
28
- autoComplete={'new-password'}
29
- onChange={(e) => {
30
- setConfig(ModelProvider.SenseNova, { sensenovaAccessKeyID: e.target.value });
31
- }}
32
- placeholder={t('sensenova.sensenovaAccessKeyID.placeholder')}
33
- type={'block'}
34
- value={sensenovaAccessKeyID}
35
- />
36
- <Input.Password
37
- autoComplete={'new-password'}
38
- onChange={(e) => {
39
- setConfig(ModelProvider.SenseNova, { sensenovaAccessKeySecret: e.target.value });
40
- }}
41
- placeholder={t('sensenova.sensenovaAccessKeySecret.placeholder')}
42
- type={'block'}
43
- value={sensenovaAccessKeySecret}
44
- />
45
- </FormAction>
46
- );
47
- });
48
-
49
- export default SenseNovaForm;