Optimize the structure and naming of projects (#335)
This commit is contained in:
parent
a3c77480f7
commit
823f4b7ad1
26
client/src/api/core/dataset/data.d.ts
vendored
Normal file
26
client/src/api/core/dataset/data.d.ts
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
|
import type { RequestPaging } from '@/types';
|
||||||
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
|
|
||||||
|
export type PushDataProps = {
|
||||||
|
kbId: string;
|
||||||
|
data: DatasetItemType[];
|
||||||
|
mode: `${TrainingModeEnum}`;
|
||||||
|
prompt?: string;
|
||||||
|
};
|
||||||
|
export type PushDataResponse = {
|
||||||
|
insertLen: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateDataPrams = {
|
||||||
|
dataId: string;
|
||||||
|
kbId: string;
|
||||||
|
a?: string;
|
||||||
|
q?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetDatasetDataListProps = RequestPaging & {
|
||||||
|
kbId: string;
|
||||||
|
searchText: string;
|
||||||
|
fileId: string;
|
||||||
|
};
|
||||||
72
client/src/api/core/dataset/data.ts
Normal file
72
client/src/api/core/dataset/data.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { GET, POST, PUT, DELETE } from '@/api/request';
|
||||||
|
import type { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||||
|
import type {
|
||||||
|
PushDataProps,
|
||||||
|
PushDataResponse,
|
||||||
|
UpdateDataPrams,
|
||||||
|
GetDatasetDataListProps
|
||||||
|
} from './data.d';
|
||||||
|
import { QuoteItemType } from '@/types/chat';
|
||||||
|
import { getToken } from '@/utils/user';
|
||||||
|
import download from 'downloadjs';
|
||||||
|
|
||||||
|
/* kb data */
|
||||||
|
export const getDatasetDataList = (data: GetDatasetDataListProps) =>
|
||||||
|
POST(`/core/dataset/data/getDataList`, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* export and download data
|
||||||
|
*/
|
||||||
|
export const exportDatasetData = (data: { kbId: string }) =>
|
||||||
|
fetch(`/api/core/dataset/data/exportAll?kbId=${data.kbId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
token: getToken()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
throw new Error(data?.message || 'Export failed');
|
||||||
|
}
|
||||||
|
return res.blob();
|
||||||
|
})
|
||||||
|
.then((blob) => download(blob, 'dataset.csv', 'text/csv'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模型正在拆分数据的数量
|
||||||
|
*/
|
||||||
|
export const getTrainingData = (data: { kbId: string; init: boolean }) =>
|
||||||
|
POST<{
|
||||||
|
qaListLen: number;
|
||||||
|
vectorListLen: number;
|
||||||
|
}>(`/core/dataset/data/getTrainingData`, data);
|
||||||
|
|
||||||
|
/* get length of system training queue */
|
||||||
|
export const getTrainingQueueLen = () => GET<number>(`/core/dataset/data/getQueueLen`);
|
||||||
|
|
||||||
|
export const getDatasetDataItemById = (dataId: string) =>
|
||||||
|
GET<QuoteItemType>(`/core/dataset/data/getDataById`, { dataId });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* push data to training queue
|
||||||
|
*/
|
||||||
|
export const postChunks2Dataset = (data: PushDataProps) =>
|
||||||
|
POST<PushDataResponse>(`/core/dataset/data/pushData`, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert one data to dataset (immediately insert)
|
||||||
|
*/
|
||||||
|
export const postData2Dataset = (data: { kbId: string; data: DatasetDataItemType }) =>
|
||||||
|
POST<string>(`/core/dataset/data/insertData`, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新一条数据
|
||||||
|
*/
|
||||||
|
export const putDatasetDataById = (data: UpdateDataPrams) =>
|
||||||
|
PUT('/core/dataset/data/updateData', data);
|
||||||
|
/**
|
||||||
|
* 删除一条知识库数据
|
||||||
|
*/
|
||||||
|
export const delOneDatasetDataById = (dataId: string) =>
|
||||||
|
DELETE(`/core/dataset/data/delDataById?dataId=${dataId}`);
|
||||||
@ -1,14 +1,15 @@
|
|||||||
import { GET, POST, PUT, DELETE } from '@/api/request';
|
import { GET, POST, PUT, DELETE } from '@/api/request';
|
||||||
import type { FileInfo, KbFileItemType } from '@/types/plugin';
|
import type { DatasetFileItemType } from '@/types/core/dataset/file';
|
||||||
|
import type { GSFileInfoType } from '@/types/common/file';
|
||||||
|
|
||||||
import type { GetFileListProps, UpdateFileProps } from './file.d';
|
import type { GetFileListProps, UpdateFileProps } from './file.d';
|
||||||
|
|
||||||
export const getDatasetFiles = (data: GetFileListProps) =>
|
export const getDatasetFiles = (data: GetFileListProps) =>
|
||||||
POST<KbFileItemType[]>(`/core/dataset/file/list`, data);
|
POST<DatasetFileItemType[]>(`/core/dataset/file/list`, data);
|
||||||
export const delDatasetFileById = (params: { fileId: string; kbId: string }) =>
|
export const delDatasetFileById = (params: { fileId: string; kbId: string }) =>
|
||||||
DELETE(`/core/dataset/file/delById`, params);
|
DELETE(`/core/dataset/file/delById`, params);
|
||||||
export const getFileInfoById = (fileId: string) =>
|
export const getFileInfoById = (fileId: string) =>
|
||||||
GET<FileInfo>(`/core/dataset/file/detail`, { fileId });
|
GET<GSFileInfoType>(`/core/dataset/file/detail`, { fileId });
|
||||||
export const delDatasetEmptyFiles = (kbId: string) =>
|
export const delDatasetEmptyFiles = (kbId: string) =>
|
||||||
DELETE(`/core/dataset/file/delEmptyFiles`, { kbId });
|
DELETE(`/core/dataset/file/delEmptyFiles`, { kbId });
|
||||||
|
|
||||||
|
|||||||
34
client/src/api/core/dataset/index.d.ts
vendored
Normal file
34
client/src/api/core/dataset/index.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
|
import type { RequestPaging } from '@/types';
|
||||||
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
|
import type { SearchTestItemType } from '@/types/core/dataset';
|
||||||
|
|
||||||
|
export type DatasetUpdateParams = {
|
||||||
|
id: string;
|
||||||
|
parentId?: string;
|
||||||
|
tags?: string;
|
||||||
|
name?: string;
|
||||||
|
avatar?: string;
|
||||||
|
};
|
||||||
|
export type CreateDatasetParams = {
|
||||||
|
parentId?: string;
|
||||||
|
name: string;
|
||||||
|
tags: string[];
|
||||||
|
avatar: string;
|
||||||
|
vectorModel?: string;
|
||||||
|
type: `${KbTypeEnum}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DatasetUpdateParams = {
|
||||||
|
id: string;
|
||||||
|
parentId?: string;
|
||||||
|
tags?: string;
|
||||||
|
name?: string;
|
||||||
|
avatar?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SearchTestProps = {
|
||||||
|
kbId: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
export type SearchTestResponseType = SearchTestItemType['results'];
|
||||||
32
client/src/api/core/dataset/index.ts
Normal file
32
client/src/api/core/dataset/index.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { GET, POST, PUT, DELETE } from '@/api/request';
|
||||||
|
import type { DatasetItemType, DatasetsItemType, DatasetPathItemType } from '@/types/core/dataset';
|
||||||
|
import type {
|
||||||
|
DatasetUpdateParams,
|
||||||
|
CreateDatasetParams,
|
||||||
|
SearchTestProps,
|
||||||
|
SearchTestResponseType
|
||||||
|
} from './index.d';
|
||||||
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
|
|
||||||
|
export const getDatasets = (data: { parentId?: string; type?: `${KbTypeEnum}` }) =>
|
||||||
|
GET<DatasetsItemType[]>(`/core/dataset/list`, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get type=dataset list
|
||||||
|
*/
|
||||||
|
export const getAllDataset = () => GET<DatasetsItemType[]>(`/core/dataset/allDataset`);
|
||||||
|
|
||||||
|
export const getDatasetPaths = (parentId?: string) =>
|
||||||
|
GET<DatasetPathItemType[]>('/core/dataset/paths', { parentId });
|
||||||
|
|
||||||
|
export const getDatasetById = (id: string) => GET<DatasetItemType>(`/core/dataset/detail?id=${id}`);
|
||||||
|
|
||||||
|
export const postCreateDataset = (data: CreateDatasetParams) =>
|
||||||
|
POST<string>(`/core/dataset/create`, data);
|
||||||
|
|
||||||
|
export const putDatasetById = (data: DatasetUpdateParams) => PUT(`/core/dataset/update`, data);
|
||||||
|
|
||||||
|
export const delDatasetById = (id: string) => DELETE(`/core/dataset/delete?id=${id}`);
|
||||||
|
|
||||||
|
export const postSearchText = (data: SearchTestProps) =>
|
||||||
|
POST<SearchTestResponseType>(`/core/dataset/searchTest`, data);
|
||||||
@ -1,106 +0,0 @@
|
|||||||
import { GET, POST, PUT, DELETE } from '../request';
|
|
||||||
import type { DatasetItemType, KbItemType, KbListItemType, KbPathItemType } from '@/types/plugin';
|
|
||||||
import { TrainingModeEnum } from '@/constants/plugin';
|
|
||||||
import {
|
|
||||||
Props as PushDataProps,
|
|
||||||
Response as PushDateResponse
|
|
||||||
} from '@/pages/api/openapi/kb/pushData';
|
|
||||||
import {
|
|
||||||
Props as SearchTestProps,
|
|
||||||
Response as SearchTestResponse
|
|
||||||
} from '@/pages/api/openapi/kb/searchTest';
|
|
||||||
import { Props as UpdateDataProps } from '@/pages/api/openapi/kb/updateData';
|
|
||||||
import type { KbUpdateParams, CreateKbParams, GetKbDataListProps } from '../request/kb';
|
|
||||||
import { QuoteItemType } from '@/types/chat';
|
|
||||||
import { KbTypeEnum } from '@/constants/kb';
|
|
||||||
import { getToken } from '@/utils/user';
|
|
||||||
import download from 'downloadjs';
|
|
||||||
|
|
||||||
/* knowledge base */
|
|
||||||
export const getKbList = (data: { parentId?: string; type?: `${KbTypeEnum}` }) =>
|
|
||||||
GET<KbListItemType[]>(`/plugins/kb/list`, data);
|
|
||||||
export const getAllDataset = () => GET<KbListItemType[]>(`/plugins/kb/allDataset`);
|
|
||||||
|
|
||||||
export const getKbPaths = (parentId?: string) =>
|
|
||||||
GET<KbPathItemType[]>('/plugins/kb/paths', { parentId });
|
|
||||||
|
|
||||||
export const getKbById = (id: string) => GET<KbItemType>(`/plugins/kb/detail?id=${id}`);
|
|
||||||
|
|
||||||
export const postCreateKb = (data: CreateKbParams) => POST<string>(`/plugins/kb/create`, data);
|
|
||||||
|
|
||||||
export const putKbById = (data: KbUpdateParams) => PUT(`/plugins/kb/update`, data);
|
|
||||||
|
|
||||||
export const delKbById = (id: string) => DELETE(`/plugins/kb/delete?id=${id}`);
|
|
||||||
|
|
||||||
/* kb data */
|
|
||||||
export const getKbDataList = (data: GetKbDataListProps) =>
|
|
||||||
POST(`/plugins/kb/data/getDataList`, data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* export and download data
|
|
||||||
*/
|
|
||||||
export const exportDataset = (data: { kbId: string }) =>
|
|
||||||
fetch(`/api/plugins/kb/data/exportAll?kbId=${data.kbId}`, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
token: getToken()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(async (res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
const data = await res.json();
|
|
||||||
throw new Error(data?.message || 'Export failed');
|
|
||||||
}
|
|
||||||
return res.blob();
|
|
||||||
})
|
|
||||||
.then((blob) => download(blob, 'dataset.csv', 'text/csv'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取模型正在拆分数据的数量
|
|
||||||
*/
|
|
||||||
export const getTrainingData = (data: { kbId: string; init: boolean }) =>
|
|
||||||
POST<{
|
|
||||||
qaListLen: number;
|
|
||||||
vectorListLen: number;
|
|
||||||
}>(`/plugins/kb/data/getTrainingData`, data);
|
|
||||||
|
|
||||||
/* get length of system training queue */
|
|
||||||
export const getTrainingQueueLen = () => GET<number>(`/plugins/kb/data/getQueueLen`);
|
|
||||||
|
|
||||||
export const getKbDataItemById = (dataId: string) =>
|
|
||||||
GET<QuoteItemType>(`/plugins/kb/data/getDataById`, { dataId });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接push数据
|
|
||||||
*/
|
|
||||||
export const postKbDataFromList = (data: PushDataProps) =>
|
|
||||||
POST<PushDateResponse>(`/openapi/kb/pushData`, data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* insert one data to dataset
|
|
||||||
*/
|
|
||||||
export const insertData2Kb = (data: { kbId: string; data: DatasetItemType }) =>
|
|
||||||
POST<string>(`/plugins/kb/data/insertData`, data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新一条数据
|
|
||||||
*/
|
|
||||||
export const putKbDataById = (data: UpdateDataProps) => PUT('/openapi/kb/updateData', data);
|
|
||||||
/**
|
|
||||||
* 删除一条知识库数据
|
|
||||||
*/
|
|
||||||
export const delOneKbDataByDataId = (dataId: string) =>
|
|
||||||
DELETE(`/openapi/kb/delDataById?dataId=${dataId}`);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拆分数据
|
|
||||||
*/
|
|
||||||
export const postSplitData = (data: {
|
|
||||||
kbId: string;
|
|
||||||
chunks: string[];
|
|
||||||
prompt: string;
|
|
||||||
mode: `${TrainingModeEnum}`;
|
|
||||||
}) => POST(`/openapi/text/pushData`, data);
|
|
||||||
|
|
||||||
export const searchText = (data: SearchTestProps) =>
|
|
||||||
POST<SearchTestResponse>(`/openapi/kb/searchTest`, data);
|
|
||||||
24
client/src/api/request/kb.d.ts
vendored
24
client/src/api/request/kb.d.ts
vendored
@ -1,24 +0,0 @@
|
|||||||
import { KbTypeEnum } from '@/constants/kb';
|
|
||||||
import type { RequestPaging } from '@/types';
|
|
||||||
|
|
||||||
export type KbUpdateParams = {
|
|
||||||
id: string;
|
|
||||||
parentId?: string;
|
|
||||||
tags?: string;
|
|
||||||
name?: string;
|
|
||||||
avatar?: string;
|
|
||||||
};
|
|
||||||
export type CreateKbParams = {
|
|
||||||
parentId?: string;
|
|
||||||
name: string;
|
|
||||||
tags: string[];
|
|
||||||
avatar: string;
|
|
||||||
vectorModel?: string;
|
|
||||||
type: `${KbTypeEnum}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type GetKbDataListProps = RequestPaging & {
|
|
||||||
kbId: string;
|
|
||||||
searchText: string;
|
|
||||||
fileId: string;
|
|
||||||
};
|
|
||||||
@ -19,7 +19,8 @@ import { useQuery, useMutation } from '@tanstack/react-query';
|
|||||||
import { useLoading } from '@/hooks/useLoading';
|
import { useLoading } from '@/hooks/useLoading';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { AddIcon, DeleteIcon } from '@chakra-ui/icons';
|
import { AddIcon, DeleteIcon } from '@chakra-ui/icons';
|
||||||
import { getErrText, useCopyData } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
|
import { useCopyData } from '@/hooks/useCopyData';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import MyIcon from '../Icon';
|
import MyIcon from '../Icon';
|
||||||
import MyModal from '../MyModal';
|
import MyModal from '../MyModal';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { ModalBody, Box, useTheme } from '@chakra-ui/react';
|
import { ModalBody, Box, useTheme } from '@chakra-ui/react';
|
||||||
import { getKbDataItemById } from '@/api/plugins/kb';
|
import { getDatasetDataItemById } from '@/api/core/dataset/data';
|
||||||
import { useLoading } from '@/hooks/useLoading';
|
import { useLoading } from '@/hooks/useLoading';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
@ -8,10 +8,10 @@ import { QuoteItemType } from '@/types/chat';
|
|||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import InputDataModal, { RawFileText } from '@/pages/kb/detail/components/InputDataModal';
|
import InputDataModal, { RawFileText } from '@/pages/kb/detail/components/InputDataModal';
|
||||||
import MyModal from '../MyModal';
|
import MyModal from '../MyModal';
|
||||||
import { KbDataItemType } from '@/types/plugin';
|
import type { PgDataItemType } from '@/types/core/dataset/data';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
type SearchType = KbDataItemType & {
|
type SearchType = PgDataItemType & {
|
||||||
kb_id?: string;
|
kb_id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ const QuoteModal = ({
|
|||||||
if (!item.id) return;
|
if (!item.id) return;
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const data = await getKbDataItemById(item.id);
|
const data = await getDatasetDataItemById(item.id);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
onUpdateQuote(item.id, '已删除');
|
onUpdateQuote(item.id, '已删除');
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useTranslation } from 'next-i18next';
|
|||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import Avatar from '../Avatar';
|
import Avatar from '../Avatar';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { KbTypeEnum } from '@/constants/kb';
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
|
import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
|
||||||
|
|
||||||
const SelectDataset = ({
|
const SelectDataset = ({
|
||||||
|
|||||||
@ -16,13 +16,9 @@ import {
|
|||||||
ExportChatType
|
ExportChatType
|
||||||
} from '@/types/chat';
|
} from '@/types/chat';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import {
|
import { voiceBroadcast, cancelBroadcast, hasVoiceApi } from '@/utils/web/voice';
|
||||||
useCopyData,
|
import { getErrText } from '@/utils/tools';
|
||||||
voiceBroadcast,
|
import { useCopyData } from '@/hooks/useCopyData';
|
||||||
cancelBroadcast,
|
|
||||||
hasVoiceApi,
|
|
||||||
getErrText
|
|
||||||
} from '@/utils/tools';
|
|
||||||
import { Box, Card, Flex, Input, Textarea, Button, useTheme, BoxProps } from '@chakra-ui/react';
|
import { Box, Card, Flex, Input, Textarea, Button, useTheme, BoxProps } from '@chakra-ui/react';
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import { event } from '@/utils/plugin/eventbus';
|
import { event } from '@/utils/plugin/eventbus';
|
||||||
@ -32,7 +28,7 @@ import { VariableItemType } from '@/types/app';
|
|||||||
import { VariableInputEnum } from '@/constants/app';
|
import { VariableInputEnum } from '@/constants/app';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { MessageItemType } from '@/pages/api/openapi/v1/chat/completions';
|
import { MessageItemType } from '@/pages/api/openapi/v1/chat/completions';
|
||||||
import { fileDownload } from '@/utils/file';
|
import { fileDownload } from '@/utils/web/file';
|
||||||
import { htmlTemplate } from '@/constants/common';
|
import { htmlTemplate } from '@/constants/common';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Menu, MenuButton, MenuItem, MenuList, MenuButtonProps } from '@chakra-ui/react';
|
import { Menu, MenuButton, MenuItem, MenuList, MenuButtonProps } from '@chakra-ui/react';
|
||||||
import { getLangStore, LangEnum, setLangStore, langMap } from '@/utils/i18n';
|
import { getLangStore, LangEnum, setLangStore, langMap } from '@/utils/web/i18n';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
import { Box, Flex, useColorModeValue } from '@chakra-ui/react';
|
import { Box, Flex, useColorModeValue } from '@chakra-ui/react';
|
||||||
import Icon from '@/components/Icon';
|
import Icon from '@/components/Icon';
|
||||||
import { useCopyData } from '@/utils/tools';
|
import { useCopyData } from '@/hooks/useCopyData';
|
||||||
|
|
||||||
const codeLight: { [key: string]: React.CSSProperties } = {
|
const codeLight: { [key: string]: React.CSSProperties } = {
|
||||||
'code[class*=language-]': {
|
'code[class*=language-]': {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Box, useTheme } from '@chakra-ui/react';
|
import { Box, useTheme } from '@chakra-ui/react';
|
||||||
import { getFileAndOpen } from '@/utils/common/file';
|
import { getFileAndOpen } from '@/utils/web/file';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { getKbList, getKbPaths } from '@/api/plugins/kb';
|
import { getDatasets, getDatasetPaths } from '@/api/core/dataset';
|
||||||
import MyModal from '@/components/MyModal';
|
import MyModal from '@/components/MyModal';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import React, { Dispatch, useMemo, useState } from 'react';
|
import React, { Dispatch, useMemo, useState } from 'react';
|
||||||
@ -12,7 +12,7 @@ type PathItemType = {
|
|||||||
parentName: string;
|
parentName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DatasetSelectModal = ({
|
const DatasetSelectContainer = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
parentId,
|
parentId,
|
||||||
setParentId,
|
setParentId,
|
||||||
@ -97,7 +97,7 @@ export const useDatasetSelect = () => {
|
|||||||
const [parentId, setParentId] = useState<string>();
|
const [parentId, setParentId] = useState<string>();
|
||||||
|
|
||||||
const { data } = useQuery(['loadDatasetData', parentId], () =>
|
const { data } = useQuery(['loadDatasetData', parentId], () =>
|
||||||
Promise.all([getKbList({ parentId }), getKbPaths(parentId)])
|
Promise.all([getDatasets({ parentId }), getDatasetPaths(parentId)])
|
||||||
);
|
);
|
||||||
|
|
||||||
const paths = useMemo(
|
const paths = useMemo(
|
||||||
@ -119,4 +119,4 @@ export const useDatasetSelect = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DatasetSelectModal;
|
export default DatasetSelectContainer;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { KbItemType } from '@/types/plugin';
|
import type { DatasetItemType } from '@/types/core/dataset';
|
||||||
|
|
||||||
export const defaultKbDetail: KbItemType = {
|
export const defaultKbDetail: DatasetItemType = {
|
||||||
_id: '',
|
_id: '',
|
||||||
userId: '',
|
userId: '',
|
||||||
avatar: '/icon/logo.svg',
|
avatar: '/icon/logo.svg',
|
||||||
39
client/src/hooks/useCopyData.tsx
Normal file
39
client/src/hooks/useCopyData.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useToast } from './useToast';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copy text data
|
||||||
|
*/
|
||||||
|
export const useCopyData = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
return {
|
||||||
|
copyData: async (
|
||||||
|
data: string,
|
||||||
|
title: string | null = t('common.Copy Successful'),
|
||||||
|
duration = 1000
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
await navigator.clipboard.writeText(data);
|
||||||
|
} else {
|
||||||
|
throw new Error('');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.value = data;
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title,
|
||||||
|
status: 'success',
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -10,7 +10,7 @@ import NProgress from 'nprogress'; //nprogress module
|
|||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
import { clientInitData, feConfigs } from '@/store/static';
|
import { clientInitData, feConfigs } from '@/store/static';
|
||||||
import { appWithTranslation, useTranslation } from 'next-i18next';
|
import { appWithTranslation, useTranslation } from 'next-i18next';
|
||||||
import { getLangStore, setLangStore } from '@/utils/i18n';
|
import { getLangStore, setLangStore } from '@/utils/web/i18n';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
|
|
||||||
@ -85,7 +85,10 @@ function App({ Component, pageProps }: AppProps) {
|
|||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{feConfigs?.systemTitle || 'AI'}</title>
|
<title>{feConfigs?.systemTitle || 'AI'}</title>
|
||||||
<meta name="description" content="Embedding + LLM, Build AI knowledge base" />
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="FastGPT is a knowledge-based question answering system built on the LLM. It offers out-of-the-box data processing and model invocation capabilities. Moreover, it allows for workflow orchestration through Flow visualization, thereby enabling complex question and answer scenarios!"
|
||||||
|
/>
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no, viewport-fit=cover"
|
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no, viewport-fit=cover"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
import { addLog } from '@/service/utils/tools';
|
import { addLog } from '@/service/utils/tools';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import { UserType } from '@/types/user';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { compressImg } from '@/utils/file';
|
import { compressImg } from '@/utils/web/file';
|
||||||
import { feConfigs, systemVersion } from '@/store/static';
|
import { feConfigs, systemVersion } from '@/store/static';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { timezoneList } from '@/utils/user';
|
import { timezoneList } from '@/utils/user';
|
||||||
@ -28,7 +28,7 @@ import Loading from '@/components/Loading';
|
|||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { getLangStore, LangEnum, langMap, setLangStore } from '@/utils/i18n';
|
import { getLangStore, LangEnum, langMap, setLangStore } from '@/utils/web/i18n';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import MyMenu from '@/components/MyMenu';
|
import MyMenu from '@/components/MyMenu';
|
||||||
import MySelect from '@/components/Select';
|
import MySelect from '@/components/Select';
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import { useLoading } from '@/hooks/useLoading';
|
|||||||
|
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import { useCopyData } from '@/utils/tools';
|
import { useCopyData } from '@/hooks/useCopyData';
|
||||||
import { usePagination } from '@/hooks/usePagination';
|
import { usePagination } from '@/hooks/usePagination';
|
||||||
import { PromotionRecordType } from '@/api/response/user';
|
import { PromotionRecordType } from '@/api/response/user';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import PageContainer from '@/components/PageContainer';
|
|||||||
import SideTabs from '@/components/SideTabs';
|
import SideTabs from '@/components/SideTabs';
|
||||||
import Tabs from '@/components/Tabs';
|
import Tabs from '@/components/Tabs';
|
||||||
import UserInfo from './components/Info';
|
import UserInfo from './components/Info';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { connectToDatabase, KB } from '@/service/mongo';
|
import { connectToDatabase, KB } from '@/service/mongo';
|
||||||
import { KbTypeEnum } from '@/constants/kb';
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { connectToDatabase, KB } from '@/service/mongo';
|
import { connectToDatabase, KB } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { getVectorModel } from '@/service/utils/data';
|
import { getVectorModel } from '@/service/utils/data';
|
||||||
import { KbListItemType } from '@/types/plugin';
|
import type { DatasetsItemType } from '@/types/core/dataset';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@ -22,7 +22,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
vectorModel: getVectorModel(item.vectorModel)
|
vectorModel: getVectorModel(item.vectorModel)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jsonRes<KbListItemType[]>(res, {
|
jsonRes<DatasetsItemType[]>(res, {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -2,11 +2,11 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { connectToDatabase, KB } from '@/service/mongo';
|
import { connectToDatabase, KB } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import type { CreateKbParams } from '@/api/request/kb';
|
import type { CreateDatasetParams } from '@/api/core/dataset/index.d';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const { name, tags, avatar, vectorModel, parentId, type } = req.body as CreateKbParams;
|
const { name, tags, avatar, vectorModel, parentId, type } = req.body as CreateDatasetParams;
|
||||||
|
|
||||||
// 凭证校验
|
// 凭证校验
|
||||||
const { userId } = await authUser({ req, authToken: true });
|
const { userId } = await authUser({ req, authToken: true });
|
||||||
@ -3,8 +3,8 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import type { KbDataItemType } from '@/types/plugin';
|
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
|
import type { PgDataItemType } from '@/types/core/dataset/data';
|
||||||
|
|
||||||
export type Response = {
|
export type Response = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -29,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
|
|
||||||
const where: any = [['user_id', userId], 'AND', ['id', dataId]];
|
const where: any = [['user_id', userId], 'AND', ['id', dataId]];
|
||||||
|
|
||||||
const searchRes = await PgClient.select<KbDataItemType>(PgDatasetTableName, {
|
const searchRes = await PgClient.select<PgDataItemType>(PgDatasetTableName, {
|
||||||
fields: ['kb_id', 'id', 'q', 'a', 'source', 'file_id'],
|
fields: ['kb_id', 'id', 'q', 'a', 'source', 'file_id'],
|
||||||
where,
|
where,
|
||||||
limit: 1
|
limit: 1
|
||||||
@ -3,9 +3,9 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import type { KbDataItemType } from '@/types/plugin';
|
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
import { OtherFileId } from '@/constants/kb';
|
import { OtherFileId } from '@/constants/dataset';
|
||||||
|
import type { PgDataItemType } from '@/types/core/dataset/data';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@ -50,7 +50,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
];
|
];
|
||||||
|
|
||||||
const [searchRes, total] = await Promise.all([
|
const [searchRes, total] = await Promise.all([
|
||||||
PgClient.select<KbDataItemType>(PgDatasetTableName, {
|
PgClient.select<PgDataItemType>(PgDatasetTableName, {
|
||||||
fields: ['id', 'q', 'a', 'source', 'file_id'],
|
fields: ['id', 'q', 'a', 'source', 'file_id'],
|
||||||
where,
|
where,
|
||||||
order: [{ field: 'id', mode: 'DESC' }],
|
order: [{ field: 'id', mode: 'DESC' }],
|
||||||
@ -1,18 +1,18 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { connectToDatabase, KB } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { authKb, authUser } from '@/service/utils/auth';
|
import { authKb, authUser } from '@/service/utils/auth';
|
||||||
import { withNextCors } from '@/service/utils/tools';
|
import { withNextCors } from '@/service/utils/tools';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
import { insertKbItem, PgClient } from '@/service/pg';
|
import { insertData2Dataset, PgClient } from '@/service/pg';
|
||||||
import { getVectorModel } from '@/service/utils/data';
|
import { getVectorModel } from '@/service/utils/data';
|
||||||
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||||
import { DatasetItemType } from '@/types/plugin';
|
import { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||||
import { countPromptTokens } from '@/utils/common/tiktoken';
|
import { countPromptTokens } from '@/utils/common/tiktoken';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
kbId: string;
|
kbId: string;
|
||||||
data: DatasetItemType;
|
data: DatasetDataItemType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
@ -58,7 +58,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
userId
|
userId
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await insertKbItem({
|
const response = await insertData2Dataset({
|
||||||
userId,
|
userId,
|
||||||
kbId,
|
kbId,
|
||||||
data: [
|
data: [
|
||||||
@ -8,19 +8,9 @@ import { PgDatasetTableName, TrainingModeEnum } from '@/constants/plugin';
|
|||||||
import { startQueue } from '@/service/utils/tools';
|
import { startQueue } from '@/service/utils/tools';
|
||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import { getVectorModel } from '@/service/utils/data';
|
import { getVectorModel } from '@/service/utils/data';
|
||||||
import { DatasetItemType } from '@/types/plugin';
|
import { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||||
import { countPromptTokens } from '@/utils/common/tiktoken';
|
import { countPromptTokens } from '@/utils/common/tiktoken';
|
||||||
|
import type { PushDataProps, PushDataResponse } from '@/api/core/dataset/data.d';
|
||||||
export type Props = {
|
|
||||||
kbId: string;
|
|
||||||
data: DatasetItemType[];
|
|
||||||
mode: `${TrainingModeEnum}`;
|
|
||||||
prompt?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Response = {
|
|
||||||
insertLen: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
const modeMap = {
|
const modeMap = {
|
||||||
[TrainingModeEnum.index]: true,
|
[TrainingModeEnum.index]: true,
|
||||||
@ -29,7 +19,7 @@ const modeMap = {
|
|||||||
|
|
||||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const { kbId, data, mode = TrainingModeEnum.index, prompt } = req.body as Props;
|
const { kbId, data, mode = TrainingModeEnum.index, prompt } = req.body as PushDataProps;
|
||||||
|
|
||||||
if (!kbId || !Array.isArray(data)) {
|
if (!kbId || !Array.isArray(data)) {
|
||||||
throw new Error('KbId or data is empty');
|
throw new Error('KbId or data is empty');
|
||||||
@ -48,7 +38,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
// 凭证校验
|
// 凭证校验
|
||||||
const { userId } = await authUser({ req });
|
const { userId } = await authUser({ req });
|
||||||
|
|
||||||
jsonRes<Response>(res, {
|
jsonRes<PushDataResponse>(res, {
|
||||||
data: await pushDataToKb({
|
data: await pushDataToKb({
|
||||||
kbId,
|
kbId,
|
||||||
data,
|
data,
|
||||||
@ -71,7 +61,7 @@ export async function pushDataToKb({
|
|||||||
data,
|
data,
|
||||||
mode,
|
mode,
|
||||||
prompt
|
prompt
|
||||||
}: { userId: string } & Props): Promise<Response> {
|
}: { userId: string } & PushDataProps): Promise<PushDataResponse> {
|
||||||
const [kb, vectorModel] = await Promise.all([
|
const [kb, vectorModel] = await Promise.all([
|
||||||
authKb({
|
authKb({
|
||||||
userId,
|
userId,
|
||||||
@ -94,7 +84,7 @@ export async function pushDataToKb({
|
|||||||
|
|
||||||
// 过滤重复的 qa 内容
|
// 过滤重复的 qa 内容
|
||||||
const set = new Set();
|
const set = new Set();
|
||||||
const filterData: DatasetItemType[] = [];
|
const filterData: DatasetDataItemType[] = [];
|
||||||
|
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
if (!item.q) return;
|
if (!item.q) return;
|
||||||
@ -150,7 +140,7 @@ export async function pushDataToKb({
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
.filter((item) => item.status === 'fulfilled')
|
.filter((item) => item.status === 'fulfilled')
|
||||||
.map<DatasetItemType>((item: any) => item.value);
|
.map<DatasetDataItemType>((item: any) => item.value);
|
||||||
|
|
||||||
// 插入记录
|
// 插入记录
|
||||||
const insertRes = await TrainingData.insertMany(
|
const insertRes = await TrainingData.insertMany(
|
||||||
@ -4,19 +4,13 @@ import { authUser } from '@/service/utils/auth';
|
|||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import { withNextCors } from '@/service/utils/tools';
|
import { withNextCors } from '@/service/utils/tools';
|
||||||
import { KB, connectToDatabase } from '@/service/mongo';
|
import { KB, connectToDatabase } from '@/service/mongo';
|
||||||
import { getVector } from '../plugin/vector';
|
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
|
import type { UpdateDataPrams } from '@/api/core/dataset/data.d';
|
||||||
export type Props = {
|
|
||||||
dataId: string;
|
|
||||||
kbId: string;
|
|
||||||
a?: string;
|
|
||||||
q?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const { dataId, a = '', q = '', kbId } = req.body as Props;
|
const { dataId, a = '', q = '', kbId } = req.body as UpdateDataPrams;
|
||||||
|
|
||||||
if (!dataId) {
|
if (!dataId) {
|
||||||
throw new Error('缺少参数');
|
throw new Error('缺少参数');
|
||||||
@ -6,7 +6,7 @@ import { GridFSStorage } from '@/service/lib/gridfs';
|
|||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
import { Types } from 'mongoose';
|
import { Types } from 'mongoose';
|
||||||
import { OtherFileId } from '@/constants/kb';
|
import { OtherFileId } from '@/constants/dataset';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { GridFSStorage } from '@/service/lib/gridfs';
|
import { GridFSStorage } from '@/service/lib/gridfs';
|
||||||
import { OtherFileId } from '@/constants/kb';
|
import { OtherFileId } from '@/constants/dataset';
|
||||||
import type { FileInfo } from '@/types/plugin';
|
import type { GSFileInfoType } from '@/types/common/file';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@ -15,7 +15,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
const { userId } = await authUser({ req, authToken: true });
|
const { userId } = await authUser({ req, authToken: true });
|
||||||
|
|
||||||
if (fileId === OtherFileId) {
|
if (fileId === OtherFileId) {
|
||||||
return jsonRes<FileInfo>(res, {
|
return jsonRes<GSFileInfoType>(res, {
|
||||||
data: {
|
data: {
|
||||||
id: OtherFileId,
|
id: OtherFileId,
|
||||||
size: 0,
|
size: 0,
|
||||||
@ -31,7 +31,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
|
|
||||||
const file = await gridFs.findAndAuthFile(fileId);
|
const file = await gridFs.findAndAuthFile(fileId);
|
||||||
|
|
||||||
jsonRes<FileInfo>(res, {
|
jsonRes<GSFileInfoType>(res, {
|
||||||
data: file
|
data: file
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { authUser } from '@/service/utils/auth';
|
|||||||
import { GridFSStorage } from '@/service/lib/gridfs';
|
import { GridFSStorage } from '@/service/lib/gridfs';
|
||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
import { FileStatusEnum, OtherFileId } from '@/constants/kb';
|
import { FileStatusEnum, OtherFileId } from '@/constants/dataset';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { connectToDatabase, KB } from '@/service/mongo';
|
import { connectToDatabase, KB } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { getVectorModel } from '@/service/utils/data';
|
import { getVectorModel } from '@/service/utils/data';
|
||||||
import { KbListItemType } from '@/types/plugin';
|
import type { DatasetsItemType } from '@/types/core/dataset';
|
||||||
import { KbTypeEnum } from '@/constants/kb';
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@ -27,7 +27,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
jsonRes<KbListItemType[]>(res, {
|
jsonRes<DatasetsItemType[]>(res, {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { connectToDatabase, KB } from '@/service/mongo';
|
import { connectToDatabase, KB } from '@/service/mongo';
|
||||||
import { KbPathItemType } from '@/types/plugin';
|
import type { DatasetPathItemType } from '@/types/core/dataset';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@ -9,7 +9,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
|
|
||||||
const { parentId } = req.query as { parentId: string };
|
const { parentId } = req.query as { parentId: string };
|
||||||
|
|
||||||
jsonRes<KbPathItemType[]>(res, {
|
jsonRes<DatasetPathItemType[]>(res, {
|
||||||
data: await getParents(parentId)
|
data: await getParents(parentId)
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getParents(parentId?: string): Promise<KbPathItemType[]> {
|
async function getParents(parentId?: string): Promise<DatasetPathItemType[]> {
|
||||||
if (!parentId) {
|
if (!parentId) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -3,20 +3,14 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import { withNextCors } from '@/service/utils/tools';
|
import { withNextCors } from '@/service/utils/tools';
|
||||||
import { getVector } from '../plugin/vector';
|
import { getVector } from '../../openapi/plugin/vector';
|
||||||
import type { KbTestItemType } from '@/types/plugin';
|
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
import { KB } from '@/service/mongo';
|
import { KB } from '@/service/mongo';
|
||||||
|
import type { SearchTestProps, SearchTestResponseType } from '@/api/core/dataset/index.d';
|
||||||
export type Props = {
|
|
||||||
kbId: string;
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
export type Response = KbTestItemType['results'];
|
|
||||||
|
|
||||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const { kbId, text } = req.body as Props;
|
const { kbId, text } = req.body as SearchTestProps;
|
||||||
|
|
||||||
if (!kbId || !text) {
|
if (!kbId || !text) {
|
||||||
throw new Error('缺少参数');
|
throw new Error('缺少参数');
|
||||||
@ -49,7 +43,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
COMMIT;`
|
COMMIT;`
|
||||||
);
|
);
|
||||||
|
|
||||||
jsonRes<Response>(res, {
|
jsonRes<SearchTestResponseType>(res, {
|
||||||
data: response?.[2]?.rows || []
|
data: response?.[2]?.rows || []
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -2,11 +2,11 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { connectToDatabase, KB } from '@/service/mongo';
|
import { connectToDatabase, KB } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import type { KbUpdateParams } from '@/api/request/kb';
|
import type { DatasetUpdateParams } from '@/api/core/dataset/index.d';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const { id, parentId, name, avatar, tags } = req.body as KbUpdateParams;
|
const { id, parentId, name, avatar, tags } = req.body as DatasetUpdateParams;
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw new Error('缺少参数');
|
throw new Error('缺少参数');
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Box, Divider, Flex, useTheme, Button, Skeleton, useDisclosure } from '@chakra-ui/react';
|
import { Box, Divider, Flex, useTheme, Button, Skeleton, useDisclosure } from '@chakra-ui/react';
|
||||||
import { useCopyData } from '@/utils/tools';
|
import { useCopyData } from '@/hooks/useCopyData';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
|
|||||||
@ -9,16 +9,16 @@ import Divider from '../modules/Divider';
|
|||||||
import Container from '../modules/Container';
|
import Container from '../modules/Container';
|
||||||
import RenderInput from '../render/RenderInput';
|
import RenderInput from '../render/RenderInput';
|
||||||
import RenderOutput from '../render/RenderOutput';
|
import RenderOutput from '../render/RenderOutput';
|
||||||
import { KBSelectModal } from '../../../KBSelectModal';
|
import { DatasetSelectModal } from '../../../DatasetSelectModal';
|
||||||
import type { SelectedKbType } from '@/types/plugin';
|
import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
|
|
||||||
const KBSelect = ({
|
const KBSelect = ({
|
||||||
activeKbs = [],
|
activeKbs = [],
|
||||||
onChange
|
onChange
|
||||||
}: {
|
}: {
|
||||||
activeKbs: SelectedKbType;
|
activeKbs: SelectedDatasetType;
|
||||||
onChange: (e: SelectedKbType) => void;
|
onChange: (e: SelectedDatasetType) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { allDatasets, loadAllDatasets } = useDatasetStore();
|
const { allDatasets, loadAllDatasets } = useDatasetStore();
|
||||||
@ -57,7 +57,7 @@ const KBSelect = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
<KBSelectModal
|
<DatasetSelectModal
|
||||||
isOpen={isOpenKbSelect}
|
isOpen={isOpenKbSelect}
|
||||||
activeKbs={activeKbs}
|
activeKbs={activeKbs}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import type { AppSchema } from '@/types/mongoSchema';
|
|||||||
import { useUserStore } from '@/store/user';
|
import { useUserStore } from '@/store/user';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useCopyData } from '@/utils/tools';
|
import { useCopyData } from '@/hooks/useCopyData';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
|
|||||||
@ -56,13 +56,13 @@ import MyIcon from '@/components/Icon';
|
|||||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||||
|
|
||||||
import { addVariable } from '../VariableEditModal';
|
import { addVariable } from '../VariableEditModal';
|
||||||
import { KbParamsModal } from '../KBSelectModal';
|
import { KbParamsModal } from '../DatasetSelectModal';
|
||||||
import { AppTypeEnum } from '@/constants/app';
|
import { AppTypeEnum } from '@/constants/app';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
const VariableEditModal = dynamic(() => import('../VariableEditModal'));
|
const VariableEditModal = dynamic(() => import('../VariableEditModal'));
|
||||||
const InfoModal = dynamic(() => import('../InfoModal'));
|
const InfoModal = dynamic(() => import('../InfoModal'));
|
||||||
const KBSelectModal = dynamic(() => import('../KBSelectModal'));
|
const DatasetSelectModal = dynamic(() => import('../DatasetSelectModal'));
|
||||||
const AIChatSettingsModal = dynamic(() => import('../AIChatSettingsModal'));
|
const AIChatSettingsModal = dynamic(() => import('../AIChatSettingsModal'));
|
||||||
|
|
||||||
const Settings = ({ appId }: { appId: string }) => {
|
const Settings = ({ appId }: { appId: string }) => {
|
||||||
@ -565,7 +565,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isOpenKbSelect && (
|
{isOpenKbSelect && (
|
||||||
<KBSelectModal
|
<DatasetSelectModal
|
||||||
isOpen={isOpenKbSelect}
|
isOpen={isOpenKbSelect}
|
||||||
activeKbs={selectedKbList.map((item) => ({
|
activeKbs={selectedKbList.map((item) => ({
|
||||||
kbId: item._id,
|
kbId: item._id,
|
||||||
|
|||||||
@ -14,18 +14,18 @@ import {
|
|||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import type { SelectedKbType } from '@/types/plugin';
|
import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import MySlider from '@/components/Slider';
|
import MySlider from '@/components/Slider';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import MyModal from '@/components/MyModal';
|
import MyModal from '@/components/MyModal';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { KbTypeEnum } from '@/constants/kb';
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
|
import DatasetSelectContainer, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
|
||||||
|
|
||||||
export type KbParamsType = {
|
export type KbParamsType = {
|
||||||
searchSimilarity: number;
|
searchSimilarity: number;
|
||||||
@ -33,20 +33,20 @@ export type KbParamsType = {
|
|||||||
searchEmptyText: string;
|
searchEmptyText: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KBSelectModal = ({
|
export const DatasetSelectModal = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
activeKbs = [],
|
activeKbs = [],
|
||||||
onChange,
|
onChange,
|
||||||
onClose
|
onClose
|
||||||
}: {
|
}: {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
activeKbs: SelectedKbType;
|
activeKbs: SelectedDatasetType;
|
||||||
onChange: (e: SelectedKbType) => void;
|
onChange: (e: SelectedDatasetType) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [selectedKbList, setSelectedKbList] = useState<SelectedKbType>(activeKbs);
|
const [selectedKbList, setSelectedKbList] = useState<SelectedDatasetType>(activeKbs);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { paths, parentId, setParentId, datasets } = useDatasetSelect();
|
const { paths, parentId, setParentId, datasets } = useDatasetSelect();
|
||||||
const { allDatasets, loadAllDatasets } = useDatasetStore();
|
const { allDatasets, loadAllDatasets } = useDatasetStore();
|
||||||
@ -61,7 +61,7 @@ export const KBSelectModal = ({
|
|||||||
}, [datasets, allDatasets, selectedKbList]);
|
}, [datasets, allDatasets, selectedKbList]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DatasetSelectModal
|
<DatasetSelectContainer
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
paths={paths}
|
paths={paths}
|
||||||
parentId={parentId}
|
parentId={parentId}
|
||||||
@ -186,7 +186,7 @@ export const KBSelectModal = ({
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
// filter out the kb that is not in the kList
|
// filter out the kb that is not in the kList
|
||||||
const filterKbList = selectedKbList.filter((kb) => {
|
const filterKbList = selectedKbList.filter((kb) => {
|
||||||
return datasets.find((item) => item._id === kb.kbId);
|
return allDatasets.find((item) => item._id === kb.kbId);
|
||||||
});
|
});
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
@ -196,7 +196,7 @@ export const KBSelectModal = ({
|
|||||||
完成
|
完成
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</DatasetSelectModal>
|
</DatasetSelectContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -297,4 +297,4 @@ export const KbParamsModal = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default KBSelectModal;
|
export default DatasetSelectModal;
|
||||||
@ -13,7 +13,7 @@ import { useForm } from 'react-hook-form';
|
|||||||
import { AppSchema } from '@/types/mongoSchema';
|
import { AppSchema } from '@/types/mongoSchema';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { compressImg } from '@/utils/file';
|
import { compressImg } from '@/utils/web/file';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useUserStore } from '@/store/user';
|
||||||
import { useRequest } from '@/hooks/useRequest';
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
|
|||||||
@ -30,7 +30,8 @@ import {
|
|||||||
createShareChat,
|
createShareChat,
|
||||||
putShareChat
|
putShareChat
|
||||||
} from '@/api/support/outLink';
|
} from '@/api/support/outLink';
|
||||||
import { formatTimeToChatTime, useCopyData } from '@/utils/tools';
|
import { formatTimeToChatTime } from '@/utils/tools';
|
||||||
|
import { useCopyData } from '@/hooks/useCopyData';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { defaultOutLinkForm } from '@/constants/model';
|
import { defaultOutLinkForm } from '@/constants/model';
|
||||||
import type { OutLinkEditType } from '@/types/support/outLink';
|
import type { OutLinkEditType } from '@/types/support/outLink';
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import MyIcon from '@/components/Icon';
|
|||||||
import PageContainer from '@/components/PageContainer';
|
import PageContainer from '@/components/PageContainer';
|
||||||
import Loading from '@/components/Loading';
|
import Loading from '@/components/Loading';
|
||||||
import BasicEdit from './components/BasicEdit';
|
import BasicEdit from './components/BasicEdit';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
|
|
||||||
const AdEdit = dynamic(() => import('./components/AdEdit'), {
|
const AdEdit = dynamic(() => import('./components/AdEdit'), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { compressImg } from '@/utils/file';
|
import { compressImg } from '@/utils/web/file';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { postCreateApp } from '@/api/app';
|
import { postCreateApp } from '@/api/app';
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import { AddIcon } from '@chakra-ui/icons';
|
|||||||
import { delModelById } from '@/api/app';
|
import { delModelById } from '@/api/app';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import type { ShareAppItem } from '@/types/app';
|
|||||||
import { useUserStore } from '@/store/user';
|
import { useUserStore } from '@/store/user';
|
||||||
import ShareModelList from './components/list';
|
import ShareModelList from './components/list';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
|
|
||||||
const modelList = () => {
|
const modelList = () => {
|
||||||
const { Loading } = useLoading();
|
const { Loading } = useLoading();
|
||||||
|
|||||||
@ -30,7 +30,7 @@ import SliderApps from './components/SliderApps';
|
|||||||
import ChatHeader from './components/ChatHeader';
|
import ChatHeader from './components/ChatHeader';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useUserStore } from '@/store/user';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
|
|
||||||
const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/
|
|||||||
import PageContainer from '@/components/PageContainer';
|
import PageContainer from '@/components/PageContainer';
|
||||||
import ChatHeader from './components/ChatHeader';
|
import ChatHeader from './components/ChatHeader';
|
||||||
import ChatHistorySlider from './components/ChatHistorySlider';
|
import ChatHistorySlider from './components/ChatHistorySlider';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
|
|
||||||
const OutLink = ({ shareId, chatId }: { shareId: string; chatId: string }) => {
|
const OutLink = ({ shareId, chatId }: { shareId: string; chatId: string }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Box } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
import Navbar from './components/Navbar';
|
import Navbar from './components/Navbar';
|
||||||
@ -10,6 +10,7 @@ import Ability from './components/Ability';
|
|||||||
import Choice from './components/Choice';
|
import Choice from './components/Choice';
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import Loading from '@/components/Loading';
|
import Loading from '@/components/Loading';
|
||||||
|
import Head from 'next/head';
|
||||||
|
|
||||||
const Home = ({ homeUrl = '/' }: { homeUrl: string }) => {
|
const Home = ({ homeUrl = '/' }: { homeUrl: string }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -23,26 +24,33 @@ const Home = ({ homeUrl = '/' }: { homeUrl: string }) => {
|
|||||||
router.prefetch('/login');
|
router.prefetch('/login');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return homeUrl === '/' ? (
|
return (
|
||||||
<Box id="home" bg={'myWhite.600'} h={'100vh'} overflowY={'auto'} overflowX={'hidden'}>
|
<>
|
||||||
<Box position={'fixed'} zIndex={10} top={0} left={0} right={0}>
|
<Head>
|
||||||
<Navbar />
|
<title>{feConfigs?.systemTitle || 'FastGPT'}</title>
|
||||||
</Box>
|
</Head>
|
||||||
<Box maxW={'1200px'} pt={'70px'} m={'auto'}>
|
{homeUrl === '/' ? (
|
||||||
<Hero />
|
<Box id="home" bg={'myWhite.600'} h={'100vh'} overflowY={'auto'} overflowX={'hidden'}>
|
||||||
<Ability />
|
<Box position={'fixed'} zIndex={10} top={0} left={0} right={0}>
|
||||||
<Box my={[4, 6]}>
|
<Navbar />
|
||||||
<Choice />
|
</Box>
|
||||||
</Box>
|
<Box maxW={'1200px'} pt={'70px'} m={'auto'}>
|
||||||
</Box>
|
<Hero />
|
||||||
{feConfigs?.show_git && (
|
<Ability />
|
||||||
<Box bg={'white'}>
|
<Box my={[4, 6]}>
|
||||||
<Footer />
|
<Choice />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
{feConfigs?.show_git && (
|
||||||
|
<Box bg={'white'}>
|
||||||
|
<Footer />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Loading />
|
||||||
)}
|
)}
|
||||||
</Box>
|
</>
|
||||||
) : (
|
|
||||||
<Loading />
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
import React, { useCallback, useState, useRef, useMemo } from 'react';
|
import React, { useCallback, useState, useRef, useMemo } from 'react';
|
||||||
import { Box, Card, IconButton, Flex, Grid, Image } from '@chakra-ui/react';
|
import { Box, Card, IconButton, Flex, Grid, Image } from '@chakra-ui/react';
|
||||||
import type { KbDataItemType } from '@/types/plugin';
|
import type { PgDataItemType } from '@/types/core/dataset/data';
|
||||||
import { usePagination } from '@/hooks/usePagination';
|
import { usePagination } from '@/hooks/usePagination';
|
||||||
import { getKbDataList, delOneKbDataByDataId, getTrainingData } from '@/api/plugins/kb';
|
import {
|
||||||
|
getDatasetDataList,
|
||||||
|
delOneDatasetDataById,
|
||||||
|
getTrainingData
|
||||||
|
} from '@/api/core/dataset/data';
|
||||||
import { getFileInfoById } from '@/api/core/dataset/file';
|
import { getFileInfoById } from '@/api/core/dataset/file';
|
||||||
import { DeleteIcon, RepeatIcon } from '@chakra-ui/icons';
|
import { DeleteIcon, RepeatIcon } from '@chakra-ui/icons';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
@ -39,8 +43,8 @@ const DataCard = ({ kbId }: { kbId: string }) => {
|
|||||||
getData,
|
getData,
|
||||||
pageNum,
|
pageNum,
|
||||||
pageSize
|
pageSize
|
||||||
} = usePagination<KbDataItemType>({
|
} = usePagination<PgDataItemType>({
|
||||||
api: getKbDataList,
|
api: getDatasetDataList,
|
||||||
pageSize: 24,
|
pageSize: 24,
|
||||||
params: {
|
params: {
|
||||||
kbId,
|
kbId,
|
||||||
@ -205,7 +209,7 @@ const DataCard = ({ kbId }: { kbId: string }) => {
|
|||||||
openConfirm(async () => {
|
openConfirm(async () => {
|
||||||
try {
|
try {
|
||||||
setIsDeleting(true);
|
setIsDeleting(true);
|
||||||
await delOneKbDataByDataId(item.id);
|
await delOneDatasetDataById(item.id);
|
||||||
getData(pageNum);
|
getData(pageNum);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
|
|||||||
@ -10,12 +10,9 @@ import {
|
|||||||
Td,
|
Td,
|
||||||
Tbody,
|
Tbody,
|
||||||
Image,
|
Image,
|
||||||
MenuButton,
|
MenuButton
|
||||||
Menu,
|
|
||||||
MenuList,
|
|
||||||
MenuItem
|
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { getTrainingData } from '@/api/plugins/kb';
|
import { getTrainingData } from '@/api/core/dataset/data';
|
||||||
import { getDatasetFiles, delDatasetFileById, updateDatasetFile } from '@/api/core/dataset/file';
|
import { getDatasetFiles, delDatasetFileById, updateDatasetFile } from '@/api/core/dataset/file';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
@ -28,10 +25,10 @@ import dayjs from 'dayjs';
|
|||||||
import { fileImgs } from '@/constants/common';
|
import { fileImgs } from '@/constants/common';
|
||||||
import { useRequest } from '@/hooks/useRequest';
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
import { useLoading } from '@/hooks/useLoading';
|
import { useLoading } from '@/hooks/useLoading';
|
||||||
import { FileStatusEnum, OtherFileId } from '@/constants/kb';
|
import { FileStatusEnum, OtherFileId } from '@/constants/dataset';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { usePagination } from '@/hooks/usePagination';
|
import { usePagination } from '@/hooks/usePagination';
|
||||||
import { KbFileItemType } from '@/types/plugin';
|
import type { DatasetFileItemType } from '@/types/core/dataset/file';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
import MyMenu from '@/components/MyMenu';
|
import MyMenu from '@/components/MyMenu';
|
||||||
import { useEditTitle } from '@/hooks/useEditTitle';
|
import { useEditTitle } from '@/hooks/useEditTitle';
|
||||||
@ -56,7 +53,7 @@ const FileCard = ({ kbId }: { kbId: string }) => {
|
|||||||
isLoading,
|
isLoading,
|
||||||
pageNum,
|
pageNum,
|
||||||
pageSize
|
pageSize
|
||||||
} = usePagination<KbFileItemType>({
|
} = usePagination<DatasetFileItemType>({
|
||||||
api: getDatasetFiles,
|
api: getDatasetFiles,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
params: {
|
params: {
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import { useToast } from '@/hooks/useToast';
|
|||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { postKbDataFromList } from '@/api/plugins/kb';
|
|
||||||
import { splitText2Chunks } from '@/utils/file';
|
import { splitText2Chunks } from '@/utils/file';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { formatPrice } from '@/utils/user';
|
import { formatPrice } from '@/utils/user';
|
||||||
@ -28,6 +27,7 @@ import { TrainingModeEnum } from '@/constants/plugin';
|
|||||||
import FileSelect, { type FileItemType } from './FileSelect';
|
import FileSelect, { type FileItemType } from './FileSelect';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { updateDatasetFile } from '@/api/core/dataset/file';
|
import { updateDatasetFile } from '@/api/core/dataset/file';
|
||||||
|
import { chunksUpload } from '@/utils/web/core/dataset';
|
||||||
|
|
||||||
const fileExtension = '.txt, .doc, .docx, .pdf, .md';
|
const fileExtension = '.txt, .doc, .docx, .pdf, .md';
|
||||||
|
|
||||||
@ -75,22 +75,18 @@ const ChunkImport = ({ kbId }: { kbId: string }) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// subsection import
|
// upload data
|
||||||
let success = 0;
|
const { insertLen } = await chunksUpload({
|
||||||
const step = 300;
|
kbId,
|
||||||
for (let i = 0; i < chunks.length; i += step) {
|
chunks,
|
||||||
const { insertLen } = await postKbDataFromList({
|
mode: TrainingModeEnum.index,
|
||||||
kbId,
|
onUploading: (insertLen) => {
|
||||||
data: chunks.slice(i, i + step),
|
setSuccessChunks(insertLen);
|
||||||
mode: TrainingModeEnum.index
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
success += insertLen;
|
|
||||||
setSuccessChunks(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: `去重后共导入 ${success} 条数据,请耐心等待训练.`,
|
title: `去重后共导入 ${insertLen} 条数据,请耐心等待训练.`,
|
||||||
status: 'success'
|
status: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { Box, Flex, Button, useTheme, Image } from '@chakra-ui/react';
|
|||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { postKbDataFromList } from '@/api/plugins/kb';
|
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
|
import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
|
||||||
@ -12,6 +11,7 @@ import FileSelect, { type FileItemType } from './FileSelect';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { updateDatasetFile } from '@/api/core/dataset/file';
|
import { updateDatasetFile } from '@/api/core/dataset/file';
|
||||||
|
import { chunksUpload } from '@/utils/web/core/dataset';
|
||||||
|
|
||||||
const fileExtension = '.csv';
|
const fileExtension = '.csv';
|
||||||
|
|
||||||
@ -62,22 +62,18 @@ const CsvImport = ({ kbId }: { kbId: string }) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// subsection import
|
// upload data
|
||||||
let success = 0;
|
const { insertLen } = await chunksUpload({
|
||||||
const step = 300;
|
kbId,
|
||||||
for (let i = 0; i < filterChunks.length; i += step) {
|
chunks,
|
||||||
const { insertLen } = await postKbDataFromList({
|
mode: TrainingModeEnum.index,
|
||||||
kbId,
|
onUploading: (insertLen) => {
|
||||||
data: filterChunks.slice(i, i + step),
|
setSuccessChunks(insertLen);
|
||||||
mode: TrainingModeEnum.index
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
success += insertLen;
|
|
||||||
setSuccessChunks(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: `去重后共导入 ${success} 条数据,请耐心等待训练.`,
|
title: `去重后共导入 ${insertLen} 条数据,请耐心等待训练.`,
|
||||||
status: 'success'
|
status: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -2,22 +2,24 @@ import MyIcon from '@/components/Icon';
|
|||||||
import { useLoading } from '@/hooks/useLoading';
|
import { useLoading } from '@/hooks/useLoading';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
|
import { simpleText, splitText2Chunks } from '@/utils/file';
|
||||||
import {
|
import {
|
||||||
|
uploadFiles,
|
||||||
fileDownload,
|
fileDownload,
|
||||||
readCsvContent,
|
readCsvContent,
|
||||||
simpleText,
|
readTxtContent,
|
||||||
splitText2Chunks,
|
readPdfContent,
|
||||||
uploadFiles
|
readDocContent
|
||||||
} from '@/utils/file';
|
} from '@/utils/web/file';
|
||||||
import { Box, Flex, useDisclosure, type BoxProps } from '@chakra-ui/react';
|
import { Box, Flex, useDisclosure, type BoxProps } from '@chakra-ui/react';
|
||||||
import { fileImgs } from '@/constants/common';
|
import { fileImgs } from '@/constants/common';
|
||||||
import { DragEvent, useCallback, useState } from 'react';
|
import { DragEvent, useCallback, useState } from 'react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { readTxtContent, readPdfContent, readDocContent } from '@/utils/file';
|
|
||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { FetchResultItem, DatasetItemType } from '@/types/plugin';
|
import { FetchResultItem } from '@/types/plugin';
|
||||||
|
import type { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
@ -30,7 +32,7 @@ const csvTemplate = `index,content,source\n"被索引的内容","对应的答案
|
|||||||
export type FileItemType = {
|
export type FileItemType = {
|
||||||
id: string;
|
id: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
chunks: DatasetItemType[];
|
chunks: DatasetDataItemType[];
|
||||||
text: string;
|
text: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
tokens: number;
|
tokens: number;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useForm } from 'react-hook-form';
|
|||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useRequest } from '@/hooks/useRequest';
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { postKbDataFromList } from '@/api/plugins/kb';
|
import { postChunks2Dataset } from '@/api/core/dataset/data';
|
||||||
import { TrainingModeEnum } from '@/constants/plugin';
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
@ -38,7 +38,7 @@ const ManualImport = ({ kbId }: { kbId: string }) => {
|
|||||||
q: e.q,
|
q: e.q,
|
||||||
source: '手动录入'
|
source: '手动录入'
|
||||||
};
|
};
|
||||||
const { insertLen } = await postKbDataFromList({
|
const { insertLen } = await postChunks2Dataset({
|
||||||
kbId,
|
kbId,
|
||||||
mode: TrainingModeEnum.index,
|
mode: TrainingModeEnum.index,
|
||||||
data: [data]
|
data: [data]
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { Box, Flex, Button, useTheme, Image, Input } from '@chakra-ui/react';
|
|||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { postKbDataFromList } from '@/api/plugins/kb';
|
|
||||||
import { splitText2Chunks } from '@/utils/file';
|
import { splitText2Chunks } from '@/utils/file';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { formatPrice } from '@/utils/user';
|
import { formatPrice } from '@/utils/user';
|
||||||
@ -19,6 +18,7 @@ import { useRouter } from 'next/router';
|
|||||||
import { updateDatasetFile } from '@/api/core/dataset/file';
|
import { updateDatasetFile } from '@/api/core/dataset/file';
|
||||||
import { Prompt_AgentQA } from '@/prompts/core/agent';
|
import { Prompt_AgentQA } from '@/prompts/core/agent';
|
||||||
import { replaceVariable } from '@/utils/common/tools/text';
|
import { replaceVariable } from '@/utils/common/tools/text';
|
||||||
|
import { chunksUpload } from '@/utils/web/core/dataset';
|
||||||
|
|
||||||
const fileExtension = '.txt, .doc, .docx, .pdf, .md';
|
const fileExtension = '.txt, .doc, .docx, .pdf, .md';
|
||||||
|
|
||||||
@ -74,23 +74,19 @@ const QAImport = ({ kbId }: { kbId: string }) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// subsection import
|
// upload data
|
||||||
let success = 0;
|
const { insertLen } = await chunksUpload({
|
||||||
const step = 200;
|
kbId,
|
||||||
for (let i = 0; i < chunks.length; i += step) {
|
chunks,
|
||||||
const { insertLen } = await postKbDataFromList({
|
mode: TrainingModeEnum.qa,
|
||||||
kbId,
|
prompt: previewQAPrompt,
|
||||||
data: chunks.slice(i, i + step),
|
onUploading: (insertLen) => {
|
||||||
mode: TrainingModeEnum.qa,
|
setSuccessChunks(insertLen);
|
||||||
prompt: previewQAPrompt
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
success += insertLen;
|
|
||||||
setSuccessChunks(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: `共导入 ${success} 条数据,请耐心等待训练.`,
|
title: `共导入 ${insertLen} 条数据,请耐心等待训练.`,
|
||||||
status: 'success'
|
status: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -9,14 +9,14 @@ import React, {
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { Box, Flex, Button, FormControl, IconButton, Input } from '@chakra-ui/react';
|
import { Box, Flex, Button, FormControl, IconButton, Input } from '@chakra-ui/react';
|
||||||
import { QuestionOutlineIcon, DeleteIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon, DeleteIcon } from '@chakra-ui/icons';
|
||||||
import { delKbById, putKbById } from '@/api/plugins/kb';
|
import { delDatasetById, putDatasetById } from '@/api/core/dataset';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
import { compressImg } from '@/utils/file';
|
import { compressImg } from '@/utils/web/file';
|
||||||
import type { KbItemType } from '@/types/plugin';
|
import type { DatasetItemType } from '@/types/core/dataset';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import Tag from '@/components/Tag';
|
import Tag from '@/components/Tag';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
@ -26,7 +26,7 @@ export interface ComponentRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Info = (
|
const Info = (
|
||||||
{ kbId, form }: { kbId: string; form: UseFormReturn<KbItemType, any> },
|
{ kbId, form }: { kbId: string; form: UseFormReturn<DatasetItemType, any> },
|
||||||
ref: ForwardedRef<ComponentRef>
|
ref: ForwardedRef<ComponentRef>
|
||||||
) => {
|
) => {
|
||||||
const { getValues, formState, setValue, register, handleSubmit } = form;
|
const { getValues, formState, setValue, register, handleSubmit } = form;
|
||||||
@ -53,7 +53,7 @@ const Info = (
|
|||||||
const onclickDelKb = useCallback(async () => {
|
const onclickDelKb = useCallback(async () => {
|
||||||
setBtnLoading(true);
|
setBtnLoading(true);
|
||||||
try {
|
try {
|
||||||
await delKbById(kbId);
|
await delDatasetById(kbId);
|
||||||
toast({
|
toast({
|
||||||
title: '删除成功',
|
title: '删除成功',
|
||||||
status: 'success'
|
status: 'success'
|
||||||
@ -70,10 +70,10 @@ const Info = (
|
|||||||
}, [setBtnLoading, kbId, toast, router, loadKbList]);
|
}, [setBtnLoading, kbId, toast, router, loadKbList]);
|
||||||
|
|
||||||
const saveSubmitSuccess = useCallback(
|
const saveSubmitSuccess = useCallback(
|
||||||
async (data: KbItemType) => {
|
async (data: DatasetItemType) => {
|
||||||
setBtnLoading(true);
|
setBtnLoading(true);
|
||||||
try {
|
try {
|
||||||
await putKbById({
|
await putDatasetById({
|
||||||
id: kbId,
|
id: kbId,
|
||||||
...data
|
...data
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
import React, { useState, useCallback } from 'react';
|
import React, { useState, useCallback } from 'react';
|
||||||
import { Box, Flex, Button, Textarea, IconButton, BoxProps } from '@chakra-ui/react';
|
import { Box, Flex, Button, Textarea, IconButton, BoxProps } from '@chakra-ui/react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { insertData2Kb, putKbDataById, delOneKbDataByDataId } from '@/api/plugins/kb';
|
import {
|
||||||
|
postData2Dataset,
|
||||||
|
putDatasetDataById,
|
||||||
|
delOneDatasetDataById
|
||||||
|
} from '@/api/core/dataset/data';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
@ -9,12 +13,12 @@ import MyModal from '@/components/MyModal';
|
|||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { DatasetItemType } from '@/types/plugin';
|
import { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { getFileAndOpen } from '@/utils/common/file';
|
import { getFileAndOpen } from '@/utils/web/file';
|
||||||
|
|
||||||
export type FormData = { dataId?: string } & DatasetItemType;
|
export type FormData = { dataId?: string } & DatasetDataItemType;
|
||||||
|
|
||||||
const InputDataModal = ({
|
const InputDataModal = ({
|
||||||
onClose,
|
onClose,
|
||||||
@ -65,7 +69,7 @@ const InputDataModal = ({
|
|||||||
q: e.q,
|
q: e.q,
|
||||||
source: '手动录入'
|
source: '手动录入'
|
||||||
};
|
};
|
||||||
data.dataId = await insertData2Kb({
|
data.dataId = await postData2Dataset({
|
||||||
kbId,
|
kbId,
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
@ -104,7 +108,7 @@ const InputDataModal = ({
|
|||||||
a: e.a,
|
a: e.a,
|
||||||
q: e.q === defaultValues.q ? '' : e.q
|
q: e.q === defaultValues.q ? '' : e.q
|
||||||
};
|
};
|
||||||
await putKbDataById(data);
|
await putDatasetDataById(data);
|
||||||
onSuccess(data);
|
onSuccess(data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toast({
|
toast({
|
||||||
@ -211,7 +215,7 @@ const InputDataModal = ({
|
|||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (!onDelete || !defaultValues.dataId) return;
|
if (!onDelete || !defaultValues.dataId) return;
|
||||||
try {
|
try {
|
||||||
await delOneKbDataByDataId(defaultValues.dataId);
|
await delOneDatasetDataById(defaultValues.dataId);
|
||||||
onDelete();
|
onDelete();
|
||||||
onClose();
|
onClose();
|
||||||
toast({
|
toast({
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { Box, Textarea, Button, Flex, useTheme, Grid, Progress } from '@chakra-ui/react';
|
import { Box, Textarea, Button, Flex, useTheme, Grid, Progress } from '@chakra-ui/react';
|
||||||
import { useDatasetStore } from '@/store/dataset';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import type { KbTestItemType } from '@/types/plugin';
|
import type { SearchTestItemType } from '@/types/core/dataset';
|
||||||
import { searchText, getKbDataItemById } from '@/api/plugins/kb';
|
import { getDatasetDataItemById } from '@/api/core/dataset/data';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { useRequest } from '@/hooks/useRequest';
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
import { formatTimeToChatTime } from '@/utils/tools';
|
import { formatTimeToChatTime } from '@/utils/tools';
|
||||||
@ -13,6 +13,7 @@ import { useToast } from '@/hooks/useToast';
|
|||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
|
import { postSearchText } from '@/api/core/dataset';
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||||
|
|
||||||
const Test = ({ kbId }: { kbId: string }) => {
|
const Test = ({ kbId }: { kbId: string }) => {
|
||||||
@ -22,7 +23,7 @@ const Test = ({ kbId }: { kbId: string }) => {
|
|||||||
const { kbDetail, kbTestList, pushKbTestItem, delKbTestItemById, updateKbItemById } =
|
const { kbDetail, kbTestList, pushKbTestItem, delKbTestItemById, updateKbItemById } =
|
||||||
useDatasetStore();
|
useDatasetStore();
|
||||||
const [inputText, setInputText] = useState('');
|
const [inputText, setInputText] = useState('');
|
||||||
const [kbTestItem, setKbTestItem] = useState<KbTestItemType>();
|
const [kbTestItem, setKbTestItem] = useState<SearchTestItemType>();
|
||||||
const [editData, setEditData] = useState<FormData>();
|
const [editData, setEditData] = useState<FormData>();
|
||||||
|
|
||||||
const kbTestHistory = useMemo(
|
const kbTestHistory = useMemo(
|
||||||
@ -31,7 +32,7 @@ const Test = ({ kbId }: { kbId: string }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { mutate, isLoading } = useRequest({
|
const { mutate, isLoading } = useRequest({
|
||||||
mutationFn: () => searchText({ kbId, text: inputText.trim() }),
|
mutationFn: () => postSearchText({ kbId, text: inputText.trim() }),
|
||||||
onSuccess(res) {
|
onSuccess(res) {
|
||||||
const testItem = {
|
const testItem = {
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
@ -197,7 +198,7 @@ const Test = ({ kbId }: { kbId: string }) => {
|
|||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const data = await getKbDataItemById(item.id);
|
const data = await getDatasetDataItemById(item.id);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
throw new Error('该数据已被删除');
|
throw new Error('该数据已被删除');
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { Box, Flex, IconButton, useTheme } from '@chakra-ui/react';
|
|||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { KbItemType } from '@/types/plugin';
|
import { DatasetItemType } from '@/types/core/dataset';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
import { type ComponentRef } from './components/Info';
|
import { type ComponentRef } from './components/Info';
|
||||||
@ -15,9 +15,9 @@ import SideTabs from '@/components/SideTabs';
|
|||||||
import PageContainer from '@/components/PageContainer';
|
import PageContainer from '@/components/PageContainer';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import Info from './components/Info';
|
import Info from './components/Info';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { getTrainingQueueLen } from '@/api/plugins/kb';
|
import { getTrainingQueueLen } from '@/api/core/dataset/data';
|
||||||
import { delDatasetEmptyFiles } from '@/api/core/dataset/file';
|
import { delDatasetEmptyFiles } from '@/api/core/dataset/file';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
@ -72,7 +72,7 @@ const Detail = ({ kbId, currentTab }: { kbId: string; currentTab: `${TabEnum}` }
|
|||||||
[kbId, router]
|
[kbId, router]
|
||||||
);
|
);
|
||||||
|
|
||||||
const form = useForm<KbItemType>({
|
const form = useForm<DatasetItemType>({
|
||||||
defaultValues: kbDetail
|
defaultValues: kbDetail
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React, { useCallback, useState, useRef } from 'react';
|
|||||||
import { Box, Flex, Button, ModalHeader, ModalFooter, ModalBody, Input } from '@chakra-ui/react';
|
import { Box, Flex, Button, ModalHeader, ModalFooter, ModalBody, Input } from '@chakra-ui/react';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { compressImg } from '@/utils/file';
|
import { compressImg } from '@/utils/web/file';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
@ -11,8 +11,8 @@ import { useRequest } from '@/hooks/useRequest';
|
|||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import MyModal from '@/components/MyModal';
|
import MyModal from '@/components/MyModal';
|
||||||
import { postCreateKb } from '@/api/plugins/kb';
|
import { postCreateDataset } from '@/api/core/dataset';
|
||||||
import type { CreateKbParams } from '@/api/request/kb';
|
import type { CreateDatasetParams } from '@/api/core/dataset/index.d';
|
||||||
import { vectorModelList } from '@/store/static';
|
import { vectorModelList } from '@/store/static';
|
||||||
import MySelect from '@/components/Select';
|
import MySelect from '@/components/Select';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
@ -23,7 +23,7 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
const { register, setValue, getValues, handleSubmit } = useForm<CreateKbParams>({
|
const { register, setValue, getValues, handleSubmit } = useForm<CreateDatasetParams>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
avatar: '/icon/logo.svg',
|
avatar: '/icon/logo.svg',
|
||||||
name: '',
|
name: '',
|
||||||
@ -64,8 +64,8 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
|
|||||||
|
|
||||||
/* create a new kb and router to it */
|
/* create a new kb and router to it */
|
||||||
const { mutate: onclickCreate, isLoading: creating } = useRequest({
|
const { mutate: onclickCreate, isLoading: creating } = useRequest({
|
||||||
mutationFn: async (data: CreateKbParams) => {
|
mutationFn: async (data: CreateDatasetParams) => {
|
||||||
const id = await postCreateKb(data);
|
const id = await postCreateDataset(data);
|
||||||
return id;
|
return id;
|
||||||
},
|
},
|
||||||
successToast: '创建成功',
|
successToast: '创建成功',
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { ModalFooter, ModalBody, Input, Button } from '@chakra-ui/react';
|
|||||||
import MyModal from '@/components/MyModal';
|
import MyModal from '@/components/MyModal';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useRequest } from '@/hooks/useRequest';
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
import { postCreateKb, putKbById } from '@/api/plugins/kb';
|
import { postCreateDataset, putDatasetById } from '@/api/core/dataset';
|
||||||
import { FolderAvatarSrc, KbTypeEnum } from '@/constants/kb';
|
import { FolderAvatarSrc, KbTypeEnum } from '@/constants/dataset';
|
||||||
|
|
||||||
const EditFolderModal = ({
|
const EditFolderModal = ({
|
||||||
onClose,
|
onClose,
|
||||||
@ -39,12 +39,12 @@ const EditFolderModal = ({
|
|||||||
const val = inputRef.current?.value;
|
const val = inputRef.current?.value;
|
||||||
if (!val) return Promise.resolve('');
|
if (!val) return Promise.resolve('');
|
||||||
if (id) {
|
if (id) {
|
||||||
return putKbById({
|
return putDatasetById({
|
||||||
id,
|
id,
|
||||||
name: val
|
name: val
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return postCreateKb({
|
return postCreateDataset({
|
||||||
parentId,
|
parentId,
|
||||||
name: val,
|
name: val,
|
||||||
type: KbTypeEnum.folder,
|
type: KbTypeEnum.folder,
|
||||||
|
|||||||
@ -10,15 +10,14 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
Grid
|
Grid
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { getKbPaths } from '@/api/plugins/kb';
|
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import MyModal from '@/components/MyModal';
|
import MyModal from '@/components/MyModal';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { KbTypeEnum } from '@/constants/kb';
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { getKbList, putKbById } from '@/api/plugins/kb';
|
import { getDatasets, putDatasetById, getDatasetPaths } from '@/api/core/dataset';
|
||||||
import { useRequest } from '@/hooks/useRequest';
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
|
|
||||||
const MoveModal = ({
|
const MoveModal = ({
|
||||||
@ -35,8 +34,8 @@ const MoveModal = ({
|
|||||||
|
|
||||||
const [parentId, setParentId] = useState<string>('');
|
const [parentId, setParentId] = useState<string>('');
|
||||||
|
|
||||||
const { data } = useQuery(['getKbList', parentId], () => {
|
const { data } = useQuery(['getDatasets', parentId], () => {
|
||||||
return Promise.all([getKbList({ parentId, type: 'folder' }), getKbPaths(parentId)]);
|
return Promise.all([getDatasets({ parentId, type: 'folder' }), getDatasetPaths(parentId)]);
|
||||||
});
|
});
|
||||||
const paths = useMemo(
|
const paths = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@ -54,7 +53,7 @@ const MoveModal = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { mutate, isLoading } = useRequest({
|
const { mutate, isLoading } = useRequest({
|
||||||
mutationFn: () => putKbById({ id: moveDataId, parentId }),
|
mutationFn: () => putDatasetById({ id: moveDataId, parentId }),
|
||||||
onSuccess,
|
onSuccess,
|
||||||
errorToast: t('kb.Move Failed')
|
errorToast: t('kb.Move Failed')
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,13 +15,14 @@ import PageContainer from '@/components/PageContainer';
|
|||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { AddIcon } from '@chakra-ui/icons';
|
import { AddIcon } from '@chakra-ui/icons';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { delKbById, exportDataset, getKbPaths, putKbById } from '@/api/plugins/kb';
|
import { delDatasetById, getDatasetPaths, putDatasetById } from '@/api/core/dataset';
|
||||||
|
import { exportDatasetData } from '@/api/core/dataset/data';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { FolderAvatarSrc, KbTypeEnum } from '@/constants/kb';
|
import { FolderAvatarSrc, KbTypeEnum } from '@/constants/dataset';
|
||||||
import Tag from '@/components/Tag';
|
import Tag from '@/components/Tag';
|
||||||
import MyMenu from '@/components/MyMenu';
|
import MyMenu from '@/components/MyMenu';
|
||||||
import { useRequest } from '@/hooks/useRequest';
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
@ -71,7 +72,7 @@ const Kb = () => {
|
|||||||
const { mutate: onclickDelKb } = useRequest({
|
const { mutate: onclickDelKb } = useRequest({
|
||||||
mutationFn: async (id: string) => {
|
mutationFn: async (id: string) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await delKbById(id);
|
await delDatasetById(id);
|
||||||
return id;
|
return id;
|
||||||
},
|
},
|
||||||
onSuccess(id: string) {
|
onSuccess(id: string) {
|
||||||
@ -88,7 +89,7 @@ const Kb = () => {
|
|||||||
const { mutate: onclickExport } = useRequest({
|
const { mutate: onclickExport } = useRequest({
|
||||||
mutationFn: (kbId: string) => {
|
mutationFn: (kbId: string) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
return exportDataset({ kbId });
|
return exportDatasetData({ kbId });
|
||||||
},
|
},
|
||||||
onSettled() {
|
onSettled() {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@ -98,7 +99,7 @@ const Kb = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { data, refetch } = useQuery(['loadDataset', parentId], () => {
|
const { data, refetch } = useQuery(['loadDataset', parentId], () => {
|
||||||
return Promise.all([loadKbList(parentId), getKbPaths(parentId)]);
|
return Promise.all([loadKbList(parentId), getDatasetPaths(parentId)]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const paths = useMemo(
|
const paths = useMemo(
|
||||||
@ -240,7 +241,7 @@ const Kb = () => {
|
|||||||
if (!dragTargetId || !dragStartId || dragTargetId === dragStartId) return;
|
if (!dragTargetId || !dragStartId || dragTargetId === dragStartId) return;
|
||||||
// update parentId
|
// update parentId
|
||||||
try {
|
try {
|
||||||
await putKbById({
|
await putDatasetById({
|
||||||
id: dragStartId,
|
id: dragStartId,
|
||||||
parentId: dragTargetId
|
parentId: dragTargetId
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { useUserStore } from '@/store/user';
|
|||||||
import { useChatStore } from '@/store/chat';
|
import { useChatStore } from '@/store/chat';
|
||||||
import LoginForm from './components/LoginForm';
|
import LoginForm from './components/LoginForm';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { setToken } from '@/utils/user';
|
import { setToken } from '@/utils/user';
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import CommunityModal from '@/components/CommunityModal';
|
import CommunityModal from '@/components/CommunityModal';
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { setToken } from '@/utils/user';
|
|||||||
import { oauthLogin } from '@/api/user';
|
import { oauthLogin } from '@/api/user';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import Loading from '@/components/Loading';
|
import Loading from '@/components/Loading';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { ChevronRightIcon } from '@chakra-ui/icons';
|
|||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import { serviceSideProps } from '@/utils/i18n';
|
import { serviceSideProps } from '@/utils/web/i18n';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const Tools = () => {
|
const Tools = () => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { TrainingData } from '@/service/mongo';
|
import { TrainingData } from '@/service/mongo';
|
||||||
import { pushQABill } from '@/service/events/pushBill';
|
import { pushQABill } from '@/service/events/pushBill';
|
||||||
import { pushDataToKb } from '@/pages/api/openapi/kb/pushData';
|
import { pushDataToKb } from '@/pages/api/core/dataset/data/pushData';
|
||||||
import { TrainingModeEnum } from '@/constants/plugin';
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
import { ERROR_ENUM } from '../errorCode';
|
import { ERROR_ENUM } from '../errorCode';
|
||||||
import { sendInform } from '@/pages/api/user/inform/send';
|
import { sendInform } from '@/pages/api/user/inform/send';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { insertKbItem } from '@/service/pg';
|
import { insertData2Dataset } from '@/service/pg';
|
||||||
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||||
import { TrainingData } from '../models/trainingData';
|
import { TrainingData } from '../models/trainingData';
|
||||||
import { ERROR_ENUM } from '../errorCode';
|
import { ERROR_ENUM } from '../errorCode';
|
||||||
@ -68,7 +68,7 @@ export async function generateVector(): Promise<any> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 生成结果插入到 pg
|
// 生成结果插入到 pg
|
||||||
await insertKbItem({
|
await insertData2Dataset({
|
||||||
userId,
|
userId,
|
||||||
kbId,
|
kbId,
|
||||||
data: vectors.map((vector, i) => ({
|
data: vectors.map((vector, i) => ({
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import mongoose, { Types } from 'mongoose';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import fsp from 'fs/promises';
|
import fsp from 'fs/promises';
|
||||||
import { ERROR_ENUM } from '../errorCode';
|
import { ERROR_ENUM } from '../errorCode';
|
||||||
import type { FileInfo } from '@/types/plugin';
|
import type { GSFileInfoType } from '@/types/common/file';
|
||||||
|
|
||||||
enum BucketNameEnum {
|
enum BucketNameEnum {
|
||||||
dataset = 'dataset'
|
dataset = 'dataset'
|
||||||
@ -60,7 +60,7 @@ export class GridFSStorage {
|
|||||||
|
|
||||||
return String(stream.id);
|
return String(stream.id);
|
||||||
}
|
}
|
||||||
async findAndAuthFile(id: string): Promise<FileInfo> {
|
async findAndAuthFile(id: string): Promise<GSFileInfoType> {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return Promise.reject(`id is empty`);
|
return Promise.reject(`id is empty`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Schema, model, models, Model } from 'mongoose';
|
import { Schema, model, models, Model } from 'mongoose';
|
||||||
import { kbSchema as SchemaType } from '@/types/mongoSchema';
|
import { kbSchema as SchemaType } from '@/types/mongoSchema';
|
||||||
import { KbTypeMap } from '@/constants/kb';
|
import { KbTypeMap } from '@/constants/dataset';
|
||||||
|
|
||||||
const kbSchema = new Schema({
|
const kbSchema = new Schema({
|
||||||
parentId: {
|
parentId: {
|
||||||
|
|||||||
@ -3,14 +3,14 @@ import type { ChatHistoryItemResType } from '@/types/chat';
|
|||||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||||
import { countModelPrice } from '@/service/events/pushBill';
|
import { countModelPrice } from '@/service/events/pushBill';
|
||||||
import type { SelectedKbType } from '@/types/plugin';
|
import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||||
import type { QuoteItemType } from '@/types/chat';
|
import type { QuoteItemType } from '@/types/chat';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||||
import { ModuleDispatchProps } from '@/types/core/modules';
|
import { ModuleDispatchProps } from '@/types/core/modules';
|
||||||
|
|
||||||
type KBSearchProps = ModuleDispatchProps<{
|
type KBSearchProps = ModuleDispatchProps<{
|
||||||
kbList: SelectedKbType;
|
kbList: SelectedDatasetType;
|
||||||
similarity: number;
|
similarity: number;
|
||||||
limit: number;
|
limit: number;
|
||||||
userChatInput: string;
|
userChatInput: string;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Pool } from 'pg';
|
|||||||
import type { QueryResultRow } from 'pg';
|
import type { QueryResultRow } from 'pg';
|
||||||
import { PgDatasetTableName } from '@/constants/plugin';
|
import { PgDatasetTableName } from '@/constants/plugin';
|
||||||
import { addLog } from './utils/tools';
|
import { addLog } from './utils/tools';
|
||||||
import { DatasetItemType } from '@/types/plugin';
|
import type { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||||
|
|
||||||
export const connectPg = async (): Promise<Pool> => {
|
export const connectPg = async (): Promise<Pool> => {
|
||||||
if (global.pgClient) {
|
if (global.pgClient) {
|
||||||
@ -161,16 +161,16 @@ class Pg {
|
|||||||
export const PgClient = new Pg();
|
export const PgClient = new Pg();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* data insert kb
|
* data insert dataset
|
||||||
*/
|
*/
|
||||||
export const insertKbItem = ({
|
export const insertData2Dataset = ({
|
||||||
userId,
|
userId,
|
||||||
kbId,
|
kbId,
|
||||||
data
|
data
|
||||||
}: {
|
}: {
|
||||||
userId: string;
|
userId: string;
|
||||||
kbId: string;
|
kbId: string;
|
||||||
data: (DatasetItemType & {
|
data: (DatasetDataItemType & {
|
||||||
vector: number[];
|
vector: number[];
|
||||||
})[];
|
})[];
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { devtools, persist } from 'zustand/middleware';
|
import { devtools, persist } from 'zustand/middleware';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
import { type KbTestItemType } from '@/types/plugin';
|
import type { SearchTestItemType } from '@/types/core/dataset';
|
||||||
import type { KbItemType, KbListItemType } from '@/types/plugin';
|
import type { DatasetItemType, DatasetsItemType } from '@/types/core/dataset';
|
||||||
import { getKbList, getKbById, getAllDataset, putKbById } from '@/api/plugins/kb';
|
import { getAllDataset, getDatasets, getDatasetById, putDatasetById } from '@/api/core/dataset';
|
||||||
import { defaultKbDetail } from '@/constants/kb';
|
import { defaultKbDetail } from '@/constants/dataset';
|
||||||
import { KbUpdateParams } from '@/api/request/kb';
|
import type { DatasetUpdateParams } from '@/api/core/dataset/index.d';
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
allDatasets: KbListItemType[];
|
allDatasets: DatasetsItemType[];
|
||||||
loadAllDatasets: () => Promise<KbListItemType[]>;
|
loadAllDatasets: () => Promise<DatasetsItemType[]>;
|
||||||
myKbList: KbListItemType[];
|
myKbList: DatasetsItemType[];
|
||||||
loadKbList: (parentId?: string) => Promise<any>;
|
loadKbList: (parentId?: string) => Promise<any>;
|
||||||
setKbList(val: KbListItemType[]): void;
|
setKbList(val: DatasetsItemType[]): void;
|
||||||
kbDetail: KbItemType;
|
kbDetail: DatasetItemType;
|
||||||
getKbDetail: (id: string, init?: boolean) => Promise<KbItemType>;
|
getKbDetail: (id: string, init?: boolean) => Promise<DatasetItemType>;
|
||||||
updateDataset: (data: KbUpdateParams) => Promise<any>;
|
updateDataset: (data: DatasetUpdateParams) => Promise<any>;
|
||||||
|
|
||||||
kbTestList: KbTestItemType[];
|
kbTestList: SearchTestItemType[];
|
||||||
pushKbTestItem: (data: KbTestItemType) => void;
|
pushKbTestItem: (data: SearchTestItemType) => void;
|
||||||
delKbTestItemById: (id: string) => void;
|
delKbTestItemById: (id: string) => void;
|
||||||
updateKbItemById: (data: KbTestItemType) => void;
|
updateKbItemById: (data: SearchTestItemType) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDatasetStore = create<State>()(
|
export const useDatasetStore = create<State>()(
|
||||||
@ -37,7 +37,7 @@ export const useDatasetStore = create<State>()(
|
|||||||
},
|
},
|
||||||
myKbList: [],
|
myKbList: [],
|
||||||
async loadKbList(parentId = '') {
|
async loadKbList(parentId = '') {
|
||||||
const res = await getKbList({ parentId });
|
const res = await getDatasets({ parentId });
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.myKbList = res;
|
state.myKbList = res;
|
||||||
});
|
});
|
||||||
@ -52,7 +52,7 @@ export const useDatasetStore = create<State>()(
|
|||||||
async getKbDetail(id: string, init = false) {
|
async getKbDetail(id: string, init = false) {
|
||||||
if (id === get().kbDetail._id && !init) return get().kbDetail;
|
if (id === get().kbDetail._id && !init) return get().kbDetail;
|
||||||
|
|
||||||
const data = await getKbById(id);
|
const data = await getDatasetById(id);
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.kbDetail = data;
|
state.kbDetail = data;
|
||||||
@ -80,7 +80,7 @@ export const useDatasetStore = create<State>()(
|
|||||||
: item
|
: item
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
await putKbById(data);
|
await putDatasetById(data);
|
||||||
},
|
},
|
||||||
kbTestList: [],
|
kbTestList: [],
|
||||||
pushKbTestItem(data) {
|
pushKbTestItem(data) {
|
||||||
@ -93,7 +93,7 @@ export const useDatasetStore = create<State>()(
|
|||||||
state.kbTestList = state.kbTestList.filter((item) => item.id !== id);
|
state.kbTestList = state.kbTestList.filter((item) => item.id !== id);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
updateKbItemById(data: KbTestItemType) {
|
updateKbItemById(data: SearchTestItemType) {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.kbTestList = state.kbTestList.map((item) => (item.id === data.id ? data : item));
|
state.kbTestList = state.kbTestList.map((item) => (item.id === data.id ? data : item));
|
||||||
});
|
});
|
||||||
|
|||||||
4
client/src/types/chat.d.ts
vendored
4
client/src/types/chat.d.ts
vendored
@ -3,7 +3,7 @@ import type { InitChatResponse, InitShareChatResponse } from '@/api/response/cha
|
|||||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { ClassifyQuestionAgentItemType } from './app';
|
import { ClassifyQuestionAgentItemType } from './app';
|
||||||
import { ChatItemSchema } from './mongoSchema';
|
import { ChatItemSchema } from './mongoSchema';
|
||||||
import { KbDataItemType } from './plugin';
|
import type { PgDataItemType } from '@/types/core/dataset/data';
|
||||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||||
|
|
||||||
export type ExportChatType = 'md' | 'pdf' | 'html';
|
export type ExportChatType = 'md' | 'pdf' | 'html';
|
||||||
@ -43,7 +43,7 @@ export type ShareChatType = InitShareChatResponse & {
|
|||||||
history: ShareChatHistoryItemType;
|
history: ShareChatHistoryItemType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type QuoteItemType = KbDataItemType & {
|
export type QuoteItemType = PgDataItemType & {
|
||||||
kb_id: string;
|
kb_id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
8
client/src/types/common/file.d.ts
vendored
Normal file
8
client/src/types/common/file.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export type GSFileInfoType = {
|
||||||
|
id: string;
|
||||||
|
filename: string;
|
||||||
|
size: number;
|
||||||
|
contentType: string;
|
||||||
|
encoding: string;
|
||||||
|
uploadDate: Date;
|
||||||
|
};
|
||||||
9
client/src/types/core/dataset/data.d.ts
vendored
Normal file
9
client/src/types/core/dataset/data.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export type DatasetDataItemType = {
|
||||||
|
q: string; // 提问词
|
||||||
|
a: string; // 原文
|
||||||
|
source?: string;
|
||||||
|
file_id?: string;
|
||||||
|
};
|
||||||
|
export type PgDataItemType = DatasetItemType & {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
10
client/src/types/core/dataset/file.d.ts
vendored
Normal file
10
client/src/types/core/dataset/file.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { FileStatusEnum } from '@/constants/dataset';
|
||||||
|
|
||||||
|
export type DatasetFileItemType = {
|
||||||
|
id: string;
|
||||||
|
size: number;
|
||||||
|
filename: string;
|
||||||
|
uploadTime: Date;
|
||||||
|
chunkLength: number;
|
||||||
|
status: `${FileStatusEnum}`;
|
||||||
|
};
|
||||||
32
client/src/types/core/dataset/index.d.ts
vendored
Normal file
32
client/src/types/core/dataset/index.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { FileStatusEnum } from '@/constants/dataset';
|
||||||
|
import { PgDataItemType } from './data';
|
||||||
|
import { VectorModelItemType } from '../../model';
|
||||||
|
import type { kbSchema } from '../../mongoSchema';
|
||||||
|
|
||||||
|
export type DatasetsItemType = Omit<kbSchema, 'vectorModel'> & {
|
||||||
|
vectorModel: VectorModelItemType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DatasetItemType = {
|
||||||
|
_id: string;
|
||||||
|
avatar: string;
|
||||||
|
name: string;
|
||||||
|
userId: string;
|
||||||
|
vectorModel: VectorModelItemType;
|
||||||
|
tags: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DatasetPathItemType = {
|
||||||
|
parentId: string;
|
||||||
|
parentName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SearchTestItemType = {
|
||||||
|
id: string;
|
||||||
|
kbId: string;
|
||||||
|
text: string;
|
||||||
|
time: Date;
|
||||||
|
results: (PgDataItemType & { score: number })[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SelectedDatasetType = { kbId: string; vectorModel: VectorModelItemType }[];
|
||||||
2
client/src/types/mongoSchema.d.ts
vendored
2
client/src/types/mongoSchema.d.ts
vendored
@ -6,7 +6,7 @@ import { TrainingModeEnum } from '@/constants/plugin';
|
|||||||
import type { AppModuleItemType } from './app';
|
import type { AppModuleItemType } from './app';
|
||||||
import { ChatSourceEnum } from '@/constants/chat';
|
import { ChatSourceEnum } from '@/constants/chat';
|
||||||
import { AppTypeEnum } from '@/constants/app';
|
import { AppTypeEnum } from '@/constants/app';
|
||||||
import { KbTypeEnum } from '@/constants/kb';
|
import { KbTypeEnum } from '@/constants/dataset';
|
||||||
|
|
||||||
export interface UserModelSchema {
|
export interface UserModelSchema {
|
||||||
_id: string;
|
_id: string;
|
||||||
|
|||||||
61
client/src/types/plugin.d.ts
vendored
61
client/src/types/plugin.d.ts
vendored
@ -1,65 +1,4 @@
|
|||||||
import { FileStatusEnum } from '@/constants/kb';
|
|
||||||
import { VectorModelItemType } from './model';
|
|
||||||
import type { kbSchema } from './mongoSchema';
|
|
||||||
|
|
||||||
export type SelectedKbType = { kbId: string; vectorModel: VectorModelItemType }[];
|
|
||||||
|
|
||||||
export type KbListItemType = Omit<kbSchema, 'vectorModel'> & {
|
|
||||||
vectorModel: VectorModelItemType;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type KbPathItemType = {
|
|
||||||
parentId: string;
|
|
||||||
parentName: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* kb type */
|
|
||||||
export interface KbItemType {
|
|
||||||
_id: string;
|
|
||||||
avatar: string;
|
|
||||||
name: string;
|
|
||||||
userId: string;
|
|
||||||
vectorModel: VectorModelItemType;
|
|
||||||
tags: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type KbFileItemType = {
|
|
||||||
id: string;
|
|
||||||
size: number;
|
|
||||||
filename: string;
|
|
||||||
uploadTime: Date;
|
|
||||||
chunkLength: number;
|
|
||||||
status: `${FileStatusEnum}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DatasetItemType = {
|
|
||||||
q: string; // 提问词
|
|
||||||
a: string; // 原文
|
|
||||||
source?: string;
|
|
||||||
file_id?: string;
|
|
||||||
};
|
|
||||||
export type KbDataItemType = DatasetItemType & {
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type KbTestItemType = {
|
|
||||||
id: string;
|
|
||||||
kbId: string;
|
|
||||||
text: string;
|
|
||||||
time: Date;
|
|
||||||
results: (KbDataItemType & { score: number })[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FetchResultItem = {
|
export type FetchResultItem = {
|
||||||
url: string;
|
url: string;
|
||||||
content: string;
|
content: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FileInfo = {
|
|
||||||
id: string;
|
|
||||||
filename: string;
|
|
||||||
size: number;
|
|
||||||
contentType: string;
|
|
||||||
encoding: string;
|
|
||||||
uploadDate: Date;
|
|
||||||
};
|
|
||||||
|
|||||||
@ -7,14 +7,14 @@ import {
|
|||||||
SpecialInputKeyEnum
|
SpecialInputKeyEnum
|
||||||
} from '@/constants/flow';
|
} from '@/constants/flow';
|
||||||
import { SystemInputEnum } from '@/constants/app';
|
import { SystemInputEnum } from '@/constants/app';
|
||||||
import type { SelectedKbType } from '@/types/plugin';
|
import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||||
import { FlowInputItemType } from '@/types/flow';
|
import { FlowInputItemType } from '@/types/flow';
|
||||||
import type { AIChatProps } from '@/types/core/aiChat';
|
import type { AIChatProps } from '@/types/core/aiChat';
|
||||||
|
|
||||||
export type EditFormType = {
|
export type EditFormType = {
|
||||||
chatModel: AIChatProps;
|
chatModel: AIChatProps;
|
||||||
kb: {
|
kb: {
|
||||||
list: SelectedKbType;
|
list: SelectedDatasetType;
|
||||||
searchSimilarity: number;
|
searchSimilarity: number;
|
||||||
searchLimit: number;
|
searchLimit: number;
|
||||||
searchEmptyText: string;
|
searchEmptyText: string;
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
import { getFileViewUrl } from '@/api/support/file';
|
|
||||||
|
|
||||||
export async function getFileAndOpen(fileId: string) {
|
|
||||||
const url = await getFileViewUrl(fileId);
|
|
||||||
const asPath = `${location.origin}${url}`;
|
|
||||||
window.open(asPath, '_blank');
|
|
||||||
}
|
|
||||||
@ -1,179 +1,6 @@
|
|||||||
import mammoth from 'mammoth';
|
|
||||||
import Papa from 'papaparse';
|
|
||||||
import { getErrText } from './tools';
|
import { getErrText } from './tools';
|
||||||
import { uploadImg, postUploadFiles } from '@/api/support/file';
|
|
||||||
import { countPromptTokens } from './common/tiktoken';
|
import { countPromptTokens } from './common/tiktoken';
|
||||||
|
|
||||||
/**
|
|
||||||
* upload file to mongo gridfs
|
|
||||||
*/
|
|
||||||
export const uploadFiles = (
|
|
||||||
files: File[],
|
|
||||||
metadata: Record<string, any> = {},
|
|
||||||
percentListen?: (percent: number) => void
|
|
||||||
) => {
|
|
||||||
const form = new FormData();
|
|
||||||
form.append('metadata', JSON.stringify(metadata));
|
|
||||||
files.forEach((file) => {
|
|
||||||
form.append('file', file, encodeURIComponent(file.name));
|
|
||||||
});
|
|
||||||
return postUploadFiles(form, (e) => {
|
|
||||||
if (!e.total) return;
|
|
||||||
|
|
||||||
const percent = Math.round((e.loaded / e.total) * 100);
|
|
||||||
percentListen && percentListen(percent);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取 txt 文件内容
|
|
||||||
*/
|
|
||||||
export const readTxtContent = (file: File) => {
|
|
||||||
return new Promise((resolve: (_: string) => void, reject) => {
|
|
||||||
try {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => {
|
|
||||||
resolve(reader.result as string);
|
|
||||||
};
|
|
||||||
reader.onerror = (err) => {
|
|
||||||
console.log('error txt read:', err);
|
|
||||||
reject('读取 txt 文件失败');
|
|
||||||
};
|
|
||||||
reader.readAsText(file);
|
|
||||||
} catch (error) {
|
|
||||||
reject('浏览器不支持文件内容读取');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取 pdf 内容
|
|
||||||
*/
|
|
||||||
export const readPdfContent = (file: File) =>
|
|
||||||
new Promise<string>((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
const pdfjsLib = window['pdfjs-dist/build/pdf'];
|
|
||||||
pdfjsLib.workerSrc = '/js/pdf.worker.js';
|
|
||||||
|
|
||||||
const readPDFPage = async (doc: any, pageNo: number) => {
|
|
||||||
const page = await doc.getPage(pageNo);
|
|
||||||
const tokenizedText = await page.getTextContent();
|
|
||||||
|
|
||||||
const pageText = tokenizedText.items
|
|
||||||
.map((token: any) => token.str)
|
|
||||||
.filter((item: string) => item)
|
|
||||||
.join('');
|
|
||||||
return pageText;
|
|
||||||
};
|
|
||||||
|
|
||||||
let reader = new FileReader();
|
|
||||||
reader.readAsArrayBuffer(file);
|
|
||||||
reader.onload = async (event) => {
|
|
||||||
if (!event?.target?.result) return reject('解析 PDF 失败');
|
|
||||||
try {
|
|
||||||
const doc = await pdfjsLib.getDocument(event.target.result).promise;
|
|
||||||
const pageTextPromises = [];
|
|
||||||
for (let pageNo = 1; pageNo <= doc.numPages; pageNo++) {
|
|
||||||
pageTextPromises.push(readPDFPage(doc, pageNo));
|
|
||||||
}
|
|
||||||
const pageTexts = await Promise.all(pageTextPromises);
|
|
||||||
resolve(pageTexts.join('\n'));
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err, 'pdf load error');
|
|
||||||
reject('解析 PDF 失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.onerror = (err) => {
|
|
||||||
console.log(err, 'pdf load error');
|
|
||||||
reject('解析 PDF 失败');
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
reject('浏览器不支持文件内容读取');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取doc
|
|
||||||
*/
|
|
||||||
export const readDocContent = (file: File) =>
|
|
||||||
new Promise<string>((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsArrayBuffer(file);
|
|
||||||
reader.onload = async ({ target }) => {
|
|
||||||
if (!target?.result) return reject('读取 doc 文件失败');
|
|
||||||
try {
|
|
||||||
const res = await mammoth.extractRawText({
|
|
||||||
arrayBuffer: target.result as ArrayBuffer
|
|
||||||
});
|
|
||||||
resolve(res?.value);
|
|
||||||
} catch (error) {
|
|
||||||
window.umami?.track('wordReadError', {
|
|
||||||
err: error?.toString()
|
|
||||||
});
|
|
||||||
console.log('error doc read:', error);
|
|
||||||
|
|
||||||
reject('读取 doc 文件失败, 请转换成 PDF');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.onerror = (err) => {
|
|
||||||
window.umami?.track('wordReadError', {
|
|
||||||
err: err?.toString()
|
|
||||||
});
|
|
||||||
console.log('error doc read:', err);
|
|
||||||
|
|
||||||
reject('读取 doc 文件失败');
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
reject('浏览器不支持文件内容读取');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取csv
|
|
||||||
*/
|
|
||||||
export const readCsvContent = async (file: File) => {
|
|
||||||
try {
|
|
||||||
const textArr = await readTxtContent(file);
|
|
||||||
const csvArr = Papa.parse(textArr).data as string[][];
|
|
||||||
if (csvArr.length === 0) {
|
|
||||||
throw new Error('csv 解析失败');
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
header: csvArr.shift() as string[],
|
|
||||||
data: csvArr.map((item) => item)
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject('解析 csv 文件失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* file download
|
|
||||||
*/
|
|
||||||
export const fileDownload = ({
|
|
||||||
text,
|
|
||||||
type,
|
|
||||||
filename
|
|
||||||
}: {
|
|
||||||
text: string;
|
|
||||||
type: string;
|
|
||||||
filename: string;
|
|
||||||
}) => {
|
|
||||||
// 导出为文件
|
|
||||||
const blob = new Blob([`\uFEFF${text}`], { type: `${type};charset=utf-8;` });
|
|
||||||
|
|
||||||
// 创建下载链接
|
|
||||||
const downloadLink = document.createElement('a');
|
|
||||||
downloadLink.href = window.URL.createObjectURL(blob);
|
|
||||||
downloadLink.download = filename;
|
|
||||||
|
|
||||||
// 添加链接到页面并触发下载
|
|
||||||
document.body.appendChild(downloadLink);
|
|
||||||
downloadLink.click();
|
|
||||||
document.body.removeChild(downloadLink);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* text split into chunks
|
* text split into chunks
|
||||||
* maxLen - one chunk len. max: 3500
|
* maxLen - one chunk len. max: 3500
|
||||||
@ -217,89 +44,6 @@ export const splitText2Chunks = ({ text, maxLen }: { text: string; maxLen: numbe
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fileToBase64 = (file: File) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
reader.onload = () => resolve(reader.result);
|
|
||||||
reader.onerror = (error) => reject(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* compress image. response base64
|
|
||||||
* @param maxSize The max size of the compressed image
|
|
||||||
*/
|
|
||||||
export const compressImg = ({
|
|
||||||
file,
|
|
||||||
maxW = 200,
|
|
||||||
maxH = 200,
|
|
||||||
maxSize = 1024 * 100
|
|
||||||
}: {
|
|
||||||
file: File;
|
|
||||||
maxW?: number;
|
|
||||||
maxH?: number;
|
|
||||||
maxSize?: number;
|
|
||||||
}) =>
|
|
||||||
new Promise<string>((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
reader.onload = async () => {
|
|
||||||
const img = new Image();
|
|
||||||
// @ts-ignore
|
|
||||||
img.src = reader.result;
|
|
||||||
img.onload = async () => {
|
|
||||||
let width = img.width;
|
|
||||||
let height = img.height;
|
|
||||||
|
|
||||||
if (width > height) {
|
|
||||||
if (width > maxW) {
|
|
||||||
height *= maxW / width;
|
|
||||||
width = maxW;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (height > maxH) {
|
|
||||||
width *= maxH / height;
|
|
||||||
height = maxH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
canvas.width = width;
|
|
||||||
canvas.height = height;
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
|
|
||||||
if (!ctx) {
|
|
||||||
return reject('压缩图片异常');
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.drawImage(img, 0, 0, width, height);
|
|
||||||
const compressedDataUrl = canvas.toDataURL(file.type, 0.8);
|
|
||||||
// 移除 canvas 元素
|
|
||||||
canvas.remove();
|
|
||||||
|
|
||||||
if (compressedDataUrl.length > maxSize) {
|
|
||||||
return reject('图片太大了');
|
|
||||||
}
|
|
||||||
|
|
||||||
const src = await (async () => {
|
|
||||||
try {
|
|
||||||
const src = await uploadImg(compressedDataUrl);
|
|
||||||
return src;
|
|
||||||
} catch (error) {
|
|
||||||
return compressedDataUrl;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
resolve(src);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
reader.onerror = (err) => {
|
|
||||||
console.log(err);
|
|
||||||
reject('压缩图片异常');
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/* simple text, remove chinese space and extra \n */
|
/* simple text, remove chinese space and extra \n */
|
||||||
export const simpleText = (text: string) => {
|
export const simpleText = (text: string) => {
|
||||||
text = text.replace(/([\u4e00-\u9fa5])\s+([\u4e00-\u9fa5])/g, '$1$2');
|
text = text.replace(/([\u4e00-\u9fa5])\s+([\u4e00-\u9fa5])/g, '$1$2');
|
||||||
|
|||||||
@ -1,44 +1,5 @@
|
|||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { useToast } from '@/hooks/useToast';
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* copy text data
|
|
||||||
*/
|
|
||||||
export const useCopyData = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { toast } = useToast();
|
|
||||||
|
|
||||||
return {
|
|
||||||
copyData: async (
|
|
||||||
data: string,
|
|
||||||
title: string | null = t('common.Copy Successful'),
|
|
||||||
duration = 1000
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
if (navigator.clipboard) {
|
|
||||||
await navigator.clipboard.writeText(data);
|
|
||||||
} else {
|
|
||||||
throw new Error('');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const textarea = document.createElement('textarea');
|
|
||||||
textarea.value = data;
|
|
||||||
document.body.appendChild(textarea);
|
|
||||||
textarea.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(textarea);
|
|
||||||
}
|
|
||||||
|
|
||||||
toast({
|
|
||||||
title,
|
|
||||||
status: 'success',
|
|
||||||
duration
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 密码加密
|
* 密码加密
|
||||||
@ -138,35 +99,6 @@ export const formatFileSize = (bytes: number): string => {
|
|||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const hasVoiceApi = typeof window !== 'undefined' && 'speechSynthesis' in window;
|
|
||||||
/**
|
|
||||||
* voice broadcast
|
|
||||||
*/
|
|
||||||
export const voiceBroadcast = ({ text }: { text: string }) => {
|
|
||||||
window.speechSynthesis?.cancel();
|
|
||||||
const msg = new SpeechSynthesisUtterance(text);
|
|
||||||
const voices = window.speechSynthesis?.getVoices?.(); // 获取语言包
|
|
||||||
const voice = voices.find((item) => {
|
|
||||||
return item.name === 'Microsoft Yaoyao - Chinese (Simplified, PRC)';
|
|
||||||
});
|
|
||||||
if (voice) {
|
|
||||||
msg.voice = voice;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.speechSynthesis?.speak(msg);
|
|
||||||
|
|
||||||
msg.onerror = (e) => {
|
|
||||||
console.log(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
cancel: () => window.speechSynthesis?.cancel()
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export const cancelBroadcast = () => {
|
|
||||||
window.speechSynthesis?.cancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getErrText = (err: any, def = '') => {
|
export const getErrText = (err: any, def = '') => {
|
||||||
const msg: string = typeof err === 'string' ? err : err?.message || def || '';
|
const msg: string = typeof err === 'string' ? err : err?.message || def || '';
|
||||||
msg && console.log('error =>', msg);
|
msg && console.log('error =>', msg);
|
||||||
|
|||||||
48
client/src/utils/web/core/dataset.ts
Normal file
48
client/src/utils/web/core/dataset.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { postChunks2Dataset } from '@/api/core/dataset/data';
|
||||||
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
|
import type { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||||
|
import { delay } from '@/utils/tools';
|
||||||
|
|
||||||
|
export async function chunksUpload({
|
||||||
|
kbId,
|
||||||
|
mode,
|
||||||
|
chunks,
|
||||||
|
prompt,
|
||||||
|
rate = 200,
|
||||||
|
onUploading
|
||||||
|
}: {
|
||||||
|
kbId: string;
|
||||||
|
mode: `${TrainingModeEnum}`;
|
||||||
|
chunks: DatasetDataItemType[];
|
||||||
|
prompt?: string;
|
||||||
|
rate?: number;
|
||||||
|
onUploading?: (insertLen: number, total: number) => void;
|
||||||
|
}) {
|
||||||
|
async function upload(data: DatasetDataItemType[]) {
|
||||||
|
return postChunks2Dataset({
|
||||||
|
kbId,
|
||||||
|
data,
|
||||||
|
mode,
|
||||||
|
prompt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let successInsert = 0;
|
||||||
|
let retryTimes = 10;
|
||||||
|
for (let i = 0; i < chunks.length; i += rate) {
|
||||||
|
try {
|
||||||
|
const { insertLen } = await upload(chunks.slice(i, i + rate));
|
||||||
|
onUploading && onUploading(i + rate, chunks.length);
|
||||||
|
successInsert += insertLen;
|
||||||
|
} catch (error) {
|
||||||
|
if (retryTimes === 0) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
await delay(1000);
|
||||||
|
retryTimes--;
|
||||||
|
i -= rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { insertLen: successInsert };
|
||||||
|
}
|
||||||
261
client/src/utils/web/file.ts
Normal file
261
client/src/utils/web/file.ts
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
import mammoth from 'mammoth';
|
||||||
|
import Papa from 'papaparse';
|
||||||
|
import { uploadImg, postUploadFiles, getFileViewUrl } from '@/api/support/file';
|
||||||
|
/**
|
||||||
|
* upload file to mongo gridfs
|
||||||
|
*/
|
||||||
|
export const uploadFiles = (
|
||||||
|
files: File[],
|
||||||
|
metadata: Record<string, any> = {},
|
||||||
|
percentListen?: (percent: number) => void
|
||||||
|
) => {
|
||||||
|
const form = new FormData();
|
||||||
|
form.append('metadata', JSON.stringify(metadata));
|
||||||
|
files.forEach((file) => {
|
||||||
|
form.append('file', file, encodeURIComponent(file.name));
|
||||||
|
});
|
||||||
|
return postUploadFiles(form, (e) => {
|
||||||
|
if (!e.total) return;
|
||||||
|
|
||||||
|
const percent = Math.round((e.loaded / e.total) * 100);
|
||||||
|
percentListen && percentListen(percent);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 txt 文件内容
|
||||||
|
*/
|
||||||
|
export const readTxtContent = (file: File) => {
|
||||||
|
return new Promise((resolve: (_: string) => void, reject) => {
|
||||||
|
try {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
resolve(reader.result as string);
|
||||||
|
};
|
||||||
|
reader.onerror = (err) => {
|
||||||
|
console.log('error txt read:', err);
|
||||||
|
reject('读取 txt 文件失败');
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
} catch (error) {
|
||||||
|
reject('浏览器不支持文件内容读取');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 pdf 内容
|
||||||
|
*/
|
||||||
|
export const readPdfContent = (file: File) =>
|
||||||
|
new Promise<string>((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const pdfjsLib = window['pdfjs-dist/build/pdf'];
|
||||||
|
pdfjsLib.workerSrc = '/js/pdf.worker.js';
|
||||||
|
|
||||||
|
const readPDFPage = async (doc: any, pageNo: number) => {
|
||||||
|
const page = await doc.getPage(pageNo);
|
||||||
|
const tokenizedText = await page.getTextContent();
|
||||||
|
|
||||||
|
const pageText = tokenizedText.items
|
||||||
|
.map((token: any) => token.str)
|
||||||
|
.filter((item: string) => item)
|
||||||
|
.join('');
|
||||||
|
return pageText;
|
||||||
|
};
|
||||||
|
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
reader.onload = async (event) => {
|
||||||
|
if (!event?.target?.result) return reject('解析 PDF 失败');
|
||||||
|
try {
|
||||||
|
const doc = await pdfjsLib.getDocument(event.target.result).promise;
|
||||||
|
const pageTextPromises = [];
|
||||||
|
for (let pageNo = 1; pageNo <= doc.numPages; pageNo++) {
|
||||||
|
pageTextPromises.push(readPDFPage(doc, pageNo));
|
||||||
|
}
|
||||||
|
const pageTexts = await Promise.all(pageTextPromises);
|
||||||
|
resolve(pageTexts.join('\n'));
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err, 'pdf load error');
|
||||||
|
reject('解析 PDF 失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.onerror = (err) => {
|
||||||
|
console.log(err, 'pdf load error');
|
||||||
|
reject('解析 PDF 失败');
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
reject('浏览器不支持文件内容读取');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取doc
|
||||||
|
*/
|
||||||
|
export const readDocContent = (file: File) =>
|
||||||
|
new Promise<string>((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
reader.onload = async ({ target }) => {
|
||||||
|
if (!target?.result) return reject('读取 doc 文件失败');
|
||||||
|
try {
|
||||||
|
const res = await mammoth.extractRawText({
|
||||||
|
arrayBuffer: target.result as ArrayBuffer
|
||||||
|
});
|
||||||
|
resolve(res?.value);
|
||||||
|
} catch (error) {
|
||||||
|
window.umami?.track('wordReadError', {
|
||||||
|
err: error?.toString()
|
||||||
|
});
|
||||||
|
console.log('error doc read:', error);
|
||||||
|
|
||||||
|
reject('读取 doc 文件失败, 请转换成 PDF');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.onerror = (err) => {
|
||||||
|
window.umami?.track('wordReadError', {
|
||||||
|
err: err?.toString()
|
||||||
|
});
|
||||||
|
console.log('error doc read:', err);
|
||||||
|
|
||||||
|
reject('读取 doc 文件失败');
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
reject('浏览器不支持文件内容读取');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取csv
|
||||||
|
*/
|
||||||
|
export const readCsvContent = async (file: File) => {
|
||||||
|
try {
|
||||||
|
const textArr = await readTxtContent(file);
|
||||||
|
const csvArr = Papa.parse(textArr).data as string[][];
|
||||||
|
if (csvArr.length === 0) {
|
||||||
|
throw new Error('csv 解析失败');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
header: csvArr.shift() as string[],
|
||||||
|
data: csvArr.map((item) => item)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return Promise.reject('解析 csv 文件失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* file download
|
||||||
|
*/
|
||||||
|
export const fileDownload = ({
|
||||||
|
text,
|
||||||
|
type,
|
||||||
|
filename
|
||||||
|
}: {
|
||||||
|
text: string;
|
||||||
|
type: string;
|
||||||
|
filename: string;
|
||||||
|
}) => {
|
||||||
|
// 导出为文件
|
||||||
|
const blob = new Blob([`\uFEFF${text}`], { type: `${type};charset=utf-8;` });
|
||||||
|
|
||||||
|
// 创建下载链接
|
||||||
|
const downloadLink = document.createElement('a');
|
||||||
|
downloadLink.href = window.URL.createObjectURL(blob);
|
||||||
|
downloadLink.download = filename;
|
||||||
|
|
||||||
|
// 添加链接到页面并触发下载
|
||||||
|
document.body.appendChild(downloadLink);
|
||||||
|
downloadLink.click();
|
||||||
|
document.body.removeChild(downloadLink);
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getFileAndOpen(fileId: string) {
|
||||||
|
const url = await getFileViewUrl(fileId);
|
||||||
|
const asPath = `${location.origin}${url}`;
|
||||||
|
window.open(asPath, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fileToBase64 = (file: File) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.onload = () => resolve(reader.result);
|
||||||
|
reader.onerror = (error) => reject(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compress image. response base64
|
||||||
|
* @param maxSize The max size of the compressed image
|
||||||
|
*/
|
||||||
|
export const compressImg = ({
|
||||||
|
file,
|
||||||
|
maxW = 200,
|
||||||
|
maxH = 200,
|
||||||
|
maxSize = 1024 * 100
|
||||||
|
}: {
|
||||||
|
file: File;
|
||||||
|
maxW?: number;
|
||||||
|
maxH?: number;
|
||||||
|
maxSize?: number;
|
||||||
|
}) =>
|
||||||
|
new Promise<string>((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.onload = async () => {
|
||||||
|
const img = new Image();
|
||||||
|
// @ts-ignore
|
||||||
|
img.src = reader.result;
|
||||||
|
img.onload = async () => {
|
||||||
|
let width = img.width;
|
||||||
|
let height = img.height;
|
||||||
|
|
||||||
|
if (width > height) {
|
||||||
|
if (width > maxW) {
|
||||||
|
height *= maxW / width;
|
||||||
|
width = maxW;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (height > maxH) {
|
||||||
|
width *= maxH / height;
|
||||||
|
height = maxH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return reject('压缩图片异常');
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.drawImage(img, 0, 0, width, height);
|
||||||
|
const compressedDataUrl = canvas.toDataURL(file.type, 0.8);
|
||||||
|
// 移除 canvas 元素
|
||||||
|
canvas.remove();
|
||||||
|
|
||||||
|
if (compressedDataUrl.length > maxSize) {
|
||||||
|
return reject('图片太大了');
|
||||||
|
}
|
||||||
|
|
||||||
|
const src = await (async () => {
|
||||||
|
try {
|
||||||
|
const src = await uploadImg(compressedDataUrl);
|
||||||
|
return src;
|
||||||
|
} catch (error) {
|
||||||
|
return compressedDataUrl;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
resolve(src);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
reader.onerror = (err) => {
|
||||||
|
console.log(err);
|
||||||
|
reject('压缩图片异常');
|
||||||
|
};
|
||||||
|
});
|
||||||
28
client/src/utils/web/voice.ts
Normal file
28
client/src/utils/web/voice.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
export const hasVoiceApi = typeof window !== 'undefined' && 'speechSynthesis' in window;
|
||||||
|
/**
|
||||||
|
* voice broadcast
|
||||||
|
*/
|
||||||
|
export const voiceBroadcast = ({ text }: { text: string }) => {
|
||||||
|
window.speechSynthesis?.cancel();
|
||||||
|
const msg = new SpeechSynthesisUtterance(text);
|
||||||
|
const voices = window.speechSynthesis?.getVoices?.(); // 获取语言包
|
||||||
|
const voice = voices.find((item) => {
|
||||||
|
return item.name === 'Microsoft Yaoyao - Chinese (Simplified, PRC)';
|
||||||
|
});
|
||||||
|
if (voice) {
|
||||||
|
msg.voice = voice;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.speechSynthesis?.speak(msg);
|
||||||
|
|
||||||
|
msg.onerror = (e) => {
|
||||||
|
console.log(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
cancel: () => window.speechSynthesis?.cancel()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export const cancelBroadcast = () => {
|
||||||
|
window.speechSynthesis?.cancel();
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user