* Milvus (#1644)

* feat: support regx

* 4.8.3 test and fix (#1648)

* perf: version tip

* feat: sandbox support log

* fix: debug component render

* fix: share page header

* fix: input guide auth

* fix: iso viewport

* remove file

* fix: route url

* feat: add debug timout

* perf: reference select support trigger

* perf: session code

* perf: theme

* perf: load milvus
This commit is contained in:
Archer
2024-06-01 09:26:11 +08:00
committed by GitHub
parent 9fc6a8c74a
commit a259d034b8
81 changed files with 1775 additions and 594 deletions

View File

@@ -18,8 +18,14 @@ OPENAI_BASE_URL=https://api.openai.com/v1
CHAT_API_KEY=sk-xxxx
# mongo 数据库连接参数本地开发时mongo可能需要增加 directConnection=true 参数,才能连接上。
MONGODB_URI=mongodb://username:password@0.0.0.0:27017/fastgpt?authSource=admin
# PG 数据库连接参数
# 向量库优先级: pg > milvus
# PG 向量库连接参数
PG_URL=postgresql://username:password@host:port/postgres
# mivlus 向量库连接参数
MILVUS_ADDRESS=https://in03-78bd7f60e6e2a7c.api.gcp-us-west1.zillizcloud.com
MILVUS_TOKEN=133964348b00b4b4e4b51bef680a61350950385c8c64a3ec16b1ab92d3c67dcc4e0370fb9dd15791bcd6dadaf765e98a98735d0d
# code sandbox url
SANDBOX_URL=http://localhost:3001
# 商业版地址

View File

@@ -62,9 +62,11 @@ COPY --from=builder --chown=nextjs:nodejs /app/projects/app/.next/server/chunks
# copy worker
COPY --from=builder --chown=nextjs:nodejs /app/projects/app/.next/server/worker /app/projects/app/.next/server/worker
# copy tiktoken but not copy ./node_modules/tiktoken/encoders
# copy standload packages
COPY --from=mainDeps /app/node_modules/tiktoken ./node_modules/tiktoken
RUN rm -rf ./node_modules/tiktoken/encoders
COPY --from=mainDeps /app/node_modules/@zilliz/milvus2-sdk-node ./node_modules/@zilliz/milvus2-sdk-node
# copy package.json to version file
COPY --from=builder /app/projects/app/package.json ./package.json

View File

@@ -5,7 +5,12 @@
"Reset template": "Reset template",
"Reset template confirm": "Are you sure to restore the code template? Be careful to save the current code."
},
"ifelse": {
"Input value": "Input",
"Select value": "Select"
},
"response": {
"Code log": "Log",
"Custom inputs": "Custom inputs",
"Custom outputs": "Custom outputs",
"Error": "Error"

View File

@@ -184,7 +184,7 @@
"not support": "您的浏览器不支持语音输入"
},
"system": {
"Commercial version function": "商业版特有功能",
"Commercial version function": "请升级商业版后使用该功能: https://fastgpt.in",
"Help Chatbot": "机器人助手",
"Use Helper": "使用帮助"
},

View File

@@ -5,7 +5,12 @@
"Reset template": "还原模板",
"Reset template confirm": "确认还原代码模板?请注意保存当前代码。"
},
"ifelse": {
"Input value": "输入值",
"Select value": "选择值"
},
"response": {
"Code log": "Log日志",
"Custom inputs": "自定义输入",
"Custom outputs": "自定义输出",
"Error": "错误信息"

View File

@@ -2,10 +2,12 @@
const { i18n } = require('./next-i18next.config');
const path = require('path');
const isDev = process.env.NODE_ENV === 'development';
const nextConfig = {
i18n,
output: 'standalone',
reactStrictMode: process.env.NODE_ENV === 'development' ? false : true,
reactStrictMode: isDev ? false : true,
compress: true,
webpack(config, { isServer, nextRuntime }) {
Object.assign(config.resolve.alias, {
@@ -41,11 +43,9 @@ const nextConfig = {
}
if (isServer) {
config.externals.push('worker_threads');
// config.externals.push('@zilliz/milvus2-sdk-node');
if (nextRuntime === 'nodejs') {
// config.output.globalObject = 'self';
const oldEntry = config.entry;
config = {
...config,
@@ -89,7 +89,12 @@ const nextConfig = {
transpilePackages: ['@fastgpt/*', 'ahooks'],
experimental: {
// 优化 Server Components 的构建和运行,避免不必要的客户端打包。
serverComponentsExternalPackages: ['mongoose', 'pg', '@node-rs/jieba'],
serverComponentsExternalPackages: [
'mongoose',
'pg',
'@node-rs/jieba',
'@zilliz/milvus2-sdk-node'
],
outputFileTracingRoot: path.join(__dirname, '../../')
}
};

View File

@@ -1,6 +1,6 @@
{
"name": "app",
"version": "4.8.1",
"version": "4.8.3",
"private": false,
"scripts": {
"dev": "next dev",

View File

@@ -51,16 +51,8 @@ const ChatInput = ({
name: 'files'
});
const {
shareId,
outLinkUid,
teamId,
teamToken,
isChatting,
whisperConfig,
autoTTSResponse,
chatInputGuide
} = useContextSelector(ChatBoxContext, (v) => v);
const { isChatting, whisperConfig, autoTTSResponse, chatInputGuide, outLinkAuthData } =
useContextSelector(ChatBoxContext, (v) => v);
const { isPc, whisperModel } = useSystemStore();
const canvasRef = useRef<HTMLCanvasElement>(null);
const { t } = useTranslation();
@@ -87,10 +79,7 @@ const ChatInput = ({
maxSize: 1024 * 1024 * 16,
// 7 day expired.
expiredTime: addDays(new Date(), 7),
shareId,
outLinkUid,
teamId,
teamToken
...outLinkAuthData
});
updateFile(fileIndex, {
...file,
@@ -175,7 +164,7 @@ const ChatInput = ({
speakingTimeString,
renderAudioGraph,
stream
} = useSpeech({ appId, shareId, outLinkUid, teamId, teamToken });
} = useSpeech({ appId, ...outLinkAuthData });
useEffect(() => {
if (!stream) {
return;

View File

@@ -24,6 +24,7 @@ export default function InputGuideBox({
const { t } = useTranslation();
const { chatT } = useI18n();
const chatInputGuide = useContextSelector(ChatBoxContext, (v) => v.chatInputGuide);
const outLinkAuthData = useContextSelector(ChatBoxContext, (v) => v.outLinkAuthData);
const { data = [] } = useRequest2(
async () => {
@@ -31,7 +32,8 @@ export default function InputGuideBox({
return await queryChatInputGuideList(
{
appId,
searchKey: text.slice(0, 50)
searchKey: text.slice(0, 50),
...outLinkAuthData
},
chatInputGuide.customUrl ? chatInputGuide.customUrl : undefined
);

View File

@@ -45,6 +45,7 @@ type useChatStoreType = OutLinkChatAuthProps & {
setChatHistories: React.Dispatch<React.SetStateAction<ChatSiteItemType[]>>;
isChatting: boolean;
chatInputGuide: ChatInputGuideConfigType;
outLinkAuthData: OutLinkChatAuthProps;
};
export const ChatBoxContext = createContext<useChatStoreType>({
welcomeText: '',
@@ -98,7 +99,8 @@ export const ChatBoxContext = createContext<useChatStoreType>({
chatInputGuide: {
open: false,
customUrl: ''
}
},
outLinkAuthData: {}
});
export type ChatProviderProps = OutLinkChatAuthProps & {
@@ -128,6 +130,16 @@ const Provider = ({
chatInputGuide = defaultChatInputGuideConfig
} = useMemo(() => chatConfig, [chatConfig]);
const outLinkAuthData = useMemo(
() => ({
shareId,
outLinkUid,
teamId,
teamToken
}),
[shareId, outLinkUid, teamId, teamToken]
);
// segment audio
const [audioPlayingChatId, setAudioPlayingChatId] = useState<string>();
const {
@@ -141,10 +153,7 @@ const Provider = ({
splitText2Audio
} = useAudioPlay({
ttsConfig,
shareId,
outLinkUid,
teamId,
teamToken
...outLinkAuthData
});
const autoTTSResponse =
@@ -181,7 +190,8 @@ const Provider = ({
chatHistories,
setChatHistories,
isChatting,
chatInputGuide
chatInputGuide,
outLinkAuthData
};
return <ChatBoxContext.Provider value={value}>{children}</ChatBoxContext.Provider>;

View File

@@ -321,6 +321,7 @@ export const ResponseBox = React.memo(function ResponseBox({
{/* code */}
<Row label={workflowT('response.Custom inputs')} value={activeModule?.customInputs} />
<Row label={workflowT('response.Custom outputs')} value={activeModule?.customOutputs} />
<Row label={workflowT('response.Code log')} value={activeModule?.codeLog} />
</Box>
</>
);

View File

@@ -13,19 +13,10 @@ import Auth from './auth';
const Navbar = dynamic(() => import('./navbar'));
const NavbarPhone = dynamic(() => import('./navbarPhone'));
const UpdateInviteModal = dynamic(
() => import('@/components/support/user/team/UpdateInviteModal'),
{ ssr: false }
);
const NotSufficientModal = dynamic(() => import('@/components/support/wallet/NotSufficientModal'), {
ssr: false
});
const SystemMsgModal = dynamic(() => import('@/components/support/user/inform/SystemMsgModal'), {
ssr: false
});
const ImportantInform = dynamic(() => import('@/components/support/user/inform/ImportantInform'), {
ssr: false
});
const UpdateInviteModal = dynamic(() => import('@/components/support/user/team/UpdateInviteModal'));
const NotSufficientModal = dynamic(() => import('@/components/support/wallet/NotSufficientModal'));
const SystemMsgModal = dynamic(() => import('@/components/support/user/inform/SystemMsgModal'));
const ImportantInform = dynamic(() => import('@/components/support/user/inform/ImportantInform'));
const pcUnShowLayoutRoute: Record<string, boolean> = {
'/': true,
@@ -126,7 +117,7 @@ const Layout = ({ children }: { children: JSX.Element }) => {
{feConfigs?.isPlus && (
<>
{!!userInfo && <UpdateInviteModal />}
{isNotSufficientModal && !isHideNavbar && <NotSufficientModal />}
{isNotSufficientModal && <NotSufficientModal />}
{!!userInfo && <SystemMsgModal />}
{!!userInfo && importantInforms.length > 0 && (
<ImportantInform informs={importantInforms} refetch={refetchUnRead} />

View File

@@ -5,6 +5,10 @@ const NextHead = ({ title, icon, desc }: { title?: string; icon?: string; desc?:
return (
<Head>
<title>{title}</title>
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no, viewport-fit=cover"
/>
{desc && <meta name="description" content={desc} />}
{icon && <link rel="icon" href={icon} />}
</Head>

View File

@@ -145,10 +145,27 @@ export const useDebug = () => {
node.nodeId === runtimeNode.nodeId
? {
...runtimeNode,
inputs: runtimeNode.inputs.map((input) => ({
...input,
value: data[input.key] ?? input.value
}))
inputs: runtimeNode.inputs.map((input) => {
let parseValue = (() => {
try {
if (
input.valueType === WorkflowIOValueTypeEnum.string ||
input.valueType === WorkflowIOValueTypeEnum.number ||
input.valueType === WorkflowIOValueTypeEnum.boolean
)
return data[input.key];
return JSON.parse(data[input.key]);
} catch (e) {
return data[input.key];
}
})();
return {
...input,
value: parseValue ?? input.value
};
})
}
: node
),
@@ -168,7 +185,7 @@ export const useDebug = () => {
<Box flex={'1 0 0'} overflow={'auto'} px={6}>
{renderInputs.map((input) => {
const required = input.required || false;
console.log(input.valueType);
const RenderInput = (() => {
if (input.valueType === WorkflowIOValueTypeEnum.string) {
return (
@@ -206,19 +223,23 @@ export const useDebug = () => {
</Box>
);
}
if (typeof input.value === 'string') {
return (
<JsonEditor
bg={'myGray.50'}
placeholder={t(input.placeholder || '')}
resize
value={getValues(input.key)}
onChange={(e) => {
setValue(input.key, e);
}}
/>
);
let value = getValues(input.key) || '';
if (typeof value !== 'string') {
value = JSON.stringify(value, null, 2);
}
return (
<JsonEditor
bg={'myGray.50'}
placeholder={t(input.placeholder || '')}
resize
value={value}
onChange={(e) => {
setValue(input.key, e);
}}
/>
);
})();
return !!RenderInput ? (

View File

@@ -31,6 +31,7 @@ import { Position, useReactFlow } from 'reactflow';
import { getRefData } from '@/web/core/workflow/utils';
import DragIcon from '@fastgpt/web/components/common/DndDrag/DragIcon';
import { AppContext } from '@/web/core/app/context/appContext';
import { useI18n } from '@/web/context/I18n';
const ListItem = ({
provided,
@@ -415,6 +416,7 @@ const ConditionValueInput = ({
condition?: VariableConditionEnum;
onChange: (e: string) => void;
}) => {
const { workflowT } = useI18n();
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
// get value type
@@ -439,7 +441,7 @@ const ConditionValueInput = ({
]}
onchange={onChange}
value={value}
placeholder={'选择值'}
placeholder={workflowT('ifelse.Select value')}
isDisabled={
condition === VariableConditionEnum.isEmpty ||
condition === VariableConditionEnum.isNotEmpty
@@ -450,7 +452,11 @@ const ConditionValueInput = ({
return (
<MyInput
value={value}
placeholder={'输入值'}
placeholder={
condition === VariableConditionEnum.reg
? '/^((+|00)86)?1[3-9]d{9}$/'
: workflowT('ifelse.Input value')
}
w={'100%'}
bg={'white'}
isDisabled={
@@ -461,7 +467,7 @@ const ConditionValueInput = ({
/>
);
}
}, [condition, onChange, value, valueType]);
}, [condition, onChange, value, valueType, workflowT]);
return Render;
};

View File

@@ -42,7 +42,7 @@ const Reference = ({ item, nodeId }: RenderInputProps) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const onSelect = useCallback(
(e: any) => {
(e: ReferenceValueProps) => {
const workflowStartNode = nodeList.find(
(node) => node.flowNodeType === FlowNodeTypeEnum.workflowStart
);

View File

@@ -16,7 +16,7 @@ import { WorkflowContext } from '@/components/core/workflow/context';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
const RenderList: {
types: `${FlowNodeOutputTypeEnum}`[];
types: FlowNodeOutputTypeEnum[];
Component: React.ComponentType<RenderOutputProps>;
}[] = [];

View File

@@ -1,12 +1,8 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { PgClient } from '@fastgpt/service/common/vectorStore/pg';
import { NextAPI } from '@/service/middleware/entry';
import { PgDatasetTableName } from '@fastgpt/global/common/vectorStore/constants';
import { connectionMongo } from '@fastgpt/service/common/mongo';
import { addLog } from '@fastgpt/service/common/system/log';
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
async function handler(req: NextApiRequest, res: NextApiResponse) {

View File

@@ -1,41 +0,0 @@
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { NextApiRequest, NextApiResponse } from 'next';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
import axios from 'axios';
import { NextAPI } from '@/service/middleware/entry';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { textList = [], appId, customUrl } = req.body;
if (!customUrl) {
const { teamId } = await authUserNotVisitor({ req, authToken: true });
const currentQGuide = await MongoChatInputGuide.find({ appId, teamId });
const currentTexts = currentQGuide.map((item) => item.text);
const textsToDelete = currentTexts.filter((text) => !textList.includes(text));
await MongoChatInputGuide.deleteMany({ text: { $in: textsToDelete }, appId, teamId });
const newTexts = textList.filter((text: string) => !currentTexts.includes(text));
const newDocuments = newTexts.map((text: string) => ({
text: text,
appId: appId,
teamId: teamId
}));
await MongoChatInputGuide.insertMany(newDocuments);
} else {
try {
const response = await axios.post(customUrl, {
textList,
appId
});
res.status(200).json(response.data);
} catch (error) {
res.status(500).json({ error });
}
}
}
export default NextAPI(handler);

View File

@@ -2,21 +2,29 @@ import type { NextApiResponse } from 'next';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
import { NextAPI } from '@/service/middleware/entry';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
import { authChatCert } from '@/service/support/permission/auth/chat';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
export type QueryChatInputGuideProps = {
export type QueryChatInputGuideBody = OutLinkChatAuthProps & {
appId: string;
searchKey: string;
};
export type QueryChatInputGuideResponse = string[];
async function handler(
req: ApiRequestProps<{}, QueryChatInputGuideProps>,
req: ApiRequestProps<QueryChatInputGuideBody>,
res: NextApiResponse<any>
): Promise<QueryChatInputGuideResponse> {
const { appId, searchKey } = req.query;
const { appId, searchKey } = req.body;
await authApp({ req, appId, authToken: true, authApiKey: true, per: 'r' });
// tmp auth
const { teamId } = await authChatCert({ req, authToken: true });
const app = await MongoApp.findOne({ _id: appId, teamId });
if (!app) {
return Promise.reject(AppErrEnum.unAuthApp);
}
const params = {
appId,

View File

@@ -31,26 +31,17 @@ import { useI18n } from '@/web/context/I18n';
import { useContextSelector } from 'use-context-selector';
import { AppContext } from '@/web/core/app/context/appContext';
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'), {
ssr: false
});
const DatasetParamsModal = dynamic(() => import('@/components/core/app/DatasetParamsModal'), {
ssr: false
});
const ToolSelectModal = dynamic(() => import('./ToolSelectModal'), { ssr: false });
const TTSSelect = dynamic(() => import('@/components/core/app/TTSSelect'), { ssr: false });
const QGSwitch = dynamic(() => import('@/components/core/app/QGSwitch'), { ssr: false });
const WhisperConfig = dynamic(() => import('@/components/core/app/WhisperConfig'), { ssr: false });
const InputGuideConfig = dynamic(() => import('@/components/core/app/InputGuideConfig'), {
ssr: false
});
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
const DatasetParamsModal = dynamic(() => import('@/components/core/app/DatasetParamsModal'));
const ToolSelectModal = dynamic(() => import('./ToolSelectModal'));
const TTSSelect = dynamic(() => import('@/components/core/app/TTSSelect'));
const QGSwitch = dynamic(() => import('@/components/core/app/QGSwitch'));
const WhisperConfig = dynamic(() => import('@/components/core/app/WhisperConfig'));
const InputGuideConfig = dynamic(() => import('@/components/core/app/InputGuideConfig'));
const ScheduledTriggerConfig = dynamic(
() => import('@/components/core/app/ScheduledTriggerConfig'),
{ ssr: false }
() => import('@/components/core/app/ScheduledTriggerConfig')
);
const WelcomeTextConfig = dynamic(() => import('@/components/core/app/WelcomeTextConfig'), {
ssr: false
});
const WelcomeTextConfig = dynamic(() => import('@/components/core/app/WelcomeTextConfig'));
const BoxStyles: BoxProps = {
px: 5,

View File

@@ -15,16 +15,16 @@ const ChatHeader = ({
appName,
appAvatar,
chatModels,
appId,
showHistory,
onRoute2AppDetail,
onOpenSlider
}: {
history: ChatItemType[];
appName: string;
appAvatar: string;
chatModels?: string[];
appId?: string;
showHistory?: boolean;
onRoute2AppDetail?: () => void;
onOpenSlider: () => void;
}) => {
const router = useRouter();
@@ -80,13 +80,7 @@ const ChatHeader = ({
<Flex px={3} alignItems={'center'} flex={'1 0 0'} w={0} justifyContent={'center'}>
<Avatar src={appAvatar} w={'16px'} />
<Box
ml={1}
className="textEllipsis"
onClick={() => {
appId && router.push(`/app/detail?appId=${appId}`);
}}
>
<Box ml={1} className="textEllipsis" onClick={onRoute2AppDetail}>
{appName}
</Box>
</Flex>

View File

@@ -335,10 +335,10 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
<ChatHeader
appAvatar={chatData.app.avatar}
appName={chatData.app.name}
appId={appId}
history={chatData.history}
chatModels={chatData.app.chatModels}
onOpenSlider={onOpenSlider}
onRoute2AppDetail={() => router.push(`/app/detail?appId=${appId}`)}
showHistory
/>

View File

@@ -378,7 +378,6 @@ const OutLink = ({
history={chatData.history}
showHistory={showHistory === '1'}
onOpenSlider={onOpenSlider}
appId={chatData.appId}
/>
{/* chat box */}
<Box flex={1}>

View File

@@ -1,4 +1,4 @@
import React, { useMemo, useRef, useState } from 'react';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import {
Box,
Flex,
@@ -17,7 +17,7 @@ import {
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import LeftRadio from '@fastgpt/web/components/common/Radio/LeftRadio';
import { TrainingTypeMap } from '@fastgpt/global/core/dataset/constants';
import { TrainingModeEnum, TrainingTypeMap } from '@fastgpt/global/core/dataset/constants';
import { ImportProcessWayEnum } from '@/web/core/dataset/constants';
import MyTooltip from '@/components/MyTooltip';
import { useSystemStore } from '@/web/common/system/useSystemStore';
@@ -27,6 +27,7 @@ import Preview from '../components/Preview';
import Tag from '@fastgpt/web/components/common/Tag/index';
import { useContextSelector } from 'use-context-selector';
import { DatasetImportContext } from '../Context';
import { useToast } from '@fastgpt/web/hooks/useToast';
function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean }) {
const { t } = useTranslation();
@@ -42,8 +43,10 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
maxChunkSize,
priceTip
} = useContextSelector(DatasetImportContext, (v) => v);
const { getValues, setValue, register } = processParamsForm;
const [refresh, setRefresh] = useState(false);
const { getValues, setValue, register, watch } = processParamsForm;
const { toast } = useToast();
const mode = watch('mode');
const way = watch('way');
const {
isOpen: isOpenCustomPrompt,
@@ -53,12 +56,21 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
const trainingModeList = useMemo(() => {
const list = Object.entries(TrainingTypeMap);
return list;
}, []);
return list.filter(([key, value]) => {
if (feConfigs?.isPlus) return true;
return value.openSource;
});
}, [feConfigs?.isPlus]);
const onSelectTrainWay = useCallback(
(e: TrainingModeEnum) => {
if (!feConfigs?.isPlus && !TrainingTypeMap[e]?.openSource) {
return toast({
status: 'warning',
title: t('common.system.Commercial version function')
});
}
setValue('mode', e);
},
[feConfigs?.isPlus, setValue, t, toast]
);
return (
<Box h={'100%'} display={['block', 'flex']} gap={5}>
@@ -80,11 +92,8 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
}))}
px={3}
py={2}
value={getValues('mode')}
onChange={(e) => {
setValue('mode', e);
setRefresh(!refresh);
}}
value={mode}
onChange={onSelectTrainWay}
gridTemplateColumns={'repeat(3,1fr)'}
defaultBg="white"
activeBg="white"
@@ -105,7 +114,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
title: t('core.dataset.import.Custom process'),
desc: t('core.dataset.import.Custom process desc'),
value: ImportProcessWayEnum.custom,
children: getValues('way') === ImportProcessWayEnum.custom && (
children: way === ImportProcessWayEnum.custom && (
<Box mt={5}>
{showChunkInput && chunkSizeField && (
<Box>
@@ -250,11 +259,10 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
py={3}
defaultBg="white"
activeBg="white"
value={getValues('way')}
value={way}
w={'100%'}
onChange={(e) => {
setValue('way', e);
setRefresh(!refresh);
}}
></LeftRadio>
</Flex>
@@ -286,7 +294,6 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
defaultValue={getValues('qaPrompt')}
onChange={(e) => {
setValue('qaPrompt', e);
setRefresh(!refresh);
}}
onClose={onCloseCustomPrompt}
/>

View File

@@ -18,21 +18,19 @@ import MyRadio from '@/components/common/MyRadio';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import MySelect from '@fastgpt/web/components/common/MySelect';
import AIModelSelector from '@/components/Select/AIModelSelector';
import { useI18n } from '@/web/context/I18n';
const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: string }) => {
const { t } = useTranslation();
const { datasetT } = useI18n();
const [refresh, setRefresh] = useState(false);
const { toast } = useToast();
const router = useRouter();
const { isPc, feConfigs, vectorModelList, datasetModelList } = useSystemStore();
const filterNotHiddenVectorModelList = vectorModelList.filter((item) => !item.hidden);
const { register, setValue, getValues, handleSubmit } = useForm<CreateDatasetParams>({
const { register, setValue, handleSubmit, watch } = useForm<CreateDatasetParams>({
defaultValues: {
parentId,
type: DatasetTypeEnum.dataset,
@@ -43,6 +41,10 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
agentModel: datasetModelList[0].model
}
});
const avatar = watch('avatar');
const datasetType = watch('type');
const vectorModel = watch('vectorModel');
const agentModel = watch('agentModel');
const { File, onOpen: onOpenSelectFile } = useSelectFile({
fileType: '.jpg,.png',
@@ -61,7 +63,6 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
maxH: 300
});
setValue('avatar', src);
setRefresh((state) => !state);
} catch (err: any) {
toast({
title: getErrText(err, t('common.avatar.Select Failed')),
@@ -85,6 +86,22 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
}
});
const onSelectDatasetType = useCallback(
(e: DatasetTypeEnum) => {
if (
!feConfigs?.isPlus &&
(e === DatasetTypeEnum.websiteDataset || e === DatasetTypeEnum.externalFile)
) {
return toast({
status: 'warning',
title: t('common.system.Commercial version function')
});
}
setValue('type', e);
},
[feConfigs?.isPlus, setValue, t, toast]
);
return (
<MyModal
iconSrc="/imgs/workflow/db.png"
@@ -109,28 +126,21 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
icon: 'core/dataset/commonDataset',
desc: datasetT('Common Dataset Desc')
},
...(feConfigs.isPlus
? [
{
title: datasetT('Website Dataset'),
value: DatasetTypeEnum.websiteDataset,
icon: 'core/dataset/websiteDataset',
desc: datasetT('Website Dataset Desc')
},
{
title: datasetT('External File'),
value: DatasetTypeEnum.externalFile,
icon: 'core/dataset/externalDataset',
desc: datasetT('External file Dataset Desc')
}
]
: [])
{
title: datasetT('Website Dataset'),
value: DatasetTypeEnum.websiteDataset,
icon: 'core/dataset/websiteDataset',
desc: datasetT('Website Dataset Desc')
},
{
title: datasetT('External File'),
value: DatasetTypeEnum.externalFile,
icon: 'core/dataset/externalDataset',
desc: datasetT('External file Dataset Desc')
}
]}
value={getValues('type')}
onChange={(e) => {
setValue('type', e as DatasetTypeEnum);
setRefresh(!refresh);
}}
value={datasetType}
onChange={onSelectDatasetType}
/>
</>
<Box mt={5}>
@@ -141,7 +151,7 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
<MyTooltip label={t('common.avatar.Select Avatar')}>
<Avatar
flexShrink={0}
src={getValues('avatar')}
src={avatar}
w={['28px', '32px']}
h={['28px', '32px']}
cursor={'pointer'}
@@ -173,14 +183,13 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
<Box flex={1}>
<AIModelSelector
w={'100%'}
value={getValues('vectorModel')}
value={vectorModel}
list={filterNotHiddenVectorModelList.map((item) => ({
label: item.name,
value: item.model
}))}
onchange={(e) => {
setValue('vectorModel', e);
setRefresh((state) => !state);
}}
/>
</Box>
@@ -192,14 +201,13 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
<Box flex={1}>
<AIModelSelector
w={'100%'}
value={getValues('agentModel')}
value={agentModel}
list={datasetModelList.map((item) => ({
label: item.name,
value: item.model
}))}
onchange={(e) => {
setValue('agentModel', e);
setRefresh((state) => !state);
}}
/>
</Box>

View File

@@ -1,6 +1,5 @@
import React, { useCallback, useEffect } from 'react';
import { useRouter } from 'next/router';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import type { ResLogin } from '@/global/support/api/userRes.d';
import { useChatStore } from '@/web/core/chat/storeChat';
import { useUserStore } from '@/web/support/user/useUserStore';
@@ -9,7 +8,6 @@ import { postFastLogin } from '@/web/support/user/api';
import { useToast } from '@fastgpt/web/hooks/useToast';
import Loading from '@fastgpt/web/components/common/MyLoading';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useQuery } from '@tanstack/react-query';
import { getErrText } from '@fastgpt/global/common/error/utils';
const FastLogin = ({

View File

@@ -3,6 +3,7 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '@fastgpt/global/core/workflow/node/constant';
@@ -109,7 +110,7 @@ export const appTemplates: (AppItemType & {
key: 'userChatInput',
label: 'core.module.input.label.user question',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -220,7 +221,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: WorkflowIOValueTypeEnum.chatHistory,
type: 'static'
type: FlowNodeOutputTypeEnum.static
},
{
id: 'answerText',
@@ -228,7 +229,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
}
@@ -356,7 +357,7 @@ export const appTemplates: (AppItemType & {
key: 'userChatInput',
label: 'core.module.input.label.user question',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -467,7 +468,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: WorkflowIOValueTypeEnum.chatHistory,
type: 'static'
type: FlowNodeOutputTypeEnum.static
},
{
id: 'answerText',
@@ -475,7 +476,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
}
@@ -586,7 +587,7 @@ export const appTemplates: (AppItemType & {
key: 'userChatInput',
label: 'core.module.input.label.user question',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -698,7 +699,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: WorkflowIOValueTypeEnum.chatHistory,
type: 'static'
type: FlowNodeOutputTypeEnum.static
},
{
id: 'answerText',
@@ -706,7 +707,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -795,7 +796,7 @@ export const appTemplates: (AppItemType & {
id: 'quoteQA',
key: 'quoteQA',
label: 'core.module.Dataset quote.label',
type: 'static',
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote,
description: '特殊数组格式,搜索结果为空时,返回空数组。'
}
@@ -914,7 +915,7 @@ export const appTemplates: (AppItemType & {
key: 'userChatInput',
label: 'core.module.input.label.user question',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -1026,7 +1027,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: WorkflowIOValueTypeEnum.chatHistory,
type: 'static'
type: FlowNodeOutputTypeEnum.static
},
{
id: 'answerText',
@@ -1034,7 +1035,7 @@ export const appTemplates: (AppItemType & {
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -1116,7 +1117,7 @@ export const appTemplates: (AppItemType & {
key: 'cqResult',
label: '分类结果',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -1232,7 +1233,7 @@ export const appTemplates: (AppItemType & {
key: 'quoteQA',
label: 'core.module.Dataset quote.label',
description: '特殊数组格式,搜索结果为空时,返回空数组。',
type: 'static',
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote
}
]

View File

@@ -7,6 +7,7 @@ import {
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '@fastgpt/global/core/workflow/node/constant';
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
@@ -65,7 +66,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
key: 'userChatInput',
label: 'core.module.input.label.user question',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
};
@@ -181,7 +182,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: WorkflowIOValueTypeEnum.chatHistory,
type: 'static'
type: FlowNodeOutputTypeEnum.static
},
{
id: 'answerText',
@@ -189,7 +190,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
}
@@ -315,7 +316,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: WorkflowIOValueTypeEnum.chatHistory,
type: 'static'
type: FlowNodeOutputTypeEnum.static
},
{
id: 'answerText',
@@ -323,7 +324,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: WorkflowIOValueTypeEnum.string,
type: 'static'
type: FlowNodeOutputTypeEnum.static
}
]
},
@@ -416,7 +417,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
id: 'quoteQA',
key: 'quoteQA',
label: 'core.module.Dataset quote.label',
type: 'static',
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote
}
]
@@ -537,7 +538,7 @@ export function form2AppWorkflow(data: AppSimpleEditFormType): WorkflowType {
id: 'quoteQA',
key: 'quoteQA',
label: 'core.module.Dataset quote.label',
type: 'static',
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote
}
]

View File

@@ -14,7 +14,7 @@ import type {
import type { updateInputGuideBody } from '@/pages/api/core/chat/inputGuide/update';
import type { deleteChatInputGuideQuery } from '@/pages/api/core/chat/inputGuide/delete';
import type {
QueryChatInputGuideProps,
QueryChatInputGuideBody,
QueryChatInputGuideResponse
} from '@/pages/api/core/chat/inputGuide/query';
@@ -26,10 +26,13 @@ export const getCountChatInputGuideTotal = (data: countChatInputGuideTotalQuery)
export const getChatInputGuideList = (data: ChatInputGuideProps) =>
GET<ChatInputGuideResponse>(`/core/chat/inputGuide/list`, data);
export const queryChatInputGuideList = (data: QueryChatInputGuideProps, url?: string) => {
return GET<QueryChatInputGuideResponse>(url ?? `/core/chat/inputGuide/query`, data, {
withCredentials: !url
});
export const queryChatInputGuideList = (data: QueryChatInputGuideBody, url?: string) => {
if (url) {
return GET<QueryChatInputGuideResponse>(url, data, {
withCredentials: !url
});
}
return POST<QueryChatInputGuideResponse>(`/core/chat/inputGuide/query`, data);
};
export const postChatInputGuides = (data: createInputGuideBody) =>

View File

@@ -167,7 +167,7 @@ type V1WorkflowType = {
};
defaultEditField?: {
inputType?: InputTypeEnum; // input type
outputType?: `${FlowNodeOutputTypeEnum}`;
outputType?: FlowNodeOutputTypeEnum;
required?: boolean;
key?: string;
label?: string;
@@ -219,7 +219,7 @@ type V1WorkflowType = {
};
defaultEditField?: {
inputType?: `${FlowNodeInputTypeEnum}`; // input type
outputType?: `${FlowNodeOutputTypeEnum}`;
outputType?: FlowNodeOutputTypeEnum;
required?: boolean;
key?: string;
label?: string;

View File

@@ -2,7 +2,13 @@ import { GET, POST, PUT, DELETE } from '@/web/common/api/request';
import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
export const postWorkflowDebug = (data: PostWorkflowDebugProps) =>
POST<PostWorkflowDebugResponse>('/core/workflow/debug', {
...data,
mode: 'debug'
});
POST<PostWorkflowDebugResponse>(
'/core/workflow/debug',
{
...data,
mode: 'debug'
},
{
timeout: 300000
}
);