mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 02:12:38 +00:00
v4.6.4-Outlink (#589)
This commit is contained in:
@@ -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',
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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[] = [
|
||||
|
@@ -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 =
|
||||
|
@@ -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,
|
||||
|
@@ -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>
|
||||
|
@@ -321,6 +321,7 @@ function DetailLogsModal({
|
||||
showMarkIcon
|
||||
showVoiceIcon={false}
|
||||
userGuideModule={chat?.app?.userGuideModule}
|
||||
appId={appId}
|
||||
chatId={chatId}
|
||||
/>
|
||||
</Box>
|
||||
|
@@ -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;
|
@@ -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;
|
@@ -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>
|
||||
|
@@ -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);
|
||||
|
||||
// 流请求,获取数据
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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>
|
||||
|
@@ -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}
|
||||
|
Reference in New Issue
Block a user