mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
Update docs and response tag in share page (#694)
* perf: chunk index show * share response * perf: vector query * web printFinger * remove log * fix: bucket name * perf: training schema * perf: sort index
This commit is contained in:
@@ -522,9 +522,13 @@
|
||||
},
|
||||
"score": {
|
||||
"embedding": "Embedding",
|
||||
"embedding desc": "",
|
||||
"fullText": "Full text",
|
||||
"fullText desc": "",
|
||||
"reRank": "ReRank",
|
||||
"rrf": "RRF Merge"
|
||||
"reRank desc": "",
|
||||
"rrf": "RRF Merge",
|
||||
"rrf desc": ""
|
||||
},
|
||||
"search mode": "Search Mode"
|
||||
},
|
||||
@@ -874,8 +878,6 @@
|
||||
"QPM": "QPM",
|
||||
"QPM Tips": "The maximum number of queries per IP address per minute",
|
||||
"QPM is empty": "QPM is empty",
|
||||
"Response Detail": "Quote",
|
||||
"Response Detail tips": "Whether detailed data such as references to be returned",
|
||||
"token auth": "Token Auth",
|
||||
"token auth Tips": "Identity verification server address. If this value is set, the server will be specified to send a request for identity verification before each session",
|
||||
"token auth use cases": "Review the authentication instructions"
|
||||
@@ -903,6 +905,12 @@
|
||||
"Update Your Plugin": "Update Plugin"
|
||||
},
|
||||
"support": {
|
||||
"outlink": {
|
||||
"share": {
|
||||
"Response Quote": "Show Quote",
|
||||
"Response Quote tips": "The referenced content is returned in the share link, but the user is not allowed to download the original document."
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"Price": "Price",
|
||||
"auth": {
|
||||
|
@@ -878,8 +878,6 @@
|
||||
"QPM": "",
|
||||
"QPM Tips": "每个 IP 每分钟最多提问多少次",
|
||||
"QPM is empty": "QPM 不能为空",
|
||||
"Response Detail": "返回详情",
|
||||
"Response Detail tips": "是否需要返回详情(引用内容,调用时间等,不会返回预设提示词和完整上下文)",
|
||||
"token auth": "身份验证",
|
||||
"token auth Tips": "身份校验服务器地址,如填写该值,每次对话前都会向指定服务器发送一个请求,进行身份校验",
|
||||
"token auth use cases": "查看身份验证使用说明"
|
||||
@@ -907,6 +905,12 @@
|
||||
"Update Your Plugin": "更新插件"
|
||||
},
|
||||
"support": {
|
||||
"outlink": {
|
||||
"share": {
|
||||
"Response Quote": "返回引用",
|
||||
"Response Quote tips": "在分享链接中返回引用内容,但不会允许用户下载原文档"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"Price": "计费标准",
|
||||
"auth": {
|
||||
|
@@ -133,72 +133,69 @@ const ResponseTags = ({
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
<Flex alignItems={'center'} mt={3} flexWrap={'wrap'}>
|
||||
{quoteList.length > 0 && (
|
||||
<MyTooltip label="查看引用">
|
||||
<Tag
|
||||
colorSchema="blue"
|
||||
cursor={'pointer'}
|
||||
{...TagStyles}
|
||||
onClick={() => setQuoteModalData({ rawSearch: quoteList })}
|
||||
>
|
||||
{quoteList.length}条引用
|
||||
{!isShare && (
|
||||
<Flex alignItems={'center'} mt={3} flexWrap={'wrap'}>
|
||||
{quoteList.length > 0 && (
|
||||
<MyTooltip label="查看引用">
|
||||
<Tag
|
||||
colorSchema="blue"
|
||||
cursor={'pointer'}
|
||||
{...TagStyles}
|
||||
onClick={() => setQuoteModalData({ rawSearch: quoteList })}
|
||||
>
|
||||
{quoteList.length}条引用
|
||||
</Tag>
|
||||
</MyTooltip>
|
||||
)}
|
||||
{chatAccount === 1 && (
|
||||
<>
|
||||
{historyPreview.length > 0 && (
|
||||
<MyTooltip label={'点击查看完整对话记录'}>
|
||||
<Tag
|
||||
colorSchema="green"
|
||||
cursor={'pointer'}
|
||||
{...TagStyles}
|
||||
onClick={() => setContextModalData(historyPreview)}
|
||||
>
|
||||
{historyPreview.length}条上下文
|
||||
</Tag>
|
||||
</MyTooltip>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{chatAccount > 1 && (
|
||||
<Tag colorSchema="blue" {...TagStyles}>
|
||||
多组 AI 对话
|
||||
</Tag>
|
||||
)}
|
||||
|
||||
{isPc && runningTime > 0 && (
|
||||
<MyTooltip label={'模块运行时间和'}>
|
||||
<Tag colorSchema="purple" cursor={'default'} {...TagStyles}>
|
||||
{runningTime}s
|
||||
</Tag>
|
||||
</MyTooltip>
|
||||
)}
|
||||
<MyTooltip label={t('core.chat.response.Read complete response tips')}>
|
||||
<Tag colorSchema="gray" cursor={'pointer'} {...TagStyles} onClick={onOpenWholeModal}>
|
||||
{t('core.chat.response.Read complete response')}
|
||||
</Tag>
|
||||
</MyTooltip>
|
||||
)}
|
||||
{chatAccount === 1 && (
|
||||
<>
|
||||
{historyPreview.length > 0 && (
|
||||
<MyTooltip label={'点击查看完整对话记录'}>
|
||||
<Tag
|
||||
colorSchema="green"
|
||||
cursor={'pointer'}
|
||||
{...TagStyles}
|
||||
onClick={() => setContextModalData(historyPreview)}
|
||||
>
|
||||
{historyPreview.length}条上下文
|
||||
</Tag>
|
||||
</MyTooltip>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{chatAccount > 1 && (
|
||||
<Tag colorSchema="blue" {...TagStyles}>
|
||||
多组 AI 对话
|
||||
</Tag>
|
||||
)}
|
||||
|
||||
{isPc && runningTime > 0 && (
|
||||
<MyTooltip label={'模块运行时间和'}>
|
||||
<Tag colorSchema="purple" cursor={'default'} {...TagStyles}>
|
||||
{runningTime}s
|
||||
</Tag>
|
||||
</MyTooltip>
|
||||
)}
|
||||
<MyTooltip label={t('core.chat.response.Read complete response tips')}>
|
||||
<Tag colorSchema="gray" cursor={'pointer'} {...TagStyles} onClick={onOpenWholeModal}>
|
||||
{t('core.chat.response.Read complete response')}
|
||||
</Tag>
|
||||
</MyTooltip>
|
||||
|
||||
{!!quoteModalData && (
|
||||
<QuoteModal
|
||||
{...quoteModalData}
|
||||
isShare={isShare}
|
||||
onClose={() => setQuoteModalData(undefined)}
|
||||
/>
|
||||
)}
|
||||
{!!contextModalData && (
|
||||
<ContextModal context={contextModalData} onClose={() => setContextModalData(undefined)} />
|
||||
)}
|
||||
{isOpenWholeModal && (
|
||||
<WholeResponseModal
|
||||
response={responseData}
|
||||
isShare={isShare}
|
||||
onClose={onCloseWholeModal}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{!!quoteModalData && (
|
||||
<QuoteModal
|
||||
{...quoteModalData}
|
||||
isShare={isShare}
|
||||
onClose={() => setQuoteModalData(undefined)}
|
||||
/>
|
||||
)}
|
||||
{!!contextModalData && (
|
||||
<ContextModal context={contextModalData} onClose={() => setContextModalData(undefined)} />
|
||||
)}
|
||||
{isOpenWholeModal && (
|
||||
<WholeResponseModal response={responseData} isShare={isShare} onClose={onCloseWholeModal} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -126,63 +126,88 @@ const QuoteItem = ({
|
||||
>
|
||||
<Flex alignItems={'center'} mb={3}>
|
||||
{score?.primaryScore && (
|
||||
<MyTooltip label={t(SearchScoreTypeMap[score.primaryScore.type]?.desc)}>
|
||||
<Flex
|
||||
px={'12px'}
|
||||
py={'5px'}
|
||||
mr={4}
|
||||
borderRadius={'md'}
|
||||
color={'primary.700'}
|
||||
bg={'primary.50'}
|
||||
borderWidth={'1px'}
|
||||
borderColor={'primary.200'}
|
||||
alignItems={'center'}
|
||||
fontSize={'sm'}
|
||||
>
|
||||
<Box>#{score.primaryScore.index + 1}</Box>
|
||||
<Box borderRightColor={'primary.700'} borderRightWidth={'1px'} h={'14px'} mx={2} />
|
||||
<Box>
|
||||
{t(SearchScoreTypeMap[score.primaryScore.type]?.label)}
|
||||
{SearchScoreTypeMap[score.primaryScore.type]?.showScore
|
||||
? ` ${score.primaryScore.value.toFixed(4)}`
|
||||
: ''}
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
)}
|
||||
{score.secondaryScore.map((item, i) => (
|
||||
<MyTooltip key={item.type} label={t(SearchScoreTypeMap[item.type]?.desc)}>
|
||||
<Box fontSize={'xs'} mr={3}>
|
||||
<Flex alignItems={'flex-start'} lineHeight={1.2} mb={1}>
|
||||
<Box
|
||||
px={'5px'}
|
||||
<>
|
||||
{canViewSource ? (
|
||||
<MyTooltip label={t(SearchScoreTypeMap[score.primaryScore.type]?.desc)}>
|
||||
<Flex
|
||||
px={'12px'}
|
||||
py={'5px'}
|
||||
mr={4}
|
||||
borderRadius={'md'}
|
||||
color={'primary.700'}
|
||||
bg={'primary.50'}
|
||||
borderWidth={'1px'}
|
||||
borderRadius={'sm'}
|
||||
mr={1}
|
||||
{...(scoreTheme[i] && scoreTheme[i])}
|
||||
borderColor={'primary.200'}
|
||||
alignItems={'center'}
|
||||
fontSize={'sm'}
|
||||
>
|
||||
<Box transform={'scale(0.9)'}>#{item.index + 1}</Box>
|
||||
</Box>
|
||||
<Box transform={'scale(0.9)'}>
|
||||
{t(SearchScoreTypeMap[item.type]?.label)}: {item.value.toFixed(4)}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Box h={'4px'}>
|
||||
{SearchScoreTypeMap[item.type]?.showScore && (
|
||||
<Progress
|
||||
value={item.value * 100}
|
||||
h={'4px'}
|
||||
w={'100%'}
|
||||
size="sm"
|
||||
borderRadius={'20px'}
|
||||
colorScheme={scoreTheme[i]?.colorSchema}
|
||||
bg="#E8EBF0"
|
||||
<Box>#{score.primaryScore.index + 1}</Box>
|
||||
<Box
|
||||
borderRightColor={'primary.700'}
|
||||
borderRightWidth={'1px'}
|
||||
h={'14px'}
|
||||
mx={2}
|
||||
/>
|
||||
)}
|
||||
<Box>
|
||||
{t(SearchScoreTypeMap[score.primaryScore.type]?.label)}
|
||||
{SearchScoreTypeMap[score.primaryScore.type]?.showScore
|
||||
? ` ${score.primaryScore.value.toFixed(4)}`
|
||||
: ''}
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
) : (
|
||||
<Flex
|
||||
px={'12px'}
|
||||
py={'1px'}
|
||||
mr={4}
|
||||
borderRadius={'md'}
|
||||
color={'primary.700'}
|
||||
bg={'primary.50'}
|
||||
borderWidth={'1px'}
|
||||
borderColor={'primary.200'}
|
||||
alignItems={'center'}
|
||||
fontSize={'sm'}
|
||||
>
|
||||
<Box>#{score.primaryScore.index + 1}</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{canViewSource &&
|
||||
score.secondaryScore.map((item, i) => (
|
||||
<MyTooltip key={item.type} label={t(SearchScoreTypeMap[item.type]?.desc)}>
|
||||
<Box fontSize={'xs'} mr={3}>
|
||||
<Flex alignItems={'flex-start'} lineHeight={1.2} mb={1}>
|
||||
<Box
|
||||
px={'5px'}
|
||||
borderWidth={'1px'}
|
||||
borderRadius={'sm'}
|
||||
mr={1}
|
||||
{...(scoreTheme[i] && scoreTheme[i])}
|
||||
>
|
||||
<Box transform={'scale(0.9)'}>#{item.index + 1}</Box>
|
||||
</Box>
|
||||
<Box transform={'scale(0.9)'}>
|
||||
{t(SearchScoreTypeMap[item.type]?.label)}: {item.value.toFixed(4)}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Box h={'4px'}>
|
||||
{SearchScoreTypeMap[item.type]?.showScore && (
|
||||
<Progress
|
||||
value={item.value * 100}
|
||||
h={'4px'}
|
||||
w={'100%'}
|
||||
size="sm"
|
||||
borderRadius={'20px'}
|
||||
colorScheme={scoreTheme[i]?.colorSchema}
|
||||
bg="#E8EBF0"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</MyTooltip>
|
||||
))}
|
||||
</MyTooltip>
|
||||
))}
|
||||
</Flex>
|
||||
|
||||
<Box flex={'1 0 0'}>
|
||||
|
@@ -28,5 +28,6 @@ export type DatasetDataListItemType = {
|
||||
collectionId: string;
|
||||
q: string; // embedding content
|
||||
a: string; // bonus content
|
||||
chunkIndex?: number;
|
||||
indexes: DatasetDataSchemaType['indexes'];
|
||||
};
|
||||
|
@@ -32,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
};
|
||||
|
||||
const [data, total] = await Promise.all([
|
||||
MongoDatasetData.find(match, '_id datasetId collectionId q a indexes')
|
||||
MongoDatasetData.find(match, '_id datasetId collectionId q a chunkIndex indexes')
|
||||
.sort({ chunkIndex: 1, updateTime: -1 })
|
||||
.skip((pageNum - 1) * pageSize)
|
||||
.limit(pageSize)
|
||||
|
@@ -10,6 +10,7 @@ import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
|
||||
import { getBillSourceByAuthType } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
|
||||
type Props = GetVectorProps & {
|
||||
input: string | string[];
|
||||
billId?: string;
|
||||
};
|
||||
|
||||
@@ -22,6 +23,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
throw new Error('input is nor array or string');
|
||||
}
|
||||
|
||||
const query = Array.isArray(input) ? input[0] : input;
|
||||
|
||||
const { teamId, tmbId, apikey, authType } = await authCert({
|
||||
req,
|
||||
authToken: true,
|
||||
@@ -30,7 +33,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
|
||||
await authTeamBalance(teamId);
|
||||
|
||||
const { tokens, vectors } = await getVectorsByText({ input, model });
|
||||
const { tokens, vectors } = await getVectorsByText({ input: query, model });
|
||||
|
||||
jsonRes(res, {
|
||||
data: {
|
||||
|
@@ -96,7 +96,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
<Tr>
|
||||
<Th>名称</Th>
|
||||
<Th>金额消耗</Th>
|
||||
<Th>返回详情</Th>
|
||||
<Th>返回引用</Th>
|
||||
{feConfigs?.isPlus && (
|
||||
<>
|
||||
<Th>IP限流(人/分钟)</Th>
|
||||
@@ -373,8 +373,8 @@ function EditLinkModal({
|
||||
|
||||
<Flex alignItems={'center'} mt={4}>
|
||||
<Flex flex={'0 0 90px'} alignItems={'center'}>
|
||||
{t('outlink.Response Detail')}
|
||||
<MyTooltip label={t('outlink.Response Detail tips' || '')}>
|
||||
{t('support.outlink.share.Response Quote')}
|
||||
<MyTooltip label={t('support.outlink.share.Response Quote tips' || '')}>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
|
@@ -307,7 +307,7 @@ const DataCard = () => {
|
||||
>
|
||||
<Flex zIndex={1} alignItems={'center'} justifyContent={'space-between'}>
|
||||
<Box border={theme.borders.base} px={2} fontSize={'sm'} mr={1} borderRadius={'md'}>
|
||||
# {index + 1}
|
||||
# {item.chunkIndex ?? '-'}
|
||||
</Box>
|
||||
<Box className={'textEllipsis'} color={'myGray.500'} fontSize={'xs'}>
|
||||
ID:{item._id}
|
||||
|
@@ -295,7 +295,7 @@ export async function searchDatasetData(props: {
|
||||
const embeddingRecall = async ({ query, limit }: { query: string; limit: number }) => {
|
||||
const { vectors, tokens } = await getVectorsByText({
|
||||
model,
|
||||
input: [query]
|
||||
input: query
|
||||
});
|
||||
|
||||
const { results } = await recallFromVectorStore({
|
||||
|
@@ -26,6 +26,8 @@ export async function generateVector(): Promise<any> {
|
||||
if (global.vectorQueueLen >= global.systemEnv.vectorMaxProcess) return;
|
||||
global.vectorQueueLen++;
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
// get training data
|
||||
const {
|
||||
data,
|
||||
@@ -154,6 +156,8 @@ export async function generateVector(): Promise<any> {
|
||||
await MongoDatasetTraining.findByIdAndDelete(data._id);
|
||||
reduceQueue();
|
||||
generateVector();
|
||||
|
||||
console.log(`embedding finished, time: ${Date.now() - start}ms`);
|
||||
} catch (err: any) {
|
||||
reduceQueue(true);
|
||||
// log
|
||||
|
@@ -1,26 +1,23 @@
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
|
||||
export function selectShareResponse({
|
||||
export const selectShareResponse = ({
|
||||
responseData = []
|
||||
}: {
|
||||
responseData?: ChatHistoryItemResType[];
|
||||
}) {
|
||||
const filedList = [
|
||||
'moduleType',
|
||||
'moduleName',
|
||||
'moduleLogo',
|
||||
'runningTime',
|
||||
'quoteList',
|
||||
'question'
|
||||
];
|
||||
return responseData.map((item) => {
|
||||
const obj: Record<string, any> = {};
|
||||
for (let key in item) {
|
||||
if (filedList.includes(key)) {
|
||||
// @ts-ignore
|
||||
obj[key] = item[key];
|
||||
}) => {
|
||||
const filedList = ['quoteList', 'moduleType'];
|
||||
const filterModuleTypeList: any[] = [FlowNodeTypeEnum.chatNode];
|
||||
return responseData
|
||||
.filter((item) => filterModuleTypeList.includes(item.moduleType))
|
||||
.map((item) => {
|
||||
const obj: Record<string, any> = {};
|
||||
for (let key in item) {
|
||||
if (filedList.includes(key)) {
|
||||
// @ts-ignore
|
||||
obj[key] = item[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj as ChatHistoryItemResType;
|
||||
});
|
||||
}
|
||||
return obj as ChatHistoryItemResType;
|
||||
});
|
||||
};
|
||||
|
Reference in New Issue
Block a user