@lobehub/chat 0.162.18 → 0.162.20
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 +42 -0
- package/docs/self-hosting/platform/zeabur.mdx +48 -0
- package/docs/self-hosting/platform/zeabur.zh-CN.mdx +48 -0
- package/package.json +1 -1
- package/src/app/(main)/chat/@session/features/SessionListContent/Inbox/index.tsx +10 -1
- package/src/app/(main)/chat/@session/features/SessionListContent/List/index.tsx +14 -4
- package/src/app/(main)/chat/@session/features/SessionListContent/useSwitchSession.ts +26 -0
- package/src/features/Conversation/Error/APIKeyForm/ProviderApiKeyForm.tsx +1 -1
- package/src/store/session/slices/session/action.test.ts +1 -1
- package/src/store/session/slices/session/action.ts +14 -15
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.162.20](https://github.com/lobehub/lobe-chat/compare/v0.162.19...v0.162.20)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-06-08**</sup>
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
|
|
11
|
+
<details>
|
|
12
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
13
|
+
|
|
14
|
+
</details>
|
|
15
|
+
|
|
16
|
+
<div align="right">
|
|
17
|
+
|
|
18
|
+
[](#readme-top)
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
### [Version 0.162.19](https://github.com/lobehub/lobe-chat/compare/v0.162.18...v0.162.19)
|
|
23
|
+
|
|
24
|
+
<sup>Released on **2024-06-07**</sup>
|
|
25
|
+
|
|
26
|
+
#### 🐛 Bug Fixes
|
|
27
|
+
|
|
28
|
+
- **misc**: Fix OpenAi BaseURL in api form.
|
|
29
|
+
|
|
30
|
+
<br/>
|
|
31
|
+
|
|
32
|
+
<details>
|
|
33
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
34
|
+
|
|
35
|
+
#### What's fixed
|
|
36
|
+
|
|
37
|
+
- **misc**: Fix OpenAi BaseURL in api form, closes [#2806](https://github.com/lobehub/lobe-chat/issues/2806) ([1392957](https://github.com/lobehub/lobe-chat/commit/1392957))
|
|
38
|
+
|
|
39
|
+
</details>
|
|
40
|
+
|
|
41
|
+
<div align="right">
|
|
42
|
+
|
|
43
|
+
[](#readme-top)
|
|
44
|
+
|
|
45
|
+
</div>
|
|
46
|
+
|
|
5
47
|
### [Version 0.162.18](https://github.com/lobehub/lobe-chat/compare/v0.162.17...v0.162.18)
|
|
6
48
|
|
|
7
49
|
<sup>Released on **2024-06-06**</sup>
|
|
@@ -35,3 +35,51 @@ You can use the subdomain provided by Zeabur, or choose to bind a custom domain.
|
|
|
35
35
|
|
|
36
36
|
[deploy-button-image]: https://zeabur.com/button.svg
|
|
37
37
|
[deploy-link]: https://zeabur.com/templates/VZGGTI
|
|
38
|
+
|
|
39
|
+
# Deploy LobeChat with Zeabur as serverless function
|
|
40
|
+
|
|
41
|
+
>Note: There are still issues with [middlewares and rewrites of next.js on Zeabur](https://github.com/lobehub/lobe-chat/pull/2775?notification_referrer_id=NT_kwDOAdi2DrQxMDkyODQ4MDc2NTozMDk3OTU5OA#issuecomment-2146713899), use at your own risk!
|
|
42
|
+
|
|
43
|
+
Since Zeabur does NOT officially support FREE users deploy containerized service, you may wish to deploy LobeChat as a serverless function service.
|
|
44
|
+
To deploy LobeChat as a serverless function service on Zeabur, you can follow the steps below:
|
|
45
|
+
|
|
46
|
+
## Zeabur Deployment Process
|
|
47
|
+
|
|
48
|
+
<Steps>
|
|
49
|
+
|
|
50
|
+
### Fork LobeChat
|
|
51
|
+
|
|
52
|
+
### Add Zeabur pack config file
|
|
53
|
+
|
|
54
|
+
Add a `zbpack.json` configuration file with the following content to the root dir of your fork:
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"serverless": true,
|
|
58
|
+
"ignore_dockerfile": true
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Prepare your OpenAI API Key
|
|
63
|
+
|
|
64
|
+
Go to [OpenAI API Key](https://platform.openai.com/account/api-keys) to get your OpenAI API Key.
|
|
65
|
+
|
|
66
|
+
### Login to your [Zeabur dashboard](https://dash.zeabur.com)
|
|
67
|
+
|
|
68
|
+
If you do not already have an account, you will need to register one.
|
|
69
|
+
|
|
70
|
+
### Create a project and service
|
|
71
|
+
|
|
72
|
+
Create a project, then create a service under this project.
|
|
73
|
+
|
|
74
|
+
### Link your fork of LobeChat to the just created Zeabur service.
|
|
75
|
+
|
|
76
|
+
When adding service, choose github.
|
|
77
|
+
This may triger a oAuth depend on varies factors like how you login to Zeabur and if you have already authorized Zeabur to access all your repos
|
|
78
|
+
|
|
79
|
+
### Bind a custom domain (optional)
|
|
80
|
+
|
|
81
|
+
You can create a subdomain provided by Zeabur, or choose to bind a custom domain. Currently, the domains provided by Zeabur have not been contaminated, and most regions can connect directly.
|
|
82
|
+
|
|
83
|
+
### Zeabur shall start auto build and you should be able to access it by the domain of your choice after a while.
|
|
84
|
+
|
|
85
|
+
</Steps>
|
|
@@ -34,3 +34,51 @@ tags:
|
|
|
34
34
|
|
|
35
35
|
[deploy-button-image]: https://zeabur.com/button.svg
|
|
36
36
|
[deploy-link]: https://zeabur.com/templates/VZGGTI
|
|
37
|
+
|
|
38
|
+
# 使用 Zeabur 将 LobeChat 部署为无服务器函数
|
|
39
|
+
|
|
40
|
+
>**注意:** 仍然存在关于 [Zeabur 上 next.js 的中间件和重写问题](https://github.com/lobehub/lobe-chat/pull/2775?notification_referrer_id=NT_kwDOAdi2DrQxMDkyODQ4MDc2NTozMDk3OTU5OA#issuecomment-2146713899),请自担风险!
|
|
41
|
+
|
|
42
|
+
由于 Zeabur 并未官方支持免费用户部署容器化服务,您可能希望将 LobeChat 部署为无服务器函数服务。
|
|
43
|
+
要在 Zeabur 上将 LobeChat 部署为无服务器函数服务,您可以按照以下步骤操作:
|
|
44
|
+
|
|
45
|
+
## Zeabur 部署流程
|
|
46
|
+
|
|
47
|
+
<Steps>
|
|
48
|
+
|
|
49
|
+
### Fork LobeChat
|
|
50
|
+
|
|
51
|
+
### 添加 Zeabur 打包配置文件
|
|
52
|
+
|
|
53
|
+
在您的分支的根目录下添加一个 `zbpack.json` 配置文件,内容如下:
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"serverless": true,
|
|
57
|
+
"ignore_dockerfile": true
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 准备您的 OpenAI API 密钥
|
|
62
|
+
|
|
63
|
+
前往 [OpenAI API 密钥](https://platform.openai.com/account/api-keys) 获取您的 OpenAI API 密钥。
|
|
64
|
+
|
|
65
|
+
### 登录到您的 [Zeabur 仪表板](https://dash.zeabur.com)
|
|
66
|
+
|
|
67
|
+
如果您尚未拥有一个账号,您需要注册一个。
|
|
68
|
+
|
|
69
|
+
### 创建项目与服务。
|
|
70
|
+
|
|
71
|
+
创建一个项目,并再这个项目下新建一个服务。
|
|
72
|
+
|
|
73
|
+
### 将您的 LobeChat 分支链接到刚创建的 Zeabur 服务。
|
|
74
|
+
|
|
75
|
+
在添加服务时,选择 github。
|
|
76
|
+
这可能会触发一个 oAuth,取决于诸如您如何登录到 Zeabur以及您是否已经授权 Zeabur 访问所有您的存储库等各种因素。
|
|
77
|
+
|
|
78
|
+
### 绑定自定义域名(可选)
|
|
79
|
+
|
|
80
|
+
您可以创建 Zeabur 提供的子域名,或选择绑定自定义域名。目前,Zeabur 提供的域名尚未受到污染,大多数地区可以直接连接。
|
|
81
|
+
|
|
82
|
+
### Zeabur 将开始自动构建,您应该可以在一段时间后通过您选择的域名访问它。
|
|
83
|
+
|
|
84
|
+
</Steps>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.162.
|
|
3
|
+
"version": "0.162.20",
|
|
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",
|
|
@@ -9,14 +9,23 @@ import { useServerConfigStore } from '@/store/serverConfig';
|
|
|
9
9
|
import { useSessionStore } from '@/store/session';
|
|
10
10
|
|
|
11
11
|
import ListItem from '../ListItem';
|
|
12
|
+
import { useSwitchSession } from '../useSwitchSession';
|
|
12
13
|
|
|
13
14
|
const Inbox = memo(() => {
|
|
14
15
|
const { t } = useTranslation('chat');
|
|
15
16
|
const mobile = useServerConfigStore((s) => s.isMobile);
|
|
16
17
|
const activeId = useSessionStore((s) => s.activeId);
|
|
18
|
+
const switchSession = useSwitchSession();
|
|
17
19
|
|
|
18
20
|
return (
|
|
19
|
-
<Link
|
|
21
|
+
<Link
|
|
22
|
+
aria-label={t('inbox.title')}
|
|
23
|
+
href={SESSION_CHAT_URL(INBOX_SESSION_ID, mobile)}
|
|
24
|
+
onClick={(e) => {
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
switchSession(INBOX_SESSION_ID);
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
20
29
|
<ListItem
|
|
21
30
|
active={activeId === INBOX_SESSION_ID}
|
|
22
31
|
avatar={DEFAULT_INBOX_AVATAR}
|
|
@@ -13,6 +13,7 @@ import { sessionSelectors } from '@/store/session/selectors';
|
|
|
13
13
|
import { LobeAgentSession } from '@/types/session';
|
|
14
14
|
|
|
15
15
|
import SkeletonList from '../../SkeletonList';
|
|
16
|
+
import { useSwitchSession } from '../useSwitchSession';
|
|
16
17
|
import AddButton from './AddButton';
|
|
17
18
|
import SessionItem from './Item';
|
|
18
19
|
|
|
@@ -28,19 +29,28 @@ interface SessionListProps {
|
|
|
28
29
|
}
|
|
29
30
|
const SessionList = memo<SessionListProps>(({ dataSource, groupId, showAddButton = true }) => {
|
|
30
31
|
const { t } = useTranslation('chat');
|
|
31
|
-
const isInit = useSessionStore((s) => sessionSelectors.isSessionListInit(s));
|
|
32
|
-
const { showCreateSession } = useServerConfigStore(featureFlagsSelectors);
|
|
33
|
-
|
|
34
32
|
const { styles } = useStyles();
|
|
35
33
|
|
|
34
|
+
const isInit = useSessionStore(sessionSelectors.isSessionListInit);
|
|
35
|
+
const { showCreateSession } = useServerConfigStore(featureFlagsSelectors);
|
|
36
36
|
const mobile = useServerConfigStore((s) => s.isMobile);
|
|
37
|
+
|
|
38
|
+
const switchSession = useSwitchSession();
|
|
39
|
+
|
|
37
40
|
const isEmpty = !dataSource || dataSource.length === 0;
|
|
38
41
|
return !isInit ? (
|
|
39
42
|
<SkeletonList />
|
|
40
43
|
) : !isEmpty ? (
|
|
41
44
|
dataSource.map(({ id }) => (
|
|
42
45
|
<LazyLoad className={styles} key={id}>
|
|
43
|
-
<Link
|
|
46
|
+
<Link
|
|
47
|
+
aria-label={id}
|
|
48
|
+
href={SESSION_CHAT_URL(id, mobile)}
|
|
49
|
+
onClick={(e) => {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
switchSession(id);
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
44
54
|
<SessionItem id={id} />
|
|
45
55
|
</Link>
|
|
46
56
|
</LazyLoad>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useQueryRoute } from '@/hooks/useQueryRoute';
|
|
4
|
+
import { useServerConfigStore } from '@/store/serverConfig';
|
|
5
|
+
import { useSessionStore } from '@/store/session';
|
|
6
|
+
|
|
7
|
+
export const useSwitchSession = () => {
|
|
8
|
+
const switchSession = useSessionStore((s) => s.switchSession);
|
|
9
|
+
const mobile = useServerConfigStore((s) => s.isMobile);
|
|
10
|
+
const router = useQueryRoute();
|
|
11
|
+
|
|
12
|
+
return useCallback(
|
|
13
|
+
(id: string) => {
|
|
14
|
+
switchSession(id);
|
|
15
|
+
|
|
16
|
+
if (mobile) {
|
|
17
|
+
setTimeout(() => {
|
|
18
|
+
router.push('/chat', {
|
|
19
|
+
query: { session: id, showMobileWorkspace: 'true' },
|
|
20
|
+
});
|
|
21
|
+
}, 50);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
[mobile],
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -51,7 +51,7 @@ const ProviderApiKeyForm = memo<ProviderApiKeyFormProps>(
|
|
|
51
51
|
(showProxy ? (
|
|
52
52
|
<Input
|
|
53
53
|
onChange={(e) => {
|
|
54
|
-
setConfig(provider, {
|
|
54
|
+
setConfig(provider, { baseURL: e.target.value });
|
|
55
55
|
}}
|
|
56
56
|
placeholder={'https://api.openai.com/v1'}
|
|
57
57
|
type={'block'}
|
|
@@ -35,10 +35,9 @@ const SEARCH_SESSIONS_KEY = 'searchSessions';
|
|
|
35
35
|
/* eslint-disable typescript-sort-keys/interface */
|
|
36
36
|
export interface SessionAction {
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
* @param sessionId
|
|
38
|
+
* switch the session
|
|
40
39
|
*/
|
|
41
|
-
|
|
40
|
+
switchSession: (sessionId: string) => void;
|
|
42
41
|
/**
|
|
43
42
|
* reset sessions to default
|
|
44
43
|
*/
|
|
@@ -94,19 +93,13 @@ export const createSessionSlice: StateCreator<
|
|
|
94
93
|
[],
|
|
95
94
|
SessionAction
|
|
96
95
|
> = (set, get) => ({
|
|
97
|
-
activeSession: (sessionId) => {
|
|
98
|
-
if (get().activeId === sessionId) return;
|
|
99
|
-
|
|
100
|
-
set({ activeId: sessionId }, false, n(`activeSession/${sessionId}`));
|
|
101
|
-
},
|
|
102
|
-
|
|
103
96
|
clearSessions: async () => {
|
|
104
97
|
await sessionService.removeAllSessions();
|
|
105
98
|
await get().refreshSessions();
|
|
106
99
|
},
|
|
107
100
|
|
|
108
101
|
createSession: async (agent, isSwitchSession = true) => {
|
|
109
|
-
const {
|
|
102
|
+
const { switchSession, refreshSessions } = get();
|
|
110
103
|
|
|
111
104
|
// merge the defaultAgent in settings
|
|
112
105
|
const defaultAgent = merge(
|
|
@@ -120,12 +113,13 @@ export const createSessionSlice: StateCreator<
|
|
|
120
113
|
await refreshSessions();
|
|
121
114
|
|
|
122
115
|
// Whether to goto to the new session after creation, the default is to switch to
|
|
123
|
-
if (isSwitchSession)
|
|
116
|
+
if (isSwitchSession) switchSession(id);
|
|
124
117
|
|
|
125
118
|
return id;
|
|
126
119
|
},
|
|
120
|
+
|
|
127
121
|
duplicateSession: async (id) => {
|
|
128
|
-
const {
|
|
122
|
+
const { switchSession, refreshSessions } = get();
|
|
129
123
|
const session = sessionSelectors.getSessionById(id)(get());
|
|
130
124
|
|
|
131
125
|
if (!session) return;
|
|
@@ -154,9 +148,8 @@ export const createSessionSlice: StateCreator<
|
|
|
154
148
|
message.destroy(messageLoadingKey);
|
|
155
149
|
message.success(t('duplicateSession.success', { ns: 'chat' }));
|
|
156
150
|
|
|
157
|
-
|
|
151
|
+
switchSession(newId);
|
|
158
152
|
},
|
|
159
|
-
|
|
160
153
|
pinSession: async (id, pinned) => {
|
|
161
154
|
await get().internal_updateSession(id, { pinned });
|
|
162
155
|
},
|
|
@@ -167,10 +160,16 @@ export const createSessionSlice: StateCreator<
|
|
|
167
160
|
|
|
168
161
|
// If the active session deleted, switch to the inbox session
|
|
169
162
|
if (sessionId === get().activeId) {
|
|
170
|
-
get().
|
|
163
|
+
get().switchSession(INBOX_SESSION_ID);
|
|
171
164
|
}
|
|
172
165
|
},
|
|
173
166
|
|
|
167
|
+
switchSession: (sessionId) => {
|
|
168
|
+
if (get().activeId === sessionId) return;
|
|
169
|
+
|
|
170
|
+
set({ activeId: sessionId }, false, n(`activeSession/${sessionId}`));
|
|
171
|
+
},
|
|
172
|
+
|
|
174
173
|
updateSearchKeywords: (keywords) => {
|
|
175
174
|
set(
|
|
176
175
|
{ isSearching: !!keywords, sessionSearchKeywords: keywords },
|