@lobehub/chat 0.44.3 → 0.45.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 CHANGED
@@ -9,5 +9,6 @@ config.rules['unicorn/no-null'] = 0;
9
9
  config.rules['unicorn/no-typeof-undefined'] = 0;
10
10
  config.rules['unicorn/explicit-length-check'] = 0;
11
11
  config.rules['unicorn/prefer-code-point'] = 0;
12
+ config.rules['no-extra-boolean-cast'] = 0;
12
13
 
13
14
  module.exports = config;
package/CHANGELOG.md CHANGED
@@ -2,6 +2,65 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 0.45.0](https://github.com/lobehub/lobe-chat/compare/v0.44.4...v0.45.0)
6
+
7
+ <sup>Released on **2023-08-14**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: 优化每个角色的初始引导.
12
+
13
+ #### 💄 Styles
14
+
15
+ - **misc**: 优化初始化加载状态,等到会话加载完毕再显示内容.
16
+
17
+ <br/>
18
+
19
+ <details>
20
+ <summary><kbd>Improvements and Fixes</kbd></summary>
21
+
22
+ #### What's improved
23
+
24
+ - **misc**: 优化每个角色的初始引导, closes [#76](https://github.com/lobehub/lobe-chat/issues/76) ([8d78dc5](https://github.com/lobehub/lobe-chat/commit/8d78dc5))
25
+
26
+ #### Styles
27
+
28
+ - **misc**: 优化初始化加载状态,等到会话加载完毕再显示内容 ([cf603cb](https://github.com/lobehub/lobe-chat/commit/cf603cb))
29
+
30
+ </details>
31
+
32
+ <div align="right">
33
+
34
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
35
+
36
+ </div>
37
+
38
+ ### [Version 0.44.4](https://github.com/lobehub/lobe-chat/compare/v0.44.3...v0.44.4)
39
+
40
+ <sup>Released on **2023-08-13**</sup>
41
+
42
+ #### 💄 Styles
43
+
44
+ - **misc**: 优化 Chat Skeleton 样式, 优化 Inbox 样式.
45
+
46
+ <br/>
47
+
48
+ <details>
49
+ <summary><kbd>Improvements and Fixes</kbd></summary>
50
+
51
+ #### Styles
52
+
53
+ - **misc**: 优化 Chat Skeleton 样式 ([3f83be0](https://github.com/lobehub/lobe-chat/commit/3f83be0))
54
+ - **misc**: 优化 Inbox 样式 ([924c12e](https://github.com/lobehub/lobe-chat/commit/924c12e))
55
+
56
+ </details>
57
+
58
+ <div align="right">
59
+
60
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
61
+
62
+ </div>
63
+
5
64
  ### [Version 0.44.3](https://github.com/lobehub/lobe-chat/compare/v0.44.2...v0.44.3)
6
65
 
7
66
  <sup>Released on **2023-08-13**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.44.3",
3
+ "version": "0.45.0",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -91,7 +91,7 @@
91
91
  "react-dom": "^18",
92
92
  "react-hotkeys-hook": "^4",
93
93
  "react-i18next": "^13",
94
- "react-layout-kit": "^1",
94
+ "react-layout-kit": "^1.7.1",
95
95
  "serpapi": "^2",
96
96
  "swr": "^2",
97
97
  "ts-md5": "^1",
@@ -105,7 +105,7 @@
105
105
  "@lobehub/i18n-cli": "latest",
106
106
  "@lobehub/lint": "latest",
107
107
  "@next/eslint-plugin-next": "^13",
108
- "@testing-library/jest-dom": "^5",
108
+ "@testing-library/jest-dom": "^6",
109
109
  "@testing-library/react": "^14",
110
110
  "@types/chroma-js": "^2",
111
111
  "@types/lodash-es": "^4",
@@ -1,6 +1,10 @@
1
1
  export default {
2
2
  about: '关于',
3
3
  advanceSettings: '高级设置',
4
+ agentDefaultMessage:
5
+ '你好,我是你的自定义助手,你可以立即与我开始对话,也可以前往 [助手设置](/chat/{{id}}/setting) 完善我的信息。',
6
+ agentDefaultMessageWithSystemRole:
7
+ '你好,我是你的自定义助手,我的角色设定如下: \n\n --- \n\n {{systemRole}} \n\n --- \n\n 立即与我开始对话吧~',
4
8
  agentMaxToken: '会话最大长度',
5
9
  agentModel: '模型',
6
10
  agentProfile: '助手信息',
@@ -31,6 +35,7 @@ export default {
31
35
  },
32
36
  feedback: '反馈与建议',
33
37
  import: '导入配置',
38
+
34
39
  inbox: {
35
40
  defaultMessage:
36
41
  '你好,我是你的智能助手,你可以问我任何问题,我会尽力回答你。如果需要获得更加专业或定制的助手,可以点击「+」创建自定义助手',
@@ -16,6 +16,7 @@ const Inbox = memo(() => {
16
16
  <List.Item
17
17
  active={activeId === INBOX_SESSION_ID}
18
18
  avatar={<Avatar avatar={DEFAULT_INBOX_AVATAR} size={46} style={{ padding: 3 }} />}
19
+ style={{ alignItems: 'center' }}
19
20
  title={t('inbox.title')}
20
21
  />
21
22
  </Link>
@@ -24,6 +24,7 @@ const SkeletonList = memo(() => {
24
24
  <Skeleton
25
25
  active
26
26
  avatar={{ size: 40 }}
27
+ className={styles.user}
27
28
  paragraph={{ width: ['50%', '30%'] }}
28
29
  round
29
30
  title={false}
@@ -31,10 +32,8 @@ const SkeletonList = memo(() => {
31
32
  <Skeleton
32
33
  active
33
34
  avatar={{ size: 40 }}
34
- className={styles.user}
35
35
  paragraph={{ width: ['50%', '30%'] }}
36
36
  round
37
- // style={{ display: 'flex', flexDirection: 'row-reverse' }}
38
37
  title={false}
39
38
  />
40
39
  </Flexbox>
@@ -1,15 +1,13 @@
1
1
  import { ChatList, RenderErrorMessage, RenderMessage } from '@lobehub/ui';
2
2
  import isEqual from 'fast-deep-equal';
3
- import { memo, useCallback, useMemo } from 'react';
3
+ import { memo, useCallback } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
- import { DEFAULT_INBOX_AVATAR } from '@/const/meta';
8
- import { INBOX_SESSION_ID } from '@/const/session';
9
7
  import {
10
8
  agentSelectors,
11
9
  chatSelectors,
12
- useSessionHydrated,
10
+ useSessionChatInit,
13
11
  useSessionStore,
14
12
  } from '@/store/session';
15
13
  import { ChatMessage } from '@/types/chatMessage';
@@ -35,14 +33,13 @@ const renderErrorMessage: RenderErrorMessage = (error, message) => {
35
33
  };
36
34
 
37
35
  const List = () => {
38
- const init = useSessionHydrated();
36
+ const init = useSessionChatInit();
39
37
  const { t } = useTranslation('common');
40
38
 
41
- const data = useSessionStore(chatSelectors.currentChats, isEqual);
39
+ const data = useSessionStore(chatSelectors.currentChatsWithGuideMessage, isEqual);
42
40
 
43
- const [isInbox, displayMode, chatLoadingId, deleteMessage, resendMessage, dispatchMessage] =
41
+ const [displayMode, chatLoadingId, deleteMessage, resendMessage, dispatchMessage] =
44
42
  useSessionStore((s) => [
45
- s.activeId === INBOX_SESSION_ID,
46
43
  agentSelectors.currentAgentConfig(s).displayMode,
47
44
  s.chatLoadingId,
48
45
  s.deleteMessage,
@@ -81,28 +78,11 @@ const List = () => {
81
78
  [chatLoadingId],
82
79
  );
83
80
 
84
- // 针对 inbox 添加初始化时的自定义消息
85
- const displayDataSource = useMemo(() => {
86
- const emptyGuideMessage = {
87
- content: t('inbox.defaultMessage'),
88
- createAt: Date.now(),
89
- extra: {},
90
- id: 'default',
91
- meta: {
92
- avatar: DEFAULT_INBOX_AVATAR,
93
- },
94
- role: 'assistant',
95
- updateAt: Date.now(),
96
- } as ChatMessage;
97
-
98
- return isInbox && data.length === 0 ? [emptyGuideMessage] : data;
99
- }, [data]);
100
-
101
81
  return !init ? (
102
82
  <SkeletonList />
103
83
  ) : (
104
84
  <ChatList
105
- data={displayDataSource}
85
+ data={data}
106
86
  loadingId={chatLoadingId}
107
87
  onActionClick={(key, id) => {
108
88
  switch (key) {
@@ -11,12 +11,12 @@ import HeaderTitle from '@/components/HeaderTitle';
11
11
  import Tag from '@/components/Tag';
12
12
  import { INBOX_SESSION_ID } from '@/const/session';
13
13
  import { useGlobalStore } from '@/store/global';
14
- import { agentSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
14
+ import { agentSelectors, useSessionChatInit, useSessionStore } from '@/store/session';
15
15
 
16
16
  import PluginTag from './PluginTag';
17
17
 
18
18
  const Header = memo<{ settings?: boolean }>(({ settings = true }) => {
19
- const init = useSessionHydrated();
19
+ const init = useSessionChatInit();
20
20
 
21
21
  const { t } = useTranslation('common');
22
22
 
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
7
7
  import { Flexbox } from 'react-layout-kit';
8
8
 
9
9
  import Header from '@/pages/chat/features/Sidebar/Header';
10
- import { agentSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
10
+ import { agentSelectors, useSessionChatInit, useSessionStore } from '@/store/session';
11
11
 
12
12
  const useStyles = createStyles(({ css, token }) => ({
13
13
  prompt: css`
@@ -49,7 +49,7 @@ const SystemRole = memo(() => {
49
49
  s.updateAgentConfig,
50
50
  ]);
51
51
 
52
- const hydrated = useSessionHydrated();
52
+ const init = useSessionChatInit();
53
53
  const { t } = useTranslation('common');
54
54
  return (
55
55
  <Flexbox height={'fit-content'}>
@@ -65,7 +65,9 @@ const SystemRole = memo(() => {
65
65
  title={t('settingAgent.prompt.title', { ns: 'setting' })}
66
66
  />
67
67
  <Flexbox className={styles.promptBox} height={200} padding={'0 16px 16px'}>
68
- {hydrated ? (
68
+ {!init ? (
69
+ <Skeleton active avatar={false} round style={{ marginTop: 12 }} title={false} />
70
+ ) : (
69
71
  <>
70
72
  <EditableMessage
71
73
  classNames={{ markdown: styles.prompt }}
@@ -86,8 +88,6 @@ const SystemRole = memo(() => {
86
88
  />
87
89
  <div className={styles.promptMask} />
88
90
  </>
89
- ) : (
90
- <Skeleton active avatar={false} style={{ marginTop: 12 }} title={false} />
91
91
  )}
92
92
  </Flexbox>
93
93
  </Flexbox>
@@ -5,13 +5,13 @@ import { Flexbox } from 'react-layout-kit';
5
5
 
6
6
  import Empty from '@/components/Empty';
7
7
  import { useGlobalStore } from '@/store/global';
8
- import { topicSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
8
+ import { topicSelectors, useSessionChatInit, useSessionStore } from '@/store/session';
9
9
 
10
10
  import SkeletonList from './SkeletonList';
11
11
  import TopicItem from './TopicItem';
12
12
 
13
13
  export const Topic = () => {
14
- const hydrated = useSessionHydrated();
14
+ const init = useSessionChatInit();
15
15
  const topics = useSessionStore(topicSelectors.currentTopics, isEqual);
16
16
  const { isDarkMode } = useThemeMode();
17
17
  const [activeTopicId] = useSessionStore((s) => [s.activeTopicId]);
@@ -22,7 +22,7 @@ export const Topic = () => {
22
22
  s.updateGuideState,
23
23
  ]);
24
24
 
25
- return !hydrated ? (
25
+ return !init ? (
26
26
  <SkeletonList />
27
27
  ) : (
28
28
  <Flexbox gap={2} style={{ marginBottom: 12 }}>
@@ -1,17 +1,59 @@
1
1
  import { ChatCompletionFunctions } from 'openai-edge/types/api';
2
2
  import { ReactNode } from 'react';
3
3
 
4
+ /**
5
+ * 插件项
6
+ * @template Result - 结果类型,默认为 any
7
+ * @template RunnerParams - 运行参数类型,默认为 any
8
+ */
4
9
  export interface PluginItem<Result = any, RunnerParams = any> {
10
+ /**
11
+ * 头像
12
+ */
5
13
  avatar: string;
14
+ /**
15
+ * 名称
16
+ */
6
17
  name: string;
18
+ /**
19
+ * 运行器
20
+ * @param params - 运行参数
21
+ * @returns 运行结果的 Promise
22
+ */
7
23
  runner: PluginRunner<RunnerParams, Result>;
24
+ /**
25
+ * 聊天完成函数的模式
26
+ */
8
27
  schema: ChatCompletionFunctions;
9
28
  }
29
+
30
+ /**
31
+ * 插件渲染函数
32
+ * @param props - 插件渲染属性
33
+ * @returns React 节点
34
+ */
10
35
  export type PluginRender = (props: PluginRenderProps) => ReactNode;
11
36
 
37
+ /**
38
+ * 插件运行器
39
+ * @template Params - 参数类型,默认为 object
40
+ * @template Result - 结果类型,默认为 any
41
+ * @param params - 运行参数
42
+ * @returns 运行结果的 Promise
43
+ */
12
44
  export type PluginRunner<Params = object, Result = any> = (params: Params) => Promise<Result>;
13
45
 
46
+ /**
47
+ * 插件渲染属性
48
+ * @template Result - 结果类型,默认为 any
49
+ */
14
50
  export interface PluginRenderProps<Result = any> {
51
+ /**
52
+ * 内容
53
+ */
15
54
  content: Result;
55
+ /**
56
+ * 名称
57
+ */
16
58
  name: string;
17
59
  }
@@ -1,2 +1,3 @@
1
1
  export * from './useOnFinishHydrationSession';
2
+ export * from './useSessionChatInit';
2
3
  export * from './useSessionHydrated';
@@ -0,0 +1,12 @@
1
+ import { useSessionStore } from '../store';
2
+ import { useSessionHydrated } from './useSessionHydrated';
3
+
4
+ /**
5
+ * 用于判断某个会话是否完全被激活
6
+ */
7
+ export const useSessionChatInit = () => {
8
+ const sessionHydrated = useSessionHydrated();
9
+ const [hasActive] = useSessionStore((s) => [!!s.activeId]);
10
+
11
+ return sessionHydrated && hasActive;
12
+ };
@@ -1,4 +1,7 @@
1
- import { DEFAULT_USER_AVATAR } from '@/const/meta';
1
+ import { t } from 'i18next';
2
+
3
+ import { DEFAULT_INBOX_AVATAR, DEFAULT_USER_AVATAR } from '@/const/meta';
4
+ import { INBOX_SESSION_ID } from '@/const/session';
2
5
  import { useGlobalStore } from '@/store/global';
3
6
  import { ChatMessage } from '@/types/chatMessage';
4
7
 
@@ -6,6 +9,7 @@ import type { SessionStore } from '../../../store';
6
9
  import { agentSelectors } from '../../agentConfig';
7
10
  import { sessionSelectors } from '../../session/selectors';
8
11
  import { getSlicedMessagesWithConfig } from '../utils';
12
+ import { currentTopics } from './topic';
9
13
  import { organizeChats } from './utils';
10
14
 
11
15
  export const getChatsById =
@@ -36,6 +40,37 @@ export const currentChats = (s: SessionStore): ChatMessage[] => {
36
40
  return getChatsById(s.activeId)(s);
37
41
  };
38
42
 
43
+ // 针对新助手添加初始化时的自定义消息
44
+ export const currentChatsWithGuideMessage = (s: SessionStore): ChatMessage[] => {
45
+ const data = currentChats(s);
46
+ const noTopic = currentTopics(s);
47
+
48
+ const isBrandNewChat = data.length === 0 && noTopic;
49
+
50
+ if (!isBrandNewChat) return data;
51
+
52
+ const [activeId, isInbox] = [s.activeId, s.activeId === INBOX_SESSION_ID];
53
+ const systemRole = agentSelectors.currentAgentSystemRole(s);
54
+
55
+ const emptyInboxGuideMessage = {
56
+ content: isInbox
57
+ ? t('inbox.defaultMessage')
58
+ : !!systemRole
59
+ ? t('agentDefaultMessageWithSystemRole', { systemRole })
60
+ : t('agentDefaultMessage', { id: activeId }),
61
+ createAt: Date.now(),
62
+ extra: {},
63
+ id: 'default',
64
+ meta: {
65
+ avatar: DEFAULT_INBOX_AVATAR,
66
+ },
67
+ role: 'assistant',
68
+ updateAt: Date.now(),
69
+ } as ChatMessage;
70
+
71
+ return [emptyInboxGuideMessage];
72
+ };
73
+
39
74
  export const currentChatsWithHistoryConfig = (s: SessionStore): ChatMessage[] => {
40
75
  const chats = currentChats(s);
41
76
  const config = agentSelectors.currentAgentConfig(s);
@@ -1,10 +1,11 @@
1
- import { currentChats, getChatsById } from './chat';
1
+ import { currentChats, currentChatsWithGuideMessage, getChatsById } from './chat';
2
2
  import { chatsTokenCount, systemRoleTokenCount, totalTokenCount } from './token';
3
3
  import { currentTopics, getTopicMessages } from './topic';
4
4
 
5
5
  export const chatSelectors = {
6
6
  chatsTokenCount,
7
7
  currentChats,
8
+ currentChatsWithGuideMessage,
8
9
  getChatsById,
9
10
  systemRoleTokenCount,
10
11
  totalTokenCount,