@lobehub/chat 0.69.0 → 0.70.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/.eslintrc.js +1 -0
- package/.github/workflows/contributor-help.yml +2 -4
- package/CHANGELOG.md +50 -0
- package/package.json +3 -3
- package/src/const/url.ts +3 -0
- package/src/features/MobileTabBar/index.tsx +3 -1
- package/src/features/SideBar/TopActions.tsx +4 -3
- package/src/pages/api/openai.ts +33 -36
- package/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/index.tsx +1 -1
- package/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/utils.ts +1 -1
- package/src/pages/chat/features/Conversation/ChatList/Plugins/SystemJsRender/index.tsx +1 -1
- package/src/pages/chat/features/Header/Mobile.tsx +6 -8
- package/src/pages/chat/features/Header/PC.tsx +15 -16
- package/src/pages/chat/features/Header/index.tsx +3 -3
- package/src/pages/chat/{SessionList → features/SessionList}/Inbox.tsx +9 -2
- package/src/pages/chat/{SessionList → features/SessionList}/List/index.tsx +10 -1
- package/src/pages/chat/features/Sidebar/index.tsx +6 -2
- package/src/pages/chat/index.page.tsx +9 -11
- package/src/pages/chat/layout.tsx +6 -1
- package/src/pages/chat/{[id] → mobile}/index.page.tsx +7 -17
- package/src/pages/chat/mobile.tsx +2 -2
- package/src/pages/chat/{[id]/setting → setting}/Header.tsx +3 -4
- package/src/pages/index.page.tsx +10 -4
- package/src/pages/settings/Header.tsx +4 -2
- package/src/pages/welcome/Banner/index.tsx +11 -3
- package/src/services/chatModel.ts +1 -2
- package/src/store/middleware/createHyperStorage/index.ts +95 -0
- package/src/store/middleware/createHyperStorage/keyMapper.ts +53 -0
- package/src/store/middleware/createHyperStorage/type.ts +14 -0
- package/src/store/middleware/createHyperStorage/urlSearch.ts +17 -0
- package/src/store/plugin/selectors.ts +1 -1
- package/src/store/session/slices/session/action.ts +18 -9
- package/src/store/session/slices/session/initialState.ts +2 -3
- package/src/store/session/slices/session/selectors/index.ts +6 -0
- package/src/store/session/store.ts +16 -8
- package/src/types/openai.ts +23 -0
- package/src/pages/chat/[id]/layout.tsx +0 -34
- package/src/pages/chat/[id]/mobile.tsx +0 -31
- package/src/store/middleware/createHashStorage.ts +0 -49
- /package/src/pages/chat/{SessionList → features/SessionList}/CollapseGroup.tsx +0 -0
- /package/src/pages/chat/{SessionList → features/SessionList}/Header.tsx +0 -0
- /package/src/pages/chat/{SessionList → features/SessionList}/List/AddButton.tsx +0 -0
- /package/src/pages/chat/{SessionList → features/SessionList}/List/Item/Actions.tsx +0 -0
- /package/src/pages/chat/{SessionList → features/SessionList}/List/Item/index.tsx +0 -0
- /package/src/pages/chat/{SessionList → features/SessionList}/List/SkeletonList.tsx +0 -0
- /package/src/pages/chat/{SessionList → features/SessionList}/index.tsx +0 -0
- /package/src/pages/chat/{[id]/setting → setting}/index.page.tsx +0 -0
- /package/src/pages/chat/{[id]/setting → setting}/mobile.tsx +0 -0
package/.eslintrc.js
CHANGED
|
@@ -12,5 +12,6 @@ config.rules['unicorn/prefer-code-point'] = 0;
|
|
|
12
12
|
config.rules['no-extra-boolean-cast'] = 0;
|
|
13
13
|
config.rules['unicorn/no-useless-undefined'] = 0;
|
|
14
14
|
config.rules['react/no-unknown-property'] = 0;
|
|
15
|
+
config.rules['unicorn/prefer-ternary'] = 0;
|
|
15
16
|
|
|
16
17
|
module.exports = config;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
name: Contributor Helper
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
# 🌏 Think about the planet! No need to update stats too frequently
|
|
5
4
|
schedule: [{ cron: '0 18 * * *' }]
|
|
6
|
-
# 💡 The following line lets you run workflow manually from the action tab!
|
|
7
5
|
workflow_dispatch:
|
|
8
6
|
jobs:
|
|
9
7
|
contributor:
|
|
@@ -21,8 +19,8 @@ jobs:
|
|
|
21
19
|
- name: Commit and push if changed
|
|
22
20
|
run: |-
|
|
23
21
|
git diff
|
|
24
|
-
git config --global user.
|
|
25
|
-
git config --global user.
|
|
22
|
+
git config --global user.name "lobehubbot"
|
|
23
|
+
git config --global user.email "i@lobehub.com"
|
|
26
24
|
git pull
|
|
27
25
|
git add -A
|
|
28
26
|
git commit -m "🤖 docs: Auto update contributors" || exit 0
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.70.0](https://github.com/lobehub/lobe-chat/compare/v0.69.1...v0.70.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-09-08**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Refactor to url state.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Refactor to url state, closes [#157](https://github.com/lobehub/lobe-chat/issues/157) ([2efac2b](https://github.com/lobehub/lobe-chat/commit/2efac2b))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.69.1](https://github.com/lobehub/lobe-chat/compare/v0.69.0...v0.69.1)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2023-09-06**</sup>
|
|
33
|
+
|
|
34
|
+
#### ♻ Code Refactoring
|
|
35
|
+
|
|
36
|
+
- **misc**: Mirgrate openai-edge to openai.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Code refactoring
|
|
44
|
+
|
|
45
|
+
- **misc**: Mirgrate openai-edge to openai, closes [#145](https://github.com/lobehub/lobe-chat/issues/145) ([75ee574](https://github.com/lobehub/lobe-chat/commit/75ee574))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 0.69.0](https://github.com/lobehub/lobe-chat/compare/v0.68.1...v0.69.0)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2023-09-06**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.70.0",
|
|
4
4
|
"description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatbot",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@emoji-mart/data": "^1",
|
|
67
67
|
"@emoji-mart/react": "^1",
|
|
68
68
|
"@icons-pack/react-simple-icons": "^9",
|
|
69
|
-
"@lobehub/chat-plugin-sdk": "^1.
|
|
69
|
+
"@lobehub/chat-plugin-sdk": "^1.17.0",
|
|
70
70
|
"@lobehub/chat-plugins-gateway": "^1.5.0",
|
|
71
71
|
"@lobehub/ui": "latest",
|
|
72
72
|
"@vercel/analytics": "^1",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"lucide-react": "latest",
|
|
86
86
|
"nanoid": "^4",
|
|
87
87
|
"next": "13.4.7",
|
|
88
|
-
"openai
|
|
88
|
+
"openai": "^4.4.0",
|
|
89
89
|
"polished": "^4",
|
|
90
90
|
"react": "^18",
|
|
91
91
|
"react-dom": "^18",
|
package/src/const/url.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pkg from '../../package.json';
|
|
2
|
+
import { INBOX_SESSION_ID } from './session';
|
|
2
3
|
|
|
3
4
|
export const GITHUB = pkg.homepage;
|
|
4
5
|
export const CHANGELOG = `${pkg.homepage}/blob/master/CHANGELOG.md`;
|
|
@@ -8,3 +9,5 @@ export const DISCORD = 'https://discord.gg/AYFPHvv2jT';
|
|
|
8
9
|
|
|
9
10
|
export const PLUGINS_INDEX_URL =
|
|
10
11
|
process.env.PLUGINS_INDEX_URL ?? 'https://chat-plugins.lobehub.com';
|
|
12
|
+
|
|
13
|
+
export const SESSION_CHAT_URL = (id: string = INBOX_SESSION_ID) => `/chat#session=${id}`;
|
|
@@ -7,6 +7,7 @@ import { memo, useMemo } from 'react';
|
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
|
|
9
9
|
import { useGlobalStore } from '@/store/global';
|
|
10
|
+
import { useSessionStore } from '@/store/session';
|
|
10
11
|
|
|
11
12
|
const useStyles = createStyles(({ css, token }) => ({
|
|
12
13
|
active: css`
|
|
@@ -20,6 +21,7 @@ export default memo<{ className?: string }>(({ className }) => {
|
|
|
20
21
|
const [tab, setTab] = useGlobalStore((s) => [s.sidebarKey, s.switchSideBar]);
|
|
21
22
|
const { t } = useTranslation('common');
|
|
22
23
|
const { styles } = useStyles();
|
|
24
|
+
const switchSession = useSessionStore((s) => s.switchSession);
|
|
23
25
|
const items: MobileTabBarProps['items'] = useMemo(
|
|
24
26
|
() => [
|
|
25
27
|
{
|
|
@@ -28,7 +30,7 @@ export default memo<{ className?: string }>(({ className }) => {
|
|
|
28
30
|
),
|
|
29
31
|
key: 'chat',
|
|
30
32
|
onClick: () => {
|
|
31
|
-
|
|
33
|
+
switchSession();
|
|
32
34
|
},
|
|
33
35
|
title: t('tab.chat'),
|
|
34
36
|
},
|
|
@@ -5,6 +5,7 @@ import { memo } from 'react';
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import { GlobalStore } from '@/store/global';
|
|
8
|
+
import { useSessionStore } from '@/store/session';
|
|
8
9
|
|
|
9
10
|
export interface TopActionProps {
|
|
10
11
|
setTab: GlobalStore['switchSideBar'];
|
|
@@ -13,7 +14,7 @@ export interface TopActionProps {
|
|
|
13
14
|
|
|
14
15
|
const TopActions = memo<TopActionProps>(({ tab, setTab }) => {
|
|
15
16
|
const { t } = useTranslation('common');
|
|
16
|
-
|
|
17
|
+
const switchBackToChat = useSessionStore((s) => s.switchBackToChat);
|
|
17
18
|
return (
|
|
18
19
|
<>
|
|
19
20
|
<ActionIcon
|
|
@@ -22,7 +23,7 @@ const TopActions = memo<TopActionProps>(({ tab, setTab }) => {
|
|
|
22
23
|
onClick={() => {
|
|
23
24
|
// 如果已经在 chat 路径下了,那么就不用再跳转了
|
|
24
25
|
if (Router.asPath.startsWith('/chat')) return;
|
|
25
|
-
|
|
26
|
+
switchBackToChat();
|
|
26
27
|
setTab('chat');
|
|
27
28
|
}}
|
|
28
29
|
size="large"
|
|
@@ -31,7 +32,7 @@ const TopActions = memo<TopActionProps>(({ tab, setTab }) => {
|
|
|
31
32
|
<ActionIcon
|
|
32
33
|
active={tab === 'market'}
|
|
33
34
|
icon={Sticker}
|
|
34
|
-
onClick={() => setTab('market')}
|
|
35
|
+
// onClick={() => setTab('market')}
|
|
35
36
|
size="large"
|
|
36
37
|
title={t('tab.market')}
|
|
37
38
|
/>
|
package/src/pages/api/openai.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { OpenAIStream,
|
|
2
|
-
import {
|
|
1
|
+
import { OpenAIStream, StreamingTextResponse } from 'ai';
|
|
2
|
+
import OpenAI, { ClientOptions } from 'openai';
|
|
3
3
|
|
|
4
4
|
import { getServerConfig } from '@/config/server';
|
|
5
5
|
import { createErrorResponse } from '@/pages/api/error';
|
|
@@ -10,25 +10,29 @@ import { OpenAIStreamPayload } from '@/types/openai';
|
|
|
10
10
|
export const createOpenAI = (userApiKey: string | null, endpoint?: string | null) => {
|
|
11
11
|
const { OPENAI_API_KEY, OPENAI_PROXY_URL } = getServerConfig();
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const baseURL = endpoint ? endpoint : OPENAI_PROXY_URL ? OPENAI_PROXY_URL : undefined;
|
|
14
|
+
|
|
15
|
+
const config: ClientOptions = {
|
|
14
16
|
apiKey: !userApiKey ? OPENAI_API_KEY : userApiKey,
|
|
15
|
-
}
|
|
17
|
+
};
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
// a bug with openai: https://github.com/openai/openai-node/issues/283
|
|
20
|
+
// TODO: should refactor when openai fix the bug
|
|
21
|
+
if (baseURL) {
|
|
22
|
+
config.baseURL = baseURL;
|
|
23
|
+
}
|
|
18
24
|
|
|
19
|
-
return new
|
|
25
|
+
return new OpenAI(config);
|
|
20
26
|
};
|
|
21
27
|
|
|
22
28
|
interface CreateChatCompletionOptions {
|
|
23
29
|
OPENAI_API_KEY: string | null;
|
|
24
|
-
callbacks?: (payload: OpenAIStreamPayload) => OpenAIStreamCallbacks;
|
|
25
30
|
endpoint?: string | null;
|
|
26
31
|
payload: OpenAIStreamPayload;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
export const createChatCompletion = async ({
|
|
30
35
|
payload,
|
|
31
|
-
callbacks,
|
|
32
36
|
OPENAI_API_KEY,
|
|
33
37
|
endpoint,
|
|
34
38
|
}: CreateChatCompletionOptions) => {
|
|
@@ -47,37 +51,30 @@ export const createChatCompletion = async ({
|
|
|
47
51
|
|
|
48
52
|
// ============ 2. 发送请求 ============ //
|
|
49
53
|
|
|
50
|
-
const requestParams = { messages: formatMessages, stream: true, ...params };
|
|
51
|
-
|
|
52
|
-
let response: Response;
|
|
53
|
-
|
|
54
54
|
try {
|
|
55
|
-
response = await openai.
|
|
55
|
+
const response = await openai.chat.completions.create({
|
|
56
|
+
messages: formatMessages,
|
|
57
|
+
...params,
|
|
58
|
+
stream: true,
|
|
59
|
+
});
|
|
60
|
+
const stream = OpenAIStream(response);
|
|
61
|
+
return new StreamingTextResponse(stream);
|
|
56
62
|
} catch (error) {
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
let error;
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
// 正常情况下应该是 OpenAI 的 JSON
|
|
67
|
-
error = await response.clone().json();
|
|
68
|
-
} catch {
|
|
69
|
-
// 如果不是 JSON,那么可能是其他接口端的响应,读 text 为结果
|
|
70
|
-
const result = await response.text();
|
|
71
|
-
|
|
72
|
-
error = { message: result };
|
|
63
|
+
// Check if the error is an OpenAI APIError
|
|
64
|
+
if (error instanceof OpenAI.APIError) {
|
|
65
|
+
return createErrorResponse(ChatErrorType.OpenAIBizError, {
|
|
66
|
+
endpoint: !!endpoint ? endpoint : undefined,
|
|
67
|
+
error: error.error ?? error.cause,
|
|
68
|
+
});
|
|
73
69
|
}
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// ============ 5. 发送正常相应 ============ //
|
|
79
|
-
|
|
80
|
-
const stream = OpenAIStream(response, callbacks?.(requestParams));
|
|
71
|
+
// track the error that not an OpenAI APIError
|
|
72
|
+
console.error(error);
|
|
81
73
|
|
|
82
|
-
|
|
74
|
+
// return as a GatewayTimeout error
|
|
75
|
+
return createErrorResponse(ChatErrorType.InternalServerError, {
|
|
76
|
+
endpoint,
|
|
77
|
+
error: JSON.stringify(error),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
83
80
|
};
|
|
@@ -4,21 +4,19 @@ import Router from 'next/router';
|
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
|
-
import { INBOX_SESSION_ID } from '@/const/session';
|
|
8
7
|
import { useGlobalStore } from '@/store/global';
|
|
9
8
|
import { useSessionStore } from '@/store/session';
|
|
10
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
9
|
+
import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
|
|
11
10
|
|
|
12
|
-
const MobileHeader = memo
|
|
11
|
+
const MobileHeader = memo(() => {
|
|
13
12
|
const { t } = useTranslation('common');
|
|
14
13
|
|
|
15
|
-
const [
|
|
16
|
-
s
|
|
14
|
+
const [isInbox, title, model] = useSessionStore((s) => [
|
|
15
|
+
sessionSelectors.isInboxSession(s),
|
|
17
16
|
agentSelectors.currentAgentTitle(s),
|
|
18
17
|
agentSelectors.currentAgentModel(s),
|
|
19
18
|
]);
|
|
20
19
|
|
|
21
|
-
const isInbox = id === INBOX_SESSION_ID;
|
|
22
20
|
const [toggleConfig] = useGlobalStore((s) => [s.toggleMobileTopic]);
|
|
23
21
|
|
|
24
22
|
const displayTitle = isInbox ? t('inbox.title') : title;
|
|
@@ -30,11 +28,11 @@ const MobileHeader = memo<{ settings?: boolean }>(({ settings = true }) => {
|
|
|
30
28
|
right={
|
|
31
29
|
<>
|
|
32
30
|
<ActionIcon icon={LayoutList} onClick={() => toggleConfig()} />
|
|
33
|
-
{
|
|
31
|
+
{!isInbox && (
|
|
34
32
|
<ActionIcon
|
|
35
33
|
icon={Settings}
|
|
36
34
|
onClick={() => {
|
|
37
|
-
Router.push(`/chat
|
|
35
|
+
Router.push({ hash: location.hash, pathname: `/chat/setting` });
|
|
38
36
|
}}
|
|
39
37
|
/>
|
|
40
38
|
)}
|
|
@@ -7,31 +7,30 @@ import { memo } from 'react';
|
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
import { Flexbox } from 'react-layout-kit';
|
|
9
9
|
|
|
10
|
-
import { INBOX_SESSION_ID } from '@/const/session';
|
|
11
10
|
import { useGlobalStore } from '@/store/global';
|
|
12
11
|
import { useSessionChatInit, useSessionStore } from '@/store/session';
|
|
13
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
12
|
+
import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
|
|
14
13
|
|
|
15
14
|
import PluginTag from './PluginTag';
|
|
16
15
|
import ShareButton from './ShareButton';
|
|
17
16
|
|
|
18
|
-
const Header = memo
|
|
17
|
+
const Header = memo(() => {
|
|
19
18
|
const init = useSessionChatInit();
|
|
20
19
|
|
|
21
20
|
const { t } = useTranslation('common');
|
|
22
21
|
|
|
23
|
-
const [
|
|
24
|
-
s
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
const [isInbox, title, description, avatar, backgroundColor, model, plugins] = useSessionStore(
|
|
23
|
+
(s) => [
|
|
24
|
+
sessionSelectors.isInboxSession(s),
|
|
25
|
+
agentSelectors.currentAgentTitle(s),
|
|
26
|
+
agentSelectors.currentAgentDescription(s),
|
|
27
|
+
agentSelectors.currentAgentAvatar(s),
|
|
28
|
+
agentSelectors.currentAgentBackgroundColor(s),
|
|
29
|
+
agentSelectors.currentAgentModel(s),
|
|
30
|
+
agentSelectors.currentAgentPlugins(s),
|
|
31
|
+
],
|
|
32
|
+
);
|
|
33
33
|
|
|
34
|
-
const isInbox = id === INBOX_SESSION_ID;
|
|
35
34
|
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
36
35
|
s.preference.showChatSideBar,
|
|
37
36
|
s.toggleChatSideBar,
|
|
@@ -77,11 +76,11 @@ const Header = memo<{ settings?: boolean }>(({ settings = true }) => {
|
|
|
77
76
|
size={{ fontSize: 24 }}
|
|
78
77
|
title={t('roleAndArchive')}
|
|
79
78
|
/>
|
|
80
|
-
{
|
|
79
|
+
{!isInbox && (
|
|
81
80
|
<ActionIcon
|
|
82
81
|
icon={Settings}
|
|
83
82
|
onClick={() => {
|
|
84
|
-
Router.push(`/chat
|
|
83
|
+
Router.push({ hash: location.hash, pathname: `/chat/setting` });
|
|
85
84
|
}}
|
|
86
85
|
size={{ fontSize: 24 }}
|
|
87
86
|
title={t('header.session', { ns: 'setting' })}
|
|
@@ -4,12 +4,12 @@ import { memo } from 'react';
|
|
|
4
4
|
import Mobile from './Mobile';
|
|
5
5
|
import PC from './PC';
|
|
6
6
|
|
|
7
|
-
const Header = memo
|
|
7
|
+
const Header = memo(() => {
|
|
8
8
|
const { mobile } = useResponsive();
|
|
9
9
|
|
|
10
|
-
if (mobile) return <Mobile
|
|
10
|
+
if (mobile) return <Mobile />;
|
|
11
11
|
|
|
12
|
-
return <PC
|
|
12
|
+
return <PC />;
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
export default Header;
|
|
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
|
|
7
7
|
import { DEFAULT_INBOX_AVATAR } from '@/const/meta';
|
|
8
8
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
9
|
+
import { SESSION_CHAT_URL } from '@/const/url';
|
|
9
10
|
import { useSessionStore } from '@/store/session';
|
|
10
11
|
|
|
11
12
|
const { Item } = List;
|
|
@@ -14,7 +15,7 @@ const Inbox = memo(() => {
|
|
|
14
15
|
const ref = useRef(null);
|
|
15
16
|
const isHovering = useHover(ref);
|
|
16
17
|
const { t } = useTranslation('common');
|
|
17
|
-
const [activeId] = useSessionStore((s) => [s.activeId]);
|
|
18
|
+
const [activeId, switchSession] = useSessionStore((s) => [s.activeId, s.switchSession]);
|
|
18
19
|
|
|
19
20
|
const avatarRender = useMemo(
|
|
20
21
|
() => (
|
|
@@ -29,7 +30,13 @@ const Inbox = memo(() => {
|
|
|
29
30
|
);
|
|
30
31
|
|
|
31
32
|
return (
|
|
32
|
-
<Link
|
|
33
|
+
<Link
|
|
34
|
+
href={SESSION_CHAT_URL()}
|
|
35
|
+
onClick={(e) => {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
switchSession(INBOX_SESSION_ID);
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
33
40
|
<Item
|
|
34
41
|
active={activeId === INBOX_SESSION_ID}
|
|
35
42
|
avatar={avatarRender}
|
|
@@ -2,6 +2,7 @@ import isEqual from 'fast-deep-equal';
|
|
|
2
2
|
import Link from 'next/link';
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
|
|
5
|
+
import { SESSION_CHAT_URL } from '@/const/url';
|
|
5
6
|
import { useSessionHydrated, useSessionStore } from '@/store/session';
|
|
6
7
|
import { sessionSelectors } from '@/store/session/selectors';
|
|
7
8
|
|
|
@@ -11,6 +12,7 @@ import SkeletonList from './SkeletonList';
|
|
|
11
12
|
|
|
12
13
|
const SessionList = memo(() => {
|
|
13
14
|
const list = useSessionStore(sessionSelectors.sessionList, isEqual);
|
|
15
|
+
const activeSession = useSessionStore((s) => s.activeSession);
|
|
14
16
|
|
|
15
17
|
const isInit = useSessionHydrated();
|
|
16
18
|
|
|
@@ -18,7 +20,14 @@ const SessionList = memo(() => {
|
|
|
18
20
|
<SkeletonList />
|
|
19
21
|
) : list.length > 0 ? (
|
|
20
22
|
list.map(({ id }) => (
|
|
21
|
-
<Link
|
|
23
|
+
<Link
|
|
24
|
+
href={SESSION_CHAT_URL(id)}
|
|
25
|
+
key={id}
|
|
26
|
+
onClick={(e) => {
|
|
27
|
+
e.preventDefault();
|
|
28
|
+
activeSession(id);
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
22
31
|
<SessionItem id={id} />
|
|
23
32
|
</Link>
|
|
24
33
|
))
|
|
@@ -8,6 +8,8 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
8
8
|
import SafeSpacing from '@/components/SafeSpacing';
|
|
9
9
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
|
10
10
|
import { useGlobalStore } from '@/store/global';
|
|
11
|
+
import { useSessionStore } from '@/store/session';
|
|
12
|
+
import { sessionSelectors } from '@/store/session/slices/session/selectors';
|
|
11
13
|
|
|
12
14
|
import Mobile from './Mobile';
|
|
13
15
|
import SystemRole from './SystemRole';
|
|
@@ -37,13 +39,15 @@ interface SideBarProps {
|
|
|
37
39
|
mobile?: boolean;
|
|
38
40
|
systemRole?: boolean;
|
|
39
41
|
}
|
|
40
|
-
const SideBar = memo<SideBarProps>(({
|
|
42
|
+
const SideBar = memo<SideBarProps>(({ mobile }) => {
|
|
41
43
|
const { styles } = useStyles(mobile);
|
|
42
44
|
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
43
45
|
s.preference.showChatSideBar,
|
|
44
46
|
s.toggleChatSideBar,
|
|
45
47
|
]);
|
|
46
48
|
|
|
49
|
+
const isInbox = useSessionStore(sessionSelectors.isInboxSession);
|
|
50
|
+
|
|
47
51
|
const { t } = useTranslation('common');
|
|
48
52
|
|
|
49
53
|
const topic = (
|
|
@@ -79,7 +83,7 @@ const SideBar = memo<SideBarProps>(({ systemRole = true, mobile }) => {
|
|
|
79
83
|
style={{ flex: 'none', height: '100%', minWidth: CHAT_SIDEBAR_WIDTH }}
|
|
80
84
|
>
|
|
81
85
|
<SafeSpacing />
|
|
82
|
-
{
|
|
86
|
+
{!isInbox && <SystemRole mobile={mobile} />}
|
|
83
87
|
|
|
84
88
|
{topic}
|
|
85
89
|
</DraggablePanelContainer>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { useResponsive } from 'antd-style';
|
|
2
2
|
import Head from 'next/head';
|
|
3
3
|
import { memo } from 'react';
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
5
4
|
import { Flexbox } from 'react-layout-kit';
|
|
6
5
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { useSessionStore } from '@/store/session';
|
|
7
|
+
import { agentSelectors } from '@/store/session/selectors';
|
|
9
8
|
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
10
9
|
|
|
11
10
|
import Conversation from './features/Conversation';
|
|
@@ -15,13 +14,12 @@ import Layout from './layout';
|
|
|
15
14
|
import Mobile from './mobile';
|
|
16
15
|
|
|
17
16
|
const Chat = memo(() => {
|
|
18
|
-
const { t } = useTranslation('common');
|
|
19
17
|
const { mobile } = useResponsive();
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
const [avatar, title] = useSessionStore((s) => [
|
|
19
|
+
agentSelectors.currentAgentAvatar(s),
|
|
20
|
+
agentSelectors.currentAgentTitle(s),
|
|
21
|
+
]);
|
|
22
|
+
const pageTitle = genSiteHeadTitle([avatar, title].filter(Boolean).join(' '));
|
|
25
23
|
|
|
26
24
|
return (
|
|
27
25
|
<>
|
|
@@ -32,10 +30,10 @@ const Chat = memo(() => {
|
|
|
32
30
|
<Mobile />
|
|
33
31
|
) : (
|
|
34
32
|
<Layout>
|
|
35
|
-
<Header
|
|
33
|
+
<Header />
|
|
36
34
|
<Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
|
|
37
35
|
<Conversation />
|
|
38
|
-
<SideBar
|
|
36
|
+
<SideBar />
|
|
39
37
|
</Flexbox>
|
|
40
38
|
</Layout>
|
|
41
39
|
)}
|
|
@@ -4,13 +4,18 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
4
4
|
|
|
5
5
|
import AppLayout from '@/layout/AppLayout';
|
|
6
6
|
import { useSwitchSideBarOnInit } from '@/store/global';
|
|
7
|
+
import { usePluginStore } from '@/store/plugin';
|
|
7
8
|
|
|
8
|
-
import { Sessions } from './SessionList';
|
|
9
|
+
import { Sessions } from './features/SessionList';
|
|
9
10
|
|
|
10
11
|
const ChatLayout = memo<PropsWithChildren>(({ children }) => {
|
|
11
12
|
const { mobile } = useResponsive();
|
|
13
|
+
|
|
12
14
|
useSwitchSideBarOnInit('chat');
|
|
13
15
|
|
|
16
|
+
const useFetchPluginList = usePluginStore((s) => s.useFetchPluginList);
|
|
17
|
+
useFetchPluginList();
|
|
18
|
+
|
|
14
19
|
return (
|
|
15
20
|
<AppLayout>
|
|
16
21
|
<Sessions />
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import { useResponsive } from 'antd-style';
|
|
2
1
|
import Head from 'next/head';
|
|
3
2
|
import { memo } from 'react';
|
|
4
3
|
import { Flexbox } from 'react-layout-kit';
|
|
5
4
|
|
|
5
|
+
import AppMobileLayout from '@/layout/AppMobileLayout';
|
|
6
|
+
import Header from '@/pages/chat/features/Header';
|
|
6
7
|
import { useSessionStore } from '@/store/session';
|
|
7
8
|
import { agentSelectors } from '@/store/session/selectors';
|
|
8
9
|
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
9
10
|
|
|
10
11
|
import Conversation from '../features/Conversation';
|
|
11
|
-
import Header from '../features/Header';
|
|
12
12
|
import SideBar from '../features/Sidebar';
|
|
13
|
-
import
|
|
14
|
-
import Mobile from './mobile';
|
|
13
|
+
import ChatLayout from '../layout';
|
|
15
14
|
|
|
16
15
|
const Chat = memo(() => {
|
|
17
|
-
const { mobile } = useResponsive();
|
|
18
16
|
const [avatar, title] = useSessionStore((s) => [
|
|
19
17
|
agentSelectors.currentAgentAvatar(s),
|
|
20
18
|
agentSelectors.currentAgentTitle(s),
|
|
@@ -27,22 +25,14 @@ const Chat = memo(() => {
|
|
|
27
25
|
<Head>
|
|
28
26
|
<title>{pageTitle}</title>
|
|
29
27
|
</Head>
|
|
30
|
-
{
|
|
31
|
-
<
|
|
28
|
+
<AppMobileLayout navBar={<Header />}>
|
|
29
|
+
<ChatLayout>
|
|
32
30
|
<Flexbox height={'calc(100vh - 44px)'} horizontal>
|
|
33
31
|
<Conversation mobile />
|
|
34
32
|
<SideBar mobile />
|
|
35
33
|
</Flexbox>
|
|
36
|
-
</
|
|
37
|
-
|
|
38
|
-
<Layout>
|
|
39
|
-
<Header />
|
|
40
|
-
<Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
|
|
41
|
-
<Conversation />
|
|
42
|
-
<SideBar />
|
|
43
|
-
</Flexbox>
|
|
44
|
-
</Layout>
|
|
45
|
-
)}
|
|
34
|
+
</ChatLayout>
|
|
35
|
+
</AppMobileLayout>
|
|
46
36
|
</>
|
|
47
37
|
);
|
|
48
38
|
});
|
|
@@ -2,10 +2,10 @@ import { useTheme } from 'antd-style';
|
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
4
|
import AppMobileLayout from '@/layout/AppMobileLayout';
|
|
5
|
-
import Header from '@/pages/chat/SessionList/Header';
|
|
6
5
|
import { useSwitchSideBarOnInit } from '@/store/global';
|
|
7
6
|
|
|
8
|
-
import { Sessions } from './SessionList';
|
|
7
|
+
import { Sessions } from './features/SessionList';
|
|
8
|
+
import Header from './features/SessionList/Header';
|
|
9
9
|
|
|
10
10
|
const ChatMobileLayout = memo(() => {
|
|
11
11
|
useSwitchSideBarOnInit('chat');
|