@lobehub/chat 1.16.2 → 1.16.4

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.

Potentially problematic release.


This version of @lobehub/chat might be problematic. Click here for more details.

Files changed (79) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +8 -8
  3. package/README.zh-CN.md +8 -8
  4. package/docs/self-hosting/advanced/auth/next-auth/logto.zh-CN.mdx +2 -2
  5. package/locales/ar/common.json +1 -1
  6. package/locales/ar/error.json +2 -1
  7. package/locales/ar/file.json +2 -0
  8. package/locales/bg-BG/common.json +1 -1
  9. package/locales/bg-BG/error.json +2 -1
  10. package/locales/bg-BG/file.json +2 -0
  11. package/locales/de-DE/common.json +1 -1
  12. package/locales/de-DE/error.json +2 -1
  13. package/locales/de-DE/file.json +2 -0
  14. package/locales/en-US/common.json +1 -1
  15. package/locales/en-US/error.json +2 -1
  16. package/locales/en-US/file.json +2 -0
  17. package/locales/es-ES/common.json +1 -1
  18. package/locales/es-ES/error.json +2 -1
  19. package/locales/es-ES/file.json +2 -0
  20. package/locales/fr-FR/common.json +1 -1
  21. package/locales/fr-FR/error.json +2 -1
  22. package/locales/fr-FR/file.json +2 -0
  23. package/locales/it-IT/common.json +1 -1
  24. package/locales/it-IT/error.json +2 -1
  25. package/locales/it-IT/file.json +2 -0
  26. package/locales/ja-JP/common.json +1 -1
  27. package/locales/ja-JP/error.json +2 -1
  28. package/locales/ja-JP/file.json +2 -0
  29. package/locales/ko-KR/common.json +1 -1
  30. package/locales/ko-KR/error.json +2 -1
  31. package/locales/ko-KR/file.json +2 -0
  32. package/locales/nl-NL/common.json +1 -1
  33. package/locales/nl-NL/error.json +2 -1
  34. package/locales/nl-NL/file.json +2 -0
  35. package/locales/pl-PL/common.json +1 -1
  36. package/locales/pl-PL/error.json +2 -1
  37. package/locales/pl-PL/file.json +2 -0
  38. package/locales/pt-BR/common.json +1 -1
  39. package/locales/pt-BR/error.json +2 -1
  40. package/locales/pt-BR/file.json +2 -0
  41. package/locales/ru-RU/common.json +1 -1
  42. package/locales/ru-RU/error.json +2 -1
  43. package/locales/ru-RU/file.json +2 -0
  44. package/locales/tr-TR/common.json +1 -1
  45. package/locales/tr-TR/error.json +2 -1
  46. package/locales/tr-TR/file.json +2 -0
  47. package/locales/vi-VN/common.json +1 -1
  48. package/locales/vi-VN/error.json +2 -1
  49. package/locales/vi-VN/file.json +2 -0
  50. package/locales/zh-CN/common.json +1 -1
  51. package/locales/zh-CN/error.json +2 -1
  52. package/locales/zh-CN/file.json +2 -0
  53. package/locales/zh-TW/common.json +1 -1
  54. package/locales/zh-TW/error.json +2 -1
  55. package/locales/zh-TW/file.json +2 -0
  56. package/package.json +4 -4
  57. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/File.tsx +4 -1
  58. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/Image.tsx +4 -1
  59. package/src/app/(main)/files/loading.tsx +3 -1
  60. package/src/components/404/index.tsx +5 -1
  61. package/src/components/CircleLoading/index.tsx +3 -1
  62. package/src/components/FullscreenLoading/index.tsx +6 -2
  63. package/src/config/modelProviders/stepfun.ts +4 -0
  64. package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +3 -3
  65. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/List.tsx +3 -3
  66. package/src/libs/agent-runtime/google/index.test.ts +4 -1
  67. package/src/libs/agent-runtime/google/index.ts +3 -3
  68. package/src/libs/agent-runtime/utils/anthropicHelpers.test.ts +9 -3
  69. package/src/libs/agent-runtime/utils/anthropicHelpers.ts +2 -2
  70. package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.test.ts +26 -2
  71. package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +4 -0
  72. package/src/libs/agent-runtime/utils/openaiHelpers.test.ts +146 -0
  73. package/src/libs/agent-runtime/utils/openaiHelpers.ts +40 -0
  74. package/src/libs/agent-runtime/zhipu/index.ts +5 -36
  75. package/src/locales/default/common.ts +1 -1
  76. package/src/locales/default/error.ts +2 -1
  77. package/src/locales/default/file.ts +2 -0
  78. package/src/utils/imageToBase64.test.ts +2 -1
  79. package/src/utils/imageToBase64.ts +16 -7
@@ -0,0 +1,40 @@
1
+ import OpenAI from 'openai';
2
+
3
+ import { imageUrlToBase64 } from '@/utils/imageToBase64';
4
+
5
+ import { parseDataUri } from './uriParser';
6
+
7
+ export const convertMessageContent = async (
8
+ content: OpenAI.ChatCompletionContentPart,
9
+ ): Promise<OpenAI.ChatCompletionContentPart> => {
10
+ if (content.type === 'image_url') {
11
+ const { type } = parseDataUri(content.image_url.url);
12
+
13
+ if (type === 'url' && process.env.LLM_VISION_IMAGE_USE_BASE64 === '1') {
14
+ const { base64, mimeType } = await imageUrlToBase64(content.image_url.url);
15
+
16
+ return {
17
+ ...content,
18
+ image_url: { ...content.image_url, url: `data:${mimeType};base64,${base64}` },
19
+ };
20
+ }
21
+ }
22
+
23
+ return content;
24
+ };
25
+
26
+ export const convertOpenAIMessages = async (messages: OpenAI.ChatCompletionMessageParam[]) => {
27
+ return (await Promise.all(
28
+ messages.map(async (message) => ({
29
+ ...message,
30
+ content:
31
+ typeof message.content === 'string'
32
+ ? message.content
33
+ : await Promise.all(
34
+ (message.content || []).map((c) =>
35
+ convertMessageContent(c as OpenAI.ChatCompletionContentPart),
36
+ ),
37
+ ),
38
+ })),
39
+ )) as OpenAI.ChatCompletionMessageParam[];
40
+ };
@@ -2,19 +2,14 @@ import OpenAI, { ClientOptions } from 'openai';
2
2
 
3
3
  import { LobeRuntimeAI } from '../BaseAI';
4
4
  import { AgentRuntimeErrorType } from '../error';
5
- import {
6
- ChatCompetitionOptions,
7
- ChatStreamPayload,
8
- ModelProvider,
9
- OpenAIChatMessage,
10
- } from '../types';
5
+ import { ChatCompetitionOptions, ChatStreamPayload, ModelProvider } from '../types';
11
6
  import { AgentRuntimeError } from '../utils/createError';
12
7
  import { debugStream } from '../utils/debugStream';
13
8
  import { desensitizeUrl } from '../utils/desensitizeUrl';
14
9
  import { handleOpenAIError } from '../utils/handleOpenAIError';
10
+ import { convertOpenAIMessages } from '../utils/openaiHelpers';
15
11
  import { StreamingResponse } from '../utils/response';
16
12
  import { OpenAIStream } from '../utils/streams';
17
- import { parseDataUri } from '../utils/uriParser';
18
13
  import { generateApiToken } from './authToken';
19
14
 
20
15
  const DEFAULT_BASE_URL = 'https://open.bigmodel.cn/api/paas/v4';
@@ -52,7 +47,7 @@ export class LobeZhipuAI implements LobeRuntimeAI {
52
47
 
53
48
  async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) {
54
49
  try {
55
- const params = this.buildCompletionsParams(payload);
50
+ const params = await this.buildCompletionsParams(payload);
56
51
 
57
52
  const response = await this.client.chat.completions.create(
58
53
  params as unknown as OpenAI.ChatCompletionCreateParamsStreaming,
@@ -85,11 +80,11 @@ export class LobeZhipuAI implements LobeRuntimeAI {
85
80
  }
86
81
  }
87
82
 
88
- private buildCompletionsParams(payload: ChatStreamPayload) {
83
+ private async buildCompletionsParams(payload: ChatStreamPayload) {
89
84
  const { messages, temperature, top_p, ...params } = payload;
90
85
 
91
86
  return {
92
- messages: messages.map((m) => this.transformMessage(m)) as any,
87
+ messages: await convertOpenAIMessages(messages as any),
93
88
  ...params,
94
89
  do_sample: temperature === 0,
95
90
  stream: true,
@@ -99,32 +94,6 @@ export class LobeZhipuAI implements LobeRuntimeAI {
99
94
  top_p: top_p === 1 ? 0.99 : top_p,
100
95
  };
101
96
  }
102
-
103
- // TODO: 临时处理,后续需要移除
104
- private transformMessage = (message: OpenAIChatMessage): OpenAIChatMessage => {
105
- return {
106
- ...message,
107
- content:
108
- typeof message.content === 'string'
109
- ? message.content
110
- : message.content.map((c) => {
111
- switch (c.type) {
112
- default:
113
- case 'text': {
114
- return c;
115
- }
116
-
117
- case 'image_url': {
118
- const { base64 } = parseDataUri(c.image_url.url);
119
- return {
120
- image_url: { ...c.image_url, url: base64 || c.image_url.url },
121
- type: 'image_url',
122
- };
123
- }
124
- }
125
- }),
126
- };
127
- };
128
97
  }
129
98
 
130
99
  export default LobeZhipuAI;
@@ -10,7 +10,7 @@ export default {
10
10
  title: '{{name}} 开始公测',
11
11
  },
12
12
  },
13
- appInitializing: '应用启动中,请耐心等待...',
13
+ appInitializing: '应用启动中...',
14
14
  autoGenerate: '自动补全',
15
15
  autoGenerateTooltip: '基于提示词自动补全助手描述',
16
16
  autoGenerateTooltipDisabled: '请填写提示词后使用自动补全功能',
@@ -16,7 +16,8 @@ export default {
16
16
  fetchErrorDetail: '错误详情',
17
17
  notFound: {
18
18
  backHome: '返回首页',
19
- desc: '我们找不到你正在寻找的页面,请检查链接是否正确',
19
+ check: '请检查你的 URL 是否正确',
20
+ desc: '我们找不到你寻找的页面',
20
21
  title: '进入了未知领域?',
21
22
  },
22
23
  pluginSettings: {
@@ -21,6 +21,7 @@ export default {
21
21
  embeddingStatus: '向量化',
22
22
  },
23
23
  },
24
+ empty: '暂无已上传文件/文件夹',
24
25
  header: {
25
26
  actions: {
26
27
  newFolder: '新建文件夹',
@@ -38,6 +39,7 @@ export default {
38
39
  new: '新建知识库',
39
40
  title: '知识库',
40
41
  },
42
+ networkError: '获取知识库失败,请检测网络连接后重试',
41
43
  notSupportGuide: {
42
44
  desc: '当前部署实例为客户端数据库模式,无法使用文件管理功能。请切换到<1>服务端数据库部署模式</1>,或直接使用 <3>LobeChat Cloud</3>',
43
45
  features: {
@@ -72,13 +72,14 @@ describe('imageUrlToBase64', () => {
72
72
  it('should convert image URL to base64 string', async () => {
73
73
  mockFetch.mockResolvedValue({
74
74
  arrayBuffer: () => Promise.resolve(mockArrayBuffer),
75
+ blob: () => Promise.resolve(new Blob([mockArrayBuffer], { type: 'image/jpg' })),
75
76
  });
76
77
 
77
78
  const result = await imageUrlToBase64('https://example.com/image.jpg');
78
79
 
79
80
  expect(mockFetch).toHaveBeenCalledWith('https://example.com/image.jpg');
80
81
  expect(global.btoa).toHaveBeenCalled();
81
- expect(result).toBe('mockBase64String');
82
+ expect(result).toEqual({ base64: 'mockBase64String', mimeType: 'image/jpg' });
82
83
  });
83
84
 
84
85
  it('should throw an error when fetch fails', async () => {
@@ -36,16 +36,25 @@ export const imageToBase64 = ({
36
36
  return canvas.toDataURL(type);
37
37
  };
38
38
 
39
- export const imageUrlToBase64 = async (imageUrl: string): Promise<string> => {
39
+ export const imageUrlToBase64 = async (
40
+ imageUrl: string,
41
+ ): Promise<{ base64: string; mimeType: string }> => {
40
42
  try {
41
43
  const res = await fetch(imageUrl);
42
- const arrayBuffer = await res.arrayBuffer();
44
+ const blob = await res.blob();
45
+ const arrayBuffer = await blob.arrayBuffer();
43
46
 
44
- return typeof btoa === 'function'
45
- ? btoa(
46
- new Uint8Array(arrayBuffer).reduce((data, byte) => data + String.fromCharCode(byte), ''),
47
- )
48
- : Buffer.from(arrayBuffer).toString('base64');
47
+ const base64 =
48
+ typeof btoa === 'function'
49
+ ? btoa(
50
+ new Uint8Array(arrayBuffer).reduce(
51
+ (data, byte) => data + String.fromCharCode(byte),
52
+ '',
53
+ ),
54
+ )
55
+ : Buffer.from(arrayBuffer).toString('base64');
56
+
57
+ return { base64, mimeType: blob.type };
49
58
  } catch (error) {
50
59
  console.error('Error converting image to base64:', error);
51
60
  throw error;