@lobehub/chat 0.62.1 → 0.63.1

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 CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.63.1](https://github.com/lobehub/lobe-chat/compare/v0.63.0...v0.63.1)
6
+
7
+ <sup>Released on **2023-08-27**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Refactor the selectors import.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Refactor the selectors import, closes [#120](https://github.com/lobehub/lobe-chat/issues/120) ([6646502](https://github.com/lobehub/lobe-chat/commit/6646502))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 0.63.0](https://github.com/lobehub/lobe-chat/compare/v0.62.1...v0.63.0)
31
+
32
+ <sup>Released on **2023-08-27**</sup>
33
+
34
+ #### ✨ Features
35
+
36
+ - **misc**: support sharing to shareGPT.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's improved
44
+
45
+ - **misc**: support sharing to shareGPT, closes [#119](https://github.com/lobehub/lobe-chat/issues/119) ([026e9ec](https://github.com/lobehub/lobe-chat/commit/026e9ec))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 0.62.1](https://github.com/lobehub/lobe-chat/compare/v0.62.0...v0.62.1)
6
56
 
7
57
  <sup>Released on **2023-08-26**</sup>
package/README.md CHANGED
@@ -129,7 +129,7 @@ This project is [MIT](./LICENSE) licensed.
129
129
 
130
130
  <!-- release -->
131
131
 
132
- [release-shield]: https://img.shields.io/npm/v/@lobehub/chat?label=%F0%9F%A4%AF%20NPM
132
+ [release-shield]: https://img.shields.io/npm/v/@lobehub/chat?label=%F0%9F%A4%AF%20Chat
133
133
  [release-url]: https://www.npmjs.com/package/@lobehub/chat
134
134
 
135
135
  <!-- releaseDate -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.62.1",
3
+ "version": "0.63.1",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -1,5 +1,6 @@
1
1
  import { settingsSelectors, useGlobalStore } from '@/store/global';
2
- import { sessionSelectors, useSessionStore } from '@/store/session';
2
+ import { useSessionStore } from '@/store/session';
3
+ import { sessionSelectors } from '@/store/session/selectors';
3
4
  import { createConfigFile, exportConfigFile } from '@/utils/config';
4
5
 
5
6
  const getSessions = () => sessionSelectors.exportSessions(useSessionStore.getState());
@@ -6,7 +6,8 @@ import { memo, useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
8
  import { exportSingleAgent, exportSingleSession } from '@/helpers/export';
9
- import { sessionSelectors, useSessionStore } from '@/store/session';
9
+ import { useSessionStore } from '@/store/session';
10
+ import { sessionSelectors } from '@/store/session/selectors';
10
11
 
11
12
  const useStyles = createStyles(({ css }) => ({
12
13
  modalRoot: css`
@@ -7,7 +7,8 @@ import { Flexbox } from 'react-layout-kit';
7
7
  import { shallow } from 'zustand/shallow';
8
8
 
9
9
  import { settingsSelectors, useGlobalStore } from '@/store/global';
10
- import { agentSelectors, sessionSelectors, useSessionStore } from '@/store/session';
10
+ import { useSessionStore } from '@/store/session';
11
+ import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
11
12
 
12
13
  import Actions from './Actions';
13
14
 
@@ -2,7 +2,8 @@ import isEqual from 'fast-deep-equal';
2
2
  import Link from 'next/link';
3
3
  import { memo } from 'react';
4
4
 
5
- import { sessionSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
5
+ import { useSessionHydrated, useSessionStore } from '@/store/session';
6
+ import { sessionSelectors } from '@/store/session/selectors';
6
7
 
7
8
  import AddButton from './AddButton';
8
9
  import SessionItem from './Item';
@@ -3,7 +3,8 @@ import Head from 'next/head';
3
3
  import { memo } from 'react';
4
4
  import { Flexbox } from 'react-layout-kit';
5
5
 
6
- import { agentSelectors, useSessionStore } from '@/store/session';
6
+ import { useSessionStore } from '@/store/session';
7
+ import { agentSelectors } from '@/store/session/selectors';
7
8
  import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
8
9
 
9
10
  import Conversation from '../features/Conversation';
@@ -8,7 +8,8 @@ import { Flexbox } from 'react-layout-kit';
8
8
  import SafeSpacing from '@/components/SafeSpacing';
9
9
  import { HEADER_HEIGHT } from '@/const/layoutTokens';
10
10
  import { AgentConfig, AgentMeta, AgentPlugin, AgentPrompt } from '@/features/AgentSetting';
11
- import { agentSelectors, useSessionStore } from '@/store/session';
11
+ import { useSessionStore } from '@/store/session';
12
+ import { agentSelectors } from '@/store/session/selectors';
12
13
  import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
13
14
 
14
15
  import ChatLayout from '../layout';
@@ -4,7 +4,8 @@ import { createStyles } from 'antd-style';
4
4
  import { ReactNode } from 'react';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
- import { agentSelectors, useSessionStore } from '@/store/session';
7
+ import { useSessionStore } from '@/store/session';
8
+ import { agentSelectors } from '@/store/session/selectors';
8
9
  import { ChatMessage } from '@/types/chatMessage';
9
10
 
10
11
  const useStyles = createStyles(({ css }) => ({
@@ -4,12 +4,8 @@ import { memo, useCallback } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
- import {
8
- agentSelectors,
9
- chatSelectors,
10
- useSessionChatInit,
11
- useSessionStore,
12
- } from '@/store/session';
7
+ import { useSessionChatInit, useSessionStore } from '@/store/session';
8
+ import { agentSelectors, chatSelectors } from '@/store/session/selectors';
13
9
  import { ChatMessage } from '@/types/chatMessage';
14
10
  import { isFunctionMessage } from '@/utils/message';
15
11
 
@@ -49,21 +45,24 @@ const List = () => {
49
45
 
50
46
  if (message.role === 'function')
51
47
  return (
52
- <Flexbox gap={12}>
48
+ <Flexbox gap={12} id={message.id}>
53
49
  <FunctionCall {...fcProps} />
54
50
  <PluginMessage loading={message.id === chatLoadingId} {...message} />
55
51
  </Flexbox>
56
52
  );
57
53
 
58
- if (message.role === 'assistant') {
59
- return isFunctionMessage(message.content) || !!message.function_call ? (
60
- <FunctionCall {...fcProps} />
61
- ) : (
62
- content
54
+ if (
55
+ message.role === 'assistant' &&
56
+ // 包含了 function 信息
57
+ isFunctionMessage(message.content)
58
+ )
59
+ return (
60
+ <div id={message.id}>
61
+ <FunctionCall {...fcProps} />
62
+ </div>
63
63
  );
64
- }
65
64
 
66
- return content;
65
+ return <div id={message.id}>{content}</div>;
67
66
  },
68
67
  [chatLoadingId],
69
68
  );
@@ -5,7 +5,8 @@ import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Flexbox } from 'react-layout-kit';
7
7
 
8
- import { agentSelectors, useSessionStore } from '@/store/session';
8
+ import { useSessionStore } from '@/store/session';
9
+ import { agentSelectors } from '@/store/session/selectors';
9
10
  import { LanguageModel } from '@/types/llm';
10
11
 
11
12
  const InputActions = memo(() => {
@@ -4,7 +4,8 @@ import { memo, useMemo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
6
  import { ModelTokens } from '@/const/modelTokens';
7
- import { agentSelectors, chatSelectors, useSessionStore } from '@/store/session';
7
+ import { useSessionStore } from '@/store/session';
8
+ import { agentSelectors, chatSelectors } from '@/store/session/selectors';
8
9
 
9
10
  const Token = memo<{ input: string }>(({ input }) => {
10
11
  const { t } = useTranslation('common');
@@ -6,7 +6,8 @@ import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { INBOX_SESSION_ID } from '@/const/session';
8
8
  import { useGlobalStore } from '@/store/global';
9
- import { agentSelectors, useSessionStore } from '@/store/session';
9
+ import { useSessionStore } from '@/store/session';
10
+ import { agentSelectors } from '@/store/session/selectors';
10
11
 
11
12
  const MobileHeader = memo<{ settings?: boolean }>(({ settings = true }) => {
12
13
  const { t } = useTranslation('common');
@@ -9,9 +9,11 @@ import { Flexbox } from 'react-layout-kit';
9
9
 
10
10
  import { INBOX_SESSION_ID } from '@/const/session';
11
11
  import { useGlobalStore } from '@/store/global';
12
- import { agentSelectors, useSessionChatInit, useSessionStore } from '@/store/session';
12
+ import { useSessionChatInit, useSessionStore } from '@/store/session';
13
+ import { agentSelectors } from '@/store/session/selectors';
13
14
 
14
15
  import PluginTag from './PluginTag';
16
+ import ShareButton from './ShareButton';
15
17
 
16
18
  const Header = memo<{ settings?: boolean }>(({ settings = true }) => {
17
19
  const init = useSessionChatInit();
@@ -68,14 +70,7 @@ const Header = memo<{ settings?: boolean }>(({ settings = true }) => {
68
70
  }
69
71
  right={
70
72
  <>
71
- {/*<ActionIcon*/}
72
- {/* icon={Share2}*/}
73
- {/* onClick={() => {*/}
74
- {/* // genShareUrl();*/}
75
- {/* }}*/}
76
- {/* size={{ fontSize: 24 }}*/}
77
- {/* title={t('share')}*/}
78
- {/*/>*/}
73
+ <ShareButton />
79
74
  <ActionIcon
80
75
  icon={showAgentSettings ? PanelRightClose : PanelRightOpen}
81
76
  onClick={() => toggleConfig()}
@@ -0,0 +1,29 @@
1
+ import { ActionIcon, Icon } from '@lobehub/ui';
2
+ import { Loader2, Share2 } from 'lucide-react';
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import { useSessionStore } from '@/store/session';
7
+
8
+ const ShareButton = memo(() => {
9
+ const { t } = useTranslation('common');
10
+
11
+ const [shareLoading, shareToShareGPT] = useSessionStore((s) => [
12
+ s.shareLoading,
13
+
14
+ s.shareToShareGPT,
15
+ ]);
16
+
17
+ return shareLoading ? (
18
+ <Icon icon={Loader2} size={{ fontSize: 24 }} spin />
19
+ ) : (
20
+ <ActionIcon
21
+ icon={Share2}
22
+ onClick={shareToShareGPT}
23
+ size={{ fontSize: 24 }}
24
+ title={t('share')}
25
+ />
26
+ );
27
+ });
28
+
29
+ export default ShareButton;
@@ -7,7 +7,8 @@ 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, useSessionChatInit, useSessionStore } from '@/store/session';
10
+ import { useSessionChatInit, useSessionStore } from '@/store/session';
11
+ import { agentSelectors } from '@/store/session/selectors';
11
12
 
12
13
  const useStyles = createStyles(({ css, token }) => ({
13
14
  prompt: css`
@@ -5,7 +5,8 @@ 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, useSessionChatInit, useSessionStore } from '@/store/session';
8
+ import { useSessionChatInit, useSessionStore } from '@/store/session';
9
+ import { topicSelectors } from '@/store/session/selectors';
9
10
 
10
11
  import SkeletonList from './SkeletonList';
11
12
  import TopicItem from './TopicItem';
@@ -1,6 +1,7 @@
1
1
  import { memo } from 'react';
2
2
 
3
- import { sessionSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
3
+ import { useSessionHydrated, useSessionStore } from '@/store/session';
4
+ import { sessionSelectors } from '@/store/session/selectors';
4
5
 
5
6
  import Chat from './chat/index.page';
6
7
  import Loading from './index/Loading';
@@ -0,0 +1,18 @@
1
+ import { ShareGPTConversation } from '@/types/share';
2
+
3
+ const SHAREGPT_URL = 'https://sharegpt.com/api/conversations';
4
+
5
+ export const genShareGPTUrl = async (conversation: ShareGPTConversation) => {
6
+ const res = await fetch(SHAREGPT_URL, {
7
+ body: JSON.stringify(conversation),
8
+ headers: {
9
+ 'Content-Type': 'application/json',
10
+ },
11
+ method: 'POST',
12
+ });
13
+
14
+ const { id } = await res.json();
15
+
16
+ // short link to the ShareGPT post
17
+ return `https://shareg.pt/${id}`;
18
+ };
@@ -1,4 +1,3 @@
1
1
  export * from './hooks';
2
- export * from './selectors';
3
2
  export type { SessionStore } from './store';
4
3
  export { useSessionStore } from './store';
@@ -3,12 +3,13 @@ import { StateCreator } from 'zustand/vanilla';
3
3
  import { SessionStore } from '@/store/session';
4
4
 
5
5
  import { ChatMessageAction, chatMessage } from './message';
6
+ import { ShareAction, chatShare } from './share';
6
7
  import { ChatTopicAction, chatTopic } from './topic';
7
8
 
8
9
  /**
9
10
  * 聊天操作
10
11
  */
11
- export interface ChatAction extends ChatTopicAction, ChatMessageAction {}
12
+ export interface ChatAction extends ChatTopicAction, ChatMessageAction, ShareAction {}
12
13
 
13
14
  export const createChatSlice: StateCreator<
14
15
  SessionStore,
@@ -18,4 +19,5 @@ export const createChatSlice: StateCreator<
18
19
  > = (...params) => ({
19
20
  ...chatTopic(...params),
20
21
  ...chatMessage(...params),
22
+ ...chatShare(...params),
21
23
  });
@@ -359,11 +359,4 @@ export const chatMessage: StateCreator<
359
359
 
360
360
  await realFetchAIResponse(chats, message.id);
361
361
  },
362
- // genShareUrl: () => {
363
- // const session = sessionSelectors.currentSession(get());
364
- // if (!session) return '';
365
- //
366
- // const agent = session.config;
367
- // return genShareMessagesUrl(session.chats, agent.systemRole);
368
- // },
369
362
  });
@@ -0,0 +1,91 @@
1
+ import { produce } from 'immer';
2
+ import { StateCreator } from 'zustand/vanilla';
3
+
4
+ import { genShareGPTUrl } from '@/services/shareGPT';
5
+ import { SessionStore } from '@/store/session';
6
+ import { ShareGPTConversation } from '@/types/share';
7
+
8
+ import { agentSelectors } from '../../agentConfig';
9
+ import { sessionSelectors } from '../../session/selectors';
10
+ import { chatSelectors } from '../selectors';
11
+
12
+ // const t = setNamespace('chat/share');
13
+ export interface ShareAction {
14
+ shareToShareGPT: () => void;
15
+ }
16
+
17
+ export const chatShare: StateCreator<
18
+ SessionStore,
19
+ [['zustand/devtools', never]],
20
+ [],
21
+ ShareAction
22
+ > = (set, get) => ({
23
+ // genShareUrl: () => {
24
+ // const session = sessionSelectors.currentSession(get());
25
+ // if (!session) return '';
26
+ //
27
+ // const agent = session.config;
28
+ // return genShareMessagesUrl(session.chats, agent.systemRole);
29
+ // },
30
+ shareToShareGPT: async () => {
31
+ const session = sessionSelectors.currentSession(get());
32
+ if (!session) return;
33
+ const messages = chatSelectors.currentChats(get());
34
+ const config = agentSelectors.currentAgentConfig(get());
35
+
36
+ const defaultMsg: ShareGPTConversation['items'] = [];
37
+
38
+ const shareMsgs = produce(defaultMsg, (draft) => {
39
+ if (!!config.systemRole) {
40
+ draft.push({
41
+ from: 'human',
42
+ value: `-------------- ### This is a system settings | 这是一条系统设定
43
+
44
+ ${config.systemRole}`,
45
+ });
46
+ }
47
+
48
+ for (const i of messages) {
49
+ switch (i.role) {
50
+ case 'user':
51
+ default: {
52
+ draft.push({ from: 'human', value: i.content });
53
+ break;
54
+ }
55
+
56
+ case 'assistant': {
57
+ draft.push({ from: 'gpt', value: i.content });
58
+ break;
59
+ }
60
+ case 'function': {
61
+ draft.push({
62
+ from: 'gpt',
63
+ value: `-------------- ### This is a function call | 这是一次插件调用
64
+ plugin name: ${i.plugin?.identifier}
65
+ function call name: ${i.plugin?.apiName}
66
+ result:
67
+ \`\`\`json
68
+ ${i.content}
69
+ \`\`\``,
70
+ });
71
+ break;
72
+ }
73
+ }
74
+ }
75
+
76
+ draft.push({
77
+ from: 'human',
78
+ value: 'Share from [LobeChat](https://github.com/lobehub/lobe-chat)',
79
+ });
80
+ });
81
+
82
+ set({ shareLoading: true });
83
+ const res = await genShareGPTUrl({
84
+ avatarUrl: 'https://npm.elemecdn.com/@lobehub/assets-logo/assets/logo-3d.webp',
85
+ items: shareMsgs,
86
+ });
87
+ set({ shareLoading: false });
88
+
89
+ window.open(res, '_blank');
90
+ },
91
+ });
@@ -3,6 +3,7 @@ export interface ChatState {
3
3
  activeTopicId?: string;
4
4
  chatLoadingId?: string;
5
5
  renameTopicId?: string;
6
+ shareLoading?: boolean;
6
7
  topicLoadingId?: string;
7
8
  }
8
9
 
@@ -0,0 +1,7 @@
1
+ export interface ShareGPTConversation {
2
+ avatarUrl?: string | null;
3
+ items: Array<{
4
+ from: 'human' | 'gpt';
5
+ value: any;
6
+ }>;
7
+ }