@lobehub/chat 0.86.5 → 0.88.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/next.config.mjs +25 -5
  3. package/package.json +1 -1
  4. package/src/app/chat/(desktop)/features/SideBar.tsx +3 -1
  5. package/src/app/chat/(desktop)/index.tsx +5 -3
  6. package/src/app/chat/(mobile)/features/TopicList.tsx +2 -1
  7. package/src/app/chat/(mobile)/mobile/index.tsx +3 -1
  8. package/src/app/chat/features/ChatHeader/ShareButton/index.tsx +2 -1
  9. package/src/app/chat/features/ChatInputContent/ActionBar/ActionLeft.tsx +4 -1
  10. package/src/app/chat/features/ChatInputContent/ActionBar/Token.tsx +2 -1
  11. package/src/app/chat/features/ChatInputContent/index.tsx +8 -4
  12. package/src/app/chat/features/SessionListContent/Inbox/index.tsx +1 -1
  13. package/src/app/chat/settings/(desktop)/index.tsx +12 -5
  14. package/src/app/market/(desktop)/features/AgentDetail.tsx +2 -1
  15. package/src/app/market/(desktop)/index.tsx +12 -5
  16. package/src/app/market/(desktop)/layout.desktop.tsx +3 -1
  17. package/src/app/market/(mobile)/features/AgentCard.tsx +31 -0
  18. package/src/app/market/(mobile)/features/AgentDetail.tsx +2 -1
  19. package/src/app/market/(mobile)/layout.mobile.tsx +3 -1
  20. package/src/app/market/features/AgentCard/index.tsx +9 -4
  21. package/src/app/market/features/AgentCard/style.ts +3 -0
  22. package/src/app/settings/(desktop)/index.tsx +5 -3
  23. package/src/app/settings/(desktop)/layout.desktop.tsx +2 -0
  24. package/src/app/settings/(desktop)/layout.responsive.tsx +4 -2
  25. package/src/app/settings/(mobile)/features/AvatarBanner.tsx +70 -0
  26. package/src/app/settings/(mobile)/mobile/index.tsx +3 -9
  27. package/src/app/settings/features/Footer.tsx +3 -3
  28. package/src/app/settings/features/UpgradeAlert.tsx +2 -1
  29. package/src/app/settings/llm/LLM/index.tsx +6 -2
  30. package/src/app/welcome/(desktop)/index.tsx +5 -3
  31. package/src/app/welcome/(desktop)/layout.desktop.tsx +2 -0
  32. package/src/app/welcome/features/Banner/Hero.tsx +3 -1
  33. package/src/app/welcome/features/Banner/index.tsx +3 -1
  34. package/src/const/meta.ts +2 -0
  35. package/src/features/AgentSetting/AgentConfig/index.tsx +5 -10
  36. package/src/features/AgentSetting/AgentMeta/index.tsx +3 -1
  37. package/src/features/AgentSetting/AgentPrompt/index.tsx +16 -11
  38. package/src/features/AvatarWithUpload/index.tsx +8 -2
  39. package/src/features/PluginDevModal/MetaForm.tsx +3 -1
  40. package/src/layout/AppLayout.mobile.tsx +3 -1
  41. package/src/layout/GlobalLayout/AppTheme.tsx +3 -2
  42. package/src/locales/default/setting.ts +5 -0
  43. package/src/store/global/selectors/settings.ts +7 -0
  44. package/src/store/session/slices/agentConfig/selectors.ts +9 -1
  45. package/src/store/session/slices/chat/actions/share.ts +2 -3
  46. package/src/types/session.ts +1 -1
  47. package/src/types/settings.ts +4 -0
  48. package/src/app/chat/(desktop)/layout.responsive.tsx +0 -12
  49. package/src/app/chat/settings/(desktop)/layout.responsive.tsx +0 -12
  50. package/src/app/market/(desktop)/layout.responsive.tsx +0 -16
  51. package/src/app/welcome/(desktop)/layout.responsive.tsx +0 -14
package/CHANGELOG.md CHANGED
@@ -2,6 +2,57 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 0.88.0](https://github.com/lobehub/lobe-chat/compare/v0.87.0...v0.88.0)
6
+
7
+ <sup>Released on **2023-10-11**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Add mobile responsiveness, create new component, modify properties, make API calls, Dynamically import components using "dynamic" function.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Add mobile responsiveness, create new component, modify properties, make API calls ([759c920](https://github.com/lobehub/lobe-chat/commit/759c920))
21
+ - **misc**: Dynamically import components using "dynamic" function ([dd9db22](https://github.com/lobehub/lobe-chat/commit/dd9db22))
22
+
23
+ </details>
24
+
25
+ <div align="right">
26
+
27
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
28
+
29
+ </div>
30
+
31
+ ## [Version 0.87.0](https://github.com/lobehub/lobe-chat/compare/v0.86.5...v0.87.0)
32
+
33
+ <sup>Released on **2023-10-11**</sup>
34
+
35
+ #### ✨ Features
36
+
37
+ - **misc**: Support custom model name.
38
+
39
+ <br/>
40
+
41
+ <details>
42
+ <summary><kbd>Improvements and Fixes</kbd></summary>
43
+
44
+ #### What's improved
45
+
46
+ - **misc**: Support custom model name, closes [#305](https://github.com/lobehub/lobe-chat/issues/305) ([84a066a](https://github.com/lobehub/lobe-chat/commit/84a066a))
47
+
48
+ </details>
49
+
50
+ <div align="right">
51
+
52
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
53
+
54
+ </div>
55
+
5
56
  ### [Version 0.86.5](https://github.com/lobehub/lobe-chat/compare/v0.86.4...v0.86.5)
6
57
 
7
58
  <sup>Released on **2023-10-11**</sup>
package/next.config.mjs CHANGED
@@ -18,11 +18,31 @@ const withPWA = nextPWA({
18
18
  const nextConfig = {
19
19
  reactStrictMode: true,
20
20
  swcMinify: true,
21
- images: {
22
- unoptimized:!isProd,
23
- },
24
- experimental: {
25
- forceSwcTransforms: true,
21
+ images: {
22
+ unoptimized: !isProd,
23
+ remotePatterns: [
24
+ {
25
+ protocol: 'https',
26
+ hostname: 'registry.npmmirror.com',
27
+ port: '',
28
+ pathname: '/@lobehub/assets-emoji/1.3.0/files/assets/**',
29
+ },
30
+ {
31
+ protocol: 'https',
32
+ hostname: 'registry.npmmirror.com',
33
+ port: '',
34
+ pathname: '/@lobehub/assets-emoji-anim/1.0.0/files/assets/**',
35
+ },
36
+ {
37
+ protocol: 'https',
38
+ hostname: 'registry.npmmirror.com',
39
+ port: '',
40
+ pathname: '/@lobehub/assets-logo/1.1.0/files/assets/**',
41
+ },
42
+ ],
43
+ },
44
+ experimental: {
45
+ forceSwcTransforms: true,
26
46
  },
27
47
  transpilePackages: ['@lobehub/ui', 'antd-style'],
28
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.86.5",
3
+ "version": "0.88.0",
4
4
  "description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -1,5 +1,6 @@
1
1
  import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
+ import dynamic from 'next/dynamic';
3
4
  import { memo } from 'react';
4
5
 
5
6
  import SafeSpacing from '@/components/SafeSpacing';
@@ -9,7 +10,8 @@ import { useSessionStore } from '@/store/session';
9
10
  import { sessionSelectors } from '@/store/session/selectors';
10
11
 
11
12
  import TopicListContent from '../../features/TopicListContent';
12
- import SystemRole from '../../features/TopicListContent/SystemRole';
13
+
14
+ const SystemRole = dynamic(() => import('../../features/TopicListContent/SystemRole'));
13
15
 
14
16
  const useStyles = createStyles(({ css, token }) => ({
15
17
  content: css`
@@ -1,17 +1,19 @@
1
1
  'use client';
2
2
 
3
- import { memo } from 'react';
3
+ import dynamic from 'next/dynamic';
4
+ import { FC, memo } from 'react';
4
5
  import { Flexbox } from 'react-layout-kit';
5
6
 
6
7
  import ResponsiveIndex from '@/components/ResponsiveIndex';
7
8
 
8
- import Mobile from '../(mobile)';
9
9
  import Conversation from '../features/Conversation';
10
10
  import PageTitle from '../features/PageTitle';
11
11
  import ChatHeader from './features/ChatHeader';
12
12
  import ChatInput from './features/ChatInput';
13
13
  import SideBar from './features/SideBar';
14
- import Layout from './layout.responsive';
14
+ import Layout from './layout.desktop';
15
+
16
+ const Mobile: FC = dynamic(() => import('../(mobile)')) as FC;
15
17
 
16
18
  const DesktopPage = memo(() => (
17
19
  <ResponsiveIndex Mobile={Mobile}>
@@ -1,10 +1,11 @@
1
1
  import { Modal } from '@lobehub/ui';
2
+ import dynamic from 'next/dynamic';
2
3
  import { memo } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
 
5
6
  import { useGlobalStore } from '@/store/global';
6
7
 
7
- import TopicListContent from '../../features/TopicListContent';
8
+ const TopicListContent = dynamic(() => import('../../features/TopicListContent'));
8
9
 
9
10
  const Topics = memo(() => {
10
11
  const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
@@ -1,13 +1,15 @@
1
1
  'use client';
2
2
 
3
+ import dynamic from 'next/dynamic';
3
4
  import { memo } from 'react';
4
5
  import { Flexbox } from 'react-layout-kit';
5
6
 
6
7
  import Conversation from '../../features/Conversation';
7
8
  import ChatInput from '../features/ChatInput';
8
- import TopicList from '../features/TopicList';
9
9
  import Layout from './layout.mobile';
10
10
 
11
+ const TopicList = dynamic(() => import('../features/TopicList'));
12
+
11
13
  const Chat = memo(() => (
12
14
  <Layout>
13
15
  <Flexbox height={'calc(100% - 44px)'} horizontal>
@@ -1,13 +1,14 @@
1
1
  import { ActionIcon, Modal } from '@lobehub/ui';
2
2
  import { useResponsive } from 'antd-style';
3
3
  import { Share2 } from 'lucide-react';
4
+ import dynamic from 'next/dynamic';
4
5
  import { memo, useState } from 'react';
5
6
  import { useTranslation } from 'react-i18next';
6
7
 
7
8
  import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
8
9
  import { useSessionStore } from '@/store/session';
9
10
 
10
- import Inner from './Inner';
11
+ const Inner = dynamic(() => import('./Inner'));
11
12
 
12
13
  const ShareButton = memo(() => {
13
14
  const [isModalOpen, setIsModalOpen] = useState(false);
@@ -5,6 +5,7 @@ import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Flexbox } from 'react-layout-kit';
7
7
 
8
+ import { settingsSelectors, useGlobalStore } from '@/store/global';
8
9
  import { useSessionStore } from '@/store/session';
9
10
  import { agentSelectors } from '@/store/session/selectors';
10
11
  import { LanguageModel } from '@/types/llm';
@@ -23,12 +24,14 @@ const ActionLeft = memo(() => {
23
24
  ];
24
25
  });
25
26
 
27
+ const modelList = useGlobalStore(settingsSelectors.modelList);
28
+
26
29
  return (
27
30
  <>
28
31
  <Dropdown
29
32
  menu={{
30
33
  activeKey: model,
31
- items: Object.values(LanguageModel).map((i) => ({ key: i, label: i })),
34
+ items: modelList.map((i) => ({ key: i, label: i })),
32
35
  onClick: (e) => {
33
36
  updateAgentConfig({ model: e.key as LanguageModel });
34
37
  },
@@ -6,6 +6,7 @@ import { ModelTokens } from '@/const/modelTokens';
6
6
  import { useTokenCount } from '@/hooks/useTokenCount';
7
7
  import { useSessionStore } from '@/store/session';
8
8
  import { agentSelectors, chatSelectors } from '@/store/session/selectors';
9
+ import { LanguageModel } from '@/types/llm';
9
10
 
10
11
  const Token = memo<{ input: string }>(({ input }) => {
11
12
  const { t } = useTranslation('common');
@@ -15,7 +16,7 @@ const Token = memo<{ input: string }>(({ input }) => {
15
16
  const [messageString, systemRole, model] = useSessionStore((s) => [
16
17
  chatSelectors.chatsMessageString(s),
17
18
  agentSelectors.currentAgentSystemRole(s),
18
- agentSelectors.currentAgentModel(s),
19
+ agentSelectors.currentAgentModel(s) as LanguageModel,
19
20
  ]);
20
21
 
21
22
  const systemRoleToken = useTokenCount(systemRole);
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { CHAT_TEXTAREA_HEIGHT } from '@/const/layoutTokens';
8
8
  import { useSessionStore } from '@/store/session';
9
+ import { agentSelectors } from '@/store/session/selectors';
9
10
 
10
11
  import ActionLeft from './ActionBar/ActionLeft';
11
12
  import ActionsRight from './ActionBar/ActionRight';
@@ -28,10 +29,11 @@ const ChatInputContent = memo<ChatContentProps>(
28
29
 
29
30
  const mobile = runtimeMobile || defaultMobile;
30
31
 
31
- const [isLoading, sendMessage, stopGenerateMessage] = useSessionStore((s) => [
32
+ const [isLoading, sendMessage, stopGenerateMessage, showTokenTag] = useSessionStore((s) => [
32
33
  !!s.chatLoadingId,
33
34
  s.sendMessage,
34
35
  s.stopGenerateMessage,
36
+ agentSelectors.showTokenTag(s),
35
37
  ]);
36
38
 
37
39
  return (
@@ -39,9 +41,11 @@ const ChatInputContent = memo<ChatContentProps>(
39
41
  actions={
40
42
  <>
41
43
  <ActionLeft />
42
- <Suspense>
43
- <Token input={message} />
44
- </Suspense>
44
+ {showTokenTag && (
45
+ <Suspense>
46
+ <Token input={message} />
47
+ </Suspense>
48
+ )}
45
49
  </>
46
50
  }
47
51
  actionsRight={<ActionsRight />}
@@ -37,7 +37,7 @@ const Inbox = memo(() => {
37
37
 
38
38
  return (
39
39
  <Link
40
- aria-label={INBOX_SESSION_ID}
40
+ aria-label={t('inbox.title')}
41
41
  href={SESSION_CHAT_URL(INBOX_SESSION_ID, mobile)}
42
42
  onClick={(e) => {
43
43
  e.preventDefault();
@@ -1,14 +1,21 @@
1
1
  'use client';
2
2
 
3
- import { memo } from 'react';
3
+ import dynamic from 'next/dynamic';
4
+ import { FC, memo } from 'react';
5
+
6
+ import ResponsiveIndex from '@/components/ResponsiveIndex';
4
7
 
5
8
  import EditPage from '../features/EditPage';
6
- import Layout from './layout.responsive';
9
+ import Layout from './layout.desktop';
10
+
11
+ const Mobile: FC = dynamic(() => import('../(mobile)')) as FC;
7
12
 
8
13
  const ChatSettings = memo(() => (
9
- <Layout>
10
- <EditPage />
11
- </Layout>
14
+ <ResponsiveIndex Mobile={Mobile}>
15
+ <Layout>
16
+ <EditPage />
17
+ </Layout>
18
+ </ResponsiveIndex>
12
19
  ));
13
20
 
14
21
  export default ChatSettings;
@@ -1,12 +1,13 @@
1
1
  import { DraggablePanel, DraggablePanelBody, DraggablePanelContainer } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
+ import dynamic from 'next/dynamic';
3
4
  import { memo, useState } from 'react';
4
5
 
5
6
  import SafeSpacing from '@/components/SafeSpacing';
6
7
  import { MARKET_SIDEBAR_WIDTH } from '@/const/layoutTokens';
7
8
  import { agentMarketSelectors, useMarketStore } from '@/store/market';
8
9
 
9
- import AgentDetailContent from '../../features/AgentDetailContent';
10
+ const AgentDetailContent = dynamic(() => import('../../features/AgentDetailContent'));
10
11
 
11
12
  const useStyles = createStyles(({ css, token, stylish }) => ({
12
13
  content: css`
@@ -1,12 +1,19 @@
1
- import { memo } from 'react';
1
+ 'use client';
2
+
3
+ import dynamic from 'next/dynamic';
4
+ import { FC, memo } from 'react';
2
5
 
3
6
  import { AgentCardProps } from '@/app/market/features/AgentCard';
7
+ import ResponsiveIndex from '@/components/ResponsiveIndex';
4
8
 
5
9
  import Index from '../index';
6
- import Layout from './layout.responsive';
10
+ import Layout from './layout.desktop';
7
11
 
12
+ const Mobile: FC = dynamic(() => import('../(mobile)')) as FC;
8
13
  export default memo<AgentCardProps>((props) => (
9
- <Layout>
10
- <Index {...props} />
11
- </Layout>
14
+ <ResponsiveIndex Mobile={Mobile}>
15
+ <Layout>
16
+ <Index {...props} />
17
+ </Layout>
18
+ </ResponsiveIndex>
12
19
  ));
@@ -1,5 +1,6 @@
1
1
  import { GridBackground } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
+ import dynamic from 'next/dynamic';
3
4
  import { PropsWithChildren, memo } from 'react';
4
5
  import { Center, Flexbox } from 'react-layout-kit';
5
6
 
@@ -9,9 +10,10 @@ import AppLayoutDesktop from '@/layout/AppLayout.desktop';
9
10
  import { useSwitchSideBarOnInit } from '@/store/global';
10
11
  import { SidebarTabKey } from '@/store/global/initialState';
11
12
 
12
- import SideBar from './features/AgentDetail';
13
13
  import Header from './features/Header';
14
14
 
15
+ const SideBar = dynamic(() => import('./features/AgentDetail'));
16
+
15
17
  const useStyles = createStyles(({ css }) => ({
16
18
  background: css`
17
19
  width: 80%;
@@ -0,0 +1,31 @@
1
+ import { SpotlightCardProps } from '@lobehub/ui';
2
+ import { createStyles } from 'antd-style';
3
+ import { memo } from 'react';
4
+ import { Flexbox } from 'react-layout-kit';
5
+
6
+ const useStyles = createStyles(({ css, token }) => ({
7
+ container: css`
8
+ overflow: hidden;
9
+ background: ${token.colorBgContainer};
10
+ border: 1px solid ${token.colorFillTertiary};
11
+ border-radius: ${token.borderRadiusLG}px;
12
+ `,
13
+ }));
14
+
15
+ const AgentCard = memo<SpotlightCardProps>(({ items, renderItem, gap = 8, ...props }) => {
16
+ const { styles } = useStyles();
17
+ return (
18
+ <Flexbox gap={gap} {...props}>
19
+ {items.map((item, index) => {
20
+ const children = renderItem(item);
21
+ return (
22
+ <div className={styles.container} key={index}>
23
+ {children}
24
+ </div>
25
+ );
26
+ })}
27
+ </Flexbox>
28
+ );
29
+ });
30
+
31
+ export default AgentCard;
@@ -1,10 +1,11 @@
1
1
  import { Modal } from '@lobehub/ui';
2
+ import dynamic from 'next/dynamic';
2
3
  import { memo } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
 
5
6
  import { agentMarketSelectors, useMarketStore } from '@/store/market';
6
7
 
7
- import AgentDetailContent from '../../features/AgentDetailContent';
8
+ const AgentDetailContent = dynamic(() => import('../../features/AgentDetailContent'));
8
9
 
9
10
  const AgentDetail = memo(() => {
10
11
  const [showAgentSidebar, deactivateAgent] = useMarketStore((s) => [
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import dynamic from 'next/dynamic';
3
4
  import { PropsWithChildren } from 'react';
4
5
  import { Flexbox } from 'react-layout-kit';
5
6
 
@@ -7,9 +8,10 @@ import AppLayoutMobile from '@/layout/AppLayout.mobile';
7
8
  import { useSwitchSideBarOnInit } from '@/store/global';
8
9
  import { SidebarTabKey } from '@/store/global/initialState';
9
10
 
10
- import DetailModal from './features/AgentDetail';
11
11
  import Header from './features/Header';
12
12
 
13
+ const DetailModal = dynamic(() => import('./features/AgentDetail'));
14
+
13
15
  const MarketLayout = ({ children }: PropsWithChildren) => {
14
16
  useSwitchSideBarOnInit(SidebarTabKey.Market);
15
17
 
@@ -1,5 +1,5 @@
1
- import { SpotlightCard } from '@lobehub/ui';
2
1
  import { useResponsive } from 'antd-style';
2
+ import dynamic from 'next/dynamic';
3
3
  import { memo, useMemo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { Flexbox } from 'react-layout-kit';
@@ -12,6 +12,9 @@ import AgentCardItem from './AgentCardItem';
12
12
  import Loading from './Loading';
13
13
  import { useStyles } from './style';
14
14
 
15
+ const AgentCardMobile = dynamic(() => import('../../(mobile)/features/AgentCard'));
16
+ const AgentCardDesktop = dynamic(() => import('@lobehub/ui/es/SpotlightCard'));
17
+
15
18
  const gridRender = (item: any) => <AgentCardItem {...item} />;
16
19
 
17
20
  export interface AgentCardProps {
@@ -39,17 +42,19 @@ const AgentCard = memo<AgentCardProps>(({ defaultAgents }) => {
39
42
 
40
43
  if (agentList.length === 0) return <Loading />;
41
44
 
45
+ const CardRender = mobile ? AgentCardMobile : AgentCardDesktop;
46
+
42
47
  return (
43
48
  <Flexbox gap={mobile ? 16 : 24}>
44
49
  <TagList />
45
50
  {keywords ? (
46
- <SpotlightCard items={agentListData} renderItem={gridRender} spotlight={false} />
51
+ <CardRender items={agentListData} renderItem={gridRender} spotlight={false} />
47
52
  ) : (
48
53
  <>
49
54
  <div className={styles.subTitle}>{t('title.recentSubmits')}</div>
50
- <SpotlightCard items={agentListData.slice(0, 3)} renderItem={gridRender} />
55
+ <CardRender items={agentListData.slice(0, 3)} renderItem={gridRender} />
51
56
  <div className={styles.subTitle}>{t('title.allAgents')}</div>
52
- <SpotlightCard items={agentListData.slice(3)} renderItem={gridRender} spotlight={false} />
57
+ <CardRender items={agentListData.slice(3)} renderItem={gridRender} spotlight={false} />
53
58
  </>
54
59
  )}
55
60
  </Flexbox>
@@ -7,6 +7,9 @@ export const useStyles = createStyles(({ css, token, responsive }) => ({
7
7
  position: relative;
8
8
  overflow: hidden;
9
9
  border-radius: 11px;
10
+ ${responsive.mobile} {
11
+ border-radius: unset;
12
+ }
10
13
  `,
11
14
  desc: css`
12
15
  color: ${token.colorTextDescription};
@@ -1,12 +1,14 @@
1
1
  'use client';
2
2
 
3
- import { memo } from 'react';
3
+ import dynamic from 'next/dynamic';
4
+ import { FC, memo } from 'react';
4
5
 
5
6
  import ResponsiveIndex from '@/components/ResponsiveIndex';
6
7
 
7
- import Mobile from '../(mobile)';
8
8
  import Common from '../common';
9
- import Layout from './layout.responsive';
9
+ import Layout from './layout.desktop';
10
+
11
+ const Mobile: FC = dynamic(() => import('../(mobile)')) as FC;
10
12
 
11
13
  export default memo(() => (
12
14
  <ResponsiveIndex Mobile={Mobile}>
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { PropsWithChildren, memo } from 'react';
2
4
  import { Center, Flexbox } from 'react-layout-kit';
3
5
 
@@ -1,12 +1,14 @@
1
1
  'use client';
2
2
 
3
- import { PropsWithChildren, memo } from 'react';
3
+ import dynamic from 'next/dynamic';
4
+ import { FC, PropsWithChildren, memo } from 'react';
4
5
 
5
6
  import ResponsiveLayout from '@/layout/ResponsiveLayout.client';
6
7
 
7
- import MobileLayout from '../(mobile)/layout.mobile';
8
8
  import DesktopLayout from './layout.desktop';
9
9
 
10
+ const MobileLayout = dynamic(() => import('../(mobile)/layout.mobile')) as FC;
11
+
10
12
  export default memo(({ children }: PropsWithChildren) => (
11
13
  <ResponsiveLayout Desktop={DesktopLayout} Mobile={MobileLayout}>
12
14
  {children}
@@ -0,0 +1,70 @@
1
+ import { DivProps } from '@lobehub/ui';
2
+ import { createStyles } from 'antd-style';
3
+ import Image from 'next/image';
4
+ import { memo } from 'react';
5
+ import { Flexbox } from 'react-layout-kit';
6
+
7
+ import { DEFAULT_USER_AVATAR_URL } from '@/const/meta';
8
+
9
+ export const useStyles = createStyles(({ css, token }, maskColor: string) => ({
10
+ banner: css`
11
+ position: relative;
12
+
13
+ overflow: hidden;
14
+
15
+ height: 172px;
16
+ min-height: 172px;
17
+ max-height: 172px;
18
+
19
+ background: ${token.colorBgLayout};
20
+ `,
21
+ bannerImg: css`
22
+ position: absolute;
23
+ top: -50%;
24
+ filter: blur(100px) saturate(2);
25
+ `,
26
+ bannerMask: css`
27
+ position: absolute;
28
+ bottom: 0;
29
+ left: 0;
30
+
31
+ width: 100%;
32
+ height: 100%;
33
+
34
+ background: linear-gradient(to bottom, transparent, ${maskColor || token.colorBgLayout});
35
+ `,
36
+ }));
37
+
38
+ interface AgentCardBannerProps extends DivProps {
39
+ avatar: string;
40
+ mask?: boolean;
41
+ maskColor?: string;
42
+ size?: number;
43
+ }
44
+
45
+ const AvatarBanner = memo<AgentCardBannerProps>(
46
+ ({ avatar, className, mask, size = 200, maskColor, children, ...props }) => {
47
+ const { styles, cx } = useStyles(maskColor);
48
+
49
+ return (
50
+ <Flexbox
51
+ align={'center'}
52
+ className={cx(styles.banner, className)}
53
+ justify={'center'}
54
+ {...props}
55
+ >
56
+ <Image
57
+ alt={'banner'}
58
+ className={styles.bannerImg}
59
+ height={size}
60
+ src={avatar || DEFAULT_USER_AVATAR_URL}
61
+ width={size}
62
+ />
63
+ {mask && <div className={styles.bannerMask} />}
64
+ {children}
65
+ </Flexbox>
66
+ );
67
+ },
68
+ );
69
+
70
+ export default AvatarBanner;
@@ -5,14 +5,13 @@ import { createStyles } from 'antd-style';
5
5
  import { memo } from 'react';
6
6
  import { Center } from 'react-layout-kit';
7
7
 
8
- import AgentCardBanner from '@/app/market/features/AgentCard/AgentCardBanner';
9
8
  import { CURRENT_VERSION } from '@/const/version';
10
9
  import AvatarWithUpload from '@/features/AvatarWithUpload';
11
10
  import { useGlobalStore, useSwitchSideBarOnInit } from '@/store/global';
12
11
  import { SidebarTabKey } from '@/store/global/initialState';
13
- import { AVATAR } from '@/store/session/slices/chat/actions/share';
14
12
 
15
13
  import List from '../../features/SideBar/List';
14
+ import AvatarBanner from '../features/AvatarBanner';
16
15
  import ExtraList from '../features/ExtraList';
17
16
  import Layout from './layout.mobile';
18
17
 
@@ -34,16 +33,11 @@ const Setting = memo(() => {
34
33
 
35
34
  return (
36
35
  <Layout>
37
- <AgentCardBanner
38
- mask
39
- meta={{ avatar: avatar || AVATAR }}
40
- size={10}
41
- style={{ height: 172, marginBottom: 0 }}
42
- >
36
+ <AvatarBanner avatar={avatar} mask>
43
37
  <Center style={{ position: 'absolute', zIndex: 2 }}>
44
38
  <AvatarWithUpload size={88} />
45
39
  </Center>
46
- </AgentCardBanner>
40
+ </AvatarBanner>
47
41
  <div style={{ width: '100%' }}>
48
42
  <List />
49
43
  <div className={styles.divider} />
@@ -5,15 +5,15 @@ import { Center } from 'react-layout-kit';
5
5
 
6
6
  const useStyles = createStyles(
7
7
  ({ css, token }) => css`
8
- font-size: 14px;
9
- color: ${token.colorTextDescription};
8
+ font-size: 12px;
9
+ color: ${token.colorTextQuaternary};
10
10
  `,
11
11
  );
12
12
 
13
13
  const Footer = memo<PropsWithChildren>(({ children }) => {
14
14
  const { styles } = useStyles();
15
15
  return (
16
- <Center style={{ maxWidth: 600, width: '100%' }}>
16
+ <Center style={{ maxWidth: 600, paddingInline: 16, width: '100%' }}>
17
17
  <Divider>
18
18
  <span className={styles}>{children}</span>
19
19
  </Divider>
@@ -22,7 +22,8 @@ const UpgradeAlert = memo(() => {
22
22
  }
23
23
  banner
24
24
  closable
25
- message={t('upgradeVersion.newVersion', { version: latestVersion })}
25
+ message={`✨ ${t('upgradeVersion.newVersion', { version: latestVersion })}`}
26
+ showIcon={false}
26
27
  type={'info'}
27
28
  />
28
29
  )
@@ -70,11 +70,15 @@ const LLM = memo(() => {
70
70
  />
71
71
  ),
72
72
  desc: useAzure ? t('llm.AzureOpenAI.endpoint.desc') : t('llm.OpenAI.endpoint.desc'),
73
-
74
73
  label: useAzure ? t('llm.AzureOpenAI.endpoint.title') : t('llm.OpenAI.endpoint.title'),
75
-
76
74
  name: [configKey, 'openAI', 'endpoint'],
77
75
  },
76
+ {
77
+ children: <Input allowClear placeholder={t('llm.OpenAI.customModelName.placeholder')} />,
78
+ desc: t('llm.OpenAI.customModelName.desc'),
79
+ label: t('llm.OpenAI.customModelName.title'),
80
+ name: [configKey, 'openAI', 'customModelName'],
81
+ },
78
82
  {
79
83
  children: (
80
84
  <Switch />
@@ -1,13 +1,15 @@
1
1
  'use client';
2
2
 
3
- import { memo } from 'react';
3
+ import dynamic from 'next/dynamic';
4
+ import { FC, memo } from 'react';
4
5
 
5
6
  import ResponsiveIndex from '@/components/ResponsiveIndex';
6
7
 
7
- import Mobile from '../(mobile)';
8
8
  import Footer from './features/Footer';
9
9
  import Showcase from './features/Showcase';
10
- import Layout from './layout.responsive';
10
+ import Layout from './layout.desktop';
11
+
12
+ const Mobile: FC = dynamic(() => import('../(mobile)')) as FC;
11
13
 
12
14
  export default memo(() => (
13
15
  <ResponsiveIndex Mobile={Mobile}>
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { Logo } from '@lobehub/ui';
2
4
  import { PropsWithChildren, memo } from 'react';
3
5
  import { Center, Flexbox } from 'react-layout-kit';
@@ -1,9 +1,11 @@
1
- import { LogoThree } from '@lobehub/ui';
1
+ import dynamic from 'next/dynamic';
2
2
  import { memo, useMemo } from 'react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
 
5
5
  import { genSize, useStyles } from './style';
6
6
 
7
+ const LogoThree = dynamic(() => import('@lobehub/ui/es/LogoThree'));
8
+
7
9
  const Hero = memo<{ mobile?: boolean; width: number }>(({ width, mobile }) => {
8
10
  const size = useMemo(
9
11
  () => ({
@@ -4,6 +4,7 @@ import { Icon } from '@lobehub/ui';
4
4
  import { useSize } from 'ahooks';
5
5
  import { Button, Upload } from 'antd';
6
6
  import { SendHorizonal } from 'lucide-react';
7
+ import dynamic from 'next/dynamic';
7
8
  import { memo, useCallback, useRef } from 'react';
8
9
  import { useTranslation } from 'react-i18next';
9
10
  import { Flexbox } from 'react-layout-kit';
@@ -11,9 +12,10 @@ import { Flexbox } from 'react-layout-kit';
11
12
  import { useImportConfig } from '@/hooks/useImportConfig';
12
13
  import { useSessionStore } from '@/store/session';
13
14
 
14
- import Hero from './Hero';
15
15
  import { useStyles } from './style';
16
16
 
17
+ const Hero = dynamic(() => import('./Hero'));
18
+
17
19
  const Banner = memo<{ mobile?: boolean }>(({ mobile }) => {
18
20
  const { importConfig } = useImportConfig();
19
21
  const ref = useRef(null);
package/src/const/meta.ts CHANGED
@@ -5,3 +5,5 @@ export const DEFAULT_USER_AVATAR = '😀';
5
5
  export const DEFAULT_BACKGROUND_COLOR = 'rgba(0,0,0,0)';
6
6
  export const DEFAULT_AGENT_META: MetaData = {};
7
7
  export const DEFAULT_INBOX_AVATAR = '🤯';
8
+ export const DEFAULT_USER_AVATAR_URL =
9
+ 'https://registry.npmmirror.com/@lobehub/assets-logo/1.1.0/files/assets/logo-3d.webp';
@@ -8,7 +8,7 @@ import { memo, useEffect } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
10
10
  import { FORM_STYLE } from '@/const/layoutTokens';
11
- import { LanguageModel } from '@/types/llm';
11
+ import { settingsSelectors, useGlobalStore } from '@/store/global';
12
12
 
13
13
  import { useStore } from '../store';
14
14
 
@@ -16,9 +16,11 @@ const AgentConfig = memo(() => {
16
16
  const { t } = useTranslation('setting');
17
17
  const updateConfig = useStore((s) => s.setAgentConfig);
18
18
  const [form] = AFrom.useForm();
19
+ const { isDarkMode } = useThemeMode();
20
+
19
21
  const config = useStore((s) => s.config, isEqual);
20
22
 
21
- const { isDarkMode } = useThemeMode();
23
+ const modelList = useGlobalStore(settingsSelectors.modelList);
22
24
 
23
25
  useEffect(() => {
24
26
  form.setFieldsValue(config);
@@ -96,14 +98,7 @@ const AgentConfig = memo(() => {
96
98
  const model: ItemGroup = {
97
99
  children: [
98
100
  {
99
- children: (
100
- <Select
101
- options={Object.values(LanguageModel).map((value) => ({
102
- label: value,
103
- value,
104
- }))}
105
- />
106
- ),
101
+ children: <Select options={modelList.map((value) => ({ label: value, value }))} />,
107
102
  desc: t('settingModel.model.desc'),
108
103
  label: t('settingModel.model.title'),
109
104
  name: 'model',
@@ -2,10 +2,10 @@ import { Form, type FormItemProps, Icon, type ItemGroup, Tooltip } from '@lobehu
2
2
  import { Button } from 'antd';
3
3
  import isEqual from 'fast-deep-equal';
4
4
  import { UserCircle, Wand2 } from 'lucide-react';
5
+ import dynamic from 'next/dynamic';
5
6
  import { memo, useMemo } from 'react';
6
7
  import { useTranslation } from 'react-i18next';
7
8
 
8
- import EmojiPicker from '@/components/EmojiPicker';
9
9
  import { FORM_STYLE } from '@/const/layoutTokens';
10
10
 
11
11
  import { useStore } from '../store';
@@ -13,6 +13,8 @@ import { SessionLoadingState } from '../store/initialState';
13
13
  import AutoGenerateInput from './AutoGenerateInput';
14
14
  import BackgroundSwatches from './BackgroundSwatches';
15
15
 
16
+ const EmojiPicker = dynamic(() => import('@/components/EmojiPicker'));
17
+
16
18
  const AgentMeta = memo(() => {
17
19
  const { t } = useTranslation('setting');
18
20
  const [hasSystemRole, updateMeta, autocompleteMeta, autocompleteAllMeta] = useStore((s) => [
@@ -9,6 +9,7 @@ import { Flexbox } from 'react-layout-kit';
9
9
  import { FORM_STYLE } from '@/const/layoutTokens';
10
10
  import { ModelTokens } from '@/const/modelTokens';
11
11
  import { useTokenCount } from '@/hooks/useTokenCount';
12
+ import { LanguageModel } from '@/types/llm';
12
13
 
13
14
  import { useStore } from '../store';
14
15
 
@@ -29,21 +30,25 @@ const AgentPrompt = memo(() => {
29
30
  const [systemRole, model] = useStore((s) => [s.config.systemRole, s.config.model]);
30
31
  const systemTokenCount = useTokenCount(systemRole);
31
32
 
33
+ const showTag = model in ModelTokens;
34
+
32
35
  return (
33
36
  <FormGroup
34
37
  extra={
35
38
  <Flexbox align={'center'} gap={8} horizontal>
36
- <TokenTag
37
- displayMode={'used'}
38
- maxValue={ModelTokens[model]}
39
- shape={'square'}
40
- text={{
41
- overload: t('tokenTag.overload', { ns: 'common' }),
42
- remained: t('tokenTag.remained', { ns: 'common' }),
43
- used: t('tokenTag.used', { ns: 'common' }),
44
- }}
45
- value={systemTokenCount}
46
- />
39
+ {showTag && (
40
+ <TokenTag
41
+ displayMode={'used'}
42
+ maxValue={ModelTokens[model as LanguageModel]}
43
+ shape={'square'}
44
+ text={{
45
+ overload: t('tokenTag.overload', { ns: 'common' }),
46
+ remained: t('tokenTag.remained', { ns: 'common' }),
47
+ used: t('tokenTag.used', { ns: 'common' }),
48
+ }}
49
+ value={systemTokenCount}
50
+ />
51
+ )}
47
52
  </Flexbox>
48
53
  }
49
54
  icon={Bot}
@@ -1,6 +1,7 @@
1
- import { Avatar, Logo } from '@lobehub/ui';
1
+ import { Logo } from '@lobehub/ui';
2
2
  import { Upload } from 'antd';
3
3
  import { createStyles } from 'antd-style';
4
+ import Avatar from 'next/image';
4
5
  import { CSSProperties, memo } from 'react';
5
6
 
6
7
  import { useGlobalStore } from '@/store/global';
@@ -10,6 +11,7 @@ import { createUploadImageHandler } from '@/utils/uploadFIle';
10
11
  const useStyle = createStyles(
11
12
  ({ css, token }) => css`
12
13
  cursor: pointer;
14
+ overflow: hidden;
13
15
  border-radius: 50%;
14
16
  transition:
15
17
  scale 400ms ${token.motionEaseOut},
@@ -49,7 +51,11 @@ const AvatarWithUpload = memo<AvatarWithUploadProps>(
49
51
  return (
50
52
  <div className={styles} id={id} style={{ maxHeight: size, maxWidth: size, ...style }}>
51
53
  <Upload beforeUpload={handleUploadAvatar} itemRender={() => void 0} maxCount={1}>
52
- {avatar ? <Avatar avatar={avatar} size={size} /> : <Logo size={size} />}
54
+ {avatar ? (
55
+ <Avatar alt={'avatar'} height={size} src={avatar} width={size} />
56
+ ) : (
57
+ <Logo size={size} />
58
+ )}
53
59
  </Upload>
54
60
  </div>
55
61
  );
@@ -1,11 +1,13 @@
1
1
  import { Form, FormItemProps, Input } from '@lobehub/ui';
2
2
  import { FormInstance } from 'antd';
3
+ import dynamic from 'next/dynamic';
3
4
  import { memo } from 'react';
4
5
  import { useTranslation } from 'react-i18next';
5
6
 
6
- import EmojiPicker from '@/components/EmojiPicker';
7
7
  import { pluginSelectors, usePluginStore } from '@/store/plugin';
8
8
 
9
+ const EmojiPicker = dynamic(() => import('@/components/EmojiPicker'));
10
+
9
11
  const MetaForm = memo<{ form: FormInstance; mode?: 'edit' | 'create' }>(({ form, mode }) => {
10
12
  const isEditMode = mode === 'edit';
11
13
 
@@ -1,10 +1,12 @@
1
1
  import { type MobileNavBarTitleProps } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
+ import dynamic from 'next/dynamic';
3
4
  import { CSSProperties, PropsWithChildren, ReactNode, memo } from 'react';
4
5
  import { Flexbox } from 'react-layout-kit';
5
6
 
6
7
  import SafeSpacing from '@/components/SafeSpacing';
7
- import MobileTabBar from '@/features/MobileTabBar';
8
+
9
+ const MobileTabBar = dynamic(() => import('@/features/MobileTabBar'));
8
10
 
9
11
  const useStyles = createStyles(({ css, cx, stylish }) => ({
10
12
  container: cx(
@@ -1,5 +1,6 @@
1
- import { NeutralColors, PrimaryColors, ThemeProvider } from '@lobehub/ui';
1
+ import { ConfigProvider, NeutralColors, PrimaryColors, ThemeProvider } from '@lobehub/ui';
2
2
  import { ThemeAppearance } from 'antd-style';
3
+ import Image from 'next/image';
3
4
  import { ReactNode, memo, useEffect } from 'react';
4
5
 
5
6
  import {
@@ -51,7 +52,7 @@ const AppTheme = memo<AppThemeProps>(
51
52
  themeMode={themeMode}
52
53
  >
53
54
  <GlobalStyle />
54
- {children}
55
+ <ConfigProvider config={{ imgAs: Image } as any}>{children}</ConfigProvider>
55
56
  </ThemeProvider>
56
57
  );
57
58
  },
@@ -50,6 +50,11 @@ export default {
50
50
  pass: '检查通过',
51
51
  title: '连通性检查',
52
52
  },
53
+ customModelName: {
54
+ desc: '增加自定义模型,多个模型使用逗号(,) 隔开',
55
+ placeholder: 'model1,model2,model3',
56
+ title: '自定义模型名称',
57
+ },
53
58
  endpoint: {
54
59
  desc: '除默认地址外,必须包含 http(s)://',
55
60
  placeholder: 'https://api.openai.com/v1',
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_OPENAI_MODEL_LIST } from '@/const/llm';
1
2
  import { DEFAULT_AGENT_META } from '@/const/meta';
2
3
  import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_SETTINGS } from '@/const/settings';
3
4
  import { Locales } from '@/locales/resources';
@@ -19,6 +20,11 @@ const openAIAPIKeySelectors = (s: GlobalStore) =>
19
20
 
20
21
  const openAIProxyUrlSelectors = (s: GlobalStore) => s.settings.languageModel.openAI.endpoint;
21
22
 
23
+ const modelListSelectors = (s: GlobalStore) => [
24
+ ...DEFAULT_OPENAI_MODEL_LIST,
25
+ ...(s.settings.languageModel.openAI.customModelName || '').split(',').filter(Boolean),
26
+ ];
27
+
22
28
  export const exportSettings = (s: GlobalStore) => {
23
29
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
30
  const { OPENAI_API_KEY: _, password: __, ...settings } = s.settings;
@@ -42,6 +48,7 @@ export const settingsSelectors = {
42
48
  defaultAgentConfig,
43
49
  defaultAgentMeta,
44
50
  exportSettings,
51
+ modelList: modelListSelectors,
45
52
  openAIAPI: openAIAPIKeySelectors,
46
53
  openAIProxyUrl: openAIProxyUrlSelectors,
47
54
  };
@@ -1,5 +1,6 @@
1
1
  import { t } from 'i18next';
2
2
 
3
+ import { DEFAULT_OPENAI_MODEL_LIST } from '@/const/llm';
3
4
  import { DEFAULT_AVATAR, DEFAULT_BACKGROUND_COLOR } from '@/const/meta';
4
5
  import { SessionStore } from '@/store/session';
5
6
  import { LanguageModel } from '@/types/llm';
@@ -42,7 +43,7 @@ const currentAgentAvatar = (s: SessionStore) => {
42
43
  return session.meta.avatar || DEFAULT_AVATAR;
43
44
  };
44
45
 
45
- const currentAgentModel = (s: SessionStore): LanguageModel => {
46
+ const currentAgentModel = (s: SessionStore): LanguageModel | string => {
46
47
  const config = currentAgentConfig(s);
47
48
 
48
49
  return config?.model || LanguageModel.GPT3_5;
@@ -66,6 +67,12 @@ const getTitle = (s: MetaData) => s.title || t('defaultSession', { ns: 'common'
66
67
  export const getDescription = (s: MetaData) =>
67
68
  s.description || t('noDescription', { ns: 'common' });
68
69
 
70
+ const showTokenTag = (s: SessionStore) => {
71
+ const model = currentAgentModel(s);
72
+
73
+ return DEFAULT_OPENAI_MODEL_LIST.includes(model);
74
+ };
75
+
69
76
  export const agentSelectors = {
70
77
  currentAgentAvatar,
71
78
  currentAgentBackgroundColor,
@@ -80,4 +87,5 @@ export const agentSelectors = {
80
87
  getDescription,
81
88
  getTitle,
82
89
  hasSystemRole,
90
+ showTokenTag,
83
91
  };
@@ -2,6 +2,7 @@ import dayjs from 'dayjs';
2
2
  import { produce } from 'immer';
3
3
  import { StateCreator } from 'zustand/vanilla';
4
4
 
5
+ import { DEFAULT_USER_AVATAR_URL } from '@/const/meta';
5
6
  import { genShareGPTUrl } from '@/services/shareGPT';
6
7
  import { SessionStore } from '@/store/session';
7
8
  import { ShareGPTConversation } from '@/types/share';
@@ -14,8 +15,6 @@ interface ShareMessage {
14
15
  from: 'human' | 'gpt';
15
16
  value: string;
16
17
  }
17
- export const AVATAR =
18
- 'data:image/webp;base64,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';
19
18
 
20
19
  const Footer: ShareMessage = {
21
20
  from: 'gpt',
@@ -108,7 +107,7 @@ export const chatShare: StateCreator<
108
107
  set({ shareLoading: true });
109
108
 
110
109
  const res = await genShareGPTUrl({
111
- avatarUrl: avatar || AVATAR,
110
+ avatarUrl: avatar || DEFAULT_USER_AVATAR_URL,
112
111
  items: shareMsgs,
113
112
  });
114
113
  set({ shareLoading: false });
@@ -58,7 +58,7 @@ export interface LobeAgentConfig {
58
58
  * 角色所使用的语言模型
59
59
  * @default gpt-3.5-turbo
60
60
  */
61
- model: LanguageModel;
61
+ model: LanguageModel | string;
62
62
  /**
63
63
  * 语言模型参数
64
64
  */
@@ -48,6 +48,10 @@ export type GlobalDefaultAgent = Pick<LobeAgentSession, 'config' | 'meta'>;
48
48
  export interface OpenAIConfig {
49
49
  OPENAI_API_KEY: string;
50
50
  azureApiVersion?: string;
51
+ /**
52
+ * custom mode name for fine-tuning or openai like model
53
+ */
54
+ customModelName?: string;
51
55
  endpoint?: string;
52
56
  models?: string[];
53
57
  useAzure?: boolean;
@@ -1,12 +0,0 @@
1
- import { PropsWithChildren, memo } from 'react';
2
-
3
- import ResponsiveLayout from '@/layout/ResponsiveLayout.client';
4
-
5
- import Mobile from '../(mobile)/layout.mobile';
6
- import Desktop from './layout.desktop';
7
-
8
- export default memo(({ children }: PropsWithChildren) => (
9
- <ResponsiveLayout Desktop={Desktop} Mobile={Mobile}>
10
- {children}
11
- </ResponsiveLayout>
12
- ));
@@ -1,12 +0,0 @@
1
- import { PropsWithChildren, memo } from 'react';
2
-
3
- import ResponsiveLayout from '@/layout/ResponsiveLayout.client';
4
-
5
- import Mobile from '../(mobile)/layout.mobile';
6
- import Desktop from './layout.desktop';
7
-
8
- export default memo(({ children }: PropsWithChildren) => (
9
- <ResponsiveLayout Desktop={Desktop} Mobile={Mobile}>
10
- {children}
11
- </ResponsiveLayout>
12
- ));
@@ -1,16 +0,0 @@
1
- 'use client';
2
-
3
- import { PropsWithChildren } from 'react';
4
-
5
- import ResponsiveLayout from '@/layout/ResponsiveLayout.client';
6
-
7
- import Mobile from '../(mobile)/layout.mobile';
8
- import Desktop from './layout.desktop';
9
-
10
- const Market = ({ children }: PropsWithChildren) => (
11
- <ResponsiveLayout Desktop={Desktop} Mobile={Mobile}>
12
- {children}
13
- </ResponsiveLayout>
14
- );
15
-
16
- export default Market;
@@ -1,14 +0,0 @@
1
- 'use client';
2
-
3
- import { PropsWithChildren, memo } from 'react';
4
-
5
- import ResponsiveLayout from '@/layout/ResponsiveLayout.client';
6
-
7
- import MobileLayout from '../(mobile)/layout.mobile';
8
- import DesktopLayout from './layout.desktop';
9
-
10
- export default memo(({ children }: PropsWithChildren) => (
11
- <ResponsiveLayout Desktop={DesktopLayout} Mobile={MobileLayout}>
12
- {children}
13
- </ResponsiveLayout>
14
- ));