mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-01 20:27:45 +00:00
v4.6.4-Outlink (#589)
This commit is contained in:
@@ -6,11 +6,13 @@ import { useTranslation } from 'next-i18next';
|
||||
import { updateChatUserFeedback } from '@/web/core/chat/api';
|
||||
|
||||
const FeedbackModal = ({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId,
|
||||
onSuccess,
|
||||
onClose
|
||||
}: {
|
||||
appId: string;
|
||||
chatId: string;
|
||||
chatItemId: string;
|
||||
onSuccess: (e: string) => void;
|
||||
@@ -23,6 +25,7 @@ const FeedbackModal = ({
|
||||
mutationFn: async () => {
|
||||
const val = ref.current?.value || t('core.chat.feedback.No Content');
|
||||
return updateChatUserFeedback({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId,
|
||||
userBadFeedback: val
|
||||
|
@@ -429,7 +429,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
|
||||
>
|
||||
{isChatting ? (
|
||||
<MyIcon
|
||||
className={styles.stopIcon}
|
||||
animation={'zoomStopIcon 0.4s infinite alternate'}
|
||||
width={['22px', '25px']}
|
||||
height={['22px', '25px']}
|
||||
cursor={'pointer'}
|
||||
|
@@ -1,7 +1,3 @@
|
||||
.stopIcon {
|
||||
animation: zoomStopIcon 0.4s infinite alternate;
|
||||
}
|
||||
|
||||
.statusAnimation {
|
||||
animation: statusBox 0.8s linear infinite alternate;
|
||||
}
|
||||
|
@@ -102,9 +102,13 @@ type Props = {
|
||||
userGuideModule?: ModuleItemType;
|
||||
showFileSelector?: boolean;
|
||||
active?: boolean; // can use
|
||||
|
||||
// not chat test params
|
||||
appId?: string;
|
||||
chatId?: string;
|
||||
shareId?: string;
|
||||
outLinkUid?: string;
|
||||
|
||||
onUpdateVariable?: (e: Record<string, any>) => void;
|
||||
onStartChat?: (e: StartChatFnProps) => Promise<{
|
||||
responseText: string;
|
||||
@@ -125,6 +129,7 @@ const ChatBox = (
|
||||
userGuideModule,
|
||||
showFileSelector,
|
||||
active = true,
|
||||
appId,
|
||||
chatId,
|
||||
shareId,
|
||||
outLinkUid,
|
||||
@@ -711,7 +716,7 @@ const ChatBox = (
|
||||
return;
|
||||
}
|
||||
return () => {
|
||||
if (!item.dataId || !chatId) return;
|
||||
if (!item.dataId || !chatId || !appId) return;
|
||||
|
||||
const isGoodFeedback = !!item.userGoodFeedback;
|
||||
setChatHistory((state) =>
|
||||
@@ -726,6 +731,7 @@ const ChatBox = (
|
||||
);
|
||||
try {
|
||||
updateChatUserFeedback({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId: item.dataId,
|
||||
shareId,
|
||||
@@ -738,7 +744,7 @@ const ChatBox = (
|
||||
onCloseUserLike={
|
||||
feedbackType === FeedbackTypeEnum.admin
|
||||
? () => {
|
||||
if (!item.dataId || !chatId) return;
|
||||
if (!item.dataId || !chatId || !appId) return;
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === item.dataId
|
||||
@@ -747,6 +753,7 @@ const ChatBox = (
|
||||
)
|
||||
);
|
||||
updateChatUserFeedback({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId: item.dataId,
|
||||
userGoodFeedback: undefined
|
||||
@@ -760,7 +767,7 @@ const ChatBox = (
|
||||
}
|
||||
if (item.userBadFeedback) {
|
||||
return () => {
|
||||
if (!item.dataId || !chatId) return;
|
||||
if (!item.dataId || !chatId || !appId) return;
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === item.dataId
|
||||
@@ -770,6 +777,7 @@ const ChatBox = (
|
||||
);
|
||||
try {
|
||||
updateChatUserFeedback({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId: item.dataId,
|
||||
shareId,
|
||||
@@ -886,8 +894,9 @@ const ChatBox = (
|
||||
/>
|
||||
) : null}
|
||||
{/* user feedback modal */}
|
||||
{!!feedbackId && chatId && (
|
||||
{!!feedbackId && chatId && appId && (
|
||||
<FeedbackModal
|
||||
appId={appId}
|
||||
chatId={chatId}
|
||||
chatItemId={feedbackId}
|
||||
onClose={() => setFeedbackId(undefined)}
|
||||
@@ -915,8 +924,9 @@ const ChatBox = (
|
||||
)
|
||||
);
|
||||
try {
|
||||
if (!chatId) return;
|
||||
if (!chatId || !appId) return;
|
||||
updateChatUserFeedback({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId: readFeedbackData.chatItemId
|
||||
});
|
||||
@@ -948,8 +958,9 @@ const ChatBox = (
|
||||
)
|
||||
);
|
||||
|
||||
if (readFeedbackData && chatId) {
|
||||
if (readFeedbackData && chatId && appId) {
|
||||
updateChatUserFeedback({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId: readFeedbackData.chatItemId,
|
||||
userBadFeedback: undefined
|
||||
|
@@ -10,6 +10,7 @@ import {
|
||||
Image
|
||||
} from '@chakra-ui/react';
|
||||
import MyIcon from '../Icon';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
export interface MyModalProps extends ModalContentProps {
|
||||
iconSrc?: string;
|
||||
@@ -30,12 +31,13 @@ const MyModal = ({
|
||||
maxW = ['90vw', '600px'],
|
||||
...props
|
||||
}: MyModalProps) => {
|
||||
const { isPc } = useSystemStore();
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={() => onClose && onClose()}
|
||||
autoFocus={false}
|
||||
isCentered={isCentered}
|
||||
isCentered={isPc ? isCentered : true}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent
|
||||
|
@@ -5,11 +5,12 @@ import { useTranslation } from 'next-i18next';
|
||||
|
||||
// @ts-ignore
|
||||
interface Props extends GridProps {
|
||||
list: { icon?: string; title: string; desc?: string; value: string | number }[];
|
||||
list: { icon?: string; title: string | React.ReactNode; desc?: string; value: any }[];
|
||||
iconSize?: string;
|
||||
align?: 'top' | 'center';
|
||||
value: string | number;
|
||||
onChange: (e: string | number) => void;
|
||||
value: any;
|
||||
hiddenCircle?: boolean;
|
||||
onChange: (e: any) => void;
|
||||
}
|
||||
|
||||
const MyRadio = ({
|
||||
@@ -17,6 +18,8 @@ const MyRadio = ({
|
||||
value,
|
||||
align = 'center',
|
||||
iconSize = '18px',
|
||||
hiddenCircle = false,
|
||||
p,
|
||||
onChange,
|
||||
...props
|
||||
}: Props) => {
|
||||
@@ -32,7 +35,8 @@ const MyRadio = ({
|
||||
userSelect={'none'}
|
||||
py={3}
|
||||
pl={'14px'}
|
||||
pr={'36px'}
|
||||
pr={hiddenCircle ? '14px' : '36px'}
|
||||
p={p !== undefined ? `${p} !important` : undefined}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
@@ -50,6 +54,7 @@ const MyRadio = ({
|
||||
})}
|
||||
_after={{
|
||||
content: '""',
|
||||
display: hiddenCircle ? 'none' : 'block',
|
||||
position: 'absolute',
|
||||
right: '14px',
|
||||
w: '16px',
|
||||
@@ -79,8 +84,8 @@ const MyRadio = ({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Box pr={2}>
|
||||
<Box>{t(item.title)}</Box>
|
||||
<Box pr={hiddenCircle ? 0 : 2} color={'myGray.800'}>
|
||||
<Box>{typeof item.title === 'string' ? t(item.title) : item.title}</Box>
|
||||
{!!item.desc && (
|
||||
<Box fontSize={['xs', 'sm']} color={'myGray.500'}>
|
||||
{t(item.desc)}
|
||||
|
@@ -10,13 +10,13 @@ import React, {
|
||||
} from 'react';
|
||||
import { Box, Flex, IconButton } from '@chakra-ui/react';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
import { streamFetch } from '@/web/common/api/fetch';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||
import { getGuideModule } from '@fastgpt/global/core/module/utils';
|
||||
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
|
||||
export type ChatTestComponentRef = {
|
||||
resetChatTest: () => void;
|
||||
@@ -40,10 +40,18 @@ const ChatTest = (
|
||||
|
||||
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 = 6;
|
||||
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);
|
||||
|
||||
// 流请求,获取数据
|
||||
|
@@ -28,7 +28,7 @@ import React, {
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { appModule2FlowEdge, appModule2FlowNode } from '@/utils/adapt';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
import { ModuleDataTypeEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
@@ -449,9 +449,9 @@ export function flowNode2Modules({
|
||||
flowType: item.data.flowType,
|
||||
showStatus: item.data.showStatus,
|
||||
position: item.position,
|
||||
inputs: item.data.inputs.map((item) => ({
|
||||
...item,
|
||||
connected: Boolean(item.value ?? item.connected ?? item.type !== FlowNodeInputTypeEnum.target)
|
||||
inputs: item.data.inputs.map((input) => ({
|
||||
...input,
|
||||
connected: false
|
||||
})),
|
||||
outputs: item.data.outputs.map((item) => ({
|
||||
...item,
|
||||
@@ -462,10 +462,11 @@ export function flowNode2Modules({
|
||||
// update inputs and outputs
|
||||
modules.forEach((module) => {
|
||||
module.inputs.forEach((input) => {
|
||||
input.connected =
|
||||
input.connected ||
|
||||
!!edges.find((edge) => edge.target === module.moduleId && edge.targetHandle === input.key);
|
||||
input.connected = !!edges.find(
|
||||
(edge) => edge.target === module.moduleId && edge.targetHandle === input.key
|
||||
);
|
||||
});
|
||||
|
||||
module.outputs.forEach((output) => {
|
||||
output.targets = edges
|
||||
.filter(
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -12,9 +12,7 @@ import {
|
||||
Flex,
|
||||
Switch,
|
||||
Input,
|
||||
Grid,
|
||||
FormControl,
|
||||
useTheme,
|
||||
Image,
|
||||
Table,
|
||||
Thead,
|
||||
@@ -39,6 +37,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { variableTip } from '@fastgpt/global/core/module/template/tip';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import MyRadio from '@/components/common/MyRadio';
|
||||
|
||||
const VariableEdit = ({
|
||||
variables,
|
||||
@@ -49,26 +48,28 @@ const VariableEdit = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const theme = useTheme();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const VariableTypeList = [
|
||||
{
|
||||
label: t('core.module.variable.input type'),
|
||||
icon: 'core/app/variable/input',
|
||||
key: VariableInputEnum.input
|
||||
},
|
||||
{
|
||||
label: t('core.module.variable.textarea type'),
|
||||
icon: 'core/app/variable/textarea',
|
||||
key: VariableInputEnum.textarea
|
||||
},
|
||||
{
|
||||
label: t('core.module.variable.select type'),
|
||||
icon: 'core/app/variable/select',
|
||||
key: VariableInputEnum.select
|
||||
}
|
||||
];
|
||||
const VariableTypeList = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: t('core.module.variable.input type'),
|
||||
icon: 'core/app/variable/input',
|
||||
value: VariableInputEnum.input
|
||||
},
|
||||
{
|
||||
title: t('core.module.variable.textarea type'),
|
||||
icon: 'core/app/variable/textarea',
|
||||
value: VariableInputEnum.textarea
|
||||
},
|
||||
{
|
||||
title: t('core.module.variable.select type'),
|
||||
icon: 'core/app/variable/select',
|
||||
value: VariableInputEnum.select
|
||||
}
|
||||
],
|
||||
[t]
|
||||
);
|
||||
|
||||
const { isOpen: isOpenEdit, onOpen: onOpenEdit, onClose: onCloseEdit } = useDisclosure();
|
||||
const {
|
||||
@@ -102,9 +103,9 @@ const VariableEdit = ({
|
||||
const formatVariables = useMemo(() => {
|
||||
return variables.map((item) => ({
|
||||
...item,
|
||||
icon: VariableTypeList.find((type) => type.key === item.type)?.icon
|
||||
icon: VariableTypeList.find((type) => type.value === item.type)?.icon
|
||||
}));
|
||||
}, [variables]);
|
||||
}, [VariableTypeList, variables]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@@ -206,38 +207,18 @@ const VariableEdit = ({
|
||||
<Box mt={5} mb={2}>
|
||||
{t('core.module.Field Type')}
|
||||
</Box>
|
||||
<Grid gridTemplateColumns={'repeat(3,1fr)'} gridGap={4}>
|
||||
{VariableTypeList.map((item) => (
|
||||
<Flex
|
||||
key={item.key}
|
||||
px={3}
|
||||
py={3}
|
||||
border={theme.borders.base}
|
||||
borderRadius={'md'}
|
||||
cursor={'pointer'}
|
||||
{...(item.key === getValuesEdit('variable.type')
|
||||
? {
|
||||
bg: 'myBlue.100',
|
||||
borderColor: 'myBlue.600',
|
||||
color: 'myBlue.600',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
: {
|
||||
color: 'myGray.600',
|
||||
_hover: {
|
||||
boxShadow: 'md'
|
||||
},
|
||||
onClick: () => {
|
||||
setValuesEdit('variable.type', item.key);
|
||||
setRefresh(!refresh);
|
||||
}
|
||||
})}
|
||||
>
|
||||
<MyIcon name={item.icon as any} w={'16px'} />
|
||||
<Box ml={2}>{item.label}</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</Grid>
|
||||
<MyRadio
|
||||
gridGap={4}
|
||||
gridTemplateColumns={'repeat(3,1fr)'}
|
||||
value={getValuesEdit('variable.type')}
|
||||
list={VariableTypeList}
|
||||
color={'myGray.600'}
|
||||
hiddenCircle
|
||||
onChange={(e) => {
|
||||
setValuesEdit('variable.type', e as any);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
|
||||
{getValuesEdit('variable.type') === VariableInputEnum.input && (
|
||||
<>
|
||||
|
@@ -97,7 +97,7 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<SourceHandle handleKey={item.key} valueType={ModuleDataTypeEnum.boolean} />
|
||||
<SourceHandle handleKey={item.key} valueType={ModuleDataTypeEnum.string} />
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
|
@@ -29,7 +29,7 @@ import TargetHandle from './TargetHandle';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import type { AIChatModuleProps } from '@fastgpt/global/core/module/node/type.d';
|
||||
import { chatModelList } from '@/web/common/system/staticData';
|
||||
import { chatModelList, cqModelList } from '@/web/common/system/staticData';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
|
||||
@@ -229,8 +229,11 @@ const RenderInput = ({
|
||||
{item.type === FlowNodeInputTypeEnum.aiSettings && (
|
||||
<AISetting inputs={sortInputs} item={item} moduleId={moduleId} />
|
||||
)}
|
||||
{item.type === FlowNodeInputTypeEnum.selectChatModel && (
|
||||
<SelectChatModelRender inputs={sortInputs} item={item} moduleId={moduleId} />
|
||||
{[
|
||||
FlowNodeInputTypeEnum.selectChatModel,
|
||||
FlowNodeInputTypeEnum.selectCQModel
|
||||
].includes(item.type as any) && (
|
||||
<SelectAIModelRender inputs={sortInputs} item={item} moduleId={moduleId} />
|
||||
)}
|
||||
{item.type === FlowNodeInputTypeEnum.selectDataset && (
|
||||
<SelectDatasetRender item={item} moduleId={moduleId} />
|
||||
@@ -446,12 +449,21 @@ const AISetting = React.memo(function AISetting({ inputs = [], moduleId }: Rende
|
||||
);
|
||||
});
|
||||
|
||||
const SelectChatModelRender = React.memo(function SelectChatModelRender({
|
||||
const SelectAIModelRender = React.memo(function SelectAIModelRender({
|
||||
inputs = [],
|
||||
item,
|
||||
moduleId
|
||||
}: RenderProps) {
|
||||
const modelList = chatModelList || [];
|
||||
const modelList = (() => {
|
||||
if (item.type === FlowNodeInputTypeEnum.selectChatModel) return chatModelList;
|
||||
if (item.type === FlowNodeInputTypeEnum.selectCQModel) return cqModelList;
|
||||
return [];
|
||||
})().map((item) => ({
|
||||
model: item.model,
|
||||
name: item.name,
|
||||
maxResponse: item.maxResponse,
|
||||
price: item.price
|
||||
}));
|
||||
|
||||
const onChangeModel = useCallback(
|
||||
(e: string) => {
|
||||
|
Reference in New Issue
Block a user