perf: outlink config (#3128)

* update action

* perf: outlink config
This commit is contained in:
Archer 2024-11-12 15:56:53 +08:00 committed by archer
parent 73d28d1fc3
commit 5e273341dd
No known key found for this signature in database
GPG Key ID: 4446499B846D4A9E
38 changed files with 469 additions and 537 deletions

View File

@ -160,7 +160,7 @@ jobs:
docker buildx build \
-f projects/app/Dockerfile \
--platform linux/amd64,linux/arm64 \
--build-arg base_url=fastai \
--build-arg base_url=/fastai \
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
--label "org.opencontainers.image.description=fastgpt image" \
--push \

View File

@ -90,6 +90,7 @@ export const chats2GPTMessages = ({
}
} else {
const aiResults: ChatCompletionMessageParam[] = [];
//AI
item.value.forEach((value, i) => {
if (value.type === ChatItemValueTypeEnum.tool && value.tools && reserveTool) {
@ -130,7 +131,7 @@ export const chats2GPTMessages = ({
if (
lastValue &&
lastValue.type === ChatItemValueTypeEnum.text &&
typeof lastResult.content === 'string'
typeof lastResult?.content === 'string'
) {
lastResult.content += value.text.content;
} else {

View File

@ -10,7 +10,3 @@ export type AuthOutLinkLimitProps = AuthOutLinkChatProps & { outLink: OutLinkSch
export type AuthOutLinkResponse = {
uid: string;
};
export type AuthOutLinkProps = {
shareId?: string;
outLinkUid?: string;
};

View File

@ -54,7 +54,7 @@ export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
// whether to hide the node status
showNodeStatus: boolean;
// whether to show the complete quote
showCompleteQuote: boolean;
showRawSource: boolean;
// response when request
immediateResponse?: string;
@ -84,7 +84,7 @@ export type OutLinkEditType<T = undefined> = {
name: string;
responseDetail?: OutLinkSchema<T>['responseDetail'];
showNodeStatus?: OutLinkSchema<T>['showNodeStatus'];
showCompleteQuote?: OutLinkSchema<T>['showCompleteQuote'];
showRawSource?: OutLinkSchema<T>['showRawSource'];
// response when request
immediateResponse?: string;
// response when error or other situation

View File

@ -89,7 +89,7 @@ try {
// get chat logs;
ChatSchema.index({ teamId: 1, appId: 1, updateTime: -1 }, { background: true });
// get share chat history
ChatSchema.index({ shareId: 1, outLinkUid: 1, updateTime: -1, source: 1 }, { background: true });
ChatSchema.index({ shareId: 1, outLinkUid: 1, updateTime: -1 }, { background: true });
// timer, clear history
ChatSchema.index({ teamId: 1, updateTime: -1 }, { background: true });

View File

@ -42,27 +42,27 @@ export const getWorkflowResponseWrite = ({
if (!res || res.closed || !useStreamResponse) return;
const detailEvent = [
SseResponseEventEnum.error,
SseResponseEventEnum.flowNodeStatus,
SseResponseEventEnum.flowResponses,
SseResponseEventEnum.interactive,
SseResponseEventEnum.toolCall,
SseResponseEventEnum.toolParams,
SseResponseEventEnum.toolResponse,
SseResponseEventEnum.updateVariables
];
// Forbid show detail
const detailEvent: Record<string, 1> = {
[SseResponseEventEnum.error]: 1,
[SseResponseEventEnum.flowNodeStatus]: 1,
[SseResponseEventEnum.flowResponses]: 1,
[SseResponseEventEnum.interactive]: 1,
[SseResponseEventEnum.toolCall]: 1,
[SseResponseEventEnum.toolParams]: 1,
[SseResponseEventEnum.toolResponse]: 1,
[SseResponseEventEnum.updateVariables]: 1
};
if (!detail && detailEvent[event]) return;
if (!detail && detailEvent.includes(event)) return;
if (
!showNodeStatus &&
(event === SseResponseEventEnum.flowNodeStatus ||
event === SseResponseEventEnum.toolCall ||
event === SseResponseEventEnum.toolParams ||
event === SseResponseEventEnum.toolResponse)
)
return;
// Forbid show running status
const statusEvent: Record<string, 1> = {
[SseResponseEventEnum.flowNodeStatus]: 1,
[SseResponseEventEnum.toolCall]: 1,
[SseResponseEventEnum.toolParams]: 1,
[SseResponseEventEnum.toolResponse]: 1
};
if (!showNodeStatus && statusEvent[event]) return;
responseWrite({
res,

View File

@ -42,6 +42,7 @@ const OutLinkSchema = new Schema({
lastTime: {
type: Date
},
responseDetail: {
type: Boolean,
default: false
@ -50,7 +51,7 @@ const OutLinkSchema = new Schema({
type: Boolean,
default: false
},
showCompleteQuote: {
showRawSource: {
type: Boolean,
default: false
},
@ -70,6 +71,8 @@ const OutLinkSchema = new Schema({
type: String
}
},
// Third part app config
app: {
type: Object // could be FeishuAppType | WecomAppType | ...
},

View File

@ -20,6 +20,7 @@
"official_account.edit_modal_title": "Edit WeChat Official Account Integration",
"official_account.name": "WeChat Official Account Integration",
"official_account.params": "WeChat Official Account Parameters",
"private_config": "Visibility configuration",
"publish_name": "Name",
"qpm_is_empty": "QPM cannot be empty",
"qpm_tips": "Maximum number of queries per minute per IP",

View File

@ -28,7 +28,7 @@
"insert_input_guide,_some_data_already_exists": "有重复数据,已自动过滤,共插入 {{len}} 条数据",
"is_chatting": "正在聊天中...请等待结束",
"items": "条",
"module_runtime_and": "模块运行时间和",
"module_runtime_and": "工作流总运行时间",
"multiple_AI_conversations": "多组 AI 对话",
"new_input_guide_lexicon": "新词库",
"no_workflow_response": "没有运行数据",

View File

@ -20,10 +20,14 @@
"official_account.edit_modal_title": "编辑微信公众号接入",
"official_account.name": "微信公众号接入",
"official_account.params": "微信公众号参数",
"private_config": "可见度配置",
"publish_name": "名称",
"qpm_is_empty": "QPM 不能为空",
"qpm_tips": "每个 IP 每分钟最多提问多少次",
"quote_content": "知识库引用",
"request_address": "请求地址",
"show_node": "实时运行状态",
"show_origin_content": "查看来源原文",
"show_share_link_modal_title": "开始使用",
"token_auth": "身份验证",
"token_auth_tips": "身份校验服务器地址",
@ -33,8 +37,5 @@
"wecom.bot_desc": "通过 API 直接接入企业微信机器人",
"wecom.create_modal_title": "创建企微机器人",
"wecom.edit_modal_title": "编辑企微机器人",
"wecom.title": "发布到企业微信机器人",
"show_node": "实时运行状态",
"quote_content": "引用内容",
"show_origin_content": "查看来源原文"
"wecom.title": "发布到企业微信机器人"
}

View File

@ -34,7 +34,9 @@ export type ChatProviderProps = OutLinkChatAuthProps & {
// not chat test params
chatId?: string;
chatType?: 'log' | 'chat' | 'share' | 'team';
chatType: 'log' | 'chat' | 'share' | 'team';
showRawSource: boolean;
showNodeStatus: boolean;
};
type useChatStoreType = OutLinkChatAuthProps &
@ -139,6 +141,8 @@ const Provider = ({
setChatHistories,
variablesForm,
chatType = 'chat',
showRawSource,
showNodeStatus,
chatConfig = {},
children,
...props
@ -241,7 +245,9 @@ const Provider = ({
outLinkAuthData,
variablesForm,
getHistoryResponseData,
chatType
chatType,
showRawSource,
showNodeStatus
};
return <ChatBoxContext.Provider value={value}>{children}</ChatBoxContext.Provider>;

View File

@ -137,7 +137,9 @@ const ChatItem = (props: Props) => {
};
const { t } = useTranslation();
const { isChatting, chatType } = useContextSelector(ChatBoxContext, (v) => v);
const isChatting = useContextSelector(ChatBoxContext, (v) => v.isChatting);
const chatType = useContextSelector(ChatBoxContext, (v) => v.chatType);
const showNodeStatus = useContextSelector(ChatBoxContext, (v) => v.showNodeStatus);
const isChatLog = chatType === 'log';
const { copyData } = useCopyData();
@ -237,7 +239,7 @@ const ChatItem = (props: Props) => {
<ChatAvatar src={avatar} type={type} />
{/* Workflow status */}
{!!chatStatusMap && statusBoxData && isLastChild && (
{!!chatStatusMap && statusBoxData && isLastChild && showNodeStatus && (
<Flex
alignItems={'center'}
px={3}

View File

@ -54,6 +54,7 @@ const ContextModal = ({ onClose, dataId }: { onClose: () => void; dataId: string
border={'base'}
_notLast={{ mb: 2 }}
position={'relative'}
bg={i % 2 === 0 ? 'white' : 'myGray.50'}
>
<Box fontWeight={'bold'}>{item.obj}</Box>
<Box>{item.value}</Box>

View File

@ -11,12 +11,14 @@ import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
const QuoteModal = ({
rawSearch = [],
onClose,
showDetail,
canEditDataset,
showRawSource,
metadata
}: {
rawSearch: SearchDataResponseItemType[];
onClose: () => void;
showDetail: boolean;
canEditDataset: boolean;
showRawSource: boolean;
metadata?: {
collectionId: string;
sourceId?: string;
@ -47,7 +49,7 @@ const QuoteModal = ({
title={
<Box>
{metadata ? (
<RawSourceBox {...metadata} canView={showDetail} />
<RawSourceBox {...metadata} canView={showRawSource} />
) : (
<>{t('common:core.chat.Quote Amount', { amount: rawSearch.length })}</>
)}
@ -58,7 +60,11 @@ const QuoteModal = ({
}
>
<ModalBody>
<QuoteList rawSearch={filterResults} showDetail={showDetail} />
<QuoteList
rawSearch={filterResults}
canEditDataset={canEditDataset}
canViewSource={showRawSource}
/>
</ModalBody>
</MyModal>
</>
@ -69,10 +75,12 @@ export default QuoteModal;
export const QuoteList = React.memo(function QuoteList({
rawSearch = [],
showDetail
canEditDataset,
canViewSource
}: {
rawSearch: SearchDataResponseItemType[];
showDetail: boolean;
canEditDataset: boolean;
canViewSource: boolean;
}) {
const theme = useTheme();
@ -89,7 +97,11 @@ export const QuoteList = React.memo(function QuoteList({
_hover={{ '& .hover-data': { display: 'flex' } }}
bg={i % 2 === 0 ? 'white' : 'myWhite.500'}
>
<QuoteItem quoteItem={item} canViewSource={showDetail} linkToDataset={showDetail} />
<QuoteItem
quoteItem={item}
canViewSource={canViewSource}
canEditDataset={canEditDataset}
/>
</Box>
))}
</>

View File

@ -7,13 +7,11 @@ import MyTag from '@fastgpt/web/components/common/Tag/index';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import ChatBoxDivider from '@/components/core/chat/Divider';
import { strIsLink } from '@fastgpt/global/common/string/tools';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { ChatSiteItemType } from '@fastgpt/global/core/chat/type';
import { addStatisticalDataToHistoryItem } from '@/global/core/chat/utils';
import { useSize } from 'ahooks';
import { ChatContext } from '@/web/core/chat/context/chatContext';
import { useContextSelector } from 'use-context-selector';
import { ChatBoxContext } from '../Provider';
@ -23,11 +21,9 @@ const WholeResponseModal = dynamic(() => import('../../../components/WholeRespon
const ResponseTags = ({
showTags,
showDetail,
historyItem
}: {
showTags: boolean;
showDetail: boolean;
historyItem: ChatSiteItemType;
}) => {
const { isPc } = useSystem();
@ -51,12 +47,9 @@ const ResponseTags = ({
}>();
const [quoteFolded, setQuoteFolded] = useState<boolean>(true);
const showCompleteQuote = useContextSelector(ChatContext, (v) => v.showCompleteQuote);
const { chatType } = useContextSelector(ChatBoxContext, (v) => v);
const showAllTag = useMemo(() => {
return chatType !== 'share' && chatType !== 'team';
}, [chatType]);
const chatType = useContextSelector(ChatBoxContext, (v) => v.chatType);
const showRawSource = useContextSelector(ChatBoxContext, (v) => v.showRawSource);
const notSharePage = useMemo(() => chatType !== 'share', [chatType]);
const {
isOpen: isOpenWholeModal,
@ -88,13 +81,20 @@ const ResponseTags = ({
sourceName: item.sourceName,
sourceId: item.sourceId,
icon: getSourceNameIcon({ sourceId: item.sourceId, sourceName: item.sourceName }),
canReadQuote: showCompleteQuote || strIsLink(item.sourceId),
collectionId: item.collectionId
}));
}, [quoteList, showCompleteQuote]);
}, [quoteList]);
const notEmptyTags =
quoteList.length > 0 ||
(llmModuleAccount === 1 && notSharePage) ||
(llmModuleAccount > 1 && notSharePage) ||
(isPc && runningTime > 0) ||
notSharePage;
return !showTags ? null : (
<>
{/* quote */}
{sourceList.length > 0 && (
<>
<Flex justifyContent={'space-between'} alignItems={'center'}>
@ -188,74 +188,74 @@ const ResponseTags = ({
</>
)}
<Flex alignItems={'center'} mt={3} flexWrap={'wrap'} gap={2}>
{quoteList.length > 0 && (
<MyTooltip label={t('chat:view_citations')}>
<MyTag
colorSchema="blue"
type="borderSolid"
cursor={'pointer'}
onClick={() => setQuoteModalData({ rawSearch: quoteList })}
>
{t('chat:citations', { num: quoteList.length })}
{notEmptyTags && (
<Flex alignItems={'center'} mt={3} flexWrap={'wrap'} gap={2}>
{quoteList.length > 0 && (
<MyTooltip label={t('chat:view_citations')}>
<MyTag
colorSchema="blue"
type="borderSolid"
cursor={'pointer'}
onClick={() => setQuoteModalData({ rawSearch: quoteList })}
>
{t('chat:citations', { num: quoteList.length })}
</MyTag>
</MyTooltip>
)}
{llmModuleAccount === 1 && notSharePage && (
<>
{historyPreviewLength > 0 && (
<MyTooltip label={t('chat:click_contextual_preview')}>
<MyTag
colorSchema="green"
cursor={'pointer'}
type="borderSolid"
onClick={onOpenContextModal}
>
{t('chat:contextual', { num: historyPreviewLength })}
</MyTag>
</MyTooltip>
)}
</>
)}
{llmModuleAccount > 1 && notSharePage && (
<MyTag type="borderSolid" colorSchema="blue">
{t('chat:multiple_AI_conversations')}
</MyTag>
</MyTooltip>
)}
{llmModuleAccount === 1 && showAllTag && (
<>
{historyPreviewLength > 0 && (
<MyTooltip label={t('chat:click_contextual_preview')}>
<MyTag
colorSchema="green"
cursor={'pointer'}
type="borderSolid"
onClick={onOpenContextModal}
>
{t('chat:contextual', { num: historyPreviewLength })}
</MyTag>
</MyTooltip>
)}
</>
)}
{llmModuleAccount > 1 && showAllTag && (
<MyTag type="borderSolid" colorSchema="blue">
{t('chat:multiple_AI_conversations')}
</MyTag>
)}
)}
{isPc && runningTime > 0 && (
<MyTooltip label={t('chat:module_runtime_and')}>
<MyTag colorSchema="purple" type="borderSolid" cursor={'default'}>
{runningTime}s
</MyTag>
</MyTooltip>
)}
{isPc && runningTime > 0 && (
<MyTooltip label={t('chat:module_runtime_and')}>
<MyTag colorSchema="purple" type="borderSolid" cursor={'default'}>
{runningTime}s
</MyTag>
</MyTooltip>
)}
{showAllTag && (
<MyTooltip label={t('common:core.chat.response.Read complete response tips')}>
<MyTag
colorSchema="gray"
type="borderSolid"
cursor={'pointer'}
onClick={onOpenWholeModal}
>
{t('common:core.chat.response.Read complete response')}
</MyTag>
</MyTooltip>
)}
</Flex>
{notSharePage && (
<MyTooltip label={t('common:core.chat.response.Read complete response tips')}>
<MyTag
colorSchema="gray"
type="borderSolid"
cursor={'pointer'}
onClick={onOpenWholeModal}
>
{t('common:core.chat.response.Read complete response')}
</MyTag>
</MyTooltip>
)}
</Flex>
)}
{!!quoteModalData && (
<QuoteModal
{...quoteModalData}
showDetail={showCompleteQuote}
canEditDataset={notSharePage}
showRawSource={showRawSource}
onClose={() => setQuoteModalData(undefined)}
/>
)}
{isOpenContextModal && <ContextModal dataId={dataId} onClose={onCloseContextModal} />}
{isOpenWholeModal && (
<WholeResponseModal dataId={dataId} showDetail={true} onClose={onCloseWholeModal} />
)}
{isOpenWholeModal && <WholeResponseModal dataId={dataId} onClose={onCloseWholeModal} />}
</>
);
};

View File

@ -566,6 +566,7 @@ const ChatBox = (
// tts audio
autoTTSResponse && splitText2Audio(responseText, true);
} catch (err: any) {
console.log(err);
toast({
title: t(getErrText(err, 'core.chat.error.Chat error') as any),
status: 'error',
@ -948,7 +949,6 @@ const ChatBox = (
>
<ResponseTags
showTags={index !== chatHistories.length - 1 || !isChatting}
showDetail={!shareId && !teamId}
historyItem={item}
/>

View File

@ -31,12 +31,10 @@ type sideTabItemType = {
/* Per response value */
export const WholeResponseContent = ({
activeModule,
hideTabs,
showDetail
hideTabs
}: {
activeModule: ChatHistoryItemResType;
hideTabs?: boolean;
showDetail: boolean;
}) => {
const { t } = useTranslation();
@ -233,7 +231,7 @@ export const WholeResponseContent = ({
{activeModule.quoteList && activeModule.quoteList.length > 0 && (
<Row
label={t('common:core.chat.response.module quoteList')}
rawDom={<QuoteList showDetail={showDetail} rawSearch={activeModule.quoteList} />}
rawDom={<QuoteList canEditDataset canViewSource rawSearch={activeModule.quoteList} />}
/>
)}
</>
@ -531,12 +529,10 @@ const SideTabItem = ({
/* Modal main container */
export const ResponseBox = React.memo(function ResponseBox({
response,
showDetail,
hideTabs = false,
useMobile = false
}: {
response: ChatHistoryItemResType[];
showDetail: boolean;
hideTabs?: boolean;
useMobile?: boolean;
}) {
@ -659,11 +655,7 @@ export const ResponseBox = React.memo(function ResponseBox({
</Box>
</Box>
<Box flex={'5 0 0'} w={0} height={'100%'}>
<WholeResponseContent
activeModule={activeModule}
hideTabs={hideTabs}
showDetail={showDetail}
/>
<WholeResponseContent activeModule={activeModule} hideTabs={hideTabs} />
</Box>
</Flex>
) : (
@ -723,11 +715,7 @@ export const ResponseBox = React.memo(function ResponseBox({
</Box>
</Flex>
<Box flex={'1 0 0'}>
<WholeResponseContent
activeModule={activeModule}
hideTabs={hideTabs}
showDetail={showDetail}
/>
<WholeResponseContent activeModule={activeModule} hideTabs={hideTabs} />
</Box>
</Flex>
)}
@ -737,15 +725,7 @@ export const ResponseBox = React.memo(function ResponseBox({
);
});
const WholeResponseModal = ({
showDetail,
onClose,
dataId
}: {
showDetail: boolean;
onClose: () => void;
dataId: string;
}) => {
const WholeResponseModal = ({ onClose, dataId }: { onClose: () => void; dataId: string }) => {
const { t } = useTranslation();
const { getHistoryResponseData } = useContextSelector(ChatBoxContext, (v) => v);
@ -774,7 +754,7 @@ const WholeResponseModal = ({
}
>
{!!response?.length ? (
<ResponseBox response={response} showDetail={showDetail} />
<ResponseBox response={response} />
) : (
<EmptyTip text={t('chat:no_workflow_response')} />
)}

View File

@ -9,8 +9,6 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import dynamic from 'next/dynamic';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { SearchScoreTypeEnum, SearchScoreTypeMap } from '@fastgpt/global/core/dataset/constants';
import { useContextSelector } from 'use-context-selector';
import { ChatBoxContext } from '../chat/ChatContainer/ChatBox/Provider';
const InputDataModal = dynamic(() => import('@/pages/dataset/detail/components/InputDataModal'));
@ -47,21 +45,15 @@ const scoreTheme: Record<
const QuoteItem = ({
quoteItem,
canViewSource,
linkToDataset
canEditDataset
}: {
quoteItem: SearchDataResponseItemType;
canViewSource?: boolean;
linkToDataset?: boolean;
canEditDataset?: boolean;
}) => {
const { t } = useTranslation();
const [editInputData, setEditInputData] = useState<{ dataId: string; collectionId: string }>();
const { chatType } = useContextSelector(ChatBoxContext, (v) => v);
const canEdit = useMemo(() => {
return chatType !== 'share' && chatType !== 'team';
}, [chatType]);
const score = useMemo(() => {
if (!Array.isArray(quoteItem.score)) {
return {
@ -118,89 +110,64 @@ const QuoteItem = ({
>
<Flex alignItems={'center'} mb={3} flexWrap={'wrap'} gap={3}>
{score?.primaryScore && (
<>
{canViewSource ? (
<MyTooltip label={t(SearchScoreTypeMap[score.primaryScore.type]?.desc as any)}>
<Flex
px={'12px'}
py={'5px'}
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 as any)}
{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 as any)}>
<Box fontSize={'xs'}>
<Flex alignItems={'flex-start'} lineHeight={1.2} mb={1}>
<Box
px={'5px'}
borderWidth={'1px'}
borderRadius={'sm'}
mr={'2px'}
{...(scoreTheme[i] && scoreTheme[i])}
>
<Box transform={'scale(0.9)'}>#{item.index + 1}</Box>
</Box>
<Box transform={'scale(0.9)'}>
{t(SearchScoreTypeMap[item.type]?.label as any)}: {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'}
{...(scoreTheme[i] && {
colorScheme: scoreTheme[i].colorScheme
})}
bg="#E8EBF0"
/>
)}
</Box>
<MyTooltip label={t(SearchScoreTypeMap[score.primaryScore.type]?.desc as any)}>
<Flex
px={'12px'}
py={'5px'}
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 as any)}
{SearchScoreTypeMap[score.primaryScore.type]?.showScore
? ` ${score.primaryScore.value.toFixed(4)}`
: ''}
</Box>
</MyTooltip>
))}
</Flex>
</MyTooltip>
)}
{score.secondaryScore.map((item, i) => (
<MyTooltip key={item.type} label={t(SearchScoreTypeMap[item.type]?.desc as any)}>
<Box fontSize={'xs'}>
<Flex alignItems={'flex-start'} lineHeight={1.2} mb={1}>
<Box
px={'5px'}
borderWidth={'1px'}
borderRadius={'sm'}
mr={'2px'}
{...(scoreTheme[i] && scoreTheme[i])}
>
<Box transform={'scale(0.9)'}>#{item.index + 1}</Box>
</Box>
<Box transform={'scale(0.9)'}>
{t(SearchScoreTypeMap[item.type]?.label as any)}: {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'}
{...(scoreTheme[i] && {
colorScheme: scoreTheme[i].colorScheme
})}
bg="#E8EBF0"
/>
)}
</Box>
</Box>
</MyTooltip>
))}
</Flex>
<Box flex={'1 0 0'}>
@ -208,73 +175,71 @@ const QuoteItem = ({
<Box color={'myGray.600'}>{quoteItem.a}</Box>
</Box>
{canViewSource && (
<Flex
alignItems={'center'}
flexWrap={'wrap'}
mt={3}
gap={4}
color={'myGray.500'}
fontSize={'xs'}
>
<MyTooltip label={t('common:core.dataset.Quote Length')}>
<Flex alignItems={'center'}>
<MyIcon name="common/text/t" w={'14px'} mr={1} color={'myGray.500'} />
{quoteItem.q.length + (quoteItem.a?.length || 0)}
</Flex>
</MyTooltip>
<RawSourceBox
fontWeight={'bold'}
color={'black'}
collectionId={quoteItem.collectionId}
sourceName={quoteItem.sourceName}
sourceId={quoteItem.sourceId}
canView={canViewSource}
/>
<Box flex={1} />
{quoteItem.id && canEdit && (
<MyTooltip label={t('common:core.dataset.data.Edit')}>
<Box
className="hover-data"
visibility={'hidden'}
display={'flex'}
alignItems={'center'}
justifyContent={'center'}
>
<MyIcon
name={'edit'}
w={['16px', '18px']}
h={['16px', '18px']}
cursor={'pointer'}
color={'myGray.600'}
_hover={{
color: 'primary.600'
}}
onClick={() =>
setEditInputData({
dataId: quoteItem.id,
collectionId: quoteItem.collectionId
})
}
/>
</Box>
</MyTooltip>
)}
{linkToDataset && canEdit && (
<Link
as={NextLink}
<Flex
alignItems={'center'}
flexWrap={'wrap'}
mt={3}
gap={4}
color={'myGray.500'}
fontSize={'xs'}
>
<MyTooltip label={t('common:core.dataset.Quote Length')}>
<Flex alignItems={'center'}>
<MyIcon name="common/text/t" w={'14px'} mr={1} color={'myGray.500'} />
{quoteItem.q.length + (quoteItem.a?.length || 0)}
</Flex>
</MyTooltip>
<RawSourceBox
fontWeight={'bold'}
color={'black'}
collectionId={quoteItem.collectionId}
sourceName={quoteItem.sourceName}
sourceId={quoteItem.sourceId}
canView={canViewSource}
/>
<Box flex={1} />
{quoteItem.id && canEditDataset && (
<MyTooltip label={t('common:core.dataset.data.Edit')}>
<Box
className="hover-data"
visibility={'hidden'}
display={'flex'}
alignItems={'center'}
color={'primary.500'}
href={`/dataset/detail?datasetId=${quoteItem.datasetId}&currentTab=dataCard&collectionId=${quoteItem.collectionId}`}
justifyContent={'center'}
>
{t('common:core.dataset.Go Dataset')}
<MyIcon name={'common/rightArrowLight'} w={'10px'} />
</Link>
)}
</Flex>
)}
<MyIcon
name={'edit'}
w={['16px', '18px']}
h={['16px', '18px']}
cursor={'pointer'}
color={'myGray.600'}
_hover={{
color: 'primary.600'
}}
onClick={() =>
setEditInputData({
dataId: quoteItem.id,
collectionId: quoteItem.collectionId
})
}
/>
</Box>
</MyTooltip>
)}
{canEditDataset && (
<Link
as={NextLink}
className="hover-data"
visibility={'hidden'}
alignItems={'center'}
color={'primary.500'}
href={`/dataset/detail?datasetId=${quoteItem.datasetId}&currentTab=dataCard&collectionId=${quoteItem.collectionId}`}
>
{t('common:core.dataset.Go Dataset')}
<MyIcon name={'common/rightArrowLight'} w={'10px'} />
</Link>
)}
</Flex>
</MyBox>
{editInputData && (

View File

@ -6,37 +6,35 @@ import { getCollectionSourceAndOpen } from '@/web/core/dataset/hooks/readCollect
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useI18n } from '@/web/context/I18n';
import { ChatBoxContext } from '../chat/ChatContainer/ChatBox/Provider';
import { useContextSelector } from 'use-context-selector';
import { ShareChatAuthProps } from '@fastgpt/global/support/permission/chat';
type Props = BoxProps & {
sourceName?: string;
collectionId: string;
sourceId?: string;
canView?: boolean;
};
type Props = BoxProps &
ShareChatAuthProps & {
sourceName?: string;
collectionId: string;
sourceId?: string;
canView?: boolean;
};
const RawSourceBox = ({
sourceId,
collectionId,
sourceName = '',
canView = true,
shareId,
outLinkUid,
...props
}: Props) => {
const { t } = useTranslation();
const { fileT } = useI18n();
const { shareId, outLinkUid, chatType } = useContextSelector(ChatBoxContext, (v) => v);
const canPreview = !!sourceId && canView;
const icon = useMemo(() => getSourceNameIcon({ sourceId, sourceName }), [sourceId, sourceName]);
const read = getCollectionSourceAndOpen({
collectionId,
authProps: {
shareId,
outLinkUid
},
isShare: chatType === 'share'
shareId,
outLinkUid
});
return (

View File

@ -17,16 +17,8 @@ async function handler(
req: ApiRequestProps<getHistoriesBody, getHistoriesQuery>,
res: ApiResponseType<any>
): Promise<PaginationResponse<getHistoriesResponse>> {
const {
appId,
shareId,
outLinkUid,
teamId,
teamToken,
offset,
pageSize,
source = ChatSourceEnum.online
} = req.body as getHistoriesBody;
const { appId, shareId, outLinkUid, teamId, teamToken, offset, pageSize, source } =
req.body as getHistoriesBody;
const match = await (async () => {
if (shareId && outLinkUid) {
@ -35,7 +27,6 @@ async function handler(
return {
shareId,
outLinkUid: uid,
source: ChatSourceEnum.share,
updateTime: {
$gte: new Date(new Date().setDate(new Date().getDate() - 30))
}
@ -55,7 +46,7 @@ async function handler(
return {
tmbId,
appId,
source: source
source
};
}
})();

View File

@ -9,7 +9,7 @@ import { getChatItems } from '@fastgpt/service/core/chat/controller';
import { authChatCrud } from '@/service/support/permission/auth/chat';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { filterPublicNodeResponseData } from '@fastgpt/global/core/chat/utils';
import { authOutLink } from '@/service/support/permission/auth/outLink';
import { GetChatTypeEnum } from '@/global/core/chat/constants';
@ -70,9 +70,7 @@ async function handler(
[GetChatTypeEnum.normal]: `dataId obj value adminFeedback userBadFeedback userGoodFeedback time ${
DispatchNodeResponseKeyEnum.nodeResponse
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`,
[GetChatTypeEnum.outLink]: `dataId obj value userGoodFeedback userBadFeedback adminFeedback time ${
shareChat?.responseDetail || isPlugin ? `${DispatchNodeResponseKeyEnum.nodeResponse}` : ''
} `,
[GetChatTypeEnum.outLink]: `dataId obj value userGoodFeedback userBadFeedback adminFeedback time ${DispatchNodeResponseKeyEnum.nodeResponse}`,
[GetChatTypeEnum.team]: `dataId obj value userGoodFeedback userBadFeedback adminFeedback time ${DispatchNodeResponseKeyEnum.nodeResponse}`
};
@ -85,10 +83,14 @@ async function handler(
});
// Remove important information
if (type === 'outLink' && app.type !== AppTypeEnum.plugin) {
if (shareChat && app.type !== AppTypeEnum.plugin) {
histories.forEach((item) => {
if (item.obj === ChatRoleEnum.AI) {
item.responseData = filterPublicNodeResponseData({ flowResponses: item.responseData });
if (shareChat.showNodeStatus === false) {
item.value = item.value.filter((v) => v.type !== ChatItemValueTypeEnum.tool);
}
}
});
}

View File

@ -2,7 +2,6 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
import { getGuideModule, getAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { authOutLink } from '@/service/support/permission/auth/outLink';
import { MongoApp } from '@fastgpt/service/core/app/schema';
@ -54,7 +53,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
storeWelcomeText: chat?.welcomeText,
isPublicFetch: false
}),
chatModels: getChatModelNameListByModules(nodes),
name: app.name,
avatar: app.avatar,
intro: app.intro,

View File

@ -5,15 +5,13 @@ import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant
import { createFileToken } from '@fastgpt/service/support/permission/controller';
import { BucketNameEnum, ReadFileBaseUrl } from '@fastgpt/global/common/file/constants';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { AuthOutLinkProps } from '@fastgpt/global/support/outLink/api';
import { authOutLink } from '@/service/support/permission/auth/outLink';
import { ShareChatAuthProps } from '@fastgpt/global/support/permission/chat';
export type readCollectionSourceQuery = {};
export type readCollectionSourceBody = {
collectionId: string;
isShare?: boolean;
} & AuthOutLinkProps;
} & ShareChatAuthProps;
export type readCollectionSourceResponse = {
type: 'url';
@ -23,12 +21,6 @@ export type readCollectionSourceResponse = {
async function handler(
req: ApiRequestProps<readCollectionSourceBody, readCollectionSourceQuery>
): Promise<readCollectionSourceResponse> {
const { isShare, outLinkUid, shareId } = req.body;
if (isShare) {
await authOutLink({ shareId, outLinkUid });
}
const { collection, teamId, tmbId } = await authDatasetCollection({
req,
authToken: true,

View File

@ -24,7 +24,7 @@ export type OutLinkUpdateResponse = {};
async function handler(
req: ApiRequestProps<OutLinkUpdateBody, OutLinkUpdateQuery>
): Promise<OutLinkUpdateResponse> {
const { _id, name, responseDetail, limit, app, showCompleteQuote, showNodeStatus } = req.body;
const { _id, name, responseDetail, limit, app, showRawSource, showNodeStatus } = req.body;
if (!_id) {
return Promise.reject(CommonErrEnum.missingParams);
@ -35,7 +35,7 @@ async function handler(
await MongoOutLink.findByIdAndUpdate(_id, {
name,
responseDetail,
showCompleteQuote,
showRawSource,
showNodeStatus,
limit,
app

View File

@ -84,7 +84,6 @@ type AuthResponseType = {
app: AppSchema;
responseDetail?: boolean;
showNodeStatus?: boolean;
showCompleteQuote?: boolean;
authType: `${AuthUserTypeEnum}`;
apikey?: string;
canWrite: boolean;

View File

@ -181,6 +181,8 @@ const DetailLogsModal = ({
appId={appId}
chatId={chatId}
chatType="log"
showRawSource
showNodeStatus
/>
)}
</Box>

View File

@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react';
import React, { useMemo, useState } from 'react';
import {
Flex,
Box,
@ -32,7 +32,6 @@ import { useCopyData } from '@/web/common/hooks/useCopyData';
import { useForm } from 'react-hook-form';
import { defaultOutLinkForm } from '@/web/core/app/constants';
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
import { useRequest } from '@/web/common/hooks/useRequest';
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
import { useTranslation } from 'next-i18next';
import { useToast } from '@fastgpt/web/hooks/useToast';
@ -48,6 +47,7 @@ import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
@ -183,9 +183,9 @@ const Share = ({ appId }: { appId: string; type: PublishChannelEnum }) => {
setEditLinkData({
_id: item._id,
name: item.name,
responseDetail: item.responseDetail,
showCompleteQuote: item.showCompleteQuote,
showNodeStatus: item.showNodeStatus,
responseDetail: item.responseDetail ?? false,
showRawSource: item.showRawSource ?? false,
showNodeStatus: item.showNodeStatus ?? false,
limit: item.limit
})
},
@ -281,36 +281,23 @@ function EditLinkModal({
});
const responseDetail = watch('responseDetail');
const showCompleteQuote = watch('showCompleteQuote');
useEffect(() => {
if (!responseDetail) {
setValue('showCompleteQuote', false);
}
}, [responseDetail, setValue]);
useEffect(() => {
if (showCompleteQuote) {
setValue('responseDetail', true);
}
}, [showCompleteQuote, setValue]);
const showRawSource = watch('showRawSource');
const isEdit = useMemo(() => !!defaultData._id, [defaultData]);
const { mutate: onclickCreate, isLoading: creating } = useRequest({
mutationFn: async (e: OutLinkEditType) =>
const { runAsync: onclickCreate, loading: creating } = useRequest2(
async (e: OutLinkEditType) =>
createShareChat({
...e,
appId,
type
}),
errorToast: t('common:common.Create Failed'),
onSuccess: onCreate
});
const { mutate: onclickUpdate, isLoading: updating } = useRequest({
mutationFn: (e: OutLinkEditType) => {
return putShareChat(e);
},
{
errorToast: t('common:common.Create Failed'),
onSuccess: onCreate
}
);
const { runAsync: onclickUpdate, loading: updating } = useRequest2(putShareChat, {
errorToast: t('common:common.Update Failed'),
onSuccess: onEdit
});
@ -320,131 +307,133 @@ function EditLinkModal({
isOpen={true}
iconSrc="/imgs/modal/shareFill.svg"
title={isEdit ? publishT('edit_link') : publishT('create_link')}
w={'53.125rem'}
maxW={['90vw', '700px']}
w={'100%'}
h={['90vh', 'auto']}
>
<ModalBody p={6}>
<Flex flexDir={['column', 'row']}>
<Box pr={[0, 6]} borderRight={['0px', '1px']} borderColor={['', 'myGray.150']}>
<Box fontSize={'sm'} fontWeight={'500'} color={'myGray.600'}>
{t('publish:basic_info')}
</Box>
<Flex alignItems={'center'} mt={4}>
<FormLabel flex={'0 0 90px'}>{t('common:Name')}</FormLabel>
<Input
placeholder={publishT('link_name')}
maxLength={20}
{...register('name', {
required: t('common:common.name_is_empty') || 'name_is_empty'
})}
/>
</Flex>
{feConfigs?.isPlus && (
<>
<Flex alignItems={'center'} mt={4}>
<FormLabel flex={'0 0 90px'} alignItems={'center'}>
{t('common:common.Expired Time')}
</FormLabel>
<Input
type="datetime-local"
defaultValue={
defaultData.limit?.expiredTime
? dayjs(defaultData.limit?.expiredTime).format('YYYY-MM-DDTHH:mm')
: ''
}
onChange={(e) => {
setValue('limit.expiredTime', new Date(e.target.value));
}}
/>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
<FormLabel>QPM</FormLabel>
<QuestionTip ml={1} label={publishT('qpm_tips' || '')}></QuestionTip>
</Flex>
<Input
max={1000}
{...register('limit.QPM', {
min: 0,
max: 1000,
valueAsNumber: true,
required: publishT('qpm_is_empty') || ''
})}
/>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
<FormLabel>{t('common:support.outlink.Max usage points')}</FormLabel>
<QuestionTip
ml={1}
label={t('common:support.outlink.Max usage points tip')}
></QuestionTip>
</Flex>
<Input
{...register('limit.maxUsagePoints', {
min: -1,
max: 10000000,
valueAsNumber: true,
required: true
})}
/>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
<FormLabel>{publishT('token_auth')}</FormLabel>
<QuestionTip ml={1} label={publishT('token_auth_tips') || ''}></QuestionTip>
</Flex>
<Input
placeholder={publishT('token_auth_tips') || ''}
fontSize={'sm'}
{...register('limit.hookUrl')}
/>
</Flex>
<Link
href={getDocPath('/docs/development/openapi/share')}
target={'_blank'}
fontSize={'xs'}
color={'myGray.500'}
>
{publishT('token_auth_use_cases')}
</Link>
</>
)}
<ModalBody
p={6}
display={['block', 'flex']}
flex={['1 0 0', 'auto']}
overflow={'auto'}
gap={4}
>
<Box pr={[0, 4]} flex={1} borderRight={['0px', '1px']} borderColor={['', 'myGray.150']}>
<Box fontSize={'sm'} fontWeight={'500'} color={'myGray.600'}>
{t('publish:basic_info')}
</Box>
<Box pl={[0, 6]} flexGrow={1} pt={[6, 0]}>
<Box fontSize={'sm'} fontWeight={'500'} color={'myGray.600'}>
{t('publish:config')}
</Box>
<Flex alignItems={'center'} mt={4} justify={'space-between'}>
<Flex alignItems={'center'}>
<FormLabel>{t('publish:show_node')}</FormLabel>
<Flex alignItems={'center'} mt={4}>
<FormLabel flex={'0 0 90px'}>{t('common:Name')}</FormLabel>
<Input
placeholder={publishT('link_name')}
maxLength={20}
{...register('name', {
required: t('common:common.name_is_empty') || 'name_is_empty'
})}
/>
</Flex>
{feConfigs?.isPlus && (
<>
<Flex alignItems={'center'} mt={4}>
<FormLabel flex={'0 0 90px'} alignItems={'center'}>
{t('common:common.Expired Time')}
</FormLabel>
<Input
type="datetime-local"
defaultValue={
defaultData.limit?.expiredTime
? dayjs(defaultData.limit?.expiredTime).format('YYYY-MM-DDTHH:mm')
: ''
}
onChange={(e) => {
setValue('limit.expiredTime', new Date(e.target.value));
}}
/>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
<FormLabel>QPM</FormLabel>
<QuestionTip ml={1} label={publishT('qpm_tips' || '')}></QuestionTip>
</Flex>
<Input
max={1000}
{...register('limit.QPM', {
min: 0,
max: 1000,
valueAsNumber: true,
required: publishT('qpm_is_empty') || ''
})}
/>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
<FormLabel>{t('common:support.outlink.Max usage points')}</FormLabel>
<QuestionTip
ml={1}
label={t('common:support.outlink.Max usage points tip')}
></QuestionTip>
</Flex>
<Input
{...register('limit.maxUsagePoints', {
min: -1,
max: 10000000,
valueAsNumber: true,
required: true
})}
/>
</Flex>
<Switch {...register('showNodeStatus')} />
</Flex>
<Flex alignItems={'center'} mt={4} justify={'space-between'}>
<Flex alignItems={'center'}>
<FormLabel>{t('common:support.outlink.share.Response Quote')}</FormLabel>
<QuestionTip
ml={1}
label={t('common:support.outlink.share.Response Quote tips' || '')}
></QuestionTip>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
<FormLabel>{publishT('token_auth')}</FormLabel>
<QuestionTip ml={1} label={publishT('token_auth_tips') || ''}></QuestionTip>
</Flex>
<Input
placeholder={publishT('token_auth_tips') || ''}
fontSize={'sm'}
{...register('limit.hookUrl')}
/>
</Flex>
<Switch {...register('responseDetail')} isChecked={responseDetail} />
</Flex>
<Flex alignItems={'center'} mt={4} justify={'space-between'}>
<Flex alignItems={'center'}>
<FormLabel>{t('common:support.outlink.share.show_complete_quote')}</FormLabel>
<QuestionTip
ml={1}
label={t('common:support.outlink.share.show_complete_quote_tips' || '')}
></QuestionTip>
</Flex>
<Switch {...register('showCompleteQuote')} isChecked={showCompleteQuote} />
</Flex>
<Link
href={getDocPath('/docs/development/openapi/share')}
target={'_blank'}
fontSize={'xs'}
color={'myGray.500'}
>
{publishT('token_auth_use_cases')}
</Link>
</>
)}
</Box>
<Box flex={1} pt={[6, 0]}>
<Box fontSize={'sm'} fontWeight={'500'} color={'myGray.600'}>
{t('publish:private_config')}
</Box>
</Flex>
<Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
<FormLabel>{t('publish:show_node')}</FormLabel>
<Switch {...register('showNodeStatus')} />
</Flex>
<Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
<Flex alignItems={'center'}>
<FormLabel>{t('common:support.outlink.share.Response Quote')}</FormLabel>
<QuestionTip
ml={1}
label={t('common:support.outlink.share.Response Quote tips' || '')}
></QuestionTip>
</Flex>
<Switch {...register('responseDetail')} isChecked={responseDetail} />
</Flex>
{/* <Flex alignItems={'center'} mt={4} justify={'space-between'} height={'36px'}>
<Flex alignItems={'center'}>
<FormLabel>{t('common:support.outlink.share.show_complete_quote')}</FormLabel>
<QuestionTip
ml={1}
label={t('common:support.outlink.share.show_complete_quote_tips' || '')}
></QuestionTip>
</Flex>
<Switch {...register('showRawSource')} isChecked={showRawSource} />
</Flex> */}
</Box>
</ModalBody>
<ModalFooter>

View File

@ -113,6 +113,9 @@ export const useChatTest = ({
appAvatar={appDetail.avatar}
userAvatar={userInfo?.avatar}
showMarkIcon
chatType="chat"
showRawSource
showNodeStatus
chatConfig={chatConfig}
onStartChat={startChat}
onDelMessage={() => {}}

View File

@ -34,6 +34,7 @@ import { useChat } from '@/components/core/chat/ChatContainer/useChat';
import ChatBox from '@/components/core/chat/ChatContainer/ChatBox';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { InitChatResponse } from '@/global/core/chat/api';
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
const CustomPluginRunBox = dynamic(() => import('./components/CustomPluginRunBox'));
@ -283,6 +284,9 @@ const Chat = ({
onDelMessage={({ contentId }) => delChatRecordById({ contentId, appId, chatId })}
appId={appId}
chatId={chatId}
chatType={'chat'}
showRawSource
showNodeStatus
/>
)}
</Box>
@ -341,7 +345,7 @@ const Render = (props: Props) => {
}
});
const providerParams = useMemo(() => ({ appId }), [appId]);
const providerParams = useMemo(() => ({ appId, source: ChatSourceEnum.online }), [appId]);
return (
<ChatContextProvider params={providerParams}>
<Chat {...props} myApps={myApps} />

View File

@ -42,7 +42,8 @@ type Props = {
shareId: string;
authToken: string;
customUid: string;
showCompleteQuote: boolean;
showRawSource: boolean;
showNodeStatus: boolean;
};
const OutLink = (
@ -52,7 +53,7 @@ const OutLink = (
) => {
const { t } = useTranslation();
const router = useRouter();
const { outLinkUid } = props;
const { outLinkUid, showRawSource, showNodeStatus } = props;
const {
shareId = '',
chatId = '',
@ -366,6 +367,8 @@ const OutLink = (
shareId={shareId}
outLinkUid={outLinkUid}
chatType="share"
showRawSource={showRawSource}
showNodeStatus={showNodeStatus}
/>
)}
</Box>
@ -377,13 +380,13 @@ const OutLink = (
};
const Render = (props: Props) => {
const { shareId, authToken, customUid, showCompleteQuote } = props;
const { shareId, authToken, customUid } = props;
const { localUId, loaded } = useShareChatStore();
const [isLoaded, setIsLoaded] = useState(false);
const contextParams = useMemo(() => {
return { shareId, outLinkUid: authToken || localUId || customUid, showCompleteQuote };
}, [authToken, customUid, localUId, shareId, showCompleteQuote]);
return { shareId, outLinkUid: authToken || localUId || customUid };
}, [authToken, customUid, localUId, shareId]);
useMount(() => {
setIsLoaded(true);
@ -417,7 +420,7 @@ export async function getServerSideProps(context: any) {
{
shareId
},
'appId showCompleteQuote'
'appId showRawSource showNodeStatus'
)
.populate('appId', 'name avatar intro')
.lean()) as OutLinkWithAppType;
@ -433,7 +436,8 @@ export async function getServerSideProps(context: any) {
appName: app?.appId?.name ?? 'AI',
appAvatar: app?.appId?.avatar ?? '',
appIntro: app?.appId?.intro ?? 'AI',
showCompleteQuote: app?.showCompleteQuote ?? false,
showRawSource: app?.showRawSource ?? false,
showNodeStatus: app?.showNodeStatus ?? false,
shareId: shareId ?? '',
authToken: authToken ?? '',
customUid,

View File

@ -297,6 +297,8 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
teamId={teamId}
teamToken={teamToken}
chatType="team"
showRawSource
showNodeStatus
/>
)}
</Box>

View File

@ -26,11 +26,9 @@ import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { getDefaultIndex, getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
import SideTabs from '@/components/SideTabs';
import DeleteIcon from '@fastgpt/web/components/common/Icon/delete';
import { defaultCollectionDetail } from '@/web/core/dataset/constants';
import { getDocPath } from '@/web/common/system/doc';
import RawSourceBox from '@/components/core/dataset/RawSourceBox';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';

View File

@ -10,8 +10,6 @@ import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import { DatasetCollectionTypeMap, TrainingTypeMap } from '@fastgpt/global/core/dataset/constants';
import { getCollectionSourceAndOpen } from '@/web/core/dataset/hooks/readCollectionSource';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useContextSelector } from 'use-context-selector';
import { ChatBoxContext } from '@/components/core/chat/ChatContainer/ChatBox/Provider';
const MetaDataCard = ({ datasetId }: { datasetId: string }) => {
const { t } = useTranslation();
@ -21,15 +19,8 @@ const MetaDataCard = ({ datasetId }: { datasetId: string }) => {
datasetId: string;
};
const { shareId, outLinkUid, chatType } = useContextSelector(ChatBoxContext, (v) => v);
const readSource = getCollectionSourceAndOpen({
collectionId,
authProps: {
shareId,
outLinkUid
},
isShare: chatType === 'share'
collectionId
});
const { data: collection, loading: isLoading } = useRequest2(
() => getDatasetCollectionById(collectionId),

View File

@ -3,9 +3,9 @@ import type {
AuthOutLinkChatProps,
AuthOutLinkLimitProps,
AuthOutLinkInitProps,
AuthOutLinkResponse,
AuthOutLinkProps
AuthOutLinkResponse
} from '@fastgpt/global/support/outLink/api.d';
import { ShareChatAuthProps } from '@fastgpt/global/support/permission/chat';
import { authOutLinkValid } from '@fastgpt/service/support/permission/publish/authLink';
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
@ -24,7 +24,7 @@ export function authOutLinkChatLimit(data: AuthOutLinkLimitProps): Promise<AuthO
export const authOutLink = async ({
shareId,
outLinkUid
}: AuthOutLinkProps): Promise<{
}: ShareChatAuthProps): Promise<{
uid: string;
appId: string;
shareChat: OutLinkSchema;

View File

@ -24,7 +24,7 @@ export const defaultOutLinkForm: OutLinkEditType = {
name: '',
responseDetail: false,
showNodeStatus: false,
showCompleteQuote: false,
showRawSource: false,
limit: {
QPM: 100,
maxUsagePoints: -1

View File

@ -44,7 +44,6 @@ type ChatContextType = {
isLoading: boolean;
histories: ChatHistoryItemType[];
onUpdateHistoryTitle: ({ chatId, newTitle }: { chatId: string; newTitle: string }) => void;
showCompleteQuote: boolean;
};
export const ChatContext = createContext<ChatContextType>({
@ -86,8 +85,7 @@ export const ChatContext = createContext<ChatContextType>({
onChangeAppId: function (appId: string): void {
throw new Error('Function not implemented.');
},
isLoading: false,
showCompleteQuote: true
isLoading: false
});
const ChatContextProvider = ({
@ -96,7 +94,6 @@ const ChatContextProvider = ({
}: ChatContextValueType & { children: ReactNode }) => {
const router = useRouter();
const { chatId = '' } = router.query as { chatId: string };
const { showCompleteQuote }: { showCompleteQuote?: boolean } = params;
const forbidLoadChat = useRef(false);
@ -228,8 +225,7 @@ const ChatContextProvider = ({
ScrollData,
loadHistories,
histories,
onUpdateHistoryTitle,
showCompleteQuote: showCompleteQuote ?? true
onUpdateHistoryTitle
};
return <ChatContext.Provider value={contextValue}>{children}</ChatContext.Provider>;
};

View File

@ -34,10 +34,7 @@ import type { CreateDatasetParams, InsertOneDatasetDataProps } from '@/global/co
import type { DatasetCollectionItemType } from '@fastgpt/global/core/dataset/type';
import { DatasetCollectionSyncResultEnum } from '@fastgpt/global/core/dataset/constants';
import type { DatasetDataItemType } from '@fastgpt/global/core/dataset/type';
import type {
DatasetCollectionsListItemType,
DatasetDataListItemType
} from '@/global/core/dataset/type.d';
import type { DatasetCollectionsListItemType } from '@/global/core/dataset/type.d';
import { PagingData } from '@/types';
import type { getDatasetTrainingQueueResponse } from '@/pages/api/core/dataset/training/getDatasetTrainingQueue';
import type { rebuildEmbeddingBody } from '@/pages/api/core/dataset/training/rebuildEmbedding';
@ -45,7 +42,10 @@ import type {
PostPreviewFilesChunksProps,
PreviewChunksResponse
} from '@/pages/api/core/dataset/file/getPreviewChunks';
import type { readCollectionSourceResponse } from '@/pages/api/core/dataset/collection/read';
import type {
readCollectionSourceBody,
readCollectionSourceResponse
} from '@/pages/api/core/dataset/collection/read';
import type { GetDatasetListBody } from '@/pages/api/core/dataset/list';
import type { UpdateDatasetCollectionParams } from '@/pages/api/core/dataset/collection/update';
import type {
@ -56,7 +56,6 @@ import type { UpdateDatasetDataProps } from '@fastgpt/global/core/dataset/contro
import type { DatasetFolderCreateBody } from '@/pages/api/core/dataset/folder/create';
import type { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
import type { GetScrollCollectionsProps } from '@/pages/api/core/dataset/collection/scrollList';
import { AuthOutLinkProps } from '@fastgpt/global/support/outLink/api';
/* ======================== dataset ======================= */
export const getDatasets = (data: GetDatasetListBody) =>
@ -198,6 +197,5 @@ export const getPreviewChunks = (data: PostPreviewFilesChunksProps) =>
POST<PreviewChunksResponse>('/core/dataset/file/getPreviewChunks', data);
/* ================== read source ======================== */
export const getCollectionSource = (
data: { collectionId: string; isShare?: boolean } & AuthOutLinkProps
) => POST<readCollectionSourceResponse>('/core/dataset/collection/read', data);
export const getCollectionSource = (data: readCollectionSourceBody) =>
POST<readCollectionSourceResponse>('/core/dataset/collection/read', data);

View File

@ -1,20 +1,17 @@
import { authOutLink } from '@/service/support/permission/auth/outLink';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { getCollectionSource } from '@/web/core/dataset/api';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { AuthOutLinkProps } from '@fastgpt/global/support/outLink/api';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useTranslation } from 'next-i18next';
import { ShareChatAuthProps } from '@fastgpt/global/support/permission/chat';
export function getCollectionSourceAndOpen({
collectionId,
authProps,
isShare
shareId,
outLinkUid
}: {
collectionId: string;
authProps: AuthOutLinkProps;
isShare?: boolean;
}) {
} & ShareChatAuthProps) {
const { toast } = useToast();
const { t } = useTranslation();
const { setLoading } = useSystemStore();
@ -23,7 +20,7 @@ export function getCollectionSourceAndOpen({
try {
setLoading(true);
const { value: url } = await getCollectionSource({ collectionId, isShare, ...authProps });
const { value: url } = await getCollectionSource({ collectionId, shareId, outLinkUid });
if (!url) {
throw new Error('No file found');