mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 08:25:07 +00:00
perf: 文案;feat: 知识库模糊搜索
This commit is contained in:
@@ -49,6 +49,7 @@ export const getModelTrainings = (id: string) =>
|
|||||||
|
|
||||||
type GetModelDataListProps = RequestPaging & {
|
type GetModelDataListProps = RequestPaging & {
|
||||||
modelId: string;
|
modelId: string;
|
||||||
|
searchText: string;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* 获取模型的知识库数据
|
* 获取模型的知识库数据
|
||||||
|
@@ -4,20 +4,20 @@ import { connectToDatabase } from '@/service/mongo';
|
|||||||
import { authToken } from '@/service/utils/tools';
|
import { authToken } from '@/service/utils/tools';
|
||||||
import { connectRedis } from '@/service/redis';
|
import { connectRedis } from '@/service/redis';
|
||||||
import { VecModelDataIdx } from '@/constants/redis';
|
import { VecModelDataIdx } from '@/constants/redis';
|
||||||
import { SearchOptions } from 'redis';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
let {
|
let {
|
||||||
modelId,
|
modelId,
|
||||||
pageNum = 1,
|
pageNum = 1,
|
||||||
pageSize = 10
|
pageSize = 10,
|
||||||
|
searchText = ''
|
||||||
} = req.query as {
|
} = req.query as {
|
||||||
modelId: string;
|
modelId: string;
|
||||||
pageNum: string;
|
pageNum: string;
|
||||||
pageSize: string;
|
pageSize: string;
|
||||||
|
searchText: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { authorization } = req.headers;
|
const { authorization } = req.headers;
|
||||||
|
|
||||||
pageNum = +pageNum;
|
pageNum = +pageNum;
|
||||||
@@ -40,7 +40,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
// 从 redis 中获取数据
|
// 从 redis 中获取数据
|
||||||
const searchRes = await redis.ft.search(
|
const searchRes = await redis.ft.search(
|
||||||
VecModelDataIdx,
|
VecModelDataIdx,
|
||||||
`@modelId:{${modelId}} @userId:{${userId}}`,
|
`@modelId:{${modelId}} @userId:{${userId}} ${searchText ? `*${searchText}*` : ''}`,
|
||||||
{
|
{
|
||||||
RETURN: ['q', 'text', 'status'],
|
RETURN: ['q', 'text', 'status'],
|
||||||
LIMIT: {
|
LIMIT: {
|
||||||
|
@@ -15,7 +15,8 @@ import {
|
|||||||
Menu,
|
Menu,
|
||||||
MenuButton,
|
MenuButton,
|
||||||
MenuList,
|
MenuList,
|
||||||
MenuItem
|
MenuItem,
|
||||||
|
Input
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import type { ModelSchema } from '@/types/mongoSchema';
|
import type { ModelSchema } from '@/types/mongoSchema';
|
||||||
import type { RedisModelDataItemType } from '@/types/redis';
|
import type { RedisModelDataItemType } from '@/types/redis';
|
||||||
@@ -40,9 +41,11 @@ const SelectFileModel = dynamic(() => import('./SelectFileModal'));
|
|||||||
const SelectUrlModel = dynamic(() => import('./SelectUrlModal'));
|
const SelectUrlModel = dynamic(() => import('./SelectUrlModal'));
|
||||||
const SelectCsvModal = dynamic(() => import('./SelectCsvModal'));
|
const SelectCsvModal = dynamic(() => import('./SelectCsvModal'));
|
||||||
|
|
||||||
|
let lastSearch = '';
|
||||||
|
|
||||||
const ModelDataCard = ({ model }: { model: ModelSchema }) => {
|
const ModelDataCard = ({ model }: { model: ModelSchema }) => {
|
||||||
const { Loading, setIsLoading } = useLoading();
|
const { Loading, setIsLoading } = useLoading();
|
||||||
|
const [searchText, setSearchText] = useState('');
|
||||||
const {
|
const {
|
||||||
data: modelDataList,
|
data: modelDataList,
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -54,7 +57,8 @@ const ModelDataCard = ({ model }: { model: ModelSchema }) => {
|
|||||||
api: getModelDataList,
|
api: getModelDataList,
|
||||||
pageSize: 8,
|
pageSize: 8,
|
||||||
params: {
|
params: {
|
||||||
modelId: model._id
|
modelId: model._id,
|
||||||
|
searchText
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -158,9 +162,33 @@ const ModelDataCard = ({ model }: { model: ModelSchema }) => {
|
|||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex mt={4}>
|
||||||
|
{/* 拆分数据提示 */}
|
||||||
{!!(splitDataLen && splitDataLen > 0) && (
|
{!!(splitDataLen && splitDataLen > 0) && (
|
||||||
<Box fontSize={'xs'}>{splitDataLen}条数据正在拆分...</Box>
|
<Box fontSize={'xs'}>{splitDataLen}条数据正在拆分...</Box>
|
||||||
)}
|
)}
|
||||||
|
<Box flex={1}></Box>
|
||||||
|
<Input
|
||||||
|
maxW={'240px'}
|
||||||
|
size={'sm'}
|
||||||
|
value={searchText}
|
||||||
|
placeholder="搜索相关问题和答案,回车确认"
|
||||||
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
|
onBlur={() => {
|
||||||
|
if (searchText === lastSearch) return;
|
||||||
|
getData(1);
|
||||||
|
lastSearch = searchText;
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (searchText === lastSearch) return;
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
getData(1);
|
||||||
|
lastSearch = searchText;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Box mt={4}>
|
<Box mt={4}>
|
||||||
<TableContainer minH={'500px'}>
|
<TableContainer minH={'500px'}>
|
||||||
<Table variant={'simple'}>
|
<Table variant={'simple'}>
|
||||||
|
@@ -54,20 +54,20 @@ const ModelEditForm = ({
|
|||||||
})}
|
})}
|
||||||
></Input>
|
></Input>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems={'center'} mt={4}>
|
<Flex alignItems={'center'} mt={5}>
|
||||||
<Box flex={'0 0 80px'} w={0}>
|
<Box flex={'0 0 80px'} w={0}>
|
||||||
modelId:
|
modelId:
|
||||||
</Box>
|
</Box>
|
||||||
<Box>{getValues('_id')}</Box>
|
<Box>{getValues('_id')}</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<Flex alignItems={'center'} mt={4}>
|
<Flex alignItems={'center'} mt={5}>
|
||||||
<Box flex={'0 0 80px'} w={0}>
|
<Box flex={'0 0 80px'} w={0}>
|
||||||
底层模型:
|
模型类型:
|
||||||
</Box>
|
</Box>
|
||||||
<Box>{getValues('service.modelName')}</Box>
|
<Box>{modelList.find((item) => item.model === getValues('service.modelName'))?.name}</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems={'center'} mt={4}>
|
<Flex alignItems={'center'} mt={5}>
|
||||||
<Box flex={'0 0 80px'} w={0}>
|
<Box flex={'0 0 80px'} w={0}>
|
||||||
价格:
|
价格:
|
||||||
</Box>
|
</Box>
|
||||||
@@ -80,7 +80,7 @@ const ModelEditForm = ({
|
|||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex mt={5} alignItems={'center'}>
|
<Flex mt={5} alignItems={'center'}>
|
||||||
<Box flex={'0 0 80px'}>删除:</Box>
|
<Box flex={'0 0 150px'}>删除模型和数据集</Box>
|
||||||
<Button
|
<Button
|
||||||
colorScheme={'gray'}
|
colorScheme={'gray'}
|
||||||
variant={'outline'}
|
variant={'outline'}
|
||||||
|
@@ -21,7 +21,6 @@ const ModelDetail = ({ modelId }: { modelId: string }) => {
|
|||||||
const { isPc, media } = useScreen();
|
const { isPc, media } = useScreen();
|
||||||
const { setLoading } = useGlobalStore();
|
const { setLoading } = useGlobalStore();
|
||||||
|
|
||||||
// const SelectFileDom = useRef<HTMLInputElement>(null);
|
|
||||||
const [model, setModel] = useState<ModelSchema>(defaultModel);
|
const [model, setModel] = useState<ModelSchema>(defaultModel);
|
||||||
const formHooks = useForm<ModelSchema>({
|
const formHooks = useForm<ModelSchema>({
|
||||||
defaultValues: model
|
defaultValues: model
|
||||||
@@ -243,11 +242,6 @@ const ModelDetail = ({ modelId }: { modelId: string }) => {
|
|||||||
<Grid mt={5} gridTemplateColumns={media('1fr 1fr', '1fr')} gridGap={5}>
|
<Grid mt={5} gridTemplateColumns={media('1fr 1fr', '1fr')} gridGap={5}>
|
||||||
<ModelEditForm formHooks={formHooks} handleDelModel={handleDelModel} canTrain={canTrain} />
|
<ModelEditForm formHooks={formHooks} handleDelModel={handleDelModel} canTrain={canTrain} />
|
||||||
|
|
||||||
{/* {canTrain && (
|
|
||||||
<Card p={4}>
|
|
||||||
<Training model={model} />
|
|
||||||
</Card>
|
|
||||||
)} */}
|
|
||||||
{canTrain && model._id && (
|
{canTrain && model._id && (
|
||||||
<Card
|
<Card
|
||||||
p={4}
|
p={4}
|
||||||
@@ -263,11 +257,6 @@ const ModelDetail = ({ modelId }: { modelId: string }) => {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* 文件选择 */}
|
|
||||||
{/* <Box position={'absolute'} w={0} h={0} overflow={'hidden'}>
|
|
||||||
<input ref={SelectFileDom} type="file" accept=".jsonl" onChange={startTraining} />
|
|
||||||
</Box> */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -16,6 +16,7 @@ import { formatModelStatus } from '@/constants/model';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import type { ModelSchema } from '@/types/mongoSchema';
|
import type { ModelSchema } from '@/types/mongoSchema';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
import { modelList } from '@/constants/model';
|
||||||
|
|
||||||
const ModelTable = ({
|
const ModelTable = ({
|
||||||
models = [],
|
models = [],
|
||||||
@@ -31,6 +32,15 @@ const ModelTable = ({
|
|||||||
key: 'name',
|
key: 'name',
|
||||||
dataIndex: 'name'
|
dataIndex: 'name'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '模型类型',
|
||||||
|
key: 'service',
|
||||||
|
render: (model: ModelSchema) => (
|
||||||
|
<Box fontWeight={'bold'} whiteSpace={'pre-wrap'} maxW={'200px'}>
|
||||||
|
{modelList.find((item) => item.model === model.service.modelName)?.name}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '最后更新时间',
|
title: '最后更新时间',
|
||||||
key: 'updateTime',
|
key: 'updateTime',
|
||||||
@@ -51,29 +61,20 @@ const ModelTable = ({
|
|||||||
</Tag>
|
</Tag>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'AI模型',
|
|
||||||
key: 'service',
|
|
||||||
render: (item: ModelSchema) => (
|
|
||||||
<Box wordBreak={'break-all'} whiteSpace={'pre-wrap'} maxW={'200px'}>
|
|
||||||
{item.service.modelName}
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'control',
|
key: 'control',
|
||||||
render: (item: ModelSchema) => (
|
render: (item: ModelSchema) => (
|
||||||
<>
|
<>
|
||||||
<Button mr={3} onClick={() => handlePreviewChat(item._id)}>
|
|
||||||
对话
|
|
||||||
</Button>
|
|
||||||
<Button
|
<Button
|
||||||
colorScheme={'gray'}
|
mr={3}
|
||||||
|
variant={'outline'}
|
||||||
onClick={() => router.push(`/model/detail?modelId=${item._id}`)}
|
onClick={() => router.push(`/model/detail?modelId=${item._id}`)}
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button onClick={() => handlePreviewChat(item._id)}>对话</Button>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ const BillTable = () => {
|
|||||||
<Th>类型</Th>
|
<Th>类型</Th>
|
||||||
<Th>内容长度</Th>
|
<Th>内容长度</Th>
|
||||||
<Th>Tokens 长度</Th>
|
<Th>Tokens 长度</Th>
|
||||||
<Th>消费</Th>
|
<Th>金额</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody fontSize={'sm'}>
|
<Tbody fontSize={'sm'}>
|
||||||
|
@@ -77,7 +77,7 @@ const PayRecordTable = () => {
|
|||||||
<Th>订单号</Th>
|
<Th>订单号</Th>
|
||||||
<Th>时间</Th>
|
<Th>时间</Th>
|
||||||
<Th>金额</Th>
|
<Th>金额</Th>
|
||||||
<Th>消费</Th>
|
<Th>状态</Th>
|
||||||
<Th></Th>
|
<Th></Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
|
@@ -21,7 +21,7 @@ export const pushChatBill = async ({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 计算 token 数量
|
// 计算 token 数量
|
||||||
const tokens = Math.floor(encode(text).length * 0.7);
|
const tokens = Math.floor(encode(text).length * 0.75);
|
||||||
|
|
||||||
console.log(`chat generate success. text len: ${text.length}. token len: ${tokens}`);
|
console.log(`chat generate success. text len: ${text.length}. token len: ${tokens}`);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user