mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-18 10:03:55 +00:00
perf: ui
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,5 +28,4 @@ next-env.d.ts
|
||||
platform.json
|
||||
testApi/
|
||||
local/
|
||||
.husky/
|
||||
dist/
|
6
.husky/pre-commit
Executable file
6
.husky/pre-commit
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
if command -v npx >/dev/null 2>&1; then
|
||||
npx lint-staged
|
||||
fi
|
@@ -27,7 +27,7 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
activeLink: ['/chat']
|
||||
},
|
||||
{
|
||||
label: '我的应用',
|
||||
label: '应用',
|
||||
icon: 'model',
|
||||
link: `/model?modelId=${lastModelId}`,
|
||||
activeLink: ['/model']
|
||||
@@ -39,7 +39,7 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
activeLink: ['/kb']
|
||||
},
|
||||
{
|
||||
label: '应用市场',
|
||||
label: '市场',
|
||||
icon: 'appStore',
|
||||
link: '/model/share',
|
||||
activeLink: ['/model/share']
|
||||
@@ -61,14 +61,15 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
);
|
||||
|
||||
const itemStyles: any = {
|
||||
mb: 3,
|
||||
my: 3,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
w: '60px',
|
||||
h: '45px',
|
||||
w: '54px',
|
||||
h: '54px',
|
||||
borderRadius: 'md',
|
||||
_hover: {
|
||||
color: '#ffffff'
|
||||
}
|
||||
@@ -79,7 +80,7 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
flexDirection={'column'}
|
||||
alignItems={'center'}
|
||||
pt={6}
|
||||
backgroundColor={'#465069'}
|
||||
backgroundImage={'linear-gradient(to bottom right,#465069,#000000)'}
|
||||
h={'100%'}
|
||||
w={'100%'}
|
||||
boxShadow={'4px 0px 4px 0px rgba(43, 45, 55, 0.01)'}
|
||||
@@ -99,30 +100,26 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
{/* 导航列表 */}
|
||||
<Box flex={1}>
|
||||
{navbarList.map((item) => (
|
||||
<Tooltip
|
||||
label={item.label}
|
||||
key={item.label}
|
||||
placement={'right'}
|
||||
openDelay={100}
|
||||
gutter={-10}
|
||||
>
|
||||
<Link
|
||||
key={item.link}
|
||||
as={NextLink}
|
||||
href={item.link}
|
||||
{...itemStyles}
|
||||
{...(item.activeLink.includes(router.pathname)
|
||||
? {
|
||||
color: '#ffffff ',
|
||||
backgroundImage: 'linear-gradient(270deg,#4e83fd,#3370ff)'
|
||||
backgroundImage: 'linear-gradient(to bottom right, #2152d9 0%, #4e83fd 100%)'
|
||||
}
|
||||
: {
|
||||
color: '#9096a5',
|
||||
backgroundColor: 'transparent'
|
||||
})}
|
||||
>
|
||||
<MyIcon name={item.icon as any} width={'22px'} height={'22px'} />
|
||||
<MyIcon name={item.icon as any} width={'20px'} height={'20px'} />
|
||||
<Box fontSize={'12px'} transform={'scale(0.9)'} mt={'5px'} lineHeight={1}>
|
||||
{item.label}
|
||||
</Box>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
))}
|
||||
</Box>
|
||||
{unread > 0 && (
|
||||
|
@@ -232,6 +232,10 @@ export const theme = extendTheme({
|
||||
xl: '1800px',
|
||||
'2xl': '2100px'
|
||||
},
|
||||
active: {
|
||||
activeBlueGradient: 'linear-gradient(120deg, #d6e8ff 0%, #f0f7ff 100%)',
|
||||
hoverBlueGradient: 'linear-gradient(60deg, #f0f7ff 0%, #d6e8ff 100%)'
|
||||
},
|
||||
components: {
|
||||
Modal: ModalTheme,
|
||||
Button,
|
||||
|
@@ -40,3 +40,8 @@ export const InformTypeMap = {
|
||||
label: '系统通知'
|
||||
}
|
||||
};
|
||||
|
||||
export enum MyModelsTypeEnum {
|
||||
my = 'my',
|
||||
collection = 'collection'
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import { withNextCors } from '@/service/utils/tools';
|
||||
import { TrainingModeEnum } from '@/constants/plugin';
|
||||
import { startQueue } from '@/service/utils/tools';
|
||||
import { PgClient } from '@/service/pg';
|
||||
import { modelToolMap } from '@/utils/plugin';
|
||||
|
||||
type DateItemType = { a: string; q: string; source?: string };
|
||||
|
||||
@@ -21,6 +22,11 @@ export type Response = {
|
||||
insertLen: number;
|
||||
};
|
||||
|
||||
const modeMaxToken = {
|
||||
[TrainingModeEnum.index]: 700,
|
||||
[TrainingModeEnum.qa]: 3300
|
||||
};
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
const { kbId, data, mode, prompt } = req.body as Props;
|
||||
@@ -68,7 +74,15 @@ export async function pushDataToKb({
|
||||
|
||||
data.forEach((item) => {
|
||||
const text = item.q + item.a;
|
||||
if (!set.has(text)) {
|
||||
|
||||
// count token
|
||||
const token = modelToolMap['gpt-3.5-turbo'].countTokens({
|
||||
messages: [{ obj: 'System', value: item.q }]
|
||||
});
|
||||
|
||||
if (mode === TrainingModeEnum.qa && token > modeMaxToken[TrainingModeEnum.qa]) {
|
||||
console.log('q is too long');
|
||||
} else if (!set.has(text)) {
|
||||
filterData.push(item);
|
||||
set.add(text);
|
||||
}
|
||||
|
@@ -146,31 +146,26 @@ const PcSliderBar = ({
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* chat history */}
|
||||
<Box flex={'1 0 0'} h={0} overflow={'overlay'}>
|
||||
<Box flex={'1 0 0'} h={0} overflow={'overlay'} userSelect={'none'}>
|
||||
{history.map((item) => (
|
||||
<Flex
|
||||
position={'relative'}
|
||||
key={item._id}
|
||||
position={'relative'}
|
||||
alignItems={'center'}
|
||||
py={3}
|
||||
pr={[0, 3]}
|
||||
pl={[6, 3]}
|
||||
p={3}
|
||||
mb={[2, 0]}
|
||||
cursor={'pointer'}
|
||||
transition={'background-color .2s ease-in'}
|
||||
borderLeft={['none', '5px solid transparent']}
|
||||
userSelect={'none'}
|
||||
_hover={{
|
||||
bg: ['', '#dee0e3']
|
||||
backgroundImage: ['', theme.active.hoverBlueGradient]
|
||||
}}
|
||||
{...(item._id === chatId
|
||||
? {
|
||||
bg: 'myGray.100 !important',
|
||||
borderLeftColor: 'myBlue.600 !important'
|
||||
backgroundImage: `${theme.active.activeBlueGradient}`
|
||||
}
|
||||
: {
|
||||
bg: item.top ? 'myBlue.200' : ''
|
||||
bg: item.top ? 'myGray.200' : ''
|
||||
})}
|
||||
onClick={() => {
|
||||
if (item._id === chatId) return;
|
||||
|
@@ -87,7 +87,7 @@ const KbList = ({ kbId }: { kbId: string }) => {
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<Box flex={'1 0 0'} h={0} overflow={'overlay'}>
|
||||
<Box flex={'1 0 0'} h={0} overflow={'overlay'} userSelect={'none'}>
|
||||
{kbs.map((item) => (
|
||||
<Flex
|
||||
key={item._id}
|
||||
@@ -97,14 +97,12 @@ const KbList = ({ kbId }: { kbId: string }) => {
|
||||
mb={[2, 0]}
|
||||
cursor={'pointer'}
|
||||
transition={'background-color .2s ease-in'}
|
||||
borderLeft={['', '5px solid transparent']}
|
||||
_hover={{
|
||||
backgroundColor: ['', '#dee0e3']
|
||||
backgroundImage: ['', theme.active.hoverBlueGradient]
|
||||
}}
|
||||
{...(kbId === item._id
|
||||
? {
|
||||
backgroundColor: '#eff0f1',
|
||||
borderLeftColor: 'myBlue.600 !important'
|
||||
backgroundImage: `${theme.active.activeBlueGradient} !important`
|
||||
}
|
||||
: {})}
|
||||
onClick={() => {
|
||||
|
@@ -1,5 +1,15 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { Box, Flex, useTheme, Input, IconButton, Tooltip } from '@chakra-ui/react';
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Input,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Tabs,
|
||||
TabList,
|
||||
Tab,
|
||||
useTheme
|
||||
} from '@chakra-ui/react';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { useRouter } from 'next/router';
|
||||
import MyIcon from '@/components/Icon';
|
||||
@@ -9,8 +19,15 @@ import { useToast } from '@/hooks/useToast';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { MyModelsTypeEnum } from '@/constants/user';
|
||||
|
||||
const ModelList = ({ modelId }: { modelId: string }) => {
|
||||
const tabs = useRef([
|
||||
{ label: '我的', value: MyModelsTypeEnum.my },
|
||||
{ label: '收藏', value: MyModelsTypeEnum.collection }
|
||||
]);
|
||||
const [currentTab, setCurrentTab] = useState(MyModelsTypeEnum.my);
|
||||
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
@@ -42,29 +59,23 @@ const ModelList = ({ modelId }: { modelId: string }) => {
|
||||
setIsLoading(false);
|
||||
}, [myModels.length, refreshModel, router, setIsLoading, toast]);
|
||||
|
||||
const models = useMemo(
|
||||
() =>
|
||||
[
|
||||
{
|
||||
label: '我的',
|
||||
const currentModels = useMemo(() => {
|
||||
const map = {
|
||||
[MyModelsTypeEnum.my]: {
|
||||
list: myModels.filter((item) =>
|
||||
new RegExp(searchText, 'ig').test(item.name + item.systemPrompt)
|
||||
)
|
||||
),
|
||||
emptyText: '还没有 AI 应用~\n快来创建一个吧'
|
||||
},
|
||||
{
|
||||
label: '收藏',
|
||||
[MyModelsTypeEnum.collection]: {
|
||||
list: myCollectionModels.filter((item) =>
|
||||
new RegExp(searchText, 'ig').test(item.name + item.systemPrompt)
|
||||
)
|
||||
),
|
||||
emptyText: '收藏的 AI 应用为空~\n快去市场找一个吧'
|
||||
}
|
||||
].filter((item) => item.list.length > 0),
|
||||
[myCollectionModels, myModels, searchText]
|
||||
);
|
||||
|
||||
const totalModels = useMemo(
|
||||
() => models.reduce((sum, item) => sum + item.list.length, 0),
|
||||
[models]
|
||||
);
|
||||
};
|
||||
return map[currentTab];
|
||||
}, [currentTab, myCollectionModels, myModels, searchText]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
@@ -107,13 +118,32 @@ const ModelList = ({ modelId }: { modelId: string }) => {
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<Box flex={'1 0 0'} h={0} overflow={'overlay'}>
|
||||
{models.map((item) => (
|
||||
<Box key={item.label} _notFirst={{ mt: 5 }}>
|
||||
<Box fontWeight={'bold'} pl={5}>
|
||||
<Flex mb={4} userSelect={'none'}>
|
||||
<Box flex={1}></Box>
|
||||
<Tabs
|
||||
variant="unstyled"
|
||||
defaultIndex={tabs.current.findIndex((item) => item.value === currentTab)}
|
||||
onChange={(i) => setCurrentTab(tabs.current[i].value)}
|
||||
>
|
||||
<TabList whiteSpace={'nowrap'}>
|
||||
{tabs.current.map((item) => (
|
||||
<Tab
|
||||
key={item.value}
|
||||
py={'2px'}
|
||||
px={4}
|
||||
borderRadius={'sm'}
|
||||
mr={2}
|
||||
transition={'none'}
|
||||
_selected={{ color: 'white', bg: 'myBlue.600' }}
|
||||
>
|
||||
{item.label}
|
||||
</Box>
|
||||
{item.list.map((item) => (
|
||||
</Tab>
|
||||
))}
|
||||
</TabList>
|
||||
</Tabs>
|
||||
</Flex>
|
||||
<Box flex={'1 0 0'} h={0} overflow={'overlay'} userSelect={'none'}>
|
||||
{currentModels.list.map((item) => (
|
||||
<Flex
|
||||
key={item._id}
|
||||
position={'relative'}
|
||||
@@ -122,14 +152,12 @@ const ModelList = ({ modelId }: { modelId: string }) => {
|
||||
mb={[2, 0]}
|
||||
cursor={'pointer'}
|
||||
transition={'background-color .2s ease-in'}
|
||||
borderLeft={['', '5px solid transparent']}
|
||||
_hover={{
|
||||
backgroundColor: ['', '#dee0e3']
|
||||
backgroundImage: ['', theme.active.hoverBlueGradient]
|
||||
}}
|
||||
{...(modelId === item._id
|
||||
? {
|
||||
backgroundColor: '#eff0f1',
|
||||
borderLeftColor: 'myBlue.600 !important'
|
||||
backgroundImage: `${theme.active.activeBlueGradient} !important`
|
||||
}
|
||||
: {})}
|
||||
onClick={() => {
|
||||
@@ -148,14 +176,11 @@ const ModelList = ({ modelId }: { modelId: string }) => {
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
{!isFetching && totalModels === 0 && (
|
||||
{!isFetching && currentModels.list.length === 0 && (
|
||||
<Flex h={'100%'} flexDirection={'column'} alignItems={'center'} pt={'30vh'}>
|
||||
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||
<Box mt={2} color={'myGray.500'}>
|
||||
还没有 AI 应用~
|
||||
{currentModels.emptyText}
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
|
@@ -44,7 +44,7 @@ svg {
|
||||
div {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: transparent !important;
|
||||
transition: 1s;
|
||||
transition: background 1s;
|
||||
}
|
||||
&:hover {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
|
@@ -6,14 +6,13 @@
|
||||
"prepare": "husky install",
|
||||
"format": "prettier --config \"./.prettierrc.js\" --write \"./**/src/**/*.{ts,tsx,scss}\""
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.1",
|
||||
"prettier": "^2.8.7"
|
||||
},
|
||||
"lint-staged": {
|
||||
"./**/*.{ts,tsx,scss}": "npm run format"
|
||||
"./**/**/*.{ts,tsx,scss}": "npm run format"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
|
Reference in New Issue
Block a user