This commit is contained in:
Archer
2023-10-22 23:54:04 +08:00
committed by GitHub
parent 3091a90df6
commit a3534407bf
365 changed files with 7266 additions and 6055 deletions

View File

@@ -3,7 +3,7 @@ import { ModalBody, Textarea, ModalFooter, Button } from '@chakra-ui/react';
import MyModal from '../MyModal';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useTranslation } from 'next-i18next';
import { userUpdateChatFeedback } from '@/web/core/api/chat';
import { userUpdateChatFeedback } from '@/web/core/chat/api';
const FeedbackModal = ({
chatItemId,

View File

@@ -0,0 +1,16 @@
import React, { useState } from 'react';
const MarkModal = () => {
const [adminMarkData, setAdminMarkData] = useState<{
chatItemId: string;
dataId?: string;
datasetId?: string;
collectionId?: string;
q: string;
a: string;
}>();
return <div>MarkModal</div>;
};
export default MarkModal;

View File

@@ -1,23 +1,24 @@
import React, { useCallback, useMemo, useState } from 'react';
import { ModalBody, Box, useTheme, Flex, Progress } from '@chakra-ui/react';
import { getDatasetDataItemById } from '@/web/core/api/dataset';
import { getDatasetDataItemById } from '@/web/core/dataset/api';
import { useLoading } from '@/web/common/hooks/useLoading';
import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@/utils/tools';
import { QuoteItemType } from '@/types/chat';
import { getErrText } from '@fastgpt/global/common/error/utils';
import MyIcon from '@/components/Icon';
import InputDataModal, { RawFileText } from '@/pages/kb/detail/components/InputDataModal';
import InputDataModal, {
RawSourceText,
type InputDataType
} from '@/pages/dataset/detail/components/InputDataModal';
import MyModal from '../MyModal';
import { useTranslation } from 'react-i18next';
import { useRouter } from 'next/router';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
const QuoteModal = ({
onUpdateQuote,
rawSearch = [],
onClose
}: {
onUpdateQuote: (quoteId: string, sourceText?: string) => Promise<void>;
rawSearch: QuoteItemType[];
rawSearch: SearchDataResponseItemType[];
onClose: () => void;
}) => {
const { t } = useTranslation();
@@ -25,7 +26,7 @@ const QuoteModal = ({
const router = useRouter();
const { toast } = useToast();
const { setIsLoading, Loading } = useLoading();
const [editDataItem, setEditDataItem] = useState<QuoteItemType>();
const [editInputData, setEditInputData] = useState<InputDataType>();
const isShare = useMemo(() => router.pathname === '/chat/share', [router.pathname]);
@@ -33,18 +34,17 @@ const QuoteModal = ({
* click edit, get new kbDataItem
*/
const onclickEdit = useCallback(
async (item: QuoteItemType) => {
async (item: InputDataType) => {
if (!item.id) return;
try {
setIsLoading(true);
const data = await getDatasetDataItemById(item.id);
if (!data) {
onUpdateQuote(item.id, '已删除');
throw new Error('该数据已被删除');
}
setEditDataItem(data);
setEditInputData(data);
} catch (err) {
toast({
status: 'warning',
@@ -53,7 +53,7 @@ const QuoteModal = ({
}
setIsLoading(false);
},
[setIsLoading, toast, onUpdateQuote]
[setIsLoading, toast]
);
return (
@@ -94,10 +94,7 @@ const QuoteModal = ({
>
{!isShare && (
<Flex alignItems={'center'} mb={1}>
<RawFileText
filename={item.source || t('common.Unknow') || 'Unknow'}
fileId={item.file_id}
/>
<RawSourceText sourceName={item.sourceName} sourceId={item.sourceId} />
<Box flex={'1'} />
{item.score && (
<>
@@ -150,16 +147,17 @@ const QuoteModal = ({
</ModalBody>
<Loading fixed={false} />
</MyModal>
{editDataItem && (
{editInputData && editInputData.id && (
<InputDataModal
onClose={() => setEditDataItem(undefined)}
onSuccess={() => onUpdateQuote(editDataItem.id)}
onDelete={() => onUpdateQuote(editDataItem.id, '已删除')}
kbId={editDataItem.kb_id}
defaultValues={{
...editDataItem,
dataId: editDataItem.id
onClose={() => setEditInputData(undefined)}
onSuccess={() => {
console.log('更新引用成功');
}}
onDelete={() => {
console.log('删除引用成功');
}}
datasetId={editInputData.datasetId}
defaultValues={editInputData}
/>
)}
</>

View File

@@ -3,7 +3,7 @@ import { ModalBody, ModalFooter, Button } from '@chakra-ui/react';
import MyModal from '../MyModal';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useTranslation } from 'next-i18next';
import { userUpdateChatFeedback } from '@/web/core/api/chat';
import { userUpdateChatFeedback } from '@/web/core/chat/api';
const ReadFeedbackModal = ({
chatItemId,
@@ -39,14 +39,14 @@ const ReadFeedbackModal = ({
<MyModal isOpen={true} onClose={onClose} title={t('chat.Feedback Modal')}>
<ModalBody>{content}</ModalBody>
<ModalFooter>
<Button mr={2} isLoading={isLoading} variant={'base'} onClick={mutate}>
{t('chat.Feedback Close')}
</Button>
{!isMarked && (
<Button variant={'base'} mr={2} onClick={onMark}>
<Button mr={2} onClick={onMark}>
{t('chat.Feedback Mark')}
</Button>
)}
<Button isLoading={isLoading} onClick={mutate}>
{t('chat.Feedback Close')}
</Button>
</ModalFooter>
</MyModal>
);

View File

@@ -1,8 +1,9 @@
import React, { useCallback, useMemo, useState } from 'react';
import { ChatHistoryItemResType, ChatItemType, QuoteItemType } from '@/types/chat';
import React, { useMemo, useState } from 'react';
import { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
import { Flex, BoxProps, useDisclosure } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import { useGlobalStore } from '@/web/common/store/global';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import dynamic from 'next/dynamic';
import Tag from '../Tag';
import MyTooltip from '../MyTooltip';
@@ -13,9 +14,9 @@ const ContextModal = dynamic(() => import('./ContextModal'), { ssr: false });
const WholeResponseModal = dynamic(() => import('./WholeResponseModal'), { ssr: false });
const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemResType[] }) => {
const { isPc } = useGlobalStore();
const { isPc } = useSystemStore();
const { t } = useTranslation();
const [quoteModalData, setQuoteModalData] = useState<QuoteItemType[]>();
const [quoteModalData, setQuoteModalData] = useState<SearchDataResponseItemType[]>();
const [contextModalData, setContextModalData] = useState<ChatItemType[]>();
const {
isOpen: isOpenWholeModal,
@@ -37,14 +38,12 @@ const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemRes
.filter((item) => item.moduleType === FlowModuleTypeEnum.chatNode)
.map((item) => item.quoteList)
.flat()
.filter((item) => item) as QuoteItemType[],
.filter((item) => item) as SearchDataResponseItemType[],
historyPreview: chatData?.historyPreview,
runningTime: +responseData.reduce((sum, item) => sum + (item.runningTime || 0), 0).toFixed(2)
};
}, [responseData]);
const updateQuote = useCallback(async (quoteId: string, sourceText?: string) => {}, []);
const TagStyles: BoxProps = {
mr: 2,
bg: 'transparent'
@@ -100,11 +99,7 @@ const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemRes
</MyTooltip>
{!!quoteModalData && (
<QuoteModal
rawSearch={quoteModalData}
onUpdateQuote={updateQuote}
onClose={() => setQuoteModalData(undefined)}
/>
<QuoteModal rawSearch={quoteModalData} onClose={() => setQuoteModalData(undefined)} />
)}
{!!contextModalData && (
<ContextModal context={contextModalData} onClose={() => setContextModalData(undefined)} />

View File

@@ -1,114 +0,0 @@
import React, { useState } from 'react';
import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast';
import Avatar from '../Avatar';
import MyIcon from '@/components/Icon';
import { DatasetTypeEnum } from '@fastgpt/core/dataset/constant';
import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
const SelectDataset = ({
isOpen,
onSuccess,
onClose
}: {
isOpen: boolean;
onSuccess: (kbId: string) => void;
onClose: () => void;
}) => {
const { t } = useTranslation();
const theme = useTheme();
const { toast } = useToast();
const [selectedId, setSelectedId] = useState<string>();
const { paths, parentId, setParentId, datasets } = useDatasetSelect();
return (
<DatasetSelectModal
isOpen={isOpen}
paths={paths}
onClose={onClose}
parentId={parentId}
setParentId={setParentId}
tips={t('chat.Select Mark Kb Desc')}
>
<ModalBody flex={'1 0 0'} overflowY={'auto'}>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'}
>
{datasets.map((item) =>
(() => {
const selected = selectedId === item._id;
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
h={'80px'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
{...(selected
? {
bg: 'myBlue.300'
}
: {})}
onClick={() => {
if (item.type === DatasetTypeEnum.folder) {
setParentId(item._id);
} else {
setSelectedId(item._id);
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={item.avatar} w={['24px', '28px', '32px']}></Avatar>
<Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}>
{item.name}
</Box>
</Flex>
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
<MyIcon mr={1} name="kbTest" w={'12px'} />
<Box color={'myGray.500'}>{item.vectorModel.name}</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
{datasets.length === 0 && (
<Flex mt={5} flexDirection={'column'} alignItems={'center'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
西~
</Box>
</Flex>
)}
</ModalBody>
<ModalFooter>
<Button variant={'base'} mr={2} onClick={onClose}>
{t('Cancel')}
</Button>
<Button
onClick={() => {
if (!selectedId) {
return toast({
status: 'warning',
title: t('Select value is empty')
});
}
onSuccess(selectedId);
}}
>
{t('Confirm')}
</Button>
</ModalFooter>
</DatasetSelectModal>
);
};
export default SelectDataset;

View File

@@ -0,0 +1,195 @@
import React, { useState } from 'react';
import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import Avatar from '../Avatar';
import MyIcon from '@/components/Icon';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constant';
import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
import dynamic from 'next/dynamic';
import { MarkDataType } from '@/global/core/dataset/type';
import SelectCollections from '@/web/core/dataset/components/SelectCollections';
const InputDataModal = dynamic(() => import('@/pages/dataset/detail/components/InputDataModal'));
export type AdminMarkType = {
dataId?: string;
datasetId?: string;
collectionId?: string;
q: string;
a?: string;
};
const SelectMarkCollection = ({
adminMarkData,
setAdminMarkData,
onSuccess,
onClose
}: {
adminMarkData: AdminMarkType;
setAdminMarkData: (e: AdminMarkType) => void;
onClose: () => void;
onSuccess: (adminFeedback: MarkDataType) => void;
}) => {
const { t } = useTranslation();
const theme = useTheme();
const [selectedDatasetId, setSelectedDatasetId] = useState<string>();
const [selectedDatasetCollectionIds, setSelectedDatasetCollectionIds] = useState<string[]>([]);
const { paths, parentId, setParentId, datasets, isLoading } = useDatasetSelect();
return (
<>
{/* select dataset */}
{!adminMarkData.datasetId && (
<DatasetSelectModal
isOpen
paths={paths}
onClose={onClose}
parentId={parentId}
setParentId={setParentId}
tips={t('chat.Select Mark Kb Desc')}
>
<ModalBody flex={'1 0 0'} overflowY={'auto'}>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'}
>
{datasets.map((item) =>
(() => {
const selected = selectedDatasetId === item._id;
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
h={'80px'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
{...(selected
? {
bg: 'myBlue.300'
}
: {})}
onClick={() => {
if (item.type === DatasetTypeEnum.folder) {
setParentId(item._id);
} else {
setSelectedDatasetId(item._id);
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={item.avatar} w={['24px', '28px', '32px']}></Avatar>
<Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}>
{item.name}
</Box>
</Flex>
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
<MyIcon mr={1} name="kbTest" w={'12px'} />
<Box color={'myGray.500'}>{item.vectorModel.name}</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
{datasets.length === 0 && (
<Flex mt={'10vh'} flexDirection={'column'} alignItems={'center'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
西~
</Box>
</Flex>
)}
</ModalBody>
<ModalFooter>
<Button
isLoading={isLoading}
isDisabled={!selectedDatasetId}
onClick={() => {
setAdminMarkData({ ...adminMarkData, datasetId: selectedDatasetId });
}}
>
{t('common.Next Step')}
</Button>
</ModalFooter>
</DatasetSelectModal>
)}
{/* select collection */}
{adminMarkData.datasetId && !adminMarkData.collectionId && (
<SelectCollections
datasetId={adminMarkData.datasetId}
type={'collection'}
title={t('dataset.collections.Select One Collection To Store')}
onClose={onClose}
onChange={({ collectionIds }) => {
setSelectedDatasetCollectionIds(collectionIds);
}}
CustomFooter={
<ModalFooter>
<Button
variant={'base'}
mr={2}
onClick={() => {
setAdminMarkData({
...adminMarkData,
datasetId: undefined
});
}}
>
{t('common.Last Step')}
</Button>
<Button
isDisabled={selectedDatasetCollectionIds.length === 0}
onClick={() => {
setAdminMarkData({
...adminMarkData,
collectionId: selectedDatasetCollectionIds[0]
});
}}
>
{t('common.Next Step')}
</Button>
</ModalFooter>
}
/>
)}
{/* input data */}
{adminMarkData.datasetId && adminMarkData.collectionId && (
<InputDataModal
onClose={onClose}
datasetId={adminMarkData.datasetId}
defaultValues={{
id: adminMarkData.dataId,
datasetId: adminMarkData.datasetId,
collectionId: adminMarkData.collectionId,
sourceName: '手动标注',
q: adminMarkData.q,
a: adminMarkData.a
}}
onSuccess={(data) => {
if (!data.q || !adminMarkData.datasetId || !adminMarkData.collectionId || !data.id) {
return onClose();
}
onSuccess({
dataId: data.id,
datasetId: adminMarkData.datasetId,
collectionId: adminMarkData.collectionId,
q: data.q,
a: data.a
});
onClose();
}}
/>
)}
</>
);
};
export default React.memo(SelectMarkCollection);

View File

@@ -8,7 +8,7 @@ import Tabs from '../Tabs';
import MyModal from '../MyModal';
import MyTooltip from '../MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { formatPrice } from '@fastgpt/common/bill/index';
import { formatPrice } from '@fastgpt/global/common/bill/tools';
function Row({ label, value }: { label: string; value?: string | number | React.ReactNode }) {
const theme = useTheme();

View File

@@ -10,25 +10,6 @@
}
}
.newChat {
.modelListContainer {
height: 0;
overflow: hidden;
}
.modelList {
border-radius: 6px;
}
&:hover {
.modelListContainer {
height: 60vh;
}
.modelList {
box-shadow: 0 0 5px rgba($color: #000000, $alpha: 0.05);
border: 1px solid #dee0e2;
}
}
}
.statusAnimation {
animation: statusBox 0.8s linear infinite alternate;
}

View File

@@ -8,6 +8,7 @@ import React, {
ForwardedRef,
useEffect
} from 'react';
import Script from 'next/script';
import { throttle } from 'lodash';
import {
ChatHistoryItemResType,
@@ -17,7 +18,7 @@ import {
} from '@/types/chat';
import { useToast } from '@/web/common/hooks/useToast';
import { useAudioPlay } from '@/web/common/utils/voice';
import { getErrText } from '@/utils/tools';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import {
Box,
@@ -30,7 +31,7 @@ import {
BoxProps,
FlexProps
} from '@chakra-ui/react';
import { feConfigs } from '@/web/common/store/static';
import { feConfigs } from '@/web/common/system/staticData';
import { eventBus } from '@/web/common/utils/eventbus';
import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
import { useMarkdown } from '@/web/common/hooks/useMarkdown';
@@ -38,14 +39,15 @@ import { AppModuleItemType } from '@/types/app';
import { VariableInputEnum } from '@/constants/app';
import { useForm } from 'react-hook-form';
import type { MessageItemType } from '@/types/core/chat/type';
import { fileDownload } from '@/web/common/utils/file';
import { fileDownload } from '@/web/common/file/utils';
import { htmlTemplate } from '@/constants/common';
import { useRouter } from 'next/router';
import { useGlobalStore } from '@/web/common/store/global';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { TaskResponseKeyEnum } from '@/constants/chat';
import { useTranslation } from 'react-i18next';
import { customAlphabet } from 'nanoid';
import { userUpdateChatFeedback, adminUpdateChatFeedback } from '@/web/core/api/chat';
import { adminUpdateChatFeedback, userUpdateChatFeedback } from '@/web/core/chat/api';
import type { AdminMarkType } from './SelectMarkCollection';
import MyIcon from '@/components/Icon';
import Avatar from '@/components/Avatar';
@@ -56,14 +58,11 @@ import dynamic from 'next/dynamic';
const ResponseTags = dynamic(() => import('./ResponseTags'));
const FeedbackModal = dynamic(() => import('./FeedbackModal'));
const ReadFeedbackModal = dynamic(() => import('./ReadFeedbackModal'));
const SelectDataset = dynamic(() => import('./SelectDataset'));
const InputDataModal = dynamic(() => import('@/pages/kb/detail/components/InputDataModal'));
const SelectMarkCollection = dynamic(() => import('./SelectMarkCollection'));
import styles from './index.module.scss';
import Script from 'next/script';
import { postQuestionGuide } from '@/web/core/api/ai';
import { splitGuideModule } from './utils';
import { DatasetSpecialIdEnum } from '@fastgpt/core/dataset/constant';
import { postQuestionGuide } from '@/web/core/ai/api';
import { splitGuideModule } from '@/global/core/app/modules/utils';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
@@ -131,7 +130,7 @@ const ChatBox = (
const router = useRouter();
const { t } = useTranslation();
const { toast } = useToast();
const { isPc } = useGlobalStore();
const { isPc } = useSystemStore();
const TextareaDom = useRef<HTMLTextAreaElement>(null);
const chatController = useRef(new AbortController());
const questionGuideController = useRef(new AbortController());
@@ -147,14 +146,7 @@ const ChatBox = (
content: string;
isMarked: boolean;
}>();
const [adminMarkData, setAdminMarkData] = useState<{
// mark modal data
kbId?: string;
chatItemId: string;
dataId?: string;
q: string;
a: string;
}>();
const [adminMarkData, setAdminMarkData] = useState<AdminMarkType & { chatItemId: string }>();
const [questionGuides, setQuestionGuide] = useState<string[]>([]);
const isChatting = useMemo(
@@ -674,10 +666,11 @@ const ChatBox = (
if (item.adminFeedback) {
setAdminMarkData({
chatItemId: item.dataId,
kbId: item.adminFeedback.kbId,
datasetId: item.adminFeedback.datasetId,
collectionId: item.adminFeedback.collectionId,
dataId: item.adminFeedback.dataId,
q: chatHistory[index - 1]?.value || '',
a: item.adminFeedback.content
q: item.adminFeedback.q || chatHistory[index - 1]?.value || '',
a: item.adminFeedback.a
});
} else {
setAdminMarkData({
@@ -798,7 +791,9 @@ const ChatBox = (
</Box>
<Box h={'1px'} bg={'myGray.300'} flex={'1'} />
</Flex>
<Box>{item.adminFeedback.content}</Box>
<Box whiteSpace={'pre'}>{`${item.adminFeedback.q || ''}${
item.adminFeedback.a ? `\n${item.adminFeedback.a}` : ''
}`}</Box>
</Box>
)}
</Card>
@@ -940,75 +935,44 @@ const ChatBox = (
/>
)}
{/* admin mark data */}
{showMarkIcon && (
<>
{/* select one dataset to insert markData */}
<SelectDataset
isOpen={!!adminMarkData && !adminMarkData.kbId}
onClose={() => setAdminMarkData(undefined)}
// @ts-ignore
onSuccess={(kbId) => setAdminMarkData((state) => ({ ...state, kbId }))}
/>
{!!adminMarkData && (
<SelectMarkCollection
adminMarkData={adminMarkData}
setAdminMarkData={(e) => setAdminMarkData({ ...e, chatItemId: adminMarkData.chatItemId })}
onClose={() => setAdminMarkData(undefined)}
onSuccess={(adminFeedback) => {
adminUpdateChatFeedback({
chatItemId: adminMarkData.chatItemId,
...adminFeedback
});
// update dom
setChatHistory((state) =>
state.map((chatItem) =>
chatItem.dataId === adminMarkData.chatItemId
? {
...chatItem,
adminFeedback
}
: chatItem
)
);
{/* edit markData modal */}
{adminMarkData && adminMarkData.kbId && (
<InputDataModal
onClose={() => setAdminMarkData(undefined)}
onSuccess={async (data) => {
if (!adminMarkData.kbId || !data.dataId) {
return setAdminMarkData(undefined);
}
const adminFeedback = {
kbId: adminMarkData.kbId,
dataId: data.dataId,
content: data.a
};
// update dom
setChatHistory((state) =>
state.map((chatItem) =>
chatItem.dataId === adminMarkData.chatItemId
? {
...chatItem,
adminFeedback
}
: chatItem
)
);
// request to update adminFeedback
try {
adminUpdateChatFeedback({
chatItemId: adminMarkData.chatItemId,
...adminFeedback
});
if (readFeedbackData) {
userUpdateChatFeedback({
chatItemId: readFeedbackData.chatItemId,
userFeedback: undefined
});
setChatHistory((state) =>
state.map((chatItem) =>
chatItem.dataId === readFeedbackData.chatItemId
? { ...chatItem, userFeedback: undefined }
: chatItem
)
);
setReadFeedbackData(undefined);
}
} catch (error) {}
setAdminMarkData(undefined);
}}
kbId={adminMarkData.kbId}
defaultValues={{
dataId: adminMarkData.dataId,
q: adminMarkData.q,
a: adminMarkData.a,
file_id: DatasetSpecialIdEnum.mark
}}
/>
)}
</>
if (readFeedbackData) {
userUpdateChatFeedback({
chatItemId: readFeedbackData.chatItemId,
userFeedback: undefined
});
setChatHistory((state) =>
state.map((chatItem) =>
chatItem.dataId === readFeedbackData.chatItemId
? { ...chatItem, userFeedback: undefined }
: chatItem
)
);
setReadFeedbackData(undefined);
}
}}
/>
)}
</Flex>
);

View File

@@ -1,24 +0,0 @@
import { SystemInputEnum } from '@/constants/app';
import { FlowModuleTypeEnum } from '@/constants/flow';
import { AppModuleItemType, VariableItemType } from '@/types/app';
export const getGuideModule = (modules: AppModuleItemType[]) =>
modules.find((item) => item.flowType === FlowModuleTypeEnum.userGuide);
export const splitGuideModule = (guideModules?: AppModuleItemType) => {
const welcomeText: string =
guideModules?.inputs?.find((item) => item.key === SystemInputEnum.welcomeText)?.value || '';
const variableModules: VariableItemType[] =
guideModules?.inputs.find((item) => item.key === SystemInputEnum.variables)?.value || [];
const questionGuide: boolean =
guideModules?.inputs?.find((item) => item.key === SystemInputEnum.questionGuide)?.value ||
false;
return {
welcomeText,
variableModules,
questionGuide
};
};

View File

@@ -1,4 +0,0 @@
.datePicker {
--rdp-background-color: #d6e8ff;
--rdp-accent-color: #0000ff;
}

View File

@@ -4,7 +4,6 @@ import { addDays, format } from 'date-fns';
import { type DateRange, DayPicker } from 'react-day-picker';
import MyIcon from '../Icon';
import 'react-day-picker/dist/style.css';
import styles from './index.module.scss';
import zhCN from 'date-fns/locale/zh-CN';
const DateRangePicker = ({
@@ -59,6 +58,10 @@ const DateRangePicker = ({
<Card
position={'absolute'}
zIndex={1}
css={{
'--rdp-background-color': '#d6e8ff',
' --rdp-accent-color': '#0000ff'
}}
{...(position === 'top'
? {
bottom: '40px'
@@ -69,7 +72,6 @@ const DateRangePicker = ({
locale={zhCN}
id="test"
mode="range"
className={styles.datePicker}
defaultMonth={defaultDate.to}
selected={range}
disabled={[

View File

@@ -0,0 +1,20 @@
import React from 'react';
import { Flex, Box, FlexProps } from '@chakra-ui/react';
import MyIcon from '../Icon';
type Props = FlexProps & {
text?: string | null;
};
const EmptyTip = ({ text, ...props }: Props) => {
return (
<Flex mt={5} flexDirection={'column'} alignItems={'center'} pt={'10vh'} {...props}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
{text || '没有什么数据噢~'}
</Box>
</Flex>
);
};
export default EmptyTip;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { useRouter } from 'next/router';
import { useToast } from '@chakra-ui/react';
import { useUserStore } from '@/web/support/store/user';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useQuery } from '@tanstack/react-query';
const unAuthPage: { [key: string]: boolean } = {

View File

@@ -2,14 +2,14 @@ import React, { useEffect, useMemo } from 'react';
import { Box, useColorMode, Flex } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { useLoading } from '@/web/common/hooks/useLoading';
import { useGlobalStore } from '@/web/common/store/global';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { throttle } from 'lodash';
import Auth from './auth';
import Navbar from './navbar';
import NavbarPhone from './navbarPhone';
import { useQuery } from '@tanstack/react-query';
import { useUserStore } from '@/web/support/store/user';
import { getUnreadCount } from '@/web/support/api/user';
import { useUserStore } from '@/web/support/user/useUserStore';
import { getUnreadCount } from '@/web/support/user/api';
const pcUnShowLayoutRoute: Record<string, boolean> = {
'/': true,
@@ -30,7 +30,7 @@ const Layout = ({ children }: { children: JSX.Element }) => {
const router = useRouter();
const { colorMode, setColorMode } = useColorMode();
const { Loading } = useLoading();
const { loading, setScreenWidth, isPc, loadGitStar } = useGlobalStore();
const { loading, setScreenWidth, isPc, loadGitStar } = useSystemStore();
const { userInfo } = useUserStore();
const isChatPage = useMemo(

View File

@@ -1,16 +1,16 @@
import React, { useMemo } from 'react';
import { Box, Flex, Link } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { useUserStore } from '@/web/support/store/user';
import { useChatStore } from '@/web/core/store/chat';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useChatStore } from '@/web/core/chat/storeChat';
import { HUMAN_ICON } from '@/constants/chat';
import { feConfigs } from '@/web/common/store/static';
import { feConfigs } from '@/web/common/system/staticData';
import NextLink from 'next/link';
import Badge from '../Badge';
import Avatar from '../Avatar';
import MyIcon from '../Icon';
import { useTranslation } from 'next-i18next';
import { useGlobalStore } from '@/web/common/store/global';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyTooltip from '../MyTooltip';
export enum NavbarTypeEnum {
@@ -22,7 +22,7 @@ const Navbar = ({ unread }: { unread: number }) => {
const { t } = useTranslation();
const router = useRouter();
const { userInfo } = useUserStore();
const { gitStar } = useGlobalStore();
const { gitStar } = useSystemStore();
const { lastChatAppId, lastChatId } = useChatStore();
const navbarList = useMemo(
() => [
@@ -44,8 +44,8 @@ const Navbar = ({ unread }: { unread: number }) => {
label: t('navbar.Datasets'),
icon: 'dbLight',
activeIcon: 'dbFill',
link: `/kb/list`,
activeLink: ['/kb/list', '/kb/detail']
link: `/dataset/list`,
activeLink: ['/dataset/list', '/dataset/detail']
},
...(feConfigs?.show_appStore
? [

View File

@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { useRouter } from 'next/router';
import { Flex, Box } from '@chakra-ui/react';
import { useChatStore } from '@/web/core/store/chat';
import { useChatStore } from '@/web/core/chat/storeChat';
import { useTranslation } from 'react-i18next';
import Badge from '../Badge';
import MyIcon from '../Icon';

View File

@@ -1,8 +1,8 @@
import React, { useMemo } from 'react';
import { Box, useTheme } from '@chakra-ui/react';
import { getFileAndOpen } from '@/web/common/utils/file';
import { getFileAndOpen } from '@/web/common/file/utils';
import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@/utils/tools';
import { getErrText } from '@fastgpt/global/common/error/utils';
type QuoteItemType = {
file_id?: string;

View File

@@ -22,7 +22,7 @@ const MyModal = ({
title,
children,
isCentered,
w = 'auto',
w = '100%',
maxW = ['90vw', '600px'],
...props
}: Props) => {
@@ -44,7 +44,12 @@ const MyModal = ({
>
{!!title && <ModalHeader>{title}</ModalHeader>}
{onClose && <ModalCloseButton />}
<Box overflow={'overlay'} h={'100%'} display={'flex'} flexDirection={'column'}>
<Box
overflow={props.overflow || 'overlay'}
h={'100%'}
display={'flex'}
flexDirection={'column'}
>
{children}
</Box>
</ModalContent>

View File

@@ -1,13 +1,13 @@
import React from 'react';
import { Tooltip, TooltipProps } from '@chakra-ui/react';
import { useGlobalStore } from '@/web/common/store/global';
import { useSystemStore } from '@/web/common/system/useSystemStore';
interface Props extends TooltipProps {
forceShow?: boolean;
}
const MyTooltip = ({ children, forceShow = false, shouldWrapChildren = true, ...props }: Props) => {
const { isPc } = useGlobalStore();
const { isPc } = useSystemStore();
return isPc || forceShow ? (
<Tooltip
bg={'white'}

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import MyModal from '../MyModal';
import { Box, Button, Grid, useTheme } from '@chakra-ui/react';
import { PromptTemplateItem } from '@fastgpt/core/ai/type';
import { PromptTemplateItem } from '@fastgpt/global/core/ai/type.d';
import { ModalBody, ModalFooter } from '@chakra-ui/react';
const PromptTemplate = ({

View File

@@ -0,0 +1,62 @@
import MyIcon from '@/components/Icon';
import { Box, Flex } from '@chakra-ui/react';
import { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type';
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const ParentPaths = (props: {
paths?: ParentTreePathItemType[];
rootName?: string;
FirstPathDom?: React.ReactNode;
onClick: (parentId: string) => void;
}) => {
const { t } = useTranslation();
const { paths = [], rootName = t('common.folder.Root Path'), FirstPathDom, onClick } = props;
const concatPaths = useMemo(
() => [
{
parentId: '',
parentName: rootName
},
...paths
],
[rootName, paths]
);
return paths.length === 0 && !!FirstPathDom ? (
<>{FirstPathDom}</>
) : (
<Flex flex={1}>
{concatPaths.map((item, i) => (
<Flex key={item.parentId} alignItems={'center'}>
<Box
fontSize={['md', 'lg']}
py={1}
px={[0, 2]}
borderRadius={'md'}
{...(i === concatPaths.length - 1
? {
cursor: 'default'
}
: {
cursor: 'pointer',
_hover: {
bg: 'myGray.100'
},
onClick: () => {
onClick(item.parentId);
}
})}
>
{item.parentName}
</Box>
{i !== concatPaths.length - 1 && (
<MyIcon name={'rightArrowLight'} color={'myGray.500'} w={['18px', '24px']} />
)}
</Flex>
))}
</Flex>
);
};
export default React.memo(ParentPaths);

View File

@@ -1,9 +1,9 @@
import { getDatasets, getDatasetPaths } from '@/web/core/api/dataset';
import { getDatasets, getDatasetPaths } from '@/web/core/dataset/api';
import MyModal from '@/components/MyModal';
import { useQuery } from '@tanstack/react-query';
import React, { Dispatch, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useGlobalStore } from '@/web/common/store/global';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { Box, Flex, ModalHeader } from '@chakra-ui/react';
import MyIcon from '@/components/Icon';
@@ -30,7 +30,7 @@ const DatasetSelectContainer = ({
children: React.ReactNode;
}) => {
const { t } = useTranslation();
const { isPc } = useGlobalStore();
const { isPc } = useSystemStore();
return (
<MyModal isOpen={isOpen} onClose={onClose} w={'100%'} maxW={['90vw', '900px']} isCentered>
@@ -86,11 +86,11 @@ const DatasetSelectContainer = ({
);
};
export const useDatasetSelect = () => {
export function useDatasetSelect() {
const { t } = useTranslation();
const [parentId, setParentId] = useState<string>();
const { data } = useQuery(['loadDatasetData', parentId], () =>
const { data, isLoading } = useQuery(['loadDatasetData', parentId], () =>
Promise.all([getDatasets({ parentId }), getDatasetPaths(parentId)])
);
@@ -98,7 +98,7 @@ export const useDatasetSelect = () => {
() => [
{
parentId: '',
parentName: t('kb.My Dataset')
parentName: t('dataset.My Dataset')
},
...(data?.[1] || [])
],
@@ -109,8 +109,9 @@ export const useDatasetSelect = () => {
parentId,
setParentId,
datasets: data?.[0] || [],
paths
paths,
isLoading
};
};
}
export default DatasetSelectContainer;

View File

@@ -25,14 +25,14 @@ import {
createAOpenApiKey,
delOpenApiById,
putOpenApiKey
} from '@/web/support/api/openapi';
} from '@/web/support/openapi/api';
import type { EditApiKeyProps } from '@/global/support/api/openapiReq';
import { useQuery, useMutation } from '@tanstack/react-query';
import { useLoading } from '@/web/common/hooks/useLoading';
import dayjs from 'dayjs';
import { AddIcon, QuestionOutlineIcon } from '@chakra-ui/icons';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { feConfigs } from '@/web/common/store/static';
import { feConfigs } from '@/web/common/system/staticData';
import { useTranslation } from 'react-i18next';
import MyIcon from '@/components/Icon';
import MyModal from '@/components/MyModal';