Merge branch 'dev2.4' of https://github.com/c121914yu/FastGPT into dev2.4

This commit is contained in:
archer 2023-04-04 21:59:38 +08:00
commit cc36a13f17
No known key found for this signature in database
GPG Key ID: 166CA6BF2383B2BB
5 changed files with 99 additions and 70 deletions

View File

@ -57,7 +57,7 @@ export const postModelDataJsonData = (
jsonData: { prompt: string; completion: string; vector?: number[] }[] jsonData: { prompt: string; completion: string; vector?: number[] }[]
) => POST(`/model/data/pushModelDataJson`, { modelId, data: jsonData }); ) => POST(`/model/data/pushModelDataJson`, { modelId, data: jsonData });
export const putModelDataById = (data: { dataId: string; text: string }) => export const putModelDataById = (data: { dataId: string; text: string; q?: string }) =>
PUT('/model/data/putModelData', data); PUT('/model/data/putModelData', data);
export const delOneModelData = (dataId: string) => export const delOneModelData = (dataId: string) =>
DELETE(`/model/data/delModelDataById?dataId=${dataId}`); DELETE(`/model/data/delModelDataById?dataId=${dataId}`);

View File

@ -65,20 +65,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
messages: [ messages: [
{ {
role: 'system', role: 'system',
content: `服务端逻辑生成器。根据用户输入的需求,拆解成代码实现的步骤,并按下面格式返回: content: `服务端逻辑生成器。根据用户输入的需求,拆解成代码实现的步骤,并按格式返回: 1.\n2.\n3.\n ......
1.
2.
3.
....
*
1. query phone 1. query phone
2. {error: "手机号格式错误"} 2. {error: "手机号格式错误"}
3. phone 6laf, code 3. phone 6laf, code
4. "codes" {phone, code} 4. "codes" {phone, code}
*
1. body phone code 1. body phone code
2. {error: "手机号格式错误"} 2. {error: "手机号格式错误"}
2. "codes" phone, code body参数的记录 {error:"验证码不正确"} 2. "codes" phone, code body参数的记录 {error:"验证码不正确"}

View File

@ -2,13 +2,12 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { authToken } from '@/service/utils/tools'; import { authToken } from '@/service/utils/tools';
import { connectRedis } from '@/service/redis'; import { connectRedis } from '@/service/redis';
import { ModelDataStatusEnum } from '@/constants/redis';
import { generateVector } from '@/service/events/generateVector';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {
let { dataId, text } = req.body as { const { dataId, text, q } = req.body as { dataId: string; text: string; q?: string };
dataId: string;
text: string;
};
const { authorization } = req.headers; const { authorization } = req.headers;
if (!authorization) { if (!authorization) {
@ -31,7 +30,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
} }
// 更新 // 更新
await redis.hSet(dataId, 'text', text); await redis.sendCommand([
'HMSET',
dataId,
...(q ? ['q', q, 'status', ModelDataStatusEnum.waiting] : []),
'text',
text
]);
if (q) {
generateVector();
}
jsonRes(res); jsonRes(res);
} catch (err) { } catch (err) {

View File

@ -1,7 +1,6 @@
import React, { useState, useCallback } from 'react'; import React, { useState, useCallback } from 'react';
import { import {
Box, Box,
IconButton,
Flex, Flex,
Button, Button,
Modal, Modal,
@ -9,37 +8,40 @@ import {
ModalContent, ModalContent,
ModalHeader, ModalHeader,
ModalCloseButton, ModalCloseButton,
Input,
Textarea Textarea
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useForm, useFieldArray } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { postModelDataInput } from '@/api/model'; import { postModelDataInput, putModelDataById } from '@/api/model';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { DeleteIcon } from '@chakra-ui/icons';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
type FormData = { text: string; q: string }; export type FormData = { dataId?: string; text: string; q: string };
const InputDataModal = ({ const InputDataModal = ({
onClose, onClose,
onSuccess, onSuccess,
modelId modelId,
defaultValues = {
text: '',
q: ''
}
}: { }: {
onClose: () => void; onClose: () => void;
onSuccess: () => void; onSuccess: () => void;
modelId: string; modelId: string;
defaultValues?: FormData;
}) => { }) => {
const [importing, setImporting] = useState(false); const [importing, setImporting] = useState(false);
const { toast } = useToast(); const { toast } = useToast();
const { register, handleSubmit, control } = useForm<FormData>({ const { register, handleSubmit } = useForm<FormData>({
defaultValues: { defaultValues
text: '',
q: ''
}
}); });
/**
*
*/
const sureImportData = useCallback( const sureImportData = useCallback(
async (e: FormData) => { async (e: FormData) => {
setImporting(true); setImporting(true);
@ -72,6 +74,26 @@ const InputDataModal = ({
[modelId, onClose, onSuccess, toast] [modelId, onClose, onSuccess, toast]
); );
const updateData = useCallback(
async (e: FormData) => {
if (!e.dataId) return;
if (e.text === defaultValues.text && e.q === defaultValues.q) return;
await putModelDataById({
dataId: e.dataId,
text: e.text,
q: e.q === defaultValues.q ? '' : e.q
});
toast({
title: '修改回答成功',
status: 'success'
});
onClose();
onSuccess();
},
[defaultValues.q, onClose, onSuccess, toast]
);
return ( return (
<Modal isOpen={true} onClose={onClose} isCentered> <Modal isOpen={true} onClose={onClose} isCentered>
<ModalOverlay /> <ModalOverlay />
@ -125,7 +147,10 @@ const InputDataModal = ({
<Button variant={'outline'} mr={3} onClick={onClose}> <Button variant={'outline'} mr={3} onClick={onClose}>
</Button> </Button>
<Button isLoading={importing} onClick={handleSubmit(sureImportData)}> <Button
isLoading={importing}
onClick={handleSubmit(defaultValues.dataId ? updateData : sureImportData)}
>
</Button> </Button>
</Flex> </Flex>

View File

@ -1,4 +1,4 @@
import React, { useCallback } from 'react'; import React, { useCallback, useState } from 'react';
import { import {
Box, Box,
TableContainer, TableContainer,
@ -12,7 +12,6 @@ import {
Flex, Flex,
Button, Button,
useDisclosure, useDisclosure,
Textarea,
Menu, Menu,
MenuButton, MenuButton,
MenuList, MenuList,
@ -25,22 +24,21 @@ import { usePagination } from '@/hooks/usePagination';
import { import {
getModelDataList, getModelDataList,
delOneModelData, delOneModelData,
putModelDataById,
getModelSplitDataList, getModelSplitDataList,
getExportDataList getExportDataList
} from '@/api/model'; } from '@/api/model';
import { DeleteIcon, RepeatIcon } from '@chakra-ui/icons'; import { DeleteIcon, RepeatIcon, EditIcon } from '@chakra-ui/icons';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/hooks/useLoading';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useMutation, useQuery } from '@tanstack/react-query'; import { useMutation, useQuery } from '@tanstack/react-query';
import type { FormData as InputDataType } from './InputDataModal';
const InputModel = dynamic(() => import('./InputDataModal')); const InputModel = dynamic(() => import('./InputDataModal'));
const SelectFileModel = dynamic(() => import('./SelectFileModal')); const SelectFileModel = dynamic(() => import('./SelectFileModal'));
const SelectJsonModel = dynamic(() => import('./SelectJsonModal')); const SelectJsonModel = dynamic(() => import('./SelectJsonModal'));
const ModelDataCard = ({ model }: { model: ModelSchema }) => { const ModelDataCard = ({ model }: { model: ModelSchema }) => {
const { toast } = useToast();
const { Loading } = useLoading(); const { Loading } = useLoading();
const { const {
@ -58,25 +56,8 @@ const ModelDataCard = ({ model }: { model: ModelSchema }) => {
} }
}); });
const updateAnswer = useCallback( const [editInputData, setEditInputData] = useState<InputDataType>();
async (dataId: string, text: string) => {
await putModelDataById({
dataId,
text
});
toast({
title: '修改回答成功',
status: 'success'
});
},
[toast]
);
const {
isOpen: isOpenInputModal,
onOpen: onOpenInputModal,
onClose: onCloseInputModal
} = useDisclosure();
const { const {
isOpen: isOpenSelectFileModal, isOpen: isOpenSelectFileModal,
onOpen: onOpenSelectFileModal, onOpen: onOpenSelectFileModal,
@ -151,7 +132,16 @@ const ModelDataCard = ({ model }: { model: ModelSchema }) => {
</MenuButton> </MenuButton>
<MenuList> <MenuList>
<MenuItem onClick={onOpenInputModal}></MenuItem> <MenuItem
onClick={() =>
setEditInputData({
text: '',
q: ''
})
}
>
</MenuItem>
<MenuItem onClick={onOpenSelectFileModal}></MenuItem> <MenuItem onClick={onOpenSelectFileModal}></MenuItem>
<MenuItem onClick={onOpenSelectJsonModal}>JSON导入</MenuItem> <MenuItem onClick={onOpenSelectJsonModal}>JSON导入</MenuItem>
</MenuList> </MenuList>
@ -170,34 +160,38 @@ const ModelDataCard = ({ model }: { model: ModelSchema }) => {
<Th>Question</Th> <Th>Question</Th>
<Th>Text</Th> <Th>Text</Th>
<Th>Status</Th> <Th>Status</Th>
<Th></Th> <Th></Th>
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
{modelDataList.map((item) => ( {modelDataList.map((item) => (
<Tr key={item.id}> <Tr key={item.id}>
<Td w={'350px'}> <Td>
<Box fontSize={'xs'} w={'100%'} whiteSpace={'pre-wrap'} _notLast={{ mb: 1 }}> <Box fontSize={'xs'} w={'100%'} whiteSpace={'pre-wrap'}>
{item.q} {item.q}
</Box> </Box>
</Td> </Td>
<Td minW={'200px'}> <Td minW={'200px'}>
<Textarea <Box w={'100%'} fontSize={'xs'} whiteSpace={'pre-wrap'}>
w={'100%'} {item.text}
h={'100%'} </Box>
defaultValue={item.text}
fontSize={'xs'}
resize={'both'}
onBlur={(e) => {
const oldVal = modelDataList.find((data) => item.id === data.id)?.text;
if (oldVal !== e.target.value) {
updateAnswer(item.id, e.target.value);
}
}}
></Textarea>
</Td> </Td>
<Td w={'100px'}>{ModelDataStatusMap[item.status]}</Td> <Td>{ModelDataStatusMap[item.status]}</Td>
<Td> <Td>
<IconButton
mr={5}
icon={<EditIcon />}
variant={'outline'}
aria-label={'delete'}
size={'sm'}
onClick={() =>
setEditInputData({
dataId: item.id,
q: item.q,
text: item.text
})
}
/>
<IconButton <IconButton
icon={<DeleteIcon />} icon={<DeleteIcon />}
variant={'outline'} variant={'outline'}
@ -221,8 +215,13 @@ const ModelDataCard = ({ model }: { model: ModelSchema }) => {
</Box> </Box>
<Loading loading={isLoading} fixed={false} /> <Loading loading={isLoading} fixed={false} />
{isOpenInputModal && ( {editInputData !== undefined && (
<InputModel modelId={model._id} onClose={onCloseInputModal} onSuccess={refetchData} /> <InputModel
modelId={model._id}
defaultValues={editInputData}
onClose={() => setEditInputData(undefined)}
onSuccess={refetchData}
/>
)} )}
{isOpenSelectFileModal && ( {isOpenSelectFileModal && (
<SelectFileModel <SelectFileModel