@lobehub/chat 0.159.11 → 0.160.0
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/CHANGELOG.md +50 -0
- package/README.md +8 -8
- package/README.zh-CN.md +8 -8
- package/package.json +4 -2
- package/src/app/(main)/chat/@session/features/SessionHydration.tsx +2 -0
- package/src/app/trpc/{[trpc] → edge/[trpc]}/route.ts +3 -3
- package/src/config/__tests__/server.test.ts +0 -11
- package/src/config/file.ts +34 -0
- package/src/config/server/app.ts +0 -8
- package/src/config/server/provider.ts +3 -3
- package/src/database/client/models/file.ts +2 -1
- package/src/database/client/schemas/files.ts +2 -2
- package/src/features/Conversation/Error/index.tsx +13 -4
- package/src/features/Conversation/components/VirtualizedList/index.tsx +27 -21
- package/src/libs/agent-runtime/google/index.test.ts +20 -1
- package/src/libs/agent-runtime/google/index.ts +22 -9
- package/src/libs/agent-runtime/utils/uriParser.test.ts +29 -0
- package/src/libs/agent-runtime/utils/uriParser.ts +17 -9
- package/src/libs/trpc/client.ts +5 -3
- package/src/libs/trpc/index.ts +10 -34
- package/src/libs/trpc/init.ts +26 -0
- package/src/libs/trpc/middleware/password.test.ts +87 -0
- package/src/libs/trpc/middleware/password.ts +26 -0
- package/src/libs/trpc/middleware/userAuth.test.ts +44 -0
- package/src/libs/trpc/middleware/userAuth.ts +18 -0
- package/src/server/context.ts +28 -3
- package/src/server/files/s3.ts +58 -0
- package/src/server/globalConfig/index.ts +2 -0
- package/src/server/mock.ts +2 -2
- package/src/server/routers/{config → edge/config}/index.test.ts +1 -0
- package/src/server/routers/edge/upload.ts +16 -0
- package/src/server/routers/index.ts +5 -3
- package/src/services/__tests__/global.test.ts +4 -5
- package/src/services/__tests__/sync.test.ts +56 -0
- package/src/services/__tests__/upload.test.ts +72 -0
- package/src/services/_url.ts +2 -0
- package/src/services/file/client.test.ts +102 -34
- package/src/services/file/client.ts +24 -49
- package/src/services/file/type.ts +1 -2
- package/src/services/global.ts +3 -18
- package/src/services/message/type.ts +6 -3
- package/src/services/sync.ts +19 -0
- package/src/services/upload.ts +99 -0
- package/src/store/chat/slices/builtinTool/action.test.ts +4 -2
- package/src/store/chat/slices/builtinTool/action.ts +6 -3
- package/src/store/chat/slices/enchance/action.test.ts +16 -12
- package/src/store/chat/slices/message/action.test.ts +495 -24
- package/src/store/chat/slices/message/action.ts +143 -32
- package/src/store/chat/slices/message/initialState.ts +2 -2
- package/src/store/chat/slices/message/selectors.test.ts +39 -9
- package/src/store/chat/slices/message/selectors.ts +13 -3
- package/src/store/chat/slices/message/utils.ts +7 -0
- package/src/store/chat/slices/plugin/action.test.ts +7 -2
- package/src/store/chat/slices/share/action.test.ts +19 -3
- package/src/store/chat/slices/topic/action.test.ts +13 -2
- package/src/store/chat/slices/topic/action.ts +27 -6
- package/src/store/chat/slices/topic/initialState.ts +2 -0
- package/src/store/file/slices/images/action.test.ts +10 -17
- package/src/store/file/slices/images/action.ts +4 -1
- package/src/store/file/slices/tts/action.test.ts +8 -14
- package/src/store/file/slices/tts/action.ts +4 -1
- package/src/store/serverConfig/selectors.ts +1 -0
- package/src/store/serverConfig/store.ts +10 -0
- package/src/store/user/slices/common/action.ts +26 -14
- package/src/store/user/slices/sync/action.test.ts +6 -6
- package/src/store/user/slices/sync/action.ts +3 -3
- package/src/types/serverConfig.ts +1 -0
- package/src/utils/fetch.test.ts +17 -11
- package/src/utils/fetch.ts +20 -22
- package/src/app/api/files/image/imgur.ts +0 -72
- package/src/app/api/files/image/route.ts +0 -42
- /package/src/server/routers/{config → edge/config}/__snapshots__/index.test.ts.snap +0 -0
- /package/src/server/routers/{config → edge/config}/index.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.160.0](https://github.com/lobehub/lobe-chat/compare/v0.159.12...v0.160.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-05-18**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Bump version and add enable ollama env.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Bump version and add enable ollama env, closes [#2554](https://github.com/lobehub/lobe-chat/issues/2554) ([f5ce7c9](https://github.com/lobehub/lobe-chat/commit/f5ce7c9))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.159.12](https://github.com/lobehub/lobe-chat/compare/v0.159.11...v0.159.12)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-05-15**</sup>
|
|
33
|
+
|
|
34
|
+
#### ♻ Code Refactoring
|
|
35
|
+
|
|
36
|
+
- **misc**: Refactor the create message flow to fix some bugs.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Code refactoring
|
|
44
|
+
|
|
45
|
+
- **misc**: Refactor the create message flow to fix some bugs, closes [#2521](https://github.com/lobehub/lobe-chat/issues/2521) ([7263a33](https://github.com/lobehub/lobe-chat/commit/7263a33))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 0.159.11](https://github.com/lobehub/lobe-chat/compare/v0.159.10...v0.159.11)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-05-15**</sup>
|
package/README.md
CHANGED
|
@@ -230,7 +230,7 @@ In addition, these plugins are not limited to news aggregation, but can also ext
|
|
|
230
230
|
| [Social Search](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-05-02**</sup> | The Social Search provides access to tweets, users, followers, images, media and more.<br/>`social` `twitter` `x` `search` |
|
|
231
231
|
| [Search Google via Serper](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Barry** on **2024-04-30**</sup> | Google search engine via Serper.dev free API (2500x🆓/month)<br/>`web` `search` |
|
|
232
232
|
|
|
233
|
-
> 📊 Total plugins: [<kbd>**
|
|
233
|
+
> 📊 Total plugins: [<kbd>**56**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
|
|
234
234
|
|
|
235
235
|
<!-- PLUGIN LIST -->
|
|
236
236
|
|
|
@@ -262,14 +262,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
262
262
|
|
|
263
263
|
<!-- AGENT LIST -->
|
|
264
264
|
|
|
265
|
-
| Recent Submits
|
|
266
|
-
|
|
|
267
|
-
| [
|
|
268
|
-
| [
|
|
269
|
-
| [
|
|
270
|
-
| [
|
|
265
|
+
| Recent Submits | Description |
|
|
266
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
267
|
+
| [AWS Guru](https://chat-preview.lobehub.com/market?agent=aws-guru)<br/><sup>By **[wilbeibi](https://github.com/wilbeibi)** on **2024-05-15**</sup> | Agent to answer AWS questions<br/>`programming` |
|
|
268
|
+
| [Linux Buddy](https://chat-preview.lobehub.com/market?agent=linux-buddy)<br/><sup>By **[Firpo7](https://github.com/Firpo7)** on **2024-05-15**</sup> | Your Linux expert friend<br/>`linux` `technical-support` `buddy` |
|
|
269
|
+
| [Photography Critic](https://chat-preview.lobehub.com/market?agent=photography-critic)<br/><sup>By **[Justin3go](https://github.com/Justin3go)** on **2024-05-15**</sup> | Specializes in detailed analysis of photographic works, including themes, composition, technical quality, use of light, creativity, and originality.<br/>`photography` `evaluation` `analysis` `composition` `technical-quality` |
|
|
270
|
+
| [Python Buddy](https://chat-preview.lobehub.com/market?agent=python-buddy)<br/><sup>By **[Firpo7](https://github.com/Firpo7)** on **2024-05-15**</sup> | Your Python expert friend<br/>`python` `software-development` `coding` `code` `buddy` |
|
|
271
271
|
|
|
272
|
-
> 📊 Total agents: [<kbd>**
|
|
272
|
+
> 📊 Total agents: [<kbd>**258**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
273
273
|
|
|
274
274
|
<!-- AGENT LIST -->
|
|
275
275
|
|
package/README.zh-CN.md
CHANGED
|
@@ -222,7 +222,7 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
222
222
|
| [社交搜索](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-05-02**</sup> | 社交搜索提供访问推文、用户、关注者、图片、媒体等功能。<br/>`社交` `推特` `x` `搜索` |
|
|
223
223
|
| [通过 Serper 搜索 Google](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **Barry** on **2024-04-30**</sup> | 通过 Serper.dev 免费 API 进行 Google 搜索引擎(每月 2500 次🆓)<br/>`网络` `搜索` |
|
|
224
224
|
|
|
225
|
-
> 📊 Total plugins: [<kbd>**
|
|
225
|
+
> 📊 Total plugins: [<kbd>**56**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
|
|
226
226
|
|
|
227
227
|
<!-- PLUGIN LIST -->
|
|
228
228
|
|
|
@@ -250,14 +250,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
250
250
|
|
|
251
251
|
<!-- AGENT LIST -->
|
|
252
252
|
|
|
253
|
-
| 最近新增
|
|
254
|
-
|
|
|
255
|
-
| [
|
|
256
|
-
| [
|
|
257
|
-
| [
|
|
258
|
-
| [
|
|
253
|
+
| 最近新增 | 助手说明 |
|
|
254
|
+
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
255
|
+
| [AWS Guru](https://chat-preview.lobehub.com/market?agent=aws-guru)<br/><sup>By **[wilbeibi](https://github.com/wilbeibi)** on **2024-05-15**</sup> | Agent to answer AWS questions<br/>`programming` |
|
|
256
|
+
| [Linux Buddy](https://chat-preview.lobehub.com/market?agent=linux-buddy)<br/><sup>By **[Firpo7](https://github.com/Firpo7)** on **2024-05-15**</sup> | 您的 Linux 专家朋友<br/>`linux` `technical-support` `buddy` |
|
|
257
|
+
| [摄影评论家](https://chat-preview.lobehub.com/market?agent=photography-critic)<br/><sup>By **[Justin3go](https://github.com/Justin3go)** on **2024-05-15**</sup> | 擅长摄影作品细致分析,包括主题、构图、技术质量、光线使用、创意与原创性等。<br/>`摄影` `评价` `分析` `构图` `技术质量` |
|
|
258
|
+
| [Python Buddy](https://chat-preview.lobehub.com/market?agent=python-buddy)<br/><sup>By **[Firpo7](https://github.com/Firpo7)** on **2024-05-15**</sup> | 您的 Python 专家朋友<br/>`python` `软件开发` `编程` `代码` `伙伴` |
|
|
259
259
|
|
|
260
|
-
> 📊 Total agents: [<kbd>**
|
|
260
|
+
> 📊 Total agents: [<kbd>**258**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
261
261
|
|
|
262
262
|
<!-- AGENT LIST -->
|
|
263
263
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.160.0",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -85,6 +85,8 @@
|
|
|
85
85
|
"@anthropic-ai/sdk": "^0.20.9",
|
|
86
86
|
"@auth/core": "0.28.0",
|
|
87
87
|
"@aws-sdk/client-bedrock-runtime": "^3.574.0",
|
|
88
|
+
"@aws-sdk/client-s3": "^3.577.0",
|
|
89
|
+
"@aws-sdk/s3-request-presigner": "^3.577.0",
|
|
88
90
|
"@azure/openai": "1.0.0-beta.12",
|
|
89
91
|
"@cfworker/json-schema": "^1.12.8",
|
|
90
92
|
"@clerk/localizations": "2.0.0",
|
|
@@ -108,7 +110,7 @@
|
|
|
108
110
|
"@vercel/speed-insights": "^1.0.10",
|
|
109
111
|
"ahooks": "^3.7.11",
|
|
110
112
|
"ai": "3.0.19",
|
|
111
|
-
"antd": "5.17.
|
|
113
|
+
"antd": "^5.17.2",
|
|
112
114
|
"antd-style": "^3.6.2",
|
|
113
115
|
"brotli-wasm": "^3.0.0",
|
|
114
116
|
"chroma-js": "^2.4.2",
|
|
@@ -13,6 +13,7 @@ import { useSessionStore } from '@/store/session';
|
|
|
13
13
|
const SessionHydration = memo(() => {
|
|
14
14
|
const useStoreUpdater = createStoreUpdater(useSessionStore);
|
|
15
15
|
const useAgentStoreUpdater = createStoreUpdater(useAgentStore);
|
|
16
|
+
const useChatStoreUpdater = createStoreUpdater(useChatStore);
|
|
16
17
|
const [switchTopic] = useChatStore((s) => [s.switchTopic]);
|
|
17
18
|
|
|
18
19
|
// two-way bindings the url and session store
|
|
@@ -22,6 +23,7 @@ const SessionHydration = memo(() => {
|
|
|
22
23
|
);
|
|
23
24
|
useStoreUpdater('activeId', session);
|
|
24
25
|
useAgentStoreUpdater('activeId', session);
|
|
26
|
+
useChatStoreUpdater('activeId', session);
|
|
25
27
|
|
|
26
28
|
useEffect(() => {
|
|
27
29
|
const unsubscribe = useSessionStore.subscribe(
|
|
@@ -3,7 +3,7 @@ import type { NextRequest } from 'next/server';
|
|
|
3
3
|
|
|
4
4
|
import { pino } from '@/libs/logger';
|
|
5
5
|
import { createContext } from '@/server/context';
|
|
6
|
-
import {
|
|
6
|
+
import { edgeRouter } from '@/server/routers';
|
|
7
7
|
|
|
8
8
|
export const runtime = 'edge';
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ const handler = (req: NextRequest) =>
|
|
|
14
14
|
*/
|
|
15
15
|
createContext: () => createContext(req),
|
|
16
16
|
|
|
17
|
-
endpoint: '/trpc',
|
|
17
|
+
endpoint: '/trpc/edge',
|
|
18
18
|
|
|
19
19
|
onError: ({ error, path }) => {
|
|
20
20
|
pino.info(`Error in tRPC handler (edge) on path: ${path}`);
|
|
@@ -22,7 +22,7 @@ const handler = (req: NextRequest) =>
|
|
|
22
22
|
},
|
|
23
23
|
|
|
24
24
|
req,
|
|
25
|
-
router:
|
|
25
|
+
router: edgeRouter,
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
export { handler as GET, handler as POST };
|
|
@@ -33,17 +33,6 @@ describe('getServerConfig', () => {
|
|
|
33
33
|
expect(config.OPENAI_FUNCTION_REGIONS).toStrictEqual(['iad1', 'sfo1']);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
it('returns default IMGUR_CLIENT_ID when no environment variable is set', () => {
|
|
37
|
-
const config = getServerConfig();
|
|
38
|
-
expect(config.IMGUR_CLIENT_ID).toBe('e415f320d6e24f9');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('returns custom IMGUR_CLIENT_ID when environment variable is set', () => {
|
|
42
|
-
process.env.IMGUR_CLIENT_ID = 'custom-client-id';
|
|
43
|
-
const config = getServerConfig();
|
|
44
|
-
expect(config.IMGUR_CLIENT_ID).toBe('custom-client-id');
|
|
45
|
-
});
|
|
46
|
-
|
|
47
36
|
describe('index url', () => {
|
|
48
37
|
it('should return default URLs when no environment variables are set', () => {
|
|
49
38
|
const config = getServerConfig();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createEnv } from '@t3-oss/env-nextjs';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_S3_FILE_PATH = 'files';
|
|
5
|
+
|
|
6
|
+
export const getFileConfig = () => {
|
|
7
|
+
return createEnv({
|
|
8
|
+
client: {
|
|
9
|
+
NEXT_PUBLIC_S3_DOMAIN: z.string().optional(),
|
|
10
|
+
NEXT_PUBLIC_S3_FILE_PATH: z.string().optional(),
|
|
11
|
+
},
|
|
12
|
+
runtimeEnv: {
|
|
13
|
+
NEXT_PUBLIC_S3_DOMAIN: process.env.NEXT_PUBLIC_S3_DOMAIN,
|
|
14
|
+
NEXT_PUBLIC_S3_FILE_PATH: process.env.NEXT_PUBLIC_S3_FILE_PATH || DEFAULT_S3_FILE_PATH,
|
|
15
|
+
|
|
16
|
+
S3_ACCESS_KEY_ID: process.env.S3_ACCESS_KEY_ID,
|
|
17
|
+
S3_BUCKET: process.env.S3_BUCKET,
|
|
18
|
+
S3_ENDPOINT: process.env.S3_ENDPOINT,
|
|
19
|
+
S3_REGION: process.env.S3_REGION,
|
|
20
|
+
S3_SECRET_ACCESS_KEY: process.env.S3_SECRET_ACCESS_KEY,
|
|
21
|
+
},
|
|
22
|
+
server: {
|
|
23
|
+
// S3
|
|
24
|
+
S3_ACCESS_KEY_ID: z.string().optional(),
|
|
25
|
+
S3_BUCKET: z.string().optional(),
|
|
26
|
+
S3_ENDPOINT: z.string().optional(),
|
|
27
|
+
|
|
28
|
+
S3_REGION: z.string().optional(),
|
|
29
|
+
S3_SECRET_ACCESS_KEY: z.string().optional(),
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const fileEnv = getFileConfig();
|
package/src/config/server/app.ts
CHANGED
|
@@ -6,8 +6,6 @@ declare global {
|
|
|
6
6
|
interface ProcessEnv {
|
|
7
7
|
ACCESS_CODE?: string;
|
|
8
8
|
|
|
9
|
-
IMGUR_CLIENT_ID?: string;
|
|
10
|
-
|
|
11
9
|
SITE_URL?: string;
|
|
12
10
|
|
|
13
11
|
AGENTS_INDEX_URL?: string;
|
|
@@ -25,10 +23,6 @@ declare global {
|
|
|
25
23
|
}
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
// we apply a free imgur app to get a client id
|
|
29
|
-
// refs: https://apidocs.imgur.com/
|
|
30
|
-
const DEFAULT_IMAGUR_CLIENT_ID = 'e415f320d6e24f9';
|
|
31
|
-
|
|
32
26
|
export const getAppConfig = () => {
|
|
33
27
|
if (typeof process === 'undefined') {
|
|
34
28
|
throw new Error('[Server Config] you are importing a server-only module outside of server');
|
|
@@ -45,8 +39,6 @@ export const getAppConfig = () => {
|
|
|
45
39
|
|
|
46
40
|
SITE_URL: process.env.SITE_URL,
|
|
47
41
|
|
|
48
|
-
IMGUR_CLIENT_ID: process.env.IMGUR_CLIENT_ID || DEFAULT_IMAGUR_CLIENT_ID,
|
|
49
|
-
|
|
50
42
|
AGENTS_INDEX_URL: !!process.env.AGENTS_INDEX_URL
|
|
51
43
|
? process.env.AGENTS_INDEX_URL
|
|
52
44
|
: 'https://chat-agents.lobehub.com',
|
|
@@ -22,7 +22,7 @@ declare global {
|
|
|
22
22
|
// DeepSeek Provider
|
|
23
23
|
ENABLED_DEEPSEEK?: string;
|
|
24
24
|
DEEPSEEK_API_KEY?: string;
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
// ZhiPu Provider
|
|
27
27
|
ENABLED_ZHIPU?: string;
|
|
28
28
|
ZHIPU_API_KEY?: string;
|
|
@@ -113,7 +113,7 @@ export const getProviderConfig = () => {
|
|
|
113
113
|
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID || '';
|
|
114
114
|
|
|
115
115
|
const DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || '';
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || '';
|
|
118
118
|
|
|
119
119
|
const MOONSHOT_API_KEY = process.env.MOONSHOT_API_KEY || '';
|
|
@@ -221,7 +221,7 @@ export const getProviderConfig = () => {
|
|
|
221
221
|
AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID,
|
|
222
222
|
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || '',
|
|
223
223
|
|
|
224
|
-
ENABLE_OLLAMA:
|
|
224
|
+
ENABLE_OLLAMA: process.env.ENABLE_OLLAMA === '0',
|
|
225
225
|
OLLAMA_PROXY_URL: process.env.OLLAMA_PROXY_URL || '',
|
|
226
226
|
OLLAMA_MODEL_LIST: process.env.OLLAMA_MODEL_LIST || process.env.OLLAMA_CUSTOM_MODELS,
|
|
227
227
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DBModel } from '@/database/client/core/types/db';
|
|
1
2
|
import { DB_File, DB_FileSchema } from '@/database/client/schemas/files';
|
|
2
3
|
import { nanoid } from '@/utils/uuid';
|
|
3
4
|
|
|
@@ -14,7 +15,7 @@ class _FileModel extends BaseModel<'files'> {
|
|
|
14
15
|
return this._addWithSync(file, `file-${id}`);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
async findById(id: string) {
|
|
18
|
+
async findById(id: string): Promise<DBModel<DB_File>> {
|
|
18
19
|
return this.table.get(id);
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -8,7 +8,7 @@ export const DB_FileSchema = z.object({
|
|
|
8
8
|
/**
|
|
9
9
|
* file data array buffer
|
|
10
10
|
*/
|
|
11
|
-
data: z.instanceof(ArrayBuffer),
|
|
11
|
+
data: z.instanceof(ArrayBuffer).optional(),
|
|
12
12
|
/**
|
|
13
13
|
* file type
|
|
14
14
|
* @example 'image/png'
|
|
@@ -33,7 +33,7 @@ export const DB_FileSchema = z.object({
|
|
|
33
33
|
/**
|
|
34
34
|
* file url if saveMode is url
|
|
35
35
|
*/
|
|
36
|
-
url: z.string().
|
|
36
|
+
url: z.string().optional(),
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
export type DB_File = z.infer<typeof DB_FileSchema>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { IPluginErrorType, PluginErrorType } from '@lobehub/chat-plugin-sdk';
|
|
2
2
|
import type { AlertProps } from '@lobehub/ui';
|
|
3
|
-
import {
|
|
3
|
+
import { Skeleton } from 'antd';
|
|
4
|
+
import dynamic from 'next/dynamic';
|
|
5
|
+
import { Suspense, memo } from 'react';
|
|
4
6
|
|
|
5
7
|
import { AgentRuntimeErrorType, ILobeAgentRuntimeErrorType } from '@/libs/agent-runtime';
|
|
6
8
|
import { ChatErrorType, ErrorType } from '@/types/fetch';
|
|
@@ -10,9 +12,12 @@ import ClerkLogin from './ClerkLogin';
|
|
|
10
12
|
import ErrorJsonViewer from './ErrorJsonViewer';
|
|
11
13
|
import InvalidAPIKey from './InvalidAPIKey';
|
|
12
14
|
import InvalidAccessCode from './InvalidAccessCode';
|
|
13
|
-
import OllamaBizError from './OllamaBizError';
|
|
14
15
|
import OpenAiBizError from './OpenAiBizError';
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
const loading = () => <Skeleton active />;
|
|
18
|
+
|
|
19
|
+
const OllamaBizError = dynamic(() => import('./OllamaBizError'), { loading, ssr: false });
|
|
20
|
+
const PluginSettings = dynamic(() => import('./PluginSettings'), { loading, ssr: false });
|
|
16
21
|
|
|
17
22
|
// Config for the errorMessage display
|
|
18
23
|
export const getErrorAlertConfig = (
|
|
@@ -95,4 +100,8 @@ const ErrorMessageExtra = memo<{ data: ChatMessage }>(({ data }) => {
|
|
|
95
100
|
}
|
|
96
101
|
});
|
|
97
102
|
|
|
98
|
-
export default
|
|
103
|
+
export default memo<{ data: ChatMessage }>(({ data }) => (
|
|
104
|
+
<Suspense fallback={<Skeleton active style={{ width: '100%' }} />}>
|
|
105
|
+
<ErrorMessageExtra data={data} />
|
|
106
|
+
</Suspense>
|
|
107
|
+
));
|
|
@@ -29,14 +29,17 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
|
|
|
29
29
|
|
|
30
30
|
const [id] = useChatStore((s) => [chatSelectors.currentChatKey(s)]);
|
|
31
31
|
|
|
32
|
-
const [activeTopicId, useFetchMessages, isFirstLoading] = useChatStore(
|
|
33
|
-
s
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
const [activeTopicId, useFetchMessages, isFirstLoading, isCurrentChatLoaded] = useChatStore(
|
|
33
|
+
(s) => [
|
|
34
|
+
s.activeTopicId,
|
|
35
|
+
s.useFetchMessages,
|
|
36
|
+
chatSelectors.currentChatLoadingState(s),
|
|
37
|
+
chatSelectors.isCurrentChatLoaded(s),
|
|
38
|
+
],
|
|
39
|
+
);
|
|
37
40
|
|
|
38
41
|
const [sessionId] = useSessionStore((s) => [s.activeId]);
|
|
39
|
-
|
|
42
|
+
useFetchMessages(sessionId, activeTopicId);
|
|
40
43
|
|
|
41
44
|
const data = useChatStore((s) => {
|
|
42
45
|
const showInboxWelcome = chatSelectors.showInboxWelcome(s);
|
|
@@ -77,23 +80,26 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
|
|
|
77
80
|
[mobile],
|
|
78
81
|
);
|
|
79
82
|
|
|
80
|
-
// first time loading
|
|
83
|
+
// first time loading or not loaded
|
|
81
84
|
if (isFirstLoading) return <SkeletonList mobile={mobile} />;
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
if (!isCurrentChatLoaded)
|
|
87
|
+
// use skeleton list when not loaded in server mode due to the loading duration is much longer than client mode
|
|
88
|
+
return isServerMode ? (
|
|
89
|
+
<SkeletonList mobile={mobile} />
|
|
90
|
+
) : (
|
|
91
|
+
// in client mode and switch page, using the center loading for smooth transition
|
|
92
|
+
<Center height={'100%'} width={'100%'}>
|
|
93
|
+
<Icon
|
|
94
|
+
icon={Loader2Icon}
|
|
95
|
+
size={{ fontSize: 32 }}
|
|
96
|
+
spin
|
|
97
|
+
style={{ color: theme.colorTextTertiary }}
|
|
98
|
+
/>
|
|
99
|
+
</Center>
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
return (
|
|
97
103
|
<Flexbox height={'100%'}>
|
|
98
104
|
<Virtuoso
|
|
99
105
|
atBottomStateChange={setAtBottom}
|
|
@@ -560,7 +560,7 @@ describe('LobeGoogleAI', () => {
|
|
|
560
560
|
});
|
|
561
561
|
});
|
|
562
562
|
|
|
563
|
-
it('should correctly convert message with
|
|
563
|
+
it('should correctly convert message with inline base64 image parts', () => {
|
|
564
564
|
const message: OpenAIChatMessage = {
|
|
565
565
|
role: 'user',
|
|
566
566
|
content: [
|
|
@@ -571,6 +571,25 @@ describe('LobeGoogleAI', () => {
|
|
|
571
571
|
|
|
572
572
|
const converted = instance['convertOAIMessagesToGoogleMessage'](message);
|
|
573
573
|
|
|
574
|
+
expect(converted).toEqual({
|
|
575
|
+
role: 'user',
|
|
576
|
+
parts: [
|
|
577
|
+
{ text: 'Check this image:' },
|
|
578
|
+
{ inlineData: { data: '...', mimeType: 'image/png' } },
|
|
579
|
+
],
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
it.skip('should correctly convert message with image url parts', () => {
|
|
583
|
+
const message: OpenAIChatMessage = {
|
|
584
|
+
role: 'user',
|
|
585
|
+
content: [
|
|
586
|
+
{ type: 'text', text: 'Check this image:' },
|
|
587
|
+
{ type: 'image_url', image_url: { url: 'https://image-file.com' } },
|
|
588
|
+
],
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
const converted = instance['convertOAIMessagesToGoogleMessage'](message);
|
|
592
|
+
|
|
574
593
|
expect(converted).toEqual({
|
|
575
594
|
role: 'user',
|
|
576
595
|
parts: [
|
|
@@ -115,18 +115,31 @@ export class LobeGoogleAI implements LobeRuntimeAI {
|
|
|
115
115
|
return { text: content.text };
|
|
116
116
|
}
|
|
117
117
|
case 'image_url': {
|
|
118
|
-
const { mimeType, base64 } = parseDataUri(content.image_url.url);
|
|
118
|
+
const { mimeType, base64, type } = parseDataUri(content.image_url.url);
|
|
119
119
|
|
|
120
|
-
if (
|
|
121
|
-
|
|
120
|
+
if (type === 'base64') {
|
|
121
|
+
if (!base64) {
|
|
122
|
+
throw new TypeError("Image URL doesn't contain base64 data");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
inlineData: {
|
|
127
|
+
data: base64,
|
|
128
|
+
mimeType: mimeType || 'image/png',
|
|
129
|
+
},
|
|
130
|
+
};
|
|
122
131
|
}
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
133
|
+
// if (type === 'url') {
|
|
134
|
+
// return {
|
|
135
|
+
// fileData: {
|
|
136
|
+
// fileUri: content.image_url.url,
|
|
137
|
+
// mimeType: mimeType || 'image/png',
|
|
138
|
+
// },
|
|
139
|
+
// };
|
|
140
|
+
// }
|
|
141
|
+
|
|
142
|
+
throw new TypeError(`currently we don't support image url: ${content.image_url.url}`);
|
|
130
143
|
}
|
|
131
144
|
}
|
|
132
145
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { parseDataUri } from './uriParser';
|
|
4
|
+
|
|
5
|
+
describe('parseDataUri', () => {
|
|
6
|
+
it('should parse a valid data URI', () => {
|
|
7
|
+
const dataUri = 'data:image/png;base64,abc';
|
|
8
|
+
const result = parseDataUri(dataUri);
|
|
9
|
+
expect(result).toEqual({ base64: 'abc', mimeType: 'image/png', type: 'base64' });
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should parse a valid URL', () => {
|
|
13
|
+
const url = 'https://example.com/image.jpg';
|
|
14
|
+
const result = parseDataUri(url);
|
|
15
|
+
expect(result).toEqual({ base64: null, mimeType: null, type: 'url' });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return null for an invalid input', () => {
|
|
19
|
+
const invalidInput = 'invalid-data';
|
|
20
|
+
const result = parseDataUri(invalidInput);
|
|
21
|
+
expect(result).toEqual({ base64: null, mimeType: null, type: null });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should handle an empty input', () => {
|
|
25
|
+
const emptyInput = '';
|
|
26
|
+
const result = parseDataUri(emptyInput);
|
|
27
|
+
expect(result).toEqual({ base64: null, mimeType: null, type: null });
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
interface UriParserResult {
|
|
2
|
+
base64: string | null;
|
|
3
|
+
mimeType: string | null;
|
|
4
|
+
type: 'url' | 'base64' | null;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const parseDataUri = (dataUri: string): UriParserResult => {
|
|
4
8
|
// 正则表达式匹配整个 Data URI 结构
|
|
5
9
|
const dataUriMatch = dataUri.match(/^data:([^;]+);base64,(.+)$/);
|
|
6
10
|
|
|
7
|
-
// 如果匹配成功,则返回 mimeType 和 base64,否则返回 null
|
|
8
11
|
if (dataUriMatch) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
mimeType: dataUriMatch[1],
|
|
12
|
-
};
|
|
12
|
+
// 如果是合法的 Data URI
|
|
13
|
+
return { base64: dataUriMatch[2], mimeType: dataUriMatch[1], type: 'base64' };
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
try {
|
|
17
|
+
new URL(dataUri);
|
|
18
|
+
// 如果是合法的 URL
|
|
19
|
+
return { base64: null, mimeType: null, type: 'url' };
|
|
20
|
+
} catch {
|
|
21
|
+
// 既不是 Data URI 也不是合法 URL
|
|
22
|
+
return { base64: null, mimeType: null, type: null };
|
|
23
|
+
}
|
|
16
24
|
};
|
package/src/libs/trpc/client.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { createTRPCClient, httpBatchLink } from '@trpc/client';
|
|
2
2
|
import superjson from 'superjson';
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { EdgeRouter } from '@/server/routers';
|
|
5
|
+
import { createHeaderWithAuth } from '@/services/_auth';
|
|
5
6
|
|
|
6
|
-
export const
|
|
7
|
+
export const edgeClient = createTRPCClient<EdgeRouter>({
|
|
7
8
|
links: [
|
|
8
9
|
httpBatchLink({
|
|
10
|
+
headers: async () => createHeaderWithAuth(),
|
|
9
11
|
transformer: superjson,
|
|
10
|
-
url: '/trpc',
|
|
12
|
+
url: '/trpc/edge',
|
|
11
13
|
}),
|
|
12
14
|
],
|
|
13
15
|
});
|