@lobehub/chat 0.159.3 → 0.159.5

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/docs/usage/start.mdx +1 -1
  3. package/package.json +1 -1
  4. package/src/app/(main)/chat/(workspace)/@topic/_layout/Desktop.tsx +17 -0
  5. package/src/app/(main)/chat/(workspace)/@topic/_layout/Mobile.tsx +21 -0
  6. package/src/app/(main)/chat/(workspace)/@topic/default.tsx +7 -1
  7. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/SkeletonList.tsx → SkeletonList.tsx} +1 -1
  8. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/TopicItem.tsx → TopicItem.tsx} +5 -0
  9. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/index.tsx +95 -13
  10. package/src/app/(main)/chat/(workspace)/_layout/Desktop/TopicPanel.tsx +12 -15
  11. package/src/app/(main)/chat/(workspace)/_layout/Mobile/TopicModal.tsx +9 -1
  12. package/src/app/(main)/chat/_layout/Desktop/SessionPanel.tsx +16 -25
  13. package/src/app/(main)/settings/llm/components/ProviderModelList/ModelConfigModal.tsx +25 -11
  14. package/src/components/SidebarHeader/index.tsx +1 -2
  15. package/src/components/server/MobileNavLayout.tsx +1 -0
  16. package/src/config/modelProviders/openai.ts +17 -3
  17. package/src/config/modelProviders/perplexity.ts +16 -16
  18. package/src/config/modelProviders/zeroone.ts +53 -14
  19. package/src/features/Conversation/components/InboxWelcome/AgentsSuggest.tsx +18 -22
  20. package/src/layout/GlobalProvider/AppTheme.tsx +13 -0
  21. package/src/libs/agent-runtime/openai/__snapshots__/index.test.ts.snap +6 -2
  22. package/src/server/routers/config/__snapshots__/index.test.ts.snap +5 -1
  23. package/src/store/user/slices/preference/initialState.ts +1 -0
  24. package/src/store/user/slices/settings/selectors/modelProvider.test.ts +1 -1
  25. package/src/styles/global.ts +23 -0
  26. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/Topic/index.tsx +0 -101
  27. /package/src/app/(main)/chat/(workspace)/@topic/features/{TopicListContent/Header.tsx → Header.tsx} +0 -0
  28. /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/DefaultContent.tsx → DefaultContent.tsx} +0 -0
  29. /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/TopicContent.tsx → TopicContent.tsx} +0 -0
  30. /package/src/app/(main)/chat/(workspace)/@topic/features/{TopicListContent/TopicSearchBar → TopicSearchBar}/index.tsx +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,66 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.159.5](https://github.com/lobehub/lobe-chat/compare/v0.159.4...v0.159.5)
6
+
7
+ <sup>Released on **2024-05-14**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **misc**: Fix scroll and expand.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **misc**: Fix scroll and expand, closes [#2470](https://github.com/lobehub/lobe-chat/issues/2470) ([8b1202a](https://github.com/lobehub/lobe-chat/commit/8b1202a))
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.159.4](https://github.com/lobehub/lobe-chat/compare/v0.159.3...v0.159.4)
31
+
32
+ <sup>Released on **2024-05-14**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Refresh model config form & mobile footer button lost.
37
+
38
+ #### 💄 Styles
39
+
40
+ - **misc**: Add GPT-4o model, update perplexity models, updates 01.AI model list.
41
+
42
+ <br/>
43
+
44
+ <details>
45
+ <summary><kbd>Improvements and Fixes</kbd></summary>
46
+
47
+ #### What's fixed
48
+
49
+ - **misc**: Refresh model config form & mobile footer button lost, closes [#2318](https://github.com/lobehub/lobe-chat/issues/2318) [#2319](https://github.com/lobehub/lobe-chat/issues/2319) [#1811](https://github.com/lobehub/lobe-chat/issues/1811) ([eadcefc](https://github.com/lobehub/lobe-chat/commit/eadcefc))
50
+
51
+ #### Styles
52
+
53
+ - **misc**: Add GPT-4o model, closes [#2481](https://github.com/lobehub/lobe-chat/issues/2481) ([ae6a03f](https://github.com/lobehub/lobe-chat/commit/ae6a03f))
54
+ - **misc**: Update perplexity models, closes [#2469](https://github.com/lobehub/lobe-chat/issues/2469) ([488cde7](https://github.com/lobehub/lobe-chat/commit/488cde7))
55
+ - **misc**: Updates 01.AI model list, closes [#2471](https://github.com/lobehub/lobe-chat/issues/2471) ([f28711a](https://github.com/lobehub/lobe-chat/commit/f28711a))
56
+
57
+ </details>
58
+
59
+ <div align="right">
60
+
61
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
62
+
63
+ </div>
64
+
5
65
  ### [Version 0.159.3](https://github.com/lobehub/lobe-chat/compare/v0.159.2...v0.159.3)
6
66
 
7
67
  <sup>Released on **2024-05-14**</sup>
@@ -1,5 +1,5 @@
1
1
  ---
2
- title: Get Start with LobeChat
2
+ title: Get started with LobeChat
3
3
  description: >-
4
4
  Explore the exciting features in LobeChat, including Vision Model, TTS & STT,
5
5
  Local LLMs, and Multi AI Providers. Discover more about Agent Market, Plugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.159.3",
3
+ "version": "0.159.5",
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",
@@ -0,0 +1,17 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { Flexbox } from 'react-layout-kit';
3
+
4
+ import Header from '../features/Header';
5
+
6
+ const Layout = ({ children }: PropsWithChildren) => {
7
+ return (
8
+ <>
9
+ <Header />
10
+ <Flexbox height={'100%'} style={{ overflow: 'hidden', position: 'relative' }} width={'100%'}>
11
+ {children}
12
+ </Flexbox>
13
+ </>
14
+ );
15
+ };
16
+
17
+ export default Layout;
@@ -0,0 +1,21 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { Flexbox } from 'react-layout-kit';
3
+
4
+ import TopicSearchBar from '../features/TopicSearchBar';
5
+
6
+ const Layout = ({ children }: PropsWithChildren) => {
7
+ return (
8
+ <Flexbox gap={8} height={'100%'} padding={'8px 8px 0'} style={{ overflow: 'hidden' }}>
9
+ <TopicSearchBar />
10
+ <Flexbox
11
+ height={'100%'}
12
+ style={{ marginInline: -8, overflow: 'hidden', position: 'relative' }}
13
+ width={'calc(100% + 16px)'}
14
+ >
15
+ {children}
16
+ </Flexbox>
17
+ </Flexbox>
18
+ );
19
+ };
20
+
21
+ export default Layout;
@@ -1,15 +1,21 @@
1
1
  import { isMobileDevice } from '@/utils/responsive';
2
2
 
3
+ import Desktop from './_layout/Desktop';
4
+ import Mobile from './_layout/Mobile';
3
5
  import SystemRole from './features/SystemRole';
4
6
  import TopicListContent from './features/TopicListContent';
5
7
 
6
8
  const Topic = () => {
7
9
  const mobile = isMobileDevice();
8
10
 
11
+ const Layout = mobile ? Mobile : Desktop;
12
+
9
13
  return (
10
14
  <>
11
15
  {!mobile && <SystemRole />}
12
- <TopicListContent mobile={mobile} />
16
+ <Layout>
17
+ <TopicListContent />
18
+ </Layout>
13
19
  </>
14
20
  );
15
21
  };
@@ -45,7 +45,7 @@ export const Placeholder = memo(() => {
45
45
  });
46
46
 
47
47
  export const SkeletonList = memo(() => (
48
- <Flexbox>
48
+ <Flexbox style={{ paddingTop: 6 }}>
49
49
  {Array.from({ length: 8 }).map((_, i) => (
50
50
  <Placeholder key={i} />
51
51
  ))}
@@ -19,7 +19,12 @@ const useStyles = createStyles(({ css, token, isDarkMode }) => ({
19
19
  `,
20
20
  container: css`
21
21
  cursor: pointer;
22
+
23
+ width: calc(100% - 16px);
24
+ margin-block: 2px;
25
+ margin-inline: 8px;
22
26
  padding: 8px;
27
+
23
28
  border-radius: ${token.borderRadius}px;
24
29
 
25
30
  &:hover {
@@ -1,18 +1,100 @@
1
+ 'use client';
2
+
3
+ import { EmptyCard } from '@lobehub/ui';
4
+ import { useThemeMode } from 'antd-style';
5
+ import isEqual from 'fast-deep-equal';
6
+ import React, { memo, useCallback, useRef } from 'react';
7
+ import { useTranslation } from 'react-i18next';
1
8
  import { Flexbox } from 'react-layout-kit';
9
+ import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
10
+
11
+ import { imageUrl } from '@/const/url';
12
+ import { useChatStore } from '@/store/chat';
13
+ import { topicSelectors } from '@/store/chat/selectors';
14
+ import { useUserStore } from '@/store/user';
15
+ import { ChatTopic } from '@/types/topic';
16
+
17
+ import { Placeholder, SkeletonList } from './SkeletonList';
18
+ import TopicItem from './TopicItem';
19
+
20
+ const TopicListContent = memo(() => {
21
+ const { t } = useTranslation('chat');
22
+ const virtuosoRef = useRef<VirtuosoHandle>(null);
23
+ const { isDarkMode } = useThemeMode();
24
+ const [topicsInit, activeTopicId, topicLength] = useChatStore((s) => [
25
+ s.topicsInit,
26
+ s.activeTopicId,
27
+ topicSelectors.currentTopicLength(s),
28
+ ]);
29
+ const [visible, updateGuideState] = useUserStore((s) => [
30
+ s.preference.guide?.topic,
31
+ s.updateGuideState,
32
+ ]);
33
+
34
+ const topics = useChatStore(
35
+ (s) => [
36
+ {
37
+ favorite: false,
38
+ id: 'default',
39
+ title: t('topic.defaultTitle'),
40
+ } as ChatTopic,
41
+ ...topicSelectors.displayTopics(s),
42
+ ],
43
+ isEqual,
44
+ );
45
+
46
+ const itemContent = useCallback(
47
+ (index: number, { id, favorite, title }: ChatTopic) =>
48
+ index === 0 ? (
49
+ <TopicItem active={!activeTopicId} fav={favorite} title={title} />
50
+ ) : (
51
+ <TopicItem active={activeTopicId === id} fav={favorite} id={id} key={id} title={title} />
52
+ ),
53
+ [activeTopicId],
54
+ );
55
+
56
+ const activeIndex = topics.findIndex((topic) => topic.id === activeTopicId);
2
57
 
3
- import Header from './Header';
4
- import { Topic } from './Topic';
5
- import TopicSearchBar from './TopicSearchBar';
6
-
7
- const TopicListContent = ({ mobile }: { mobile?: boolean }) => {
8
- return (
9
- <Flexbox gap={mobile ? 8 : 0} height={'100%'} style={{ overflow: 'hidden' }}>
10
- {mobile ? <TopicSearchBar /> : <Header />}
11
- <Flexbox gap={16} height={'100%'} style={{ paddingTop: 6, position: 'relative' }}>
12
- <Topic mobile={mobile} />
13
- </Flexbox>
14
- </Flexbox>
58
+ return !topicsInit ? (
59
+ <SkeletonList />
60
+ ) : (
61
+ <>
62
+ {topicLength === 0 && visible && (
63
+ <Flexbox paddingInline={8}>
64
+ <EmptyCard
65
+ alt={t('topic.guide.desc')}
66
+ cover={imageUrl(`empty_topic_${isDarkMode ? 'dark' : 'light'}.webp`)}
67
+ desc={t('topic.guide.desc')}
68
+ height={120}
69
+ imageProps={{
70
+ priority: true,
71
+ }}
72
+ onVisibleChange={(visible) => {
73
+ updateGuideState({ topic: visible });
74
+ }}
75
+ style={{ flex: 'none', marginBottom: 12 }}
76
+ title={t('topic.guide.title')}
77
+ visible={visible}
78
+ width={200}
79
+ />
80
+ </Flexbox>
81
+ )}
82
+ <Virtuoso
83
+ components={{ ScrollSeekPlaceholder: Placeholder }}
84
+ computeItemKey={(_, item) => item.id}
85
+ data={topics}
86
+ fixedItemHeight={44}
87
+ initialTopMostItemIndex={Math.max(activeIndex, 0)}
88
+ itemContent={itemContent}
89
+ overscan={44 * 10}
90
+ ref={virtuosoRef}
91
+ scrollSeekConfiguration={{
92
+ enter: (velocity) => Math.abs(velocity) > 350,
93
+ exit: (velocity) => Math.abs(velocity) < 10,
94
+ }}
95
+ />
96
+ </>
15
97
  );
16
- };
98
+ });
17
99
 
18
100
  export default TopicListContent;
@@ -2,7 +2,8 @@
2
2
 
3
3
  import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
4
4
  import { createStyles, useResponsive } from 'antd-style';
5
- import { PropsWithChildren, memo, useEffect, useLayoutEffect, useState } from 'react';
5
+ import isEqual from 'fast-deep-equal';
6
+ import { PropsWithChildren, memo, useEffect, useState } from 'react';
6
7
 
7
8
  import SafeSpacing from '@/components/SafeSpacing';
8
9
  import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
@@ -26,27 +27,23 @@ const useStyles = createStyles(({ css, token }) => ({
26
27
  const TopicPanel = memo(({ children }: PropsWithChildren) => {
27
28
  const { styles } = useStyles();
28
29
  const { md = true, lg = true } = useResponsive();
29
- const [showAgentSettings, toggleConfig, isPreferenceInit] = useGlobalStore((s) => [
30
+ const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
30
31
  s.preference.showChatSideBar,
31
32
  s.toggleChatSideBar,
32
33
  s.isPreferenceInit,
33
34
  ]);
34
- const [expand, setExpand] = useState(showAgentSettings);
35
+ const [cacheExpand, setCacheExpand] = useState<boolean>(Boolean(showAgentSettings));
35
36
 
36
- const handleExpand = (e: boolean) => {
37
- toggleConfig(e);
38
- setExpand(e);
37
+ const handleExpand = (expand: boolean) => {
38
+ if (isEqual(expand, Boolean(showAgentSettings))) return;
39
+ toggleConfig(expand);
40
+ setCacheExpand(expand);
39
41
  };
40
42
 
41
- useLayoutEffect(() => {
42
- if (!isPreferenceInit) return;
43
- setExpand(showAgentSettings);
44
- }, [isPreferenceInit, showAgentSettings]);
45
-
46
43
  useEffect(() => {
47
- if (lg && showAgentSettings) setExpand(true);
48
- if (!lg) setExpand(false);
49
- }, [lg, showAgentSettings]);
44
+ if (lg && cacheExpand) toggleConfig(true);
45
+ if (!lg) toggleConfig(false);
46
+ }, [lg, cacheExpand]);
50
47
 
51
48
  return (
52
49
  <DraggablePanel
@@ -54,7 +51,7 @@ const TopicPanel = memo(({ children }: PropsWithChildren) => {
54
51
  classNames={{
55
52
  content: styles.content,
56
53
  }}
57
- expand={expand}
54
+ expand={showAgentSettings}
58
55
  minWidth={CHAT_SIDEBAR_WIDTH}
59
56
  mode={md ? 'fixed' : 'float'}
60
57
  onExpandChange={handleExpand}
@@ -17,7 +17,15 @@ const Topics = memo(({ children }: PropsWithChildren) => {
17
17
  const { t } = useTranslation('chat');
18
18
 
19
19
  return (
20
- <Modal allowFullscreen onCancel={() => setOpen(false)} open={open} title={t('topic.title')}>
20
+ <Modal
21
+ allowFullscreen
22
+ onCancel={() => setOpen(false)}
23
+ open={open}
24
+ styles={{
25
+ body: { padding: 0 },
26
+ }}
27
+ title={t('topic.title')}
28
+ >
21
29
  {children}
22
30
  </Modal>
23
31
  );
@@ -3,7 +3,7 @@
3
3
  import { DraggablePanel, DraggablePanelContainer, type DraggablePanelProps } from '@lobehub/ui';
4
4
  import { createStyles, useResponsive } from 'antd-style';
5
5
  import isEqual from 'fast-deep-equal';
6
- import { PropsWithChildren, memo, useEffect, useLayoutEffect, useState } from 'react';
6
+ import { PropsWithChildren, memo, useEffect, useState } from 'react';
7
7
 
8
8
  import { FOLDER_WIDTH } from '@/const/layoutTokens';
9
9
  import { useGlobalStore } from '@/store/global';
@@ -18,25 +18,21 @@ export const useStyles = createStyles(({ css, token }) => ({
18
18
 
19
19
  const SessionPanel = memo<PropsWithChildren>(({ children }) => {
20
20
  const { md = true } = useResponsive();
21
+
21
22
  const { styles } = useStyles();
22
- const [sessionsWidth, sessionExpandable, updatePreference, isPreferenceInit] = useGlobalStore(
23
- (s) => [
24
- s.preference.sessionsWidth,
25
- s.preference.showSessionPanel,
26
- s.updatePreference,
27
- s.isPreferenceInit,
28
- ],
29
- );
30
- const [expand, setExpand] = useState(sessionExpandable);
23
+ const [sessionsWidth, sessionExpandable, updatePreference] = useGlobalStore((s) => [
24
+ s.preference.sessionsWidth,
25
+ s.preference.showSessionPanel,
26
+ s.updatePreference,
27
+ ]);
28
+ const [cacheExpand, setCacheExpand] = useState<boolean>(Boolean(sessionExpandable));
31
29
  const [tmpWidth, setWidth] = useState(sessionsWidth);
32
30
  if (tmpWidth !== sessionsWidth) setWidth(sessionsWidth);
33
31
 
34
- const handleExpand: DraggablePanelProps['onExpandChange'] = (e) => {
35
- updatePreference({
36
- sessionsWidth: e ? 320 : 0,
37
- showSessionPanel: e,
38
- });
39
- setExpand(e);
32
+ const handleExpand = (expand: boolean) => {
33
+ if (isEqual(expand, sessionExpandable)) return;
34
+ updatePreference({ showSessionPanel: expand });
35
+ setCacheExpand(expand);
40
36
  };
41
37
 
42
38
  const handleSizeChange: DraggablePanelProps['onSizeChange'] = (_, size) => {
@@ -47,21 +43,16 @@ const SessionPanel = memo<PropsWithChildren>(({ children }) => {
47
43
  updatePreference({ sessionsWidth: nextWidth });
48
44
  };
49
45
 
50
- useLayoutEffect(() => {
51
- if (!isPreferenceInit) return;
52
- setExpand(sessionExpandable);
53
- }, [isPreferenceInit, sessionExpandable]);
54
-
55
46
  useEffect(() => {
56
- if (md && sessionExpandable) setExpand(true);
57
- if (!md) setExpand(false);
58
- }, [md, sessionExpandable]);
47
+ if (md && cacheExpand) updatePreference({ showSessionPanel: true });
48
+ if (!md) updatePreference({ showSessionPanel: false });
49
+ }, [md, cacheExpand]);
59
50
 
60
51
  return (
61
52
  <DraggablePanel
62
53
  className={styles.panel}
63
54
  defaultSize={{ width: tmpWidth }}
64
- expand={expand}
55
+ expand={sessionExpandable}
65
56
  maxWidth={400}
66
57
  minWidth={FOLDER_WIDTH}
67
58
  mode={md ? 'fixed' : 'float'}
@@ -1,5 +1,5 @@
1
1
  import { Modal } from '@lobehub/ui';
2
- import { Checkbox, Form, Input } from 'antd';
2
+ import { Button, Checkbox, Form, Input } from 'antd';
3
3
  import isEqual from 'fast-deep-equal';
4
4
  import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
@@ -16,6 +16,7 @@ interface ModelConfigModalProps {
16
16
  const ModelConfigModal = memo<ModelConfigModalProps>(({ showAzureDeployName, provider }) => {
17
17
  const [formInstance] = Form.useForm();
18
18
  const { t } = useTranslation('setting');
19
+ const { t: tc } = useTranslation('common');
19
20
 
20
21
  const [open, id, editingProvider, dispatchCustomModelCards, toggleEditingCustomModelCard] =
21
22
  useUserStore((s) => [
@@ -38,20 +39,32 @@ const ModelConfigModal = memo<ModelConfigModalProps>(({ showAzureDeployName, pro
38
39
  return (
39
40
  <Modal
40
41
  destroyOnClose
41
- maskClosable
42
- onCancel={() => {
43
- closeModal();
44
- }}
45
- onOk={() => {
46
- if (!editingProvider || !id) return;
47
- const data = formInstance.getFieldsValue();
42
+ footer={[
43
+ <Button key="cancel" onClick={closeModal}>
44
+ {tc('cancel')}
45
+ </Button>,
46
+
47
+ <Button
48
+ key="ok"
49
+ onClick={() => {
50
+ if (!editingProvider || !id) return;
51
+ const data = formInstance.getFieldsValue();
48
52
 
49
- dispatchCustomModelCards(editingProvider as any, { id, type: 'update', value: data });
53
+ dispatchCustomModelCards(editingProvider as any, { id, type: 'update', value: data });
50
54
 
51
- closeModal();
52
- }}
55
+ closeModal();
56
+ }}
57
+ style={{ marginInlineStart: '16px' }}
58
+ type="primary"
59
+ >
60
+ {tc('ok')}
61
+ </Button>,
62
+ ]}
63
+ maskClosable
64
+ onCancel={closeModal}
53
65
  open={open}
54
66
  title={t('llm.customModelCards.modelConfig.modalTitle')}
67
+ zIndex={1051} // Select is 1050
55
68
  >
56
69
  <div
57
70
  onClick={(e) => {
@@ -66,6 +79,7 @@ const ModelConfigModal = memo<ModelConfigModalProps>(({ showAzureDeployName, pro
66
79
  form={formInstance}
67
80
  initialValues={modelCard}
68
81
  labelCol={{ span: 4 }}
82
+ preserve={false}
69
83
  style={{ marginTop: 16 }}
70
84
  wrapperCol={{ offset: 1, span: 18 }}
71
85
  >
@@ -2,10 +2,9 @@ import { createStyles } from 'antd-style';
2
2
  import { type ReactNode, memo } from 'react';
3
3
  import { Flexbox } from 'react-layout-kit';
4
4
 
5
- const useStyles = createStyles(({ css, token }) => ({
5
+ const useStyles = createStyles(({ css }) => ({
6
6
  header: css`
7
7
  z-index: 10;
8
- box-shadow: 0 2px 6px ${token.colorBgLayout};
9
8
  `,
10
9
  }));
11
10
 
@@ -16,6 +16,7 @@ const MobileContentLayout = ({
16
16
  const content = (
17
17
  <Flexbox
18
18
  height="100%"
19
+ id={'lobe-mobile-scroll-container'}
19
20
  style={{
20
21
  overflowX: 'hidden',
21
22
  overflowY: 'auto',
@@ -29,8 +29,10 @@ const OpenAI: ModelProviderCard = {
29
29
  tokens: 4096,
30
30
  },
31
31
  {
32
+ description: 'Currently points to gpt-3.5-turbo-16k-0613',
32
33
  displayName: 'GPT-3.5 Turbo 16K',
33
34
  id: 'gpt-3.5-turbo-16k',
35
+ legacy: true,
34
36
  tokens: 16_385,
35
37
  },
36
38
  {
@@ -43,9 +45,10 @@ const OpenAI: ModelProviderCard = {
43
45
  displayName: 'GPT-3.5 Turbo 16K (0613)',
44
46
  id: 'gpt-3.5-turbo-16k-0613',
45
47
  legacy: true,
46
- tokens: 4096,
48
+ tokens: 16_385,
47
49
  },
48
50
  {
51
+ description: 'Currently points to gpt-4-0125-preview',
49
52
  displayName: 'GPT-4 Turbo Preview',
50
53
  functionCall: true,
51
54
  id: 'gpt-4-turbo-preview',
@@ -58,7 +61,7 @@ const OpenAI: ModelProviderCard = {
58
61
  tokens: 128_000,
59
62
  },
60
63
  {
61
- description: 'GPT-4 视觉预览版,支持视觉任务',
64
+ description: 'Currently points to gpt-4-1106-vision-preview',
62
65
  displayName: 'GPT-4 Turbo Vision Preview',
63
66
  id: 'gpt-4-vision-preview',
64
67
  tokens: 128_000,
@@ -77,6 +80,7 @@ const OpenAI: ModelProviderCard = {
77
80
  tokens: 128_000,
78
81
  },
79
82
  {
83
+ description: 'Currently points to gpt-4-0613',
80
84
  displayName: 'GPT-4',
81
85
  functionCall: true,
82
86
  id: 'gpt-4',
@@ -89,6 +93,7 @@ const OpenAI: ModelProviderCard = {
89
93
  tokens: 8192,
90
94
  },
91
95
  {
96
+ description: 'Currently points to gpt-4-32k-0613',
92
97
  displayName: 'GPT-4 32K',
93
98
  functionCall: true,
94
99
  id: 'gpt-4-32k',
@@ -101,7 +106,7 @@ const OpenAI: ModelProviderCard = {
101
106
  tokens: 32_768,
102
107
  },
103
108
  {
104
- description: 'GPT-4 Turbo 视觉版',
109
+ description: 'GPT-4 Turbo with Vision',
105
110
  displayName: 'GPT-4 Turbo',
106
111
  enabled: true,
107
112
  functionCall: true,
@@ -117,6 +122,15 @@ const OpenAI: ModelProviderCard = {
117
122
  tokens: 128_000,
118
123
  vision: true,
119
124
  },
125
+ {
126
+ description: 'Currently points to gpt-4o-2024-05-13',
127
+ displayName: 'GPT-4o',
128
+ enabled: true,
129
+ functionCall: true,
130
+ id: 'gpt-4o',
131
+ tokens: 128_000,
132
+ vision: true,
133
+ },
120
134
  ],
121
135
  enabled: true,
122
136
  id: 'openai',
@@ -5,35 +5,35 @@ const Perplexity: ModelProviderCard = {
5
5
  chatModels: [
6
6
  {
7
7
  displayName: 'Perplexity 7B Chat',
8
- id: 'sonar-small-chat',
9
- tokens: 16_384,
8
+ id: 'llama-3-sonar-small-32k-chat',
9
+ tokens: 32_768,
10
10
  },
11
11
  {
12
- displayName: 'Perplexity 8x7B Chat',
12
+ displayName: 'Perplexity 70B Chat',
13
13
  enabled: true,
14
- id: 'sonar-medium-chat',
15
- tokens: 16_384,
14
+ id: 'llama-3-sonar-large-32k-chat',
15
+ tokens: 32_768,
16
16
  },
17
17
  {
18
18
  displayName: 'Perplexity 7B Online',
19
- id: 'sonar-small-online',
20
- tokens: 12_000,
19
+ id: 'llama-3-sonar-small-32k-online',
20
+ tokens: 28_000,
21
21
  },
22
22
  {
23
- displayName: 'Perplexity 8x7B Online',
23
+ displayName: 'Perplexity 70B Online',
24
24
  enabled: true,
25
- id: 'sonar-medium-online',
26
- tokens: 12_000,
25
+ id: 'llama-3-sonar-large-32k-online',
26
+ tokens: 28_000,
27
27
  },
28
28
  {
29
- displayName: 'Codellama 70B Instruct',
30
- id: 'codellama-70b-instruct',
31
- tokens: 16_384,
29
+ displayName: 'Llama3 8B Instruct',
30
+ id: 'llama-3-8b-instruct',
31
+ tokens: 8192,
32
32
  },
33
33
  {
34
- displayName: 'Mistral 7B Instruct',
35
- id: 'mistral-7b-instruc',
36
- tokens: 16_384,
34
+ displayName: 'Llama3 70B Instruct',
35
+ id: 'llama-3-70b-instruct',
36
+ tokens: 8192,
37
37
  },
38
38
  {
39
39
  displayName: 'Mixtral 8x7B Instruct',
@@ -1,31 +1,70 @@
1
1
  import { ModelProviderCard } from '@/types/llm';
2
2
 
3
- // ref https://platform.lingyiwanwu.com/
3
+ // ref https://platform.lingyiwanwu.com/docs#%E6%A8%A1%E5%9E%8B
4
4
  const ZeroOne: ModelProviderCard = {
5
5
  chatModels: [
6
6
  {
7
- description: '支持聊天、问答、对话、写作、翻译等功能。',
8
- displayName: 'YI 34B Chat',
7
+ description: '全新千亿参数模型,提供超强问答及文本生成能力。',
8
+ displayName: 'Yi Large',
9
9
  enabled: true,
10
- id: 'yi-34b-chat-0205',
11
- tokens: 4096, // https://huggingface.co/01-ai/Yi-34B-Chat/blob/main/config.json
10
+ id: 'yi-large',
11
+ tokens: 16_384,
12
12
  },
13
13
  {
14
- description:
15
- '支持通用图片问答、图表理解、OCR、视觉推理,能处理高分辨率(1024*1024)的图像,能在复杂视觉任务上提供优秀性能,同时支持多种语言。',
16
- displayName: 'YI Vision Plus',
14
+ description: '中型尺寸模型升级微调,能力均衡,性价比高。深度优化指令遵循能力。',
15
+ displayName: 'Yi Medium',
17
16
  enabled: true,
18
- id: 'yi-vl-plus',
17
+ id: 'yi-medium',
18
+ tokens: 16_384,
19
+ },
20
+ {
21
+ description: '复杂视觉任务模型,提供高性能图片理解、分析能力。',
22
+ displayName: 'Yi Vision',
23
+ enabled: true,
24
+ id: 'yi-vision',
19
25
  tokens: 4096,
20
- vision: true,
21
26
  },
22
27
  {
23
- description: '增强了问答对话交互和深度内容创作能力。文档问答和构建知识库小能手。',
24
- displayName: 'YI 34B Chat 200k',
28
+ description: '200K 超长上下文窗口,提供长文本深度理解和生成能力。',
29
+ displayName: 'Yi 200K',
25
30
  enabled: true,
26
- id: 'yi-34b-chat-200k',
27
- tokens: 200_000, // https://huggingface.co/01-ai/Yi-34B-200K/blob/main/config.json
31
+ id: 'yi-medium-200k',
32
+ tokens: 200_000,
28
33
  },
34
+ {
35
+ description: '小而精悍,轻量极速模型。提供强化数学运算和代码编写能力。',
36
+ displayName: 'Yi Spark',
37
+ enabled: true,
38
+ id: 'yi-spark',
39
+ tokens: 16_384,
40
+ },
41
+ {
42
+ description: '基于Yi-Large超强模型的高阶服务,结合检索与生成技术提供精准答案,支持客⼾私有知识库(请联系客服申请)。',
43
+ displayName: 'Yi Large RAG',
44
+ id: 'yi-large-rag',
45
+ tokens: 16_384,
46
+ },
47
+ {
48
+ description: '超高性价比、卓越性能。根据性能和推理速度、成本,进行平衡性高精度调优。',
49
+ displayName: 'Yi Large Turbo',
50
+ enabled: true,
51
+ id: 'yi-large-turbo',
52
+ tokens: 16_384,
53
+ },
54
+ {
55
+ description: '「兼容版本模型」文本推理能力增强。',
56
+ displayName: 'Yi Large Preview',
57
+ enabled: true,
58
+ id: 'yi-large-preview',
59
+ tokens: 16_384,
60
+ },
61
+ {
62
+ description: '「兼容版本模型」实时信息获取,以及文本推理能力增强。',
63
+ displayName: 'Yi Large RAG Preview',
64
+ id: 'yi-large-rag-preview',
65
+ tokens: 16_384,
66
+ },
67
+
29
68
  ],
30
69
  id: 'zeroone',
31
70
  };
@@ -6,7 +6,7 @@ import { createStyles } from 'antd-style';
6
6
  import isEqual from 'fast-deep-equal';
7
7
  import { RefreshCw } from 'lucide-react';
8
8
  import Link from 'next/link';
9
- import { memo, useMemo, useState } from 'react';
9
+ import { memo, useState } from 'react';
10
10
  import { useTranslation } from 'react-i18next';
11
11
  import { Flexbox } from 'react-layout-kit';
12
12
 
@@ -71,26 +71,6 @@ const AgentsSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
71
71
  </Flexbox>
72
72
  ));
73
73
 
74
- const cards = useMemo(
75
- () =>
76
- agentList.slice(sliceStart, sliceStart + agentLength).map((agent) => (
77
- <Link href={`/market?agent=${agent.identifier}`} key={agent.identifier}>
78
- <Flexbox className={styles.card} gap={8} horizontal>
79
- <Avatar avatar={agent.meta.avatar} style={{ flex: 'none' }} />
80
- <Flexbox gap={mobile ? 2 : 8} style={{ overflow: 'hidden', width: '100%' }}>
81
- <Paragraph className={styles.cardTitle} ellipsis={{ rows: 1 }}>
82
- {agent.meta.title}
83
- </Paragraph>
84
- <Paragraph className={styles.cardDesc} ellipsis={{ rows: mobile ? 1 : 2 }}>
85
- {agent.meta.description}
86
- </Paragraph>
87
- </Flexbox>
88
- </Flexbox>
89
- </Link>
90
- )),
91
- [agentList, sliceStart],
92
- );
93
-
94
74
  const handleRefresh = () => {
95
75
  if (!agentList) return;
96
76
  setSliceStart(Math.floor((Math.random() * agentList.length) / 2));
@@ -108,7 +88,23 @@ const AgentsSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
108
88
  />
109
89
  </Flexbox>
110
90
  <Grid gap={8} rows={2}>
111
- {isLoading ? loadingCards : cards}
91
+ {isLoading
92
+ ? loadingCards
93
+ : agentList.slice(sliceStart, sliceStart + agentLength).map((agent) => (
94
+ <Link href={`/market?agent=${agent.identifier}`} key={agent.identifier}>
95
+ <Flexbox className={styles.card} gap={8} horizontal>
96
+ <Avatar avatar={agent.meta.avatar} style={{ flex: 'none' }} />
97
+ <Flexbox gap={mobile ? 2 : 8} style={{ overflow: 'hidden', width: '100%' }}>
98
+ <Paragraph className={styles.cardTitle} ellipsis={{ rows: 1 }}>
99
+ {agent.meta.title}
100
+ </Paragraph>
101
+ <Paragraph className={styles.cardDesc} ellipsis={{ rows: mobile ? 1 : 2 }}>
102
+ {agent.meta.description}
103
+ </Paragraph>
104
+ </Flexbox>
105
+ </Flexbox>
106
+ </Link>
107
+ ))}
112
108
  </Grid>
113
109
  </Flexbox>
114
110
  );
@@ -30,12 +30,25 @@ const useStyles = createStyles(({ css, token }) => ({
30
30
  height: 100%;
31
31
  min-height: 100dvh;
32
32
  max-height: 100dvh;
33
+
34
+ @media (min-device-width: 576px) {
35
+ overflow: hidden;
36
+ }
33
37
  `,
34
38
  // scrollbar-width and scrollbar-color are supported from Chrome 121
35
39
  // https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
36
40
  scrollbar: css`
37
41
  scrollbar-color: ${token.colorFill} transparent;
38
42
  scrollbar-width: thin;
43
+
44
+ #lobe-mobile-scroll-container {
45
+ scrollbar-width: none;
46
+
47
+ ::-webkit-scrollbar {
48
+ width: 0;
49
+ height: 0;
50
+ }
51
+ }
39
52
  `,
40
53
 
41
54
  // so this is a polyfill for older browsers
@@ -11,15 +11,17 @@ exports[`LobeOpenAI > models > should get models 1`] = `
11
11
  "tokens": 16385,
12
12
  },
13
13
  {
14
+ "description": "Currently points to gpt-3.5-turbo-16k-0613",
14
15
  "displayName": "GPT-3.5 Turbo 16K",
15
16
  "id": "gpt-3.5-turbo-16k",
17
+ "legacy": true,
16
18
  "tokens": 16385,
17
19
  },
18
20
  {
19
21
  "displayName": "GPT-3.5 Turbo 16K (0613)",
20
22
  "id": "gpt-3.5-turbo-16k-0613",
21
23
  "legacy": true,
22
- "tokens": 4096,
24
+ "tokens": 16385,
23
25
  },
24
26
  {
25
27
  "displayName": "GPT-4 Turbo Vision Preview (1106)",
@@ -37,6 +39,7 @@ exports[`LobeOpenAI > models > should get models 1`] = `
37
39
  "tokens": 128000,
38
40
  },
39
41
  {
42
+ "description": "Currently points to gpt-4-0125-preview",
40
43
  "displayName": "GPT-4 Turbo Preview",
41
44
  "functionCall": true,
42
45
  "id": "gpt-4-turbo-preview",
@@ -69,13 +72,14 @@ exports[`LobeOpenAI > models > should get models 1`] = `
69
72
  "tokens": 128000,
70
73
  },
71
74
  {
72
- "description": "GPT-4 视觉预览版,支持视觉任务",
75
+ "description": "Currently points to gpt-4-1106-vision-preview",
73
76
  "displayName": "GPT-4 Turbo Vision Preview",
74
77
  "id": "gpt-4-vision-preview",
75
78
  "tokens": 128000,
76
79
  "vision": true,
77
80
  },
78
81
  {
82
+ "description": "Currently points to gpt-4-0613",
79
83
  "displayName": "GPT-4",
80
84
  "functionCall": true,
81
85
  "id": "gpt-4",
@@ -69,12 +69,15 @@ exports[`configRouter > getGlobalConfig > Model Provider env > OPENAI_MODEL_LIST
69
69
  "tokens": 16385,
70
70
  },
71
71
  {
72
+ "description": "Currently points to gpt-3.5-turbo-16k-0613",
72
73
  "displayName": "GPT-3.5 Turbo 16K",
73
74
  "enabled": true,
74
75
  "id": "gpt-3.5-turbo-16k",
76
+ "legacy": true,
75
77
  "tokens": 16385,
76
78
  },
77
79
  {
80
+ "description": "Currently points to gpt-4-0613",
78
81
  "displayName": "GPT-4",
79
82
  "enabled": true,
80
83
  "functionCall": true,
@@ -82,6 +85,7 @@ exports[`configRouter > getGlobalConfig > Model Provider env > OPENAI_MODEL_LIST
82
85
  "tokens": 8192,
83
86
  },
84
87
  {
88
+ "description": "Currently points to gpt-4-32k-0613",
85
89
  "displayName": "GPT-4 32K",
86
90
  "enabled": true,
87
91
  "functionCall": true,
@@ -96,7 +100,7 @@ exports[`configRouter > getGlobalConfig > Model Provider env > OPENAI_MODEL_LIST
96
100
  "tokens": 128000,
97
101
  },
98
102
  {
99
- "description": "GPT-4 视觉预览版,支持视觉任务",
103
+ "description": "Currently points to gpt-4-1106-vision-preview",
100
104
  "displayName": "GPT-4 Turbo Vision Preview",
101
105
  "enabled": true,
102
106
  "id": "gpt-4-vision-preview",
@@ -32,6 +32,7 @@ export interface UserPreferenceState {
32
32
  export const DEFAULT_PREFERENCE: UserPreference = {
33
33
  guide: {
34
34
  moveSettingsToAvatar: true,
35
+ topic: true,
35
36
  },
36
37
  telemetry: null,
37
38
  useCmdEnterToSend: false,
@@ -49,7 +49,7 @@ describe('modelProviderSelectors', () => {
49
49
  const s = merge(initialSettingsState, {}) as unknown as UserStore;
50
50
 
51
51
  const result = modelProviderSelectors.getDefaultEnabledModelsById('openai')(s);
52
- expect(result).toEqual(['gpt-3.5-turbo', 'gpt-4-turbo']);
52
+ expect(result).toEqual(['gpt-3.5-turbo', 'gpt-4-turbo', 'gpt-4o']);
53
53
  });
54
54
 
55
55
  it('should return undefined for a non-existing provider', () => {
@@ -16,10 +16,33 @@ export default ({ token }: { prefixCls: string; token: Theme }) => css`
16
16
  max-height: 100dvh;
17
17
 
18
18
  background: ${token.colorBgLayout};
19
+
20
+ @media (min-device-width: 576px) {
21
+ overflow: hidden;
22
+ }
19
23
  }
20
24
 
21
25
  * {
22
26
  scrollbar-color: ${token.colorFill} transparent;
23
27
  scrollbar-width: thin;
28
+
29
+ ::-webkit-scrollbar {
30
+ width: 0.75em;
31
+ height: 0.75em;
32
+ }
33
+
34
+ ::-webkit-scrollbar-thumb {
35
+ border-radius: 10px;
36
+ }
37
+
38
+ :hover::-webkit-scrollbar-thumb {
39
+ background-color: ${token.colorText};
40
+ background-clip: content-box;
41
+ border: 3px solid transparent;
42
+ }
43
+
44
+ ::-webkit-scrollbar-track {
45
+ background-color: transparent;
46
+ }
24
47
  }
25
48
  `;
@@ -1,101 +0,0 @@
1
- 'use client';
2
-
3
- import { EmptyCard } from '@lobehub/ui';
4
- import { useThemeMode } from 'antd-style';
5
- import isEqual from 'fast-deep-equal';
6
- import React, { memo, useCallback, useRef } from 'react';
7
- import { useTranslation } from 'react-i18next';
8
- import { Flexbox } from 'react-layout-kit';
9
- import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
10
-
11
- import { imageUrl } from '@/const/url';
12
- import { useChatStore } from '@/store/chat';
13
- import { topicSelectors } from '@/store/chat/selectors';
14
- import { useUserStore } from '@/store/user';
15
- import { ChatTopic } from '@/types/topic';
16
-
17
- import { Placeholder, SkeletonList } from './SkeletonList';
18
- import TopicItem from './TopicItem';
19
-
20
- export const Topic = memo<{ mobile?: boolean }>(({ mobile }) => {
21
- const { t } = useTranslation('chat');
22
- const virtuosoRef = useRef<VirtuosoHandle>(null);
23
- const { isDarkMode } = useThemeMode();
24
- const [topicsInit, activeTopicId, topicLength] = useChatStore((s) => [
25
- s.topicsInit,
26
- s.activeTopicId,
27
- topicSelectors.currentTopicLength(s),
28
- ]);
29
- const [visible, updateGuideState] = useUserStore((s) => [
30
- s.preference.guide?.topic,
31
- s.updateGuideState,
32
- ]);
33
-
34
- const topics = useChatStore(
35
- (s) => [
36
- {
37
- favorite: false,
38
- id: 'default',
39
- title: t('topic.defaultTitle'),
40
- } as ChatTopic,
41
- ...topicSelectors.displayTopics(s),
42
- ],
43
- isEqual,
44
- );
45
-
46
- const itemContent = useCallback(
47
- (index: number, { id, favorite, title }: ChatTopic) =>
48
- index === 0 ? (
49
- <TopicItem active={!activeTopicId} fav={favorite} title={title} />
50
- ) : (
51
- <TopicItem active={activeTopicId === id} fav={favorite} id={id} key={id} title={title} />
52
- ),
53
- [activeTopicId],
54
- );
55
-
56
- const activeIndex = topics.findIndex((topic) => topic.id === activeTopicId);
57
-
58
- return !topicsInit ? (
59
- <SkeletonList />
60
- ) : (
61
- <Flexbox
62
- gap={2}
63
- height={'100%'}
64
- paddingInline={mobile ? undefined : 8}
65
- style={{ marginBottom: 12 }}
66
- >
67
- {topicLength === 0 && (
68
- <EmptyCard
69
- alt={t('topic.guide.desc')}
70
- cover={imageUrl(`empty_topic_${isDarkMode ? 'dark' : 'light'}.webp`)}
71
- desc={t('topic.guide.desc')}
72
- height={120}
73
- imageProps={{
74
- priority: true,
75
- }}
76
- onVisibleChange={(visible) => {
77
- updateGuideState({ topic: visible });
78
- }}
79
- style={{ flex: 'none', marginBottom: 12 }}
80
- title={t('topic.guide.title')}
81
- visible={visible}
82
- width={200}
83
- />
84
- )}
85
- <Virtuoso
86
- components={{ ScrollSeekPlaceholder: Placeholder }}
87
- computeItemKey={(_, item) => item.id}
88
- data={topics}
89
- fixedItemHeight={44}
90
- initialTopMostItemIndex={Math.max(activeIndex, 0)}
91
- itemContent={itemContent}
92
- overscan={44 * 10}
93
- ref={virtuosoRef}
94
- scrollSeekConfiguration={{
95
- enter: (velocity) => Math.abs(velocity) > 350,
96
- exit: (velocity) => Math.abs(velocity) < 10,
97
- }}
98
- />
99
- </Flexbox>
100
- );
101
- });