v4.6.4-Outlink (#589)

This commit is contained in:
Archer
2023-12-12 14:42:20 +08:00
committed by GitHub
parent d2d7eac9e0
commit e18c79ca71
79 changed files with 1094 additions and 762 deletions

View File

@@ -71,47 +71,6 @@ function simpleChatTemplate({
}
]
},
{
moduleId: 'history',
name: '聊天记录',
avatar: '/imgs/module/history.png',
flowType: 'historyNode',
position: {
x: 452.5466249541586,
y: 1276.3930310334215
},
inputs: [
{
key: 'maxContext',
type: 'numberInput',
label: '最长记录数',
value: 10,
min: 0,
max: 50,
connected: true
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true
}
],
outputs: [
{
key: 'history',
label: '聊天记录',
valueType: 'chatHistory',
type: 'source',
targets: [
{
moduleId: 'chatModule',
key: 'history'
}
]
}
]
},
{
moduleId: 'chatModule',
name: 'AI 对话',
@@ -191,7 +150,6 @@ function simpleChatTemplate({
type: 'hidden',
label: '引用内容模板',
valueType: 'string',
value: '',
connected: true
},
{
@@ -199,7 +157,6 @@ function simpleChatTemplate({
type: 'hidden',
label: '引用内容提示词',
valueType: 'string',
value: '',
connected: true
},
{
@@ -234,7 +191,8 @@ function simpleChatTemplate({
type: 'target',
label: 'core.module.input.label.chat history',
valueType: 'chatHistory',
connected: true
connected: true,
value: 8
},
{
key: 'userChatInput',
@@ -318,47 +276,6 @@ function datasetTemplate({
}
]
},
{
moduleId: 'history',
name: '聊天记录',
avatar: '/imgs/module/history.png',
flowType: 'historyNode',
position: {
x: 452.5466249541586,
y: 1276.3930310334215
},
inputs: [
{
key: 'maxContext',
type: 'numberInput',
label: '最长记录数',
value: 6,
min: 0,
max: 50,
connected: true
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true
}
],
outputs: [
{
key: 'history',
label: '聊天记录',
valueType: 'chatHistory',
type: 'source',
targets: [
{
moduleId: 'chatModule',
key: 'history'
}
]
}
]
},
{
moduleId: 'datasetSearch',
name: '知识库搜索',
@@ -541,7 +458,6 @@ function datasetTemplate({
type: 'hidden',
label: '引用内容模板',
valueType: 'string',
value: '',
connected: true
},
{
@@ -549,7 +465,6 @@ function datasetTemplate({
type: 'hidden',
label: '引用内容提示词',
valueType: 'string',
value: '',
connected: true
},
{
@@ -584,7 +499,8 @@ function datasetTemplate({
type: 'target',
label: 'core.module.input.label.chat history',
valueType: 'chatHistory',
connected: true
connected: true,
value: 8
},
{
key: 'userChatInput',

View File

@@ -89,18 +89,19 @@ function chatModelInput(formData: AppSimpleEditFormType): FlowNodeInputItemType[
label: '触发器',
connected: formData.dataset.datasets.length > 0 && !!formData.dataset.searchEmptyText
},
{
key: 'history',
type: 'target',
label: 'core.module.input.label.chat history',
connected: true,
value: 6
},
{
key: 'quoteQA',
type: 'target',
label: '引用内容',
connected: formData.dataset.datasets.length > 0
},
{
key: 'history',
type: 'target',
label: '聊天记录',
connected: true
},
{
key: 'userChatInput',
type: 'target',
@@ -139,41 +140,6 @@ function simpleChatTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
},
moduleId: 'userChatInput'
},
{
name: '聊天记录',
flowType: FlowNodeTypeEnum.historyNode,
inputs: [
{
key: 'maxContext',
value: 6,
connected: true,
type: 'numberInput',
label: '最长记录数'
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true
}
],
outputs: [
{
key: 'history',
targets: [
{
moduleId: 'chatModule',
key: 'history'
}
]
}
],
position: {
x: 452.5466249541586,
y: 1276.3930310334215
},
moduleId: 'history'
},
{
name: 'AI 对话',
flowType: FlowNodeTypeEnum.chatNode,
@@ -238,41 +204,6 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
},
moduleId: 'userChatInput'
},
{
name: '聊天记录',
flowType: FlowNodeTypeEnum.historyNode,
inputs: [
{
key: 'maxContext',
value: 6,
connected: true,
type: 'numberInput',
label: '最长记录数'
},
{
key: 'history',
type: 'hidden',
label: '聊天记录',
connected: true
}
],
outputs: [
{
key: 'history',
targets: [
{
moduleId: 'chatModule',
key: 'history'
}
]
}
],
position: {
x: 452.5466249541586,
y: 1276.3930310334215
},
moduleId: 'history'
},
{
name: '知识库搜索',
flowType: FlowNodeTypeEnum.datasetSearchNode,

View File

@@ -64,8 +64,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
appId,
modules,
variables,
params: {
history,
histories: history,
startParams: {
userChatInput: prompt
},
stream: true,

View File

@@ -10,11 +10,12 @@ import { autChatCrud } from '@/service/support/permission/auth/chat';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
const { chatId, shareId, outLinkUid } = req.query as DelHistoryProps;
const { appId, chatId, shareId, outLinkUid } = req.query as DelHistoryProps;
await autChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,

View File

@@ -7,7 +7,7 @@ import { autChatCrud } from '@/service/support/permission/auth/chat';
/* 初始化我的聊天框,需要身份验证 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { chatId, chatItemId, shareId, outLinkUid, userBadFeedback, userGoodFeedback } =
const { appId, chatId, chatItemId, shareId, outLinkUid, userBadFeedback, userGoodFeedback } =
req.body as UpdateChatFeedbackProps;
try {
@@ -16,6 +16,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await autChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,

View File

@@ -8,7 +8,7 @@ import type { DeleteChatItemProps } from '@/global/core/chat/api.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
const { chatId, contentId, shareId, outLinkUid } = req.query as DeleteChatItemProps;
const { appId, chatId, contentId, shareId, outLinkUid } = req.query as DeleteChatItemProps;
if (!contentId || !chatId) {
return jsonRes(res);
@@ -17,6 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await autChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,

View File

@@ -9,11 +9,12 @@ import { autChatCrud } from '@/service/support/permission/auth/chat';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
const { chatId, shareId, outLinkUid, customTitle, top } = req.body as UpdateHistoryProps;
const { appId, chatId, shareId, outLinkUid, customTitle, top } = req.body as UpdateHistoryProps;
await autChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,

View File

@@ -16,7 +16,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const [userPlugins, plusPlugins] = await Promise.all([
MongoPlugin.find({ teamId }).lean(),
global.systemEnv.pluginBaseUrl ? GET<PluginTemplateType[]>('/core/plugin/getTemplates') : []
global.systemEnv?.pluginBaseUrl ? GET<PluginTemplateType[]>('/core/plugin/getTemplates') : []
]);
const data: FlowModuleTemplateType[] = [

View File

@@ -21,6 +21,7 @@ import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constant
import { getSimpleTemplatesFromPlus } from '@/service/core/app/utils';
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
import { getFastGPTFeConfig } from '@fastgpt/service/common/system/config/controller';
import { connectToDatabase } from '@/service/mongo';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await getInitConfig();
@@ -68,6 +69,7 @@ const defaultFeConfigs: FeConfigsType = {
export async function getInitConfig() {
try {
if (global.feConfigs) return;
await connectToDatabase();
initGlobal();
const filename =

View File

@@ -180,6 +180,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
req,
authToken: true,
authApiKey: true,
appId: app._id,
chatId,
shareId,
outLinkUid,
@@ -188,7 +189,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// get and concat history
const { history } = await getChatItems({ chatId, limit: 30, field: `dataId obj value` });
const concatHistory = history.concat(chatMessages);
const concatHistories = history.concat(chatMessages);
/* start flow controller */
const { responseData, answerText } = await dispatchModules({
@@ -200,8 +201,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
teamId: user.team.teamId,
tmbId: user.team.tmbId,
variables,
params: {
history: concatHistory,
histories: concatHistories,
startParams: {
userChatInput: question.value
},
stream,

View File

@@ -1,4 +1,4 @@
import React, { useRef, useState } from 'react';
import React, { useCallback, useRef, useState } from 'react';
import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react';
import { SmallCloseIcon } from '@chakra-ui/icons';
import { ModuleItemType } from '@fastgpt/global/core/module/type';
@@ -14,6 +14,7 @@ import MyTooltip from '@/components/MyTooltip';
import ChatTest, { type ChatTestComponentRef } from '@/components/core/module/Flow/ChatTest';
import { flowNode2Modules, useFlowProviderStore } from '@/components/core/module/Flow/FlowProvider';
import { useAppStore } from '@/web/core/app/store/useAppStore';
import { useToast } from '@/web/common/hooks/useToast';
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));
@@ -31,6 +32,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
setTestModules: React.Dispatch<ModuleItemType[] | undefined>;
}) {
const theme = useTheme();
const { toast } = useToast();
const { t } = useTranslation();
const { copyData } = useCopyData();
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
@@ -38,8 +40,8 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
const { nodes, edges, onFixView } = useFlowProviderStore();
const { mutate: onclickSave, isLoading } = useRequest({
mutationFn: () => {
const flow2ModulesAndCheck = useCallback(
(tip = false) => {
const modules = flowNode2Modules({ nodes, edges });
// check required connect
for (let i = 0; i < modules.length; i++) {
@@ -51,12 +53,24 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
return false;
})
) {
return Promise.reject(`${item.name}】存在未填或未连接参数`);
const msg = `${item.name}】存在未填或未连接参数`;
tip &&
toast({
status: 'warning',
title: msg
});
return Promise.reject(msg);
}
}
return modules;
},
[edges, nodes, toast]
);
const { mutate: onclickSave, isLoading } = useRequest({
mutationFn: async () => {
return updateAppDetail(app._id, {
modules,
modules: await flow2ModulesAndCheck(),
type: AppTypeEnum.advanced,
permission: undefined
});
@@ -139,8 +153,8 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
borderRadius={'lg'}
aria-label={'save'}
variant={'base'}
onClick={() => {
setTestModules(flowNode2Modules({ nodes, edges }));
onClick={async () => {
setTestModules(await flow2ModulesAndCheck(true));
}}
/>
</MyTooltip>

View File

@@ -321,6 +321,7 @@ function DetailLogsModal({
showMarkIcon
showVoiceIcon={false}
userGuideModule={chat?.app?.userGuideModule}
appId={appId}
chatId={chatId}
/>
</Box>

View File

@@ -1,9 +0,0 @@
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
import React from 'react';
import MyModal from '@/components/MyModal';
const EmbModal = ({ share }: { share: OutLinkSchema }) => {
return <MyModal isOpen>EmbModal</MyModal>;
};
export default EmbModal;

View File

@@ -0,0 +1,209 @@
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
import React, { useCallback, useState } from 'react';
import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next';
import { Box, Flex, FlexProps, Grid, Image, ModalBody, Switch, useTheme } from '@chakra-ui/react';
import MyRadio from '@/components/common/MyRadio';
import { useForm } from 'react-hook-form';
import MyIcon from '@/components/Icon';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { fileToBase64 } from '@/web/common/file/utils';
enum UsingWayEnum {
link = 'link',
iframe = 'iframe',
script = 'script'
}
const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose: () => void }) => {
const { t } = useTranslation();
const theme = useTheme();
const { copyData } = useCopyData();
const { File, onOpen } = useSelectFile({
multiple: false,
fileType: 'image/*'
});
const VariableTypeList = [
{
title: <Image src={'/imgs/outlink/link.svg'} alt={''} />,
value: UsingWayEnum.link
},
{
title: <Image src={'/imgs/outlink/iframe.svg'} alt={''} />,
value: UsingWayEnum.iframe
},
{
title: <Image src={'/imgs/outlink/script.svg'} alt={''} />,
value: UsingWayEnum.script
}
];
const [refresh, setRefresh] = useState(false);
const { getValues, setValue, register, watch } = useForm({
defaultValues: {
usingWay: UsingWayEnum.link,
showHistory: true,
scriptIconCanDrag: true,
scriptDefaultOpen: true,
scriptOpenIcon:
'data:image/svg+xml;base64,PHN2ZyB0PSIxNjkwNTMyNzg1NjY0IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQxMzIiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNNTEyIDMyQzI0Ny4wNCAzMiAzMiAyMjQgMzIgNDY0QTQxMC4yNCA0MTAuMjQgMCAwIDAgMTcyLjQ4IDc2OEwxNjAgOTY1LjEyYTI1LjI4IDI1LjI4IDAgMCAwIDM5LjA0IDIyLjRsMTY4LTExMkE1MjguNjQgNTI4LjY0IDAgMCAwIDUxMiA4OTZjMjY0Ljk2IDAgNDgwLTE5MiA0ODAtNDMyUzc3Ni45NiAzMiA1MTIgMzJ6IG0yNDQuOCA0MTZsLTM2MS42IDMwMS43NmExMi40OCAxMi40OCAwIDAgMS0xOS44NC0xMi40OGw1OS4yLTIzMy45MmgtMTYwYTEyLjQ4IDEyLjQ4IDAgMCAxLTcuMzYtMjMuMzZsMzYxLjYtMzAxLjc2YTEyLjQ4IDEyLjQ4IDAgMCAxIDE5Ljg0IDEyLjQ4bC01OS4yIDIzMy45MmgxNjBhMTIuNDggMTIuNDggMCAwIDEgOCAyMi4wOHoiIGZpbGw9IiM0ZTgzZmQiIHAtaWQ9IjQxMzMiPjwvcGF0aD48L3N2Zz4=',
scriptCloseIcon:
'data:image/svg+xml;base64,PHN2ZyB0PSIxNjkwNTM1NDQxNTI2IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjYzNjciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNNTEyIDEwMjRBNTEyIDUxMiAwIDEgMSA1MTIgMGE1MTIgNTEyIDAgMCAxIDAgMTAyNHpNMzA1Ljk1NjU3MSAzNzAuMzk1NDI5TDQ0Ny40ODggNTEyIDMwNS45NTY1NzEgNjUzLjYwNDU3MWE0NS41NjggNDUuNTY4IDAgMSAwIDY0LjQzODg1OCA2NC40Mzg4NThMNTEyIDU3Ni41MTJsMTQxLjYwNDU3MSAxNDEuNTMxNDI5YTQ1LjU2OCA0NS41NjggMCAwIDAgNjQuNDM4ODU4LTY0LjQzODg1OEw1NzYuNTEyIDUxMmwxNDEuNTMxNDI5LTE0MS42MDQ1NzFhNDUuNTY4IDQ1LjU2OCAwIDEgMC02NC40Mzg4NTgtNjQuNDM4ODU4TDUxMiA0NDcuNDg4IDM3MC4zOTU0MjkgMzA1Ljk1NjU3MWE0NS41NjggNDUuNTY4IDAgMCAwLTY0LjQzODg1OCA2NC40Mzg4NTh6IiBmaWxsPSIjNGU4M2ZkIiBwLWlkPSI2MzY4Ij48L3BhdGg+PC9zdmc+'
}
});
const selectFile = useCallback(
async (files: File[], key: 'scriptOpenIcon' | 'scriptCloseIcon') => {
const file = files[0];
if (!file) return;
// image to base64
const base64 = await fileToBase64(file);
setValue(key, base64);
},
[setValue]
);
watch(() => {
setRefresh(!refresh);
});
const linkUrl = `${location?.origin}/chat/share?shareId=${share?.shareId}${
getValues('showHistory') ? '' : '&showHistory=0'
}`;
const wayMap = {
[UsingWayEnum.link]: {
blockTitle: t('core.app.outLink.Link block title'),
code: linkUrl
},
[UsingWayEnum.iframe]: {
blockTitle: t('core.app.outLink.Iframe block title'),
code: `<iframe
src="${linkUrl}"
style="width: 100%; height: 100%;"
frameborder="0"
allow="microphone"
/>`
},
[UsingWayEnum.script]: {
blockTitle: t('core.app.outLink.Script block title'),
code: `<script
src="${location?.origin}/js/iframe.js"
id="chatbot-iframe"
data-bot-src="${linkUrl}"
data-default-open="${getValues('scriptDefaultOpen') ? 'true' : 'false'}"
data-drag="${getValues('scriptIconCanDrag') ? 'true' : 'false'}"
data-open-icon="${getValues('scriptOpenIcon')}"
data-close-icon="${getValues('scriptCloseIcon')}"
defer
/>`
}
};
const gridItemStyle: FlexProps = {
alignItems: 'center',
bg: 'myWhite.600',
p: 2,
borderRadius: 'md',
border: theme.borders.sm
};
return (
<MyModal
isOpen
iconSrc="/imgs/modal/usingWay.svg"
title={t('core.app.outLink.Select Using Way')}
onClose={onClose}
maxW={['90vw', '700px']}
>
<ModalBody py={4}>
<MyRadio
gridGap={2}
gridTemplateColumns={['repeat(1,1fr)', 'repeat(3,1fr)']}
value={getValues('usingWay')}
list={VariableTypeList}
hiddenCircle
p={0}
onChange={(e) => {
setValue('usingWay', e);
}}
/>
{/* config */}
<Grid gridTemplateColumns={['repeat(3,1fr)']} gridGap={4} my={5}>
<Flex {...gridItemStyle}>
<Box flex={1}>{t('core.app.outLink.Show History')}</Box>
<Switch {...register('showHistory')} />
</Flex>
{getValues('usingWay') === UsingWayEnum.script && (
<>
<Flex {...gridItemStyle}>
<Box flex={1}>{t('core.app.outLink.Can Drag')}</Box>
<Switch {...register('scriptIconCanDrag')} />
</Flex>
<Flex {...gridItemStyle}>
<Box flex={1}>{t('core.app.outLink.Default open')}</Box>
<Switch {...register('scriptDefaultOpen')} />
</Flex>
<Flex {...gridItemStyle}>
<Box flex={1}>{t('core.app.outLink.Script Open Icon')}</Box>
<Image
src={getValues('scriptOpenIcon')}
alt={''}
w={'20px'}
h={'20px'}
cursor={'pointer'}
onClick={() => onOpen('scriptOpenIcon')}
/>
</Flex>
<Flex {...gridItemStyle}>
<Box flex={1}>{t('core.app.outLink.Script Close Icon')}</Box>
<Image
src={getValues('scriptCloseIcon')}
alt={''}
w={'20px'}
h={'20px'}
cursor={'pointer'}
onClick={() => onOpen('scriptCloseIcon')}
/>
</Flex>
</>
)}
</Grid>
{/* code */}
<Box borderRadius={'md'} bg={'myGray.100'} overflow={'hidden'}>
<Flex
p={3}
bg={'myWhite.500'}
border={theme.borders.base}
borderTopLeftRadius={'md'}
borderTopRightRadius={'md'}
>
<Box flex={1}>{wayMap[getValues('usingWay')].blockTitle}</Box>
<MyIcon
name={'copy'}
w={'16px'}
color={'myGray.600'}
cursor={'pointer'}
_hover={{ color: 'myBlue.600' }}
onClick={() => {
copyData(wayMap[getValues('usingWay')].code);
}}
/>
</Flex>
<Box whiteSpace={'pre'} p={3} overflowX={'auto'}>
{wayMap[getValues('usingWay')].code}
</Box>
</Box>
</ModalBody>
<File onSelect={selectFile} />
</MyModal>
);
};
export default SelectUsingWayModal;

View File

@@ -34,7 +34,7 @@ import { formatTimeToChatTime } from '@/utils/tools';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { useForm } from 'react-hook-form';
import { defaultOutLinkForm } from '@/constants/app';
import type { OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
import { useRequest } from '@/web/common/hooks/useRequest';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
@@ -45,12 +45,16 @@ import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
import dayjs from 'dayjs';
import { getDocPath } from '@/web/common/system/doc';
import dynamic from 'next/dynamic';
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
const Share = ({ appId }: { appId: string }) => {
const { t } = useTranslation();
const { Loading, setIsLoading } = useLoading();
const { copyData } = useCopyData();
const [editLinkData, setEditLinkData] = useState<OutLinkEditType>();
const [selectedLinkData, setSelectedLinkData] = useState<OutLinkSchema>();
const { toast } = useToast();
const {
@@ -141,6 +145,15 @@ const Share = ({ appId }: { appId: string }) => {
<MyIcon name={'more'} w={'14px'} p={2} />
</MenuButton>
<MenuList color={'myGray.700'} minW={`120px !important`} zIndex={10}>
<MenuItem
onClick={() => {
setSelectedLinkData(item);
}}
py={[2, 3]}
>
<MyIcon name={'copy'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('core.app.outLink.Select Mode')}</Box>
</MenuItem>
<MenuItem
onClick={() =>
setEditLinkData({
@@ -155,28 +168,6 @@ const Share = ({ appId }: { appId: string }) => {
<MyIcon name={'edit'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Edit')}</Box>
</MenuItem>
<MenuItem
onClick={() => {
const url = `${location.origin}/chat/share?shareId=${item.shareId}`;
copyData(url, '已复制分享链接,可直接分享使用');
}}
py={[2, 3]}
>
<MyIcon name={'copy'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Copy')}</Box>
</MenuItem>
<MenuItem
onClick={() => {
const url = `${location.origin}/chat/share?shareId=${item.shareId}`;
const src = `${location.origin}/js/iframe.js`;
const script = `<script src="${src}" id="fastgpt-iframe" data-src="${url}" data-color="#4e83fd"></script>`;
copyData(script, '已复制嵌入 Script可在应用 HTML 底部嵌入', 3000);
}}
py={[2, 3]}
>
<MyIcon name={'apiLight'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('outlink.Copy IFrame')}</Box>
</MenuItem>
<MenuItem
onClick={async () => {
setIsLoading(true);
@@ -232,6 +223,12 @@ const Share = ({ appId }: { appId: string }) => {
onClose={() => setEditLinkData(undefined)}
/>
)}
{!!selectedLinkData && (
<SelectUsingWayModal
share={selectedLinkData}
onClose={() => setSelectedLinkData(undefined)}
/>
)}
<Loading loading={isFetching} fixed={false} />
</Box>
);
@@ -290,7 +287,7 @@ function EditLinkModal({
>
<ModalBody>
<Flex alignItems={'center'}>
<Box flex={'0 0 90px'}>{t('Name')}:</Box>
<Box flex={'0 0 90px'}>{t('Name')}</Box>
<Input
placeholder={t('outlink.Link Name') || 'Link Name'}
maxLength={20}
@@ -303,7 +300,7 @@ function EditLinkModal({
<>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
QPM:
QPM
<MyTooltip label={t('outlink.QPM Tips' || '')}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
@@ -320,7 +317,7 @@ function EditLinkModal({
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
{t('common.Max credit')}:
{t('common.Max credit')}
<MyTooltip label={t('common.Max credit tips' || '')}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
@@ -336,7 +333,7 @@ function EditLinkModal({
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
{t('common.Expired Time')}:
{t('common.Expired Time')}
</Flex>
<Input
type="datetime-local"
@@ -351,7 +348,7 @@ function EditLinkModal({
/>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
{t('outlink.token auth')}
<MyTooltip label={t('outlink.token auth Tips') || ''}>
<QuestionOutlineIcon ml={1} />
@@ -359,6 +356,7 @@ function EditLinkModal({
</Flex>
<Input
placeholder={t('outlink.token auth Tips') || ''}
fontSize={'sm'}
{...register('limit.hookUrl')}
/>
</Flex>
@@ -375,7 +373,7 @@ function EditLinkModal({
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
{t('outlink.Response Detail')}:
{t('outlink.Response Detail')}
<MyTooltip label={t('outlink.Response Detail tips' || '')}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>

View File

@@ -51,6 +51,7 @@ import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constant
import QGSwitch from '@/components/core/module/Flow/components/modules/QGSwitch';
import TTSSelect from '@/components/core/module/Flow/components/modules/TTSSelect';
import VariableEdit from '@/components/core/module/Flow/components/modules/VariableEdit';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
const InfoModal = dynamic(() => import('../InfoModal'));
const DatasetSelectModal = dynamic(() => import('@/components/core/module/DatasetSelectModal'));
@@ -635,10 +636,19 @@ function ChatTest({ appId }: { appId: string }) {
const startChat = useCallback(
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
const historyMaxLen =
modules
?.find((item) => item.flowType === FlowNodeTypeEnum.historyNode)
?.inputs?.find((item) => item.key === 'maxContext')?.value || 0;
let historyMaxLen = 0;
modules.forEach((module) => {
module.inputs.forEach((input) => {
if (
(input.key === ModuleInputKeyEnum.history ||
input.key === ModuleInputKeyEnum.historyMaxAmount) &&
typeof input.value === 'number'
) {
historyMaxLen = Math.max(historyMaxLen, input.value);
}
});
});
const history = chatList.slice(-historyMaxLen - 2, -2);
// 流请求,获取数据

View File

@@ -15,6 +15,7 @@ const ChatHeader = ({
appAvatar,
chatModels,
appId,
showHistory,
onOpenSlider
}: {
history: ChatItemType[];
@@ -22,6 +23,7 @@ const ChatHeader = ({
appAvatar: string;
chatModels?: string[];
appId?: string;
showHistory?: boolean;
onOpenSlider: () => void;
}) => {
const router = useRouter();
@@ -63,7 +65,16 @@ const ChatHeader = ({
</>
) : (
<>
<MyIcon name={'menu'} w={'20px'} h={'20px'} color={'myGray.900'} onClick={onOpenSlider} />
{showHistory && (
<MyIcon
name={'menu'}
w={'20px'}
h={'20px'}
color={'myGray.900'}
onClick={onOpenSlider}
/>
)}
<Flex px={3} alignItems={'center'} flex={'1 0 0'} w={0} justifyContent={'center'}>
<Avatar src={appAvatar} w={'16px'} />
<Box

View File

@@ -1,15 +1,3 @@
.stopIcon {
animation: zoomStopIcon 0.4s infinite alternate;
}
@keyframes zoomStopIcon {
0% {
transform: scale(0.8);
}
100% {
transform: scale(1.2);
}
}
.newChat {
.modelListContainer {
height: 0;

View File

@@ -297,7 +297,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
onCloseSlider();
}
}}
onDelHistory={delOneHistory}
onDelHistory={(e) => delOneHistory({ ...e, appId })}
onClearHistory={() => {
clearHistories({ appId });
router.replace({
@@ -307,10 +307,11 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
});
}}
onSetHistoryTop={(e) => {
updateHistory(e);
updateHistory({ ...e, appId });
}}
onSetCustomTitle={async (e) => {
updateHistory({
appId,
chatId: e.chatId,
title: e.title,
customTitle: e.title
@@ -334,6 +335,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
history={chatData.history}
chatModels={chatData.app.chatModels}
onOpenSlider={onOpenSlider}
showHistory
/>
{/* chat box */}
@@ -348,7 +350,8 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
feedbackType={'user'}
onUpdateVariable={(e) => {}}
onStartChat={startChat}
onDelMessage={(e) => delOneHistoryItem({ ...e, chatId })}
onDelMessage={(e) => delOneHistoryItem({ ...e, appId, chatId })}
appId={appId}
chatId={chatId}
/>
</Box>

View File

@@ -300,7 +300,9 @@ const OutLink = ({
onCloseSlider();
}
}}
onDelHistory={({ chatId }) => delOneHistory({ chatId, shareId, outLinkUid })}
onDelHistory={({ chatId }) =>
delOneHistory({ appId: chatData.appId, chatId, shareId, outLinkUid })
}
onClearHistory={() => {
clearHistories({ shareId, outLinkUid });
router.replace({
@@ -313,12 +315,14 @@ const OutLink = ({
onSetHistoryTop={(e) => {
updateHistory({
...e,
appId: chatData.appId,
shareId,
outLinkUid
});
}}
onSetCustomTitle={async (e) => {
updateHistory({
appId: chatData.appId,
chatId: e.chatId,
title: e.title,
customTitle: e.title,
@@ -343,6 +347,7 @@ const OutLink = ({
appAvatar={chatData.app.avatar}
appName={chatData.app.name}
history={chatData.history}
showHistory={showHistory === '1'}
onOpenSlider={onOpenSlider}
/>
{/* chat box */}
@@ -357,7 +362,10 @@ const OutLink = ({
feedbackType={'user'}
onUpdateVariable={(e) => {}}
onStartChat={startChat}
onDelMessage={(e) => delOneHistoryItem({ ...e, chatId, shareId, outLinkUid })}
onDelMessage={(e) =>
delOneHistoryItem({ ...e, appId: chatData.appId, chatId, shareId, outLinkUid })
}
appId={chatData.appId}
chatId={chatId}
shareId={shareId}
outLinkUid={outLinkUid}