Commit 759a2330 by Archer Committed by GitHub

V4.6.6-1 (#656)

parent 86286efb
...@@ -18,15 +18,17 @@ weight: 708 ...@@ -18,15 +18,17 @@ weight: 708
**使用时,请务必去除注释!** **使用时,请务必去除注释!**
以下配置适用于V4.6.6-alpha版本以后
```json ```json
{ {
"SystemParams": { "systemEnv": {
"pluginBaseUrl": "", // 商业版接口地址 "pluginBaseUrl": "", // 商业版接口地址
"vectorMaxProcess": 15, // 向量生成最大进程,结合数据库性能和 key 来设置 "vectorMaxProcess": 15, // 向量生成最大进程,结合数据库性能和 key 来设置
"qaMaxProcess": 15, // QA 生成最大进程,结合数据库性能和 key 来设置 "qaMaxProcess": 15, // QA 生成最大进程,结合数据库性能和 key 来设置
"pgHNSWEfSearch": 100 // pg vector 索引参数,越大精度高但速度慢 "pgHNSWEfSearch": 100 // pg vector 索引参数,越大精度高但速度慢
}, },
"ChatModels": [ // 对话模型 "chatModels": [ // 对话模型
{ {
"model": "gpt-3.5-turbo-1106", "model": "gpt-3.5-turbo-1106",
"name": "GPT35-1106", "name": "GPT35-1106",
...@@ -76,7 +78,7 @@ weight: 708 ...@@ -76,7 +78,7 @@ weight: 708
"defaultSystemChatPrompt": "" "defaultSystemChatPrompt": ""
} }
], ],
"QAModels": [ // QA 生成模型 "qaModels": [ // QA 生成模型
{ {
"model": "gpt-3.5-turbo-16k", "model": "gpt-3.5-turbo-16k",
"name": "GPT35-16k", "name": "GPT35-16k",
...@@ -85,7 +87,7 @@ weight: 708 ...@@ -85,7 +87,7 @@ weight: 708
"price": 0 "price": 0
} }
], ],
"CQModels": [ // 问题分类模型 "cqModels": [ // 问题分类模型
{ {
"model": "gpt-3.5-turbo-1106", "model": "gpt-3.5-turbo-1106",
"name": "GPT35-1106", "name": "GPT35-1106",
...@@ -105,7 +107,7 @@ weight: 708 ...@@ -105,7 +107,7 @@ weight: 708
"functionPrompt": "" "functionPrompt": ""
} }
], ],
"ExtractModels": [ // 内容提取模型 "extractModels": [ // 内容提取模型
{ {
"model": "gpt-3.5-turbo-1106", "model": "gpt-3.5-turbo-1106",
"name": "GPT35-1106", "name": "GPT35-1106",
...@@ -116,7 +118,7 @@ weight: 708 ...@@ -116,7 +118,7 @@ weight: 708
"functionPrompt": "" "functionPrompt": ""
} }
], ],
"QGModels": [ // 生成下一步指引 "qgModels": [ // 生成下一步指引
{ {
"model": "gpt-3.5-turbo-1106", "model": "gpt-3.5-turbo-1106",
"name": "GPT35-1106", "name": "GPT35-1106",
...@@ -125,7 +127,7 @@ weight: 708 ...@@ -125,7 +127,7 @@ weight: 708
"price": 0 "price": 0
} }
], ],
"VectorModels": [ // 向量模型 "vectorModels": [ // 向量模型
{ {
"model": "text-embedding-ada-002", "model": "text-embedding-ada-002",
"name": "Embedding-2", "name": "Embedding-2",
...@@ -134,8 +136,8 @@ weight: 708 ...@@ -134,8 +136,8 @@ weight: 708
"maxToken": 3000 "maxToken": 3000
} }
], ],
"ReRankModels": [], // 重排模型,暂时填空数组 "reRankModels": [], // 重排模型,暂时填空数组
"AudioSpeechModels": [ "audioSpeechModels": [
{ {
"model": "tts-1", "model": "tts-1",
"name": "OpenAI TTS1", "name": "OpenAI TTS1",
...@@ -152,7 +154,7 @@ weight: 708 ...@@ -152,7 +154,7 @@ weight: 708
] ]
} }
], ],
"WhisperModel": { "whisperModel": {
"model": "whisper-1", "model": "whisper-1",
"name": "Whisper1", "name": "Whisper1",
"price": 0 "price": 0
......
...@@ -9,7 +9,7 @@ weight: 831 ...@@ -9,7 +9,7 @@ weight: 831
## 配置文件变更 ## 配置文件变更
由于 openai 已开始用 function call,改为 toolChoice。FastGPT 同步的修改了对于的配置和调用方式,需要对配置文件做一些修改: 由于 openai 已开始用 function call,改为 toolChoice。FastGPT 同步的修改了对于的配置和调用方式,需要对配置文件做一些修改:
[点击查看最新的配置文件](/docs/development/configuration/) [点击查看最新的配置文件](/docs/development/configuration/)
......
---
title: 'V4.6.6(需要改配置文件)'
description: 'FastGPT V4.6.6'
icon: 'upgrade'
draft: false
toc: true
weight: 831
---
**版本仍在开发中……**
## 配置文件变更
为了减少代码重复度,我们对配置文件做了一些修改:[点击查看最新的配置文件](/docs/development/configuration/)
## V4.6.6 即将更新
1. UI 优化,未来将逐步替换新的UI设计。
...@@ -6,16 +6,18 @@ ...@@ -6,16 +6,18 @@
"prepare": "husky install", "prepare": "husky install",
"format-code": "prettier --config \"./.prettierrc.js\" --write \"./**/src/**/*.{ts,tsx,scss}\"", "format-code": "prettier --config \"./.prettierrc.js\" --write \"./**/src/**/*.{ts,tsx,scss}\"",
"format-doc": "zhlint --dir ./docSite *.md --fix", "format-doc": "zhlint --dir ./docSite *.md --fix",
"gen:theme-typings": "chakra-cli tokens projects/app/src/web/styles/theme.ts --out node_modules/.pnpm/node_modules/@chakra-ui/styled-system/dist/theming.types.d.ts",
"postinstall": "sh ./scripts/postinstall.sh" "postinstall": "sh ./scripts/postinstall.sh"
}, },
"devDependencies": { "devDependencies": {
"@chakra-ui/cli": "^2.4.1",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^13.2.1",
"prettier": "^3.0.3",
"zhlint": "^0.7.1",
"i18next": "^22.5.1", "i18next": "^22.5.1",
"lint-staged": "^13.2.1",
"next-i18next": "^13.3.0", "next-i18next": "^13.3.0",
"react-i18next": "^12.3.1" "prettier": "^3.0.3",
"react-i18next": "^12.3.1",
"zhlint": "^0.7.1"
}, },
"lint-staged": { "lint-staged": {
"./**/**/*.{ts,tsx,scss}": "npm run format-code", "./**/**/*.{ts,tsx,scss}": "npm run format-code",
......
/* read file to txt */
import * as pdfjsLib from 'pdfjs-dist';
export const readPdfFile = async ({ pdf }: { pdf: string | URL | ArrayBuffer }) => {
pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.js';
type TokenType = {
str: string;
dir: string;
width: number;
height: number;
transform: number[];
fontName: string;
hasEOL: boolean;
};
const readPDFPage = async (doc: any, pageNo: number) => {
const page = await doc.getPage(pageNo);
const tokenizedText = await page.getTextContent();
const viewport = page.getViewport({ scale: 1 });
const pageHeight = viewport.height;
const headerThreshold = pageHeight * 0.07; // 假设页头在页面顶部5%的区域内
const footerThreshold = pageHeight * 0.93; // 假设页脚在页面底部5%的区域内
const pageTexts: TokenType[] = tokenizedText.items.filter((token: TokenType) => {
return (
!token.transform ||
(token.transform[5] > headerThreshold && token.transform[5] < footerThreshold)
);
});
// concat empty string 'hasEOL'
for (let i = 0; i < pageTexts.length; i++) {
const item = pageTexts[i];
if (item.str === '' && pageTexts[i - 1]) {
pageTexts[i - 1].hasEOL = item.hasEOL;
pageTexts.splice(i, 1);
i--;
}
}
page.cleanup();
return pageTexts
.map((token) => {
const paragraphEnd = token.hasEOL && /([。?!.?!\n\r]|(\r\n))$/.test(token.str);
return paragraphEnd ? `${token.str}\n` : token.str;
})
.join('');
};
const doc = await pdfjsLib.getDocument(pdf).promise;
const pageTextPromises = [];
for (let pageNo = 1; pageNo <= doc.numPages; pageNo++) {
pageTextPromises.push(readPDFPage(doc, pageNo));
}
const pageTexts = await Promise.all(pageTextPromises);
return pageTexts.join('');
};
...@@ -34,3 +34,41 @@ export const simpleMarkdownText = (rawText: string) => { ...@@ -34,3 +34,41 @@ export const simpleMarkdownText = (rawText: string) => {
return rawText.trim(); return rawText.trim();
}; };
/**
* format markdown
* 1. upload base64
* 2. replace \
*/
export const uploadMarkdownBase64 = async ({
rawText,
uploadImgController
}: {
rawText: string;
uploadImgController: (base64: string) => Promise<string>;
}) => {
// match base64, upload and replace it
const base64Regex = /data:image\/.*;base64,([^\)]+)/g;
const base64Arr = rawText.match(base64Regex) || [];
// upload base64 and replace it
await Promise.all(
base64Arr.map(async (base64Img) => {
try {
const str = await uploadImgController(base64Img);
rawText = rawText.replace(base64Img, str);
} catch (error) {
rawText = rawText.replace(base64Img, '');
rawText = rawText.replace(/!\[.*\]\(\)/g, '');
}
})
);
// Remove white space on both sides of the picture
const trimReg = /(!\[.*\]\(.*\))\s*/g;
if (trimReg.test(rawText)) {
rawText = rawText.replace(trimReg, '$1');
}
return simpleMarkdownText(rawText);
};
...@@ -31,7 +31,7 @@ export const splitText2Chunks = (props: { ...@@ -31,7 +31,7 @@ export const splitText2Chunks = (props: {
// The larger maxLen is, the next sentence is less likely to trigger splitting // The larger maxLen is, the next sentence is less likely to trigger splitting
const stepReges: { reg: RegExp; maxLen: number }[] = [ const stepReges: { reg: RegExp; maxLen: number }[] = [
...customReg.map((text) => ({ reg: new RegExp(`([${text}])`, 'g'), maxLen: chunkLen * 1.4 })), ...customReg.map((text) => ({ reg: new RegExp(`(${text})`, 'g'), maxLen: chunkLen * 1.4 })),
{ reg: /^(#\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 }, { reg: /^(#\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 },
{ reg: /^(##\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 }, { reg: /^(##\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 },
{ reg: /^(###\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 }, { reg: /^(###\s[^\n]+)\n/gm, maxLen: chunkLen * 1.2 },
...@@ -64,13 +64,22 @@ export const splitText2Chunks = (props: { ...@@ -64,13 +64,22 @@ export const splitText2Chunks = (props: {
} }
]; ];
} }
const isCustomSteep = checkIsCustomStep(step);
const isMarkdownSplit = checkIsMarkdownSplit(step); const isMarkdownSplit = checkIsMarkdownSplit(step);
const independentChunk = checkIndependentChunk(step); const independentChunk = checkIndependentChunk(step);
const { reg } = stepReges[step]; const { reg } = stepReges[step];
const splitTexts = text const splitTexts = text
.replace(reg, independentChunk ? `${splitMarker}$1` : `$1${splitMarker}`) .replace(
reg,
(() => {
if (isCustomSteep) return splitMarker;
if (independentChunk) return `${splitMarker}$1`;
return `$1${splitMarker}`;
})()
)
.split(`${splitMarker}`) .split(`${splitMarker}`)
.filter((part) => part.trim()); .filter((part) => part.trim());
...@@ -128,11 +137,6 @@ export const splitText2Chunks = (props: { ...@@ -128,11 +137,6 @@ export const splitText2Chunks = (props: {
const independentChunk = checkIndependentChunk(step); const independentChunk = checkIndependentChunk(step);
const isCustomStep = checkIsCustomStep(step); const isCustomStep = checkIsCustomStep(step);
// mini text
if (text.length <= chunkLen) {
return [text];
}
// oversize // oversize
if (step >= stepReges.length) { if (step >= stepReges.length) {
if (text.length < chunkLen * 3) { if (text.length < chunkLen * 3) {
...@@ -221,6 +225,8 @@ export const splitText2Chunks = (props: { ...@@ -221,6 +225,8 @@ export const splitText2Chunks = (props: {
} else { } else {
chunks.push(`${mdTitle}${lastText}`); chunks.push(`${mdTitle}${lastText}`);
} }
} else if (lastText && chunks.length === 0) {
chunks.push(lastText);
} }
return chunks; return chunks;
......
export type FeConfigsType = { import type {
ChatModelItemType,
FunctionModelItemType,
LLMModelItemType,
VectorModelItemType,
AudioSpeechModels,
WhisperModelType,
ReRankModelItemType
} from '../../../core/ai/model.d';
/* fastgpt main */
export type FastGPTConfigFileType = {
feConfigs: FastGPTFeConfigsType;
systemEnv: SystemEnvType;
chatModels: ChatModelItemType[];
qaModels: LLMModelItemType[];
cqModels: FunctionModelItemType[];
extractModels: FunctionModelItemType[];
qgModels: LLMModelItemType[];
vectorModels: VectorModelItemType[];
reRankModels: ReRankModelItemType[];
audioSpeechModels: AudioSpeechModelType[];
whisperModel: WhisperModelType;
};
export type FastGPTFeConfigsType = {
show_emptyChat?: boolean; show_emptyChat?: boolean;
show_register?: boolean; show_register?: boolean;
show_appStore?: boolean; show_appStore?: boolean;
...@@ -34,6 +59,6 @@ export type SystemEnvType = { ...@@ -34,6 +59,6 @@ export type SystemEnvType = {
}; };
declare global { declare global {
var feConfigs: FeConfigsType; var feConfigs: FastGPTFeConfigsType;
var systemEnv: SystemEnvType; var systemEnv: SystemEnvType;
} }
...@@ -24,6 +24,7 @@ export type VectorModelItemType = { ...@@ -24,6 +24,7 @@ export type VectorModelItemType = {
defaultToken: number; defaultToken: number;
price: number; price: number;
maxToken: number; maxToken: number;
weight: number;
}; };
export type ReRankModelItemType = { export type ReRankModelItemType = {
......
...@@ -16,6 +16,7 @@ export const defaultVectorModels: VectorModelItemType[] = [ ...@@ -16,6 +16,7 @@ export const defaultVectorModels: VectorModelItemType[] = [
name: 'Embedding-2', name: 'Embedding-2',
price: 0, price: 0,
defaultToken: 500, defaultToken: 500,
maxToken: 3000 maxToken: 3000,
weight: 100
} }
]; ];
...@@ -89,6 +89,7 @@ export type DatasetTrainingSchemaType = { ...@@ -89,6 +89,7 @@ export type DatasetTrainingSchemaType = {
q: string; q: string;
a: string; a: string;
chunkIndex: number; chunkIndex: number;
weight: number;
indexes: Omit<DatasetDataIndexItemType, 'dataId'>[]; indexes: Omit<DatasetDataIndexItemType, 'dataId'>[];
}; };
......
...@@ -36,10 +36,11 @@ export const ContextExtractModule: FlowModuleTemplateType = { ...@@ -36,10 +36,11 @@ export const ContextExtractModule: FlowModuleTemplateType = {
type: FlowNodeInputTypeEnum.textarea, type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleIOValueTypeEnum.string, valueType: ModuleIOValueTypeEnum.string,
label: '提取要求描述', label: '提取要求描述',
description: '给AI一些对应的背景知识或要求描述,引导AI更好的完成任务', description:
'给AI一些对应的背景知识或要求描述,引导AI更好的完成任务。\n该输入框可使用全局变量。',
required: true, required: true,
placeholder: placeholder:
'例如: \n1. 你是一个实验室预约助手,你的任务是帮助用户预约实验室。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。', '例如: \n1. 当前时间为: {{cTime}}。你是一个实验室预约助手,你的任务是帮助用户预约实验室,从文本中获取对应的预约信息。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。',
showTargetInApp: true, showTargetInApp: true,
showTargetInPlugin: true showTargetInPlugin: true
}, },
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
"name": "@fastgpt/global", "name": "@fastgpt/global",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"axios": "^1.5.1",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"openai": "4.23.0",
"encoding": "^0.1.13", "encoding": "^0.1.13",
"js-tiktoken": "^1.0.7", "js-tiktoken": "^1.0.7",
"axios": "^1.5.1", "openai": "4.23.0",
"pdfjs-dist": "^4.0.269",
"timezones-list": "^3.0.2" "timezones-list": "^3.0.2"
}, },
"devDependencies": { "devDependencies": {
......
...@@ -20,12 +20,12 @@ export async function connectMongo({ ...@@ -20,12 +20,12 @@ export async function connectMongo({
console.log('mongo start connect'); console.log('mongo start connect');
try { try {
mongoose.set('strictQuery', true); mongoose.set('strictQuery', true);
const maxConnecting = Math.max(20, Number(process.env.DB_MAX_LINK || 20)); const maxConnecting = Math.max(30, Number(process.env.DB_MAX_LINK || 20));
await mongoose.connect(process.env.MONGODB_URI as string, { await mongoose.connect(process.env.MONGODB_URI as string, {
bufferCommands: true, bufferCommands: true,
maxConnecting: maxConnecting, maxConnecting: maxConnecting,
maxPoolSize: maxConnecting, maxPoolSize: maxConnecting,
minPoolSize: Math.max(5, Math.round(Number(process.env.DB_MAX_LINK || 5) * 0.1)), minPoolSize: 20,
connectTimeoutMS: 60000, connectTimeoutMS: 60000,
waitQueueTimeoutMS: 60000, waitQueueTimeoutMS: 60000,
socketTimeoutMS: 60000, socketTimeoutMS: 60000,
......
...@@ -9,7 +9,8 @@ export const connectPg = async (): Promise<Pool> => { ...@@ -9,7 +9,8 @@ export const connectPg = async (): Promise<Pool> => {
global.pgClient = new Pool({ global.pgClient = new Pool({
connectionString: process.env.PG_URL, connectionString: process.env.PG_URL,
max: Number(process.env.DB_MAX_LINK || 5), max: Number(process.env.DB_MAX_LINK || 20),
min: 10,
keepAlive: true, keepAlive: true,
idleTimeoutMillis: 60000, idleTimeoutMillis: 60000,
connectionTimeoutMillis: 20000 connectionTimeoutMillis: 20000
......
import { SystemConfigsTypeEnum } from '@fastgpt/global/common/system/config/constants'; import { SystemConfigsTypeEnum } from '@fastgpt/global/common/system/config/constants';
import { MongoSystemConfigs } from './schema'; import { MongoSystemConfigs } from './schema';
import { FeConfigsType } from '@fastgpt/global/common/system/types'; import { FastGPTConfigFileType } from '@fastgpt/global/common/system/types';
export const getFastGPTFeConfig = async () => { export const getFastGPTConfigFromDB = async () => {
const res = await MongoSystemConfigs.findOne({ const res = await MongoSystemConfigs.findOne({
type: SystemConfigsTypeEnum.fastgpt type: SystemConfigsTypeEnum.fastgpt
}).sort({ }).sort({
createTime: -1 createTime: -1
}); });
const config: FeConfigsType = res?.value?.FeConfig || {}; const config = res?.value || {};
return config; return config as Omit<FastGPTConfigFileType, 'systemEnv'>;
}; };
...@@ -22,7 +22,6 @@ const systemConfigSchema = new Schema({ ...@@ -22,7 +22,6 @@ const systemConfigSchema = new Schema({
}); });
try { try {
systemConfigSchema.index({ createTime: -1 }, { expireAfterSeconds: 90 * 24 * 60 * 60 });
systemConfigSchema.index({ type: 1 }); systemConfigSchema.index({ type: 1 });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
......
...@@ -79,6 +79,10 @@ const TrainingDataSchema = new Schema({ ...@@ -79,6 +79,10 @@ const TrainingDataSchema = new Schema({
type: Number, type: Number,
default: 0 default: 0
}, },
weight: {
type: Number,
default: 0
},
indexes: { indexes: {
type: [ type: [
{ {
......
...@@ -56,7 +56,7 @@ export async function parseHeaderCert({ ...@@ -56,7 +56,7 @@ export async function parseHeaderCert({
async function authCookieToken(cookie?: string, token?: string) { async function authCookieToken(cookie?: string, token?: string) {
// 获取 cookie // 获取 cookie
const cookies = Cookie.parse(cookie || ''); const cookies = Cookie.parse(cookie || '');
const cookieToken = cookies.token || token; const cookieToken = token || cookies.token;
if (!cookieToken) { if (!cookieToken) {
return Promise.reject(ERROR_ENUM.unAuthorization); return Promise.reject(ERROR_ENUM.unAuthorization);
...@@ -127,7 +127,7 @@ export async function parseHeaderCert({ ...@@ -127,7 +127,7 @@ export async function parseHeaderCert({
authType: AuthUserTypeEnum.apikey authType: AuthUserTypeEnum.apikey
}; };
} }
if (authToken && (cookie || token)) { if (authToken && (token || cookie)) {
// user token(from fastgpt web) // user token(from fastgpt web)
const res = await authCookieToken(cookie, token); const res = await authCookieToken(cookie, token);
return { return {
...@@ -182,7 +182,7 @@ export async function parseHeaderCert({ ...@@ -182,7 +182,7 @@ export async function parseHeaderCert({
export const setCookie = (res: NextApiResponse, token: string) => { export const setCookie = (res: NextApiResponse, token: string) => {
res.setHeader( res.setHeader(
'Set-Cookie', 'Set-Cookie',
`token=${token}; Path=/; HttpOnly; Max-Age=604800; Samesite=None; Secure;` `token=${token}; Path=/; HttpOnly; Max-Age=604800; Samesite=Strict; Secure;`
); );
}; };
/* clear cookie */ /* clear cookie */
......
export type CompressImgProps = {
maxW?: number;
maxH?: number;
maxSize?: number;
};
export const compressBase64ImgAndUpload = ({
base64Img,
maxW = 1080,
maxH = 1080,
maxSize = 1024 * 500, // 300kb
uploadController
}: CompressImgProps & {
base64Img: string;
uploadController: (base64: string) => Promise<string>;
}) => {
return new Promise<string>((resolve, reject) => {
const fileType =
/^data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,/.exec(base64Img)?.[1] || 'image/jpeg';
const img = new Image();
img.src = base64Img;
img.onload = async () => {
let width = img.width;
let height = img.height;
if (width > height) {
if (width > maxW) {
height *= maxW / width;
width = maxW;
}
} else {
if (height > maxH) {
width *= maxH / height;
height = maxH;
}
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
if (!ctx) {
return reject('压缩图片异常');
}
ctx.drawImage(img, 0, 0, width, height);
const compressedDataUrl = canvas.toDataURL(fileType, 1);
// 移除 canvas 元素
canvas.remove();
if (compressedDataUrl.length > maxSize) {
return reject('图片太大了');
}
try {
const src = await uploadController(compressedDataUrl);
resolve(src);
} catch (error) {
reject(error);
}
};
img.onerror = reject;
});
};
import { uploadMarkdownBase64 } from '@fastgpt/global/common/string/markdown';
import { htmlStr2Md } from '../string/markdown';
/**
* read file raw text
*/
export const readFileRawText = (file: File) => {
return new Promise((resolve: (_: string) => void, reject) => {
try {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result as string);
};
reader.onerror = (err) => {
console.log('error txt read:', err);
reject('Read file error');
};
reader.readAsText(file);
} catch (error) {
reject(error);
}
});
};
export const readMdFile = async ({
file,
uploadImgController
}: {
file: File;
uploadImgController: (base64: string) => Promise<string>;
}) => {
const md = await readFileRawText(file);
const rawText = await uploadMarkdownBase64({
rawText: md,
uploadImgController
});
return rawText;
};
export const readHtmlFile = async ({
file,
uploadImgController
}: {
file: File;
uploadImgController: (base64: string) => Promise<string>;
}) => {
const md = htmlStr2Md(await readFileRawText(file));
const rawText = await uploadMarkdownBase64({
rawText: md,
uploadImgController
});
return rawText;
};
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
"name": "@fastgpt/web", "name": "@fastgpt/web",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@fastgpt/global": "workspace:*",
"joplin-turndown-plugin-gfm": "^1.0.12", "joplin-turndown-plugin-gfm": "^1.0.12",
"turndown": "^7.1.2" "turndown": "^7.1.2"
}, },
......
LOG_DEPTH=3
# 默认用户密码,用户名为 root,每次重启时会自动更新。 # 默认用户密码,用户名为 root,每次重启时会自动更新。
DEFAULT_ROOT_PSW=123456 DEFAULT_ROOT_PSW=123456
# 数据库最大连接数 # 数据库最大连接数
......
{ {
"SystemParams": { "systemEnv": {
"pluginBaseUrl": "", "pluginBaseUrl": "",
"vectorMaxProcess": 15, "vectorMaxProcess": 15,
"qaMaxProcess": 15, "qaMaxProcess": 15,
"pgHNSWEfSearch": 100 "pgHNSWEfSearch": 100
}, },
"ChatModels": [ "chatModels": [
{ {
"model": "gpt-3.5-turbo", "model": "gpt-3.5-turbo",
"name": "GPT35", "name": "GPT35",
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
"defaultSystemChatPrompt": "" "defaultSystemChatPrompt": ""
} }
], ],
"QAModels": [ "qaModels": [
{ {
"model": "gpt-3.5-turbo-16k", "model": "gpt-3.5-turbo-16k",
"name": "GPT35-16k", "name": "GPT35-16k",
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
"price": 0 "price": 0
} }
], ],
"CQModels": [ "cqModels": [
{ {
"model": "gpt-3.5-turbo", "model": "gpt-3.5-turbo",
"name": "GPT35", "name": "GPT35",
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
"functionPrompt": "" "functionPrompt": ""
} }
], ],
"ExtractModels": [ "extractModels": [
{ {
"model": "gpt-3.5-turbo-1106", "model": "gpt-3.5-turbo-1106",
"name": "GPT35-1106", "name": "GPT35-1106",
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
"functionPrompt": "" "functionPrompt": ""
} }
], ],
"QGModels": [ "qgModels": [
{ {
"model": "gpt-3.5-turbo-1106", "model": "gpt-3.5-turbo-1106",
"name": "GPT35-1106", "name": "GPT35-1106",
...@@ -104,17 +104,18 @@ ...@@ -104,17 +104,18 @@
"price": 0 "price": 0
} }
], ],
"VectorModels": [ "vectorModels": [
{ {
"model": "text-embedding-ada-002", "model": "text-embedding-ada-002",
"name": "Embedding-2", "name": "Embedding-2",
"price": 0.2, "price": 0.2,
"defaultToken": 700, "defaultToken": 700,
"maxToken": 3000 "maxToken": 3000,
"weight": 100
} }
], ],
"ReRankModels": [], "reRankModels": [],
"AudioSpeechModels": [ "audioSpeechModels": [
{ {
"model": "tts-1", "model": "tts-1",
"name": "OpenAI TTS1", "name": "OpenAI TTS1",
...@@ -129,7 +130,7 @@ ...@@ -129,7 +130,7 @@
] ]
} }
], ],
"WhisperModel": { "whisperModel": {
"model": "whisper-1", "model": "whisper-1",
"name": "Whisper1", "name": "Whisper1",
"price": 0 "price": 0
......
...@@ -7,7 +7,7 @@ module.exports = { ...@@ -7,7 +7,7 @@ module.exports = {
i18n: { i18n: {
defaultLocale: 'zh', defaultLocale: 'zh',
locales: ['en', 'zh'], locales: ['en', 'zh'],
localeDetection: true localeDetection: false
}, },
localePath: localePath:
typeof window === 'undefined' ? require('path').resolve('./public/locales') : '/public/locales', typeof window === 'undefined' ? require('path').resolve('./public/locales') : '/public/locales',
......
{ {
"name": "app", "name": "app",
"version": "4.6.5", "version": "4.6.6",
"private": false, "private": false,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
...@@ -17,32 +17,38 @@ ...@@ -17,32 +17,38 @@
"@chakra-ui/system": "^2.6.1", "@chakra-ui/system": "^2.6.1",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@fastgpt/plugins": "workspace:*",
"@fastgpt/global": "workspace:*", "@fastgpt/global": "workspace:*",
"@fastgpt/plugins": "workspace:*",
"@fastgpt/service": "workspace:*", "@fastgpt/service": "workspace:*",
"@fastgpt/web": "workspace:*", "@fastgpt/web": "workspace:*",
"@node-rs/jieba": "^1.7.2", "@node-rs/jieba": "^1.7.2",
"@tanstack/react-query": "^4.24.10", "@tanstack/react-query": "^4.24.10",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"axios": "^1.5.1",
"date-fns": "^2.30.0", "date-fns": "^2.30.0",
"dayjs": "^1.11.7",
"echarts": "^5.4.1", "echarts": "^5.4.1",
"next": "13.5.2",
"echarts-gl": "^2.0.9", "echarts-gl": "^2.0.9",
"formidable": "^2.1.1", "formidable": "^2.1.1",
"framer-motion": "^9.0.6", "framer-motion": "^9.0.6",
"hyperdown": "^2.4.29", "hyperdown": "^2.4.29",
"i18next": "^22.5.1",
"immer": "^9.0.19", "immer": "^9.0.19",
"jschardet": "^3.0.0", "jschardet": "^3.0.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mammoth": "^1.6.0", "mammoth": "^1.6.0",
"mermaid": "^10.2.3", "mermaid": "^10.2.3",
"nanoid": "^4.0.1",
"next": "13.5.2",
"next-i18next": "^13.3.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"papaparse": "^5.4.1", "papaparse": "^5.4.1",
"react": "18.2.0", "react": "18.2.0",
"react-day-picker": "^8.7.1", "react-day-picker": "^8.7.1",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-hook-form": "^7.43.1", "react-hook-form": "^7.43.1",
"react-i18next": "^12.3.1",
"react-markdown": "^8.0.7", "react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",
"reactflow": "^11.7.4", "reactflow": "^11.7.4",
...@@ -52,13 +58,7 @@ ...@@ -52,13 +58,7 @@
"remark-math": "^5.1.1", "remark-math": "^5.1.1",
"request-ip": "^3.3.0", "request-ip": "^3.3.0",
"sass": "^1.58.3", "sass": "^1.58.3",
"zustand": "^4.3.5", "zustand": "^4.3.5"
"i18next": "^22.5.1",
"next-i18next": "^13.3.0",
"react-i18next": "^12.3.1",
"axios": "^1.5.1",
"nanoid": "^4.0.1",
"dayjs": "^1.11.7"
}, },
"devDependencies": { "devDependencies": {
"@svgr/webpack": "^6.5.1", "@svgr/webpack": "^6.5.1",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -231,7 +231,9 @@ ...@@ -231,7 +231,9 @@
}, },
"app": { "app": {
"App params config": "App Config", "App params config": "App Config",
"Chat Variable": "",
"Next Step Guide": "Next step guide", "Next Step Guide": "Next step guide",
"Question Guide": "",
"Question Guide Tip": "At the end of the conversation, three leading questions will be asked.", "Question Guide Tip": "At the end of the conversation, three leading questions will be asked.",
"Save and preview": "Save", "Save and preview": "Save",
"Select TTS": "Select TTS", "Select TTS": "Select TTS",
...@@ -297,10 +299,10 @@ ...@@ -297,10 +299,10 @@
"Stop Speak": "Stop Speak", "Stop Speak": "Stop Speak",
"Type a message": "Input problem", "Type a message": "Input problem",
"error": { "error": {
"Chat error": "Chat error",
"Messages empty": "Interface content is empty, maybe the text is too long ~", "Messages empty": "Interface content is empty, maybe the text is too long ~",
"Select dataset empty": "You didn't choose any dataset.", "Select dataset empty": "You didn't choose any dataset.",
"user input empty": "User question is empty", "user input empty": "User question is empty"
"Chat error": "Chat error"
}, },
"feedback": { "feedback": {
"Close User Good Feedback": "", "Close User Good Feedback": "",
...@@ -448,6 +450,8 @@ ...@@ -448,6 +450,8 @@
"Chunk Split": "Chunk Split", "Chunk Split": "Chunk Split",
"Chunk Split Tip": "Select the files and split the by sentences", "Chunk Split Tip": "Select the files and split the by sentences",
"Csv format error": "The csv file format is incorrect, please ensure that the index and content columns are two", "Csv format error": "The csv file format is incorrect, please ensure that the index and content columns are two",
"Custom split char": "Custom split char",
"Custom split char Tips": "Allows you to block according to custom delimiters. It is usually used for processed data, using specific delimiters to precisely block it.",
"Estimated Price": "Estimated Price", "Estimated Price": "Estimated Price",
"Estimated Price Tips": "Index generation is billed as: {{price}}/1k tokens", "Estimated Price Tips": "Index generation is billed as: {{price}}/1k tokens",
"Fetch Error": "Get link failed", "Fetch Error": "Get link failed",
...@@ -852,6 +856,17 @@ ...@@ -852,6 +856,17 @@
"To Edit Plugin": "To Edit", "To Edit Plugin": "To Edit",
"Update Your Plugin": "Update Plugin" "Update Your Plugin": "Update Plugin"
}, },
"support": {
"user": {
"auth": {
"Sending Code": "Sending"
},
"login": {
"Github": "Github",
"Google": "Google"
}
}
},
"system": { "system": {
"Help Document": "Document" "Help Document": "Document"
}, },
......
...@@ -231,7 +231,9 @@ ...@@ -231,7 +231,9 @@
}, },
"app": { "app": {
"App params config": "应用配置", "App params config": "应用配置",
"Chat Variable": "对话框变量",
"Next Step Guide": "下一步指引", "Next Step Guide": "下一步指引",
"Question Guide": "问题引导",
"Question Guide Tip": "对话结束后,会为生成 3 个引导性问题。", "Question Guide Tip": "对话结束后,会为生成 3 个引导性问题。",
"Save and preview": "保存并预览", "Save and preview": "保存并预览",
"Select TTS": "选择语音播放模式", "Select TTS": "选择语音播放模式",
...@@ -239,8 +241,6 @@ ...@@ -239,8 +241,6 @@
"TTS": "语音播报", "TTS": "语音播报",
"TTS Tip": "开启后,每次对话后可使用语音播放功能。使用该功能可能产生额外费用。", "TTS Tip": "开启后,每次对话后可使用语音播放功能。使用该功能可能产生额外费用。",
"Welcome Text": "对话开场白", "Welcome Text": "对话开场白",
"Chat Variable": "对话框变量",
"Question Guide": "问题引导",
"create app": "创建属于你的 AI 应用", "create app": "创建属于你的 AI 应用",
"edit": { "edit": {
"Confirm Save App Tip": "该应用可能为高级编排模式,保存后将会覆盖高级编排配置,请确认!", "Confirm Save App Tip": "该应用可能为高级编排模式,保存后将会覆盖高级编排配置,请确认!",
...@@ -299,10 +299,10 @@ ...@@ -299,10 +299,10 @@
"Stop Speak": "停止录音", "Stop Speak": "停止录音",
"Type a message": "输入问题", "Type a message": "输入问题",
"error": { "error": {
"Chat error": "对话出现异常",
"Messages empty": "接口内容为空,可能文本超长了~", "Messages empty": "接口内容为空,可能文本超长了~",
"Select dataset empty": "你没有选择知识库", "Select dataset empty": "你没有选择知识库",
"user input empty": "传入的用户问题为空", "user input empty": "传入的用户问题为空"
"Chat error": "对话出现异常"
}, },
"feedback": { "feedback": {
"Close User Good Feedback": "", "Close User Good Feedback": "",
...@@ -450,6 +450,8 @@ ...@@ -450,6 +450,8 @@
"Chunk Split": "直接分段", "Chunk Split": "直接分段",
"Chunk Split Tip": "选择文本文件,直接将其按分段进行处理", "Chunk Split Tip": "选择文本文件,直接将其按分段进行处理",
"Csv format error": "csv 文件格式有误,请确保 index 和 content 两列", "Csv format error": "csv 文件格式有误,请确保 index 和 content 两列",
"Custom split char": "自定义分隔符",
"Custom split char Tips": "允许你根据自定义的分隔符进行分块。通常用于已处理好的数据,使用特定的分隔符来精确分块。",
"Estimated Price": "预估价格", "Estimated Price": "预估价格",
"Estimated Price Tips": "索引生成计费为: {{price}}/1k tokens", "Estimated Price Tips": "索引生成计费为: {{price}}/1k tokens",
"Fetch Error": "获取链接失败", "Fetch Error": "获取链接失败",
...@@ -854,6 +856,17 @@ ...@@ -854,6 +856,17 @@
"To Edit Plugin": "去编辑", "To Edit Plugin": "去编辑",
"Update Your Plugin": "更新插件" "Update Your Plugin": "更新插件"
}, },
"support": {
"user": {
"auth": {
"Sending Code": "正在发送"
},
"login": {
"Github": "Github 登录",
"Google": "Google 登录"
}
}
},
"system": { "system": {
"Help Document": "帮助文档" "Help Document": "帮助文档"
}, },
......
...@@ -18,11 +18,11 @@ const Badge = ({ ...@@ -18,11 +18,11 @@ const Badge = ({
{count > 0 && ( {count > 0 && (
<Box position={'absolute'} right={0} top={0} transform={'translate(70%,-50%)'}> <Box position={'absolute'} right={0} top={0} transform={'translate(70%,-50%)'}>
{isDot ? ( {isDot ? (
<Box w={'5px'} h={'5px'} bg={'myRead.600'} borderRadius={'20px'}></Box> <Box w={'5px'} h={'5px'} bg={'red.600'} borderRadius={'20px'}></Box>
) : ( ) : (
<Box <Box
color={'white'} color={'white'}
bg={'myRead.600'} bg={'red.600'}
lineHeight={0.9} lineHeight={0.9}
borderRadius={'100px'} borderRadius={'100px'}
px={'4px'} px={'4px'}
......
...@@ -49,7 +49,7 @@ const FeedbackModal = ({ ...@@ -49,7 +49,7 @@ const FeedbackModal = ({
<Textarea ref={ref} rows={10} placeholder={t('chat.Feedback Modal Tip')} /> <Textarea ref={ref} rows={10} placeholder={t('chat.Feedback Modal Tip')} />
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={2} onClick={onClose}> <Button variant={'whiteBase'} mr={2} onClick={onClose}>
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button isLoading={isLoading} onClick={mutate}> <Button isLoading={isLoading} onClick={mutate}>
......
...@@ -216,7 +216,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')} ...@@ -216,7 +216,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
pl={5} pl={5}
alignItems={'center'} alignItems={'center'}
bg={'white'} bg={'white'}
color={'blue.500'} color={'primary.500'}
visibility={isSpeaking && isTransCription ? 'visible' : 'hidden'} visibility={isSpeaking && isTransCription ? 'visible' : 'hidden'}
> >
<Spinner size={'sm'} mr={4} /> <Spinner size={'sm'} mr={4} />
...@@ -244,7 +244,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')} ...@@ -244,7 +244,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
alignItems={'center'} alignItems={'center'}
justifyContent={'center'} justifyContent={'center'}
rounded={'md'} rounded={'md'}
color={'blue.500'} color={'primary.500'}
top={0} top={0}
left={0} left={0}
bottom={0} bottom={0}
...@@ -260,7 +260,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')} ...@@ -260,7 +260,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
h={'16px'} h={'16px'}
color={'myGray.700'} color={'myGray.700'}
cursor={'pointer'} cursor={'pointer'}
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
position={'absolute'} position={'absolute'}
bg={'white'} bg={'white'}
right={'-8px'} right={'-8px'}
...@@ -396,7 +396,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')} ...@@ -396,7 +396,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
name={isSpeaking ? 'core/chat/stopSpeechFill' : 'core/chat/recordFill'} name={isSpeaking ? 'core/chat/stopSpeechFill' : 'core/chat/recordFill'}
width={['20px', '22px']} width={['20px', '22px']}
height={['20px', '22px']} height={['20px', '22px']}
color={'blue.500'} color={'primary.500'}
/> />
</MyTooltip> </MyTooltip>
</Flex> </Flex>
...@@ -415,7 +415,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')} ...@@ -415,7 +415,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
h={['28px', '32px']} h={['28px', '32px']}
w={['28px', '32px']} w={['28px', '32px']}
borderRadius={'md'} borderRadius={'md'}
bg={isSpeaking || isChatting ? '' : !havInput ? '#E5E5E5' : 'blue.500'} bg={isSpeaking || isChatting ? '' : !havInput ? '#E5E5E5' : 'primary.500'}
cursor={havInput ? 'pointer' : 'not-allowed'} cursor={havInput ? 'pointer' : 'not-allowed'}
lineHeight={1} lineHeight={1}
onClick={() => { onClick={() => {
......
...@@ -125,7 +125,7 @@ export const QuoteList = React.memo(function QuoteList({ ...@@ -125,7 +125,7 @@ export const QuoteList = React.memo(function QuoteList({
className="hover-data" className="hover-data"
display={'none'} display={'none'}
alignItems={'center'} alignItems={'center'}
color={'blue.500'} color={'primary.500'}
href={`/dataset/detail?datasetId=${item.datasetId}&currentTab=dataCard&collectionId=${item.collectionId}`} href={`/dataset/detail?datasetId=${item.datasetId}&currentTab=dataCard&collectionId=${item.collectionId}`}
> >
{t('core.dataset.Go Dataset')} {t('core.dataset.Go Dataset')}
...@@ -184,7 +184,7 @@ export const QuoteList = React.memo(function QuoteList({ ...@@ -184,7 +184,7 @@ export const QuoteList = React.memo(function QuoteList({
cursor={'pointer'} cursor={'pointer'}
color={'myGray.600'} color={'myGray.600'}
_hover={{ _hover={{
color: 'blue.600' color: 'primary.600'
}} }}
onClick={() => onclickEdit(item)} onClick={() => onclickEdit(item)}
/> />
......
...@@ -147,7 +147,7 @@ const ResponseTags = ({ ...@@ -147,7 +147,7 @@ const ResponseTags = ({
name="common/routePushLight" name="common/routePushLight"
w={'14px'} w={'14px'}
cursor={'pointer'} cursor={'pointer'}
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
onClick={async (e) => { onClick={async (e) => {
e.stopPropagation(); e.stopPropagation();
......
...@@ -70,7 +70,7 @@ const SelectMarkCollection = ({ ...@@ -70,7 +70,7 @@ const SelectMarkCollection = ({
}} }}
{...(selected {...(selected
? { ? {
bg: 'blue.200' bg: 'primary.200'
} }
: {})} : {})}
onClick={() => { onClick={() => {
...@@ -132,7 +132,7 @@ const SelectMarkCollection = ({ ...@@ -132,7 +132,7 @@ const SelectMarkCollection = ({
CustomFooter={ CustomFooter={
<ModalFooter> <ModalFooter>
<Button <Button
variant={'base'} variant={'whiteBase'}
mr={2} mr={2}
onClick={() => { onClick={() => {
setAdminMarkData({ setAdminMarkData({
......
...@@ -505,7 +505,7 @@ const ChatBox = ( ...@@ -505,7 +505,7 @@ const ChatBox = (
const colorMap = { const colorMap = {
loading: 'myGray.700', loading: 'myGray.700',
running: '#67c13b', running: '#67c13b',
finish: 'blue.500' finish: 'primary.500'
}; };
if (!isChatting) return; if (!isChatting) return;
const chatContent = chatHistory[chatHistory.length - 1]; const chatContent = chatHistory[chatHistory.length - 1];
...@@ -673,7 +673,7 @@ const ChatBox = ( ...@@ -673,7 +673,7 @@ const ChatBox = (
<Card <Card
className="markdown" className="markdown"
{...MessageCardStyle} {...MessageCardStyle}
bg={'blue.200'} bg={'primary.200'}
borderRadius={'8px 0 8px 8px'} borderRadius={'8px 0 8px 8px'}
textAlign={'left'} textAlign={'left'}
> >
...@@ -1145,7 +1145,7 @@ function ChatAvatar({ src, type }: { src?: string; type: 'Human' | 'AI' }) { ...@@ -1145,7 +1145,7 @@ function ChatAvatar({ src, type }: { src?: string; type: 'Human' | 'AI' }) {
borderRadius={'lg'} borderRadius={'lg'}
border={theme.borders.base} border={theme.borders.base}
boxShadow={'0 0 5px rgba(0,0,0,0.1)'} boxShadow={'0 0 5px rgba(0,0,0,0.1)'}
bg={type === 'Human' ? 'white' : 'blue.50'} bg={type === 'Human' ? 'white' : 'primary.50'}
> >
<Avatar src={src} w={'100%'} h={'100%'} /> <Avatar src={src} w={'100%'} h={'100%'} />
</Box> </Box>
...@@ -1226,7 +1226,7 @@ function ChatController({ ...@@ -1226,7 +1226,7 @@ function ChatController({
<MyIcon <MyIcon
{...controlIconStyle} {...controlIconStyle}
name={'copy'} name={'copy'}
_hover={{ color: 'blue.600' }} _hover={{ color: 'primary.600' }}
onClick={() => copyData(chat.value)} onClick={() => copyData(chat.value)}
/> />
</MyTooltip> </MyTooltip>
......
...@@ -19,7 +19,7 @@ const CommunityModal = ({ onClose }: { onClose: () => void }) => { ...@@ -19,7 +19,7 @@ const CommunityModal = ({ onClose }: { onClose: () => void }) => {
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} onClick={onClose}> <Button variant={'whiteBase'} onClick={onClose}>
关闭 关闭
</Button> </Button>
</ModalFooter> </ModalFooter>
......
...@@ -74,14 +74,14 @@ const Layout = ({ children }: { children: JSX.Element }) => { ...@@ -74,14 +74,14 @@ const Layout = ({ children }: { children: JSX.Element }) => {
return ( return (
<> <>
<Box h={'100%'} bg={'myWhite.600'}> <Box h={'100%'} bg={'myGray.100'}>
{isPc === true && ( {isPc === true && (
<> <>
{pcUnShowLayoutRoute[router.pathname] ? ( {pcUnShowLayoutRoute[router.pathname] ? (
<Auth>{children}</Auth> <Auth>{children}</Auth>
) : ( ) : (
<> <>
<Box h={'100%'} position={'fixed'} left={0} top={0} w={'70px'}> <Box h={'100%'} position={'fixed'} left={0} top={0} w={'64px'}>
<Navbar unread={unread} /> <Navbar unread={unread} />
</Box> </Box>
<Box h={'100%'} ml={'70px'} overflow={'overlay'}> <Box h={'100%'} ml={'70px'} overflow={'overlay'}>
......
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { Box, Flex, Link } from '@chakra-ui/react'; import { Box, BoxProps, Flex, Link, LinkProps } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import { useChatStore } from '@/web/core/chat/storeChat'; import { useChatStore } from '@/web/core/chat/storeChat';
...@@ -77,19 +77,16 @@ const Navbar = ({ unread }: { unread: number }) => { ...@@ -77,19 +77,16 @@ const Navbar = ({ unread }: { unread: number }) => {
[lastChatAppId, lastChatId, t] [lastChatAppId, lastChatId, t]
); );
const itemStyles: any = { const itemStyles: BoxProps & LinkProps = {
my: 3, my: 3,
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
cursor: 'pointer', cursor: 'pointer',
w: '54px', w: '48px',
h: '54px', h: '58px',
borderRadius: 'md', borderRadius: 'md'
_hover: {
bg: 'myWhite.600'
}
}; };
return ( return (
...@@ -97,10 +94,8 @@ const Navbar = ({ unread }: { unread: number }) => { ...@@ -97,10 +94,8 @@ const Navbar = ({ unread }: { unread: number }) => {
flexDirection={'column'} flexDirection={'column'}
alignItems={'center'} alignItems={'center'}
pt={6} pt={6}
bg={'white'}
h={'100%'} h={'100%'}
w={'100%'} w={'100%'}
boxShadow={'2px 0px 8px 0px rgba(0,0,0,0.1)'}
userSelect={'none'} userSelect={'none'}
> >
{/* logo */} {/* logo */}
...@@ -113,13 +108,7 @@ const Navbar = ({ unread }: { unread: number }) => { ...@@ -113,13 +108,7 @@ const Navbar = ({ unread }: { unread: number }) => {
cursor={'pointer'} cursor={'pointer'}
onClick={() => router.push('/account')} onClick={() => router.push('/account')}
> >
<Avatar <Avatar w={'36px'} h={'36px'} src={userInfo?.avatar} fallbackSrc={HUMAN_ICON} />
w={'36px'}
h={'36px'}
borderRadius={'50%'}
src={userInfo?.avatar}
fallbackSrc={HUMAN_ICON}
/>
</Box> </Box>
{/* 导航列表 */} {/* 导航列表 */}
<Box flex={1}> <Box flex={1}>
...@@ -129,13 +118,17 @@ const Navbar = ({ unread }: { unread: number }) => { ...@@ -129,13 +118,17 @@ const Navbar = ({ unread }: { unread: number }) => {
{...itemStyles} {...itemStyles}
{...(item.activeLink.includes(router.pathname) {...(item.activeLink.includes(router.pathname)
? { ? {
color: 'blue.600', color: 'primary.600',
bg: 'white !important', bg: 'white',
boxShadow: '1px 1px 10px rgba(0,0,0,0.2)' boxShadow:
'0px 0px 1px 0px rgba(19, 51, 107, 0.08), 0px 4px 4px 0px rgba(19, 51, 107, 0.05)'
} }
: { : {
color: 'myGray.500', color: 'myGray.500',
backgroundColor: 'transparent' bg: 'transparent',
_hover: {
bg: 'rgba(255,255,255,0.9)'
}
})} })}
{...(item.link !== router.asPath {...(item.link !== router.asPath
? { ? {
......
...@@ -25,9 +25,15 @@ const Loading = ({ ...@@ -25,9 +25,15 @@ const Loading = ({
justifyContent={'center'} justifyContent={'center'}
flexDirection={'column'} flexDirection={'column'}
> >
<Spinner thickness="4px" speed="0.65s" emptyColor="myGray.100" color="blue.500" size="xl" /> <Spinner
thickness="4px"
speed="0.65s"
emptyColor="myGray.100"
color="primary.500"
size="xl"
/>
{text && ( {text && (
<Box mt={2} color="blue.600" fontWeight={'bold'}> <Box mt={2} color="primary.600" fontWeight={'bold'}>
{text} {text}
</Box> </Box>
)} )}
......
...@@ -23,7 +23,7 @@ function MyLink(e: any) { ...@@ -23,7 +23,7 @@ function MyLink(e: any) {
<Box as={'li'} mb={1}> <Box as={'li'} mb={1}>
<Box <Box
as={'span'} as={'span'}
color={'blue.700'} color={'primary.700'}
textDecoration={'underline'} textDecoration={'underline'}
cursor={'pointer'} cursor={'pointer'}
onClick={() => { onClick={() => {
......
...@@ -77,7 +77,7 @@ const QuestionGuide = ({ text }: { text: string }) => { ...@@ -77,7 +77,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
name={'core/chat/sendLight'} name={'core/chat/sendLight'}
w={'14px'} w={'14px'}
cursor={'pointer'} cursor={'pointer'}
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
onClick={() => eventBus.emit(EventNameEnum.sendQuestion, { text })} onClick={() => eventBus.emit(EventNameEnum.sendQuestion, { text })}
/> />
</MyTooltip> </MyTooltip>
......
...@@ -123,7 +123,7 @@ const MermaidBlock = ({ code }: { code: string }) => { ...@@ -123,7 +123,7 @@ const MermaidBlock = ({ code }: { code: string }) => {
position={'absolute'} position={'absolute'}
color={'myGray.600'} color={'myGray.600'}
_hover={{ _hover={{
color: 'blue.600' color: 'primary.600'
}} }}
right={0} right={0}
top={0} top={0}
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
width: 3px; width: 3px;
height: 14px; height: 14px;
transform: translate(4px, 2px) scaleY(1.3); transform: translate(4px, 2px) scaleY(1.3);
background-color: var(--chakra-colors-blue-700); background-color: var(--chakra-colors-primary-700);
animation: blink 0.6s infinite; animation: blink 0.6s infinite;
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
width: 3px; width: 3px;
height: 14px; height: 14px;
transform: translate(4px, 2px) scaleY(1.3); transform: translate(4px, 2px) scaleY(1.3);
background-color: var(--chakra-colors-blue-700); background-color: var(--chakra-colors-primary-700);
animation: blink 0.6s infinite; animation: blink 0.6s infinite;
} }
} }
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
.markdown dl, .markdown dl,
.markdown table, .markdown table,
.markdown pre { .markdown pre {
margin: 10px 0; margin: 14px 0;
} }
.markdown > h2:first-child, .markdown > h2:first-child,
.markdown > h1:first-child, .markdown > h1:first-child,
...@@ -368,7 +368,7 @@ ...@@ -368,7 +368,7 @@
a { a {
text-decoration: underline; text-decoration: underline;
color: var(--chakra-colors-blue-600); color: var(--chakra-colors-primary-700);
} }
table { table {
......
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import RemarkGfm from 'remark-gfm'; import 'katex/dist/katex.min.css';
import RemarkMath from 'remark-math'; import RemarkMath from 'remark-math';
import RehypeKatex from 'rehype-katex';
import RemarkBreaks from 'remark-breaks'; import RemarkBreaks from 'remark-breaks';
import RehypeKatex from 'rehype-katex';
import RemarkGfm from 'remark-gfm';
import 'katex/dist/katex.min.css';
import styles from './index.module.scss'; import styles from './index.module.scss';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
...@@ -74,7 +74,7 @@ function A({ children, ...props }: any) { ...@@ -74,7 +74,7 @@ function A({ children, ...props }: any) {
return ( return (
<MyTooltip label={t('core.chat.markdown.Quick Question')}> <MyTooltip label={t('core.chat.markdown.Quick Question')}>
<Button <Button
variant={'base'} variant={'whitePrimary'}
size={'xs'} size={'xs'}
borderRadius={'md'} borderRadius={'md'}
my={1} my={1}
...@@ -96,10 +96,10 @@ function A({ children, ...props }: any) { ...@@ -96,10 +96,10 @@ function A({ children, ...props }: any) {
name={'core/chat/quoteSign'} name={'core/chat/quoteSign'}
transform={'translateY(-2px)'} transform={'translateY(-2px)'}
w={'18px'} w={'18px'}
color={'blue.500'} color={'primary.500'}
cursor={'pointer'} cursor={'pointer'}
_hover={{ _hover={{
color: 'blue.700' color: 'primary.700'
}} }}
onClick={() => getFileAndOpen(props.href)} onClick={() => getFileAndOpen(props.href)}
/> />
...@@ -112,17 +112,6 @@ function A({ children, ...props }: any) { ...@@ -112,17 +112,6 @@ function A({ children, ...props }: any) {
} }
const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: boolean }) => { const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: boolean }) => {
const components = useMemo(
() => ({
img: Image,
pre: 'div',
p: 'div',
code: Code,
a: A
}),
[]
);
const formatSource = source const formatSource = source
.replace(/\\n/g, '\n&nbsp;') .replace(/\\n/g, '\n&nbsp;')
.replace(/(http[s]?:\/\/[^\s,。]+)([。,])/g, '$1 $2') .replace(/(http[s]?:\/\/[^\s,。]+)([。,])/g, '$1 $2')
...@@ -133,10 +122,15 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: ...@@ -133,10 +122,15 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?:
className={`markdown ${styles.markdown} className={`markdown ${styles.markdown}
${isChatting ? `${formatSource ? styles.waitingAnimation : styles.animation}` : ''} ${isChatting ? `${formatSource ? styles.waitingAnimation : styles.animation}` : ''}
`} `}
remarkPlugins={[RemarkGfm, RemarkMath, RemarkBreaks]} remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
rehypePlugins={[RehypeKatex]} rehypePlugins={[RehypeKatex]}
// @ts-ignore components={{
components={components} img: Image,
pre: 'div',
p: (pProps) => <p {...pProps} dir="auto" />,
code: Code,
a: A
}}
linkTarget={'_blank'} linkTarget={'_blank'}
> >
{formatSource} {formatSource}
......
...@@ -41,7 +41,7 @@ const MyMenu = ({ width, offset = [0, 10], Button, menuList }: Props) => { ...@@ -41,7 +41,7 @@ const MyMenu = ({ width, offset = [0, 10], Button, menuList }: Props) => {
e.stopPropagation(); e.stopPropagation();
item.onClick && item.onClick(); item.onClick && item.onClick();
}} }}
color={item.isActive ? 'blue.500' : ''} color={item.isActive ? 'primary.500' : ''}
whiteSpace={'pre-wrap'} whiteSpace={'pre-wrap'}
> >
{item.child} {item.child}
......
...@@ -70,7 +70,9 @@ const MyModal = ({ ...@@ -70,7 +70,9 @@ const MyModal = ({
)} )}
{title} {title}
<Box flex={1} /> <Box flex={1} />
{onClose && <ModalCloseButton position={'relative'} top={0} right={0} />} {onClose && (
<ModalCloseButton position={'relative'} fontSize={'sm'} top={0} right={0} />
)}
</ModalHeader> </ModalHeader>
)} )}
......
import React from 'react'; import React from 'react';
import { Box, useTheme, type BoxProps } from '@chakra-ui/react'; import { useTheme, type BoxProps } from '@chakra-ui/react';
import MyBox from '../common/MyBox'; import MyBox from '../common/MyBox';
const PageContainer = ({ children, ...props }: BoxProps & { isLoading?: boolean }) => { const PageContainer = ({
children,
isLoading,
insertProps = {},
...props
}: BoxProps & { isLoading?: boolean; insertProps?: BoxProps }) => {
const theme = useTheme(); const theme = useTheme();
return ( return (
<MyBox bg={'myGray.100'} h={'100%'} p={[0, 5]} px={[0, 6]} {...props}> <MyBox h={'100%'} py={[0, '16px']} pr={[0, '16px']} {...props}>
<Box <MyBox
isLoading={isLoading}
h={'100%'} h={'100%'}
bg={'white'} borderColor={'borderColor.base'}
borderRadius={props?.borderRadius || [0, '2xl']} borderWidth={[0, 1]}
border={['none', theme.borders.lg]} boxShadow={'1.5'}
overflow={'overlay'} overflow={'overlay'}
bg={'myGray.25'}
borderRadius={[0, '16px']}
{...insertProps}
> >
{children} {children}
</Box> </MyBox>
</MyBox> </MyBox>
); );
}; };
......
...@@ -32,7 +32,7 @@ const PromptTemplate = ({ ...@@ -32,7 +32,7 @@ const PromptTemplate = ({
cursor={'pointer'} cursor={'pointer'}
{...(item.title === selectTemplateTitle?.title {...(item.title === selectTemplateTitle?.title
? { ? {
bg: 'blue.50' bg: 'primary.50'
} }
: {})} : {})}
onClick={() => setSelectTemplateTitle(item)} onClick={() => setSelectTemplateTitle(item)}
......
...@@ -54,7 +54,7 @@ const MySelect = ( ...@@ -54,7 +54,7 @@ const MySelect = (
width={width} width={width}
px={3} px={3}
rightIcon={<ChevronDownIcon />} rightIcon={<ChevronDownIcon />}
variant={'base'} variant={'whitePrimary'}
textAlign={'left'} textAlign={'left'}
_active={{ _active={{
transform: 'none' transform: 'none'
...@@ -62,7 +62,7 @@ const MySelect = ( ...@@ -62,7 +62,7 @@ const MySelect = (
{...(isOpen {...(isOpen
? { ? {
boxShadow: '0px 0px 4px #A8DBFF', boxShadow: '0px 0px 4px #A8DBFF',
borderColor: 'blue.500' borderColor: 'primary.500'
} }
: {})} : {})}
{...props} {...props}
...@@ -93,7 +93,7 @@ const MySelect = ( ...@@ -93,7 +93,7 @@ const MySelect = (
{...menuItemStyles} {...menuItemStyles}
{...(value === item.value {...(value === item.value
? { ? {
color: 'blue.500', color: 'primary.500',
bg: 'myWhite.300' bg: 'myWhite.300'
} }
: {})} : {})}
......
...@@ -44,9 +44,9 @@ const SideTabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => ...@@ -44,9 +44,9 @@ const SideTabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) =>
alignItems={'center'} alignItems={'center'}
{...(activeId === item.id {...(activeId === item.id
? { ? {
bg: ' blue.100 !important', bg: ' primary.100 !important',
fontWeight: 'bold', fontWeight: 'bold',
color: 'blue.600 ', color: 'primary.600 ',
cursor: 'default' cursor: 'default'
} }
: { : {
......
...@@ -69,18 +69,18 @@ const MySlider = ({ ...@@ -69,18 +69,18 @@ const MySlider = ({
<SliderMark <SliderMark
value={value} value={value}
textAlign="center" textAlign="center"
bg="blue.500" bg="primary.500"
color="white" color="white"
px={1} px={1}
minW={'18px'} minW={'18px'}
w={'auto'} w={'auto'}
h={'18px'} h={'18px'}
lineHeight={'18px'}
borderRadius={'18px'} borderRadius={'18px'}
fontSize={'xs'}
transform={'translate(-50%, -155%)'} transform={'translate(-50%, -155%)'}
boxSizing={'border-box'} fontSize={'11px'}
> >
{value} <Box transform={'scale(0.9)'}>{value}</Box>
</SliderMark> </SliderMark>
<SliderTrack <SliderTrack
bg={'#EAEDF3'} bg={'#EAEDF3'}
...@@ -95,9 +95,9 @@ const MySlider = ({ ...@@ -95,9 +95,9 @@ const MySlider = ({
right: '-3px' right: '-3px'
}} }}
> >
<SliderFilledTrack bg={'blue.500'} /> <SliderFilledTrack bg={'primary.500'} />
</SliderTrack> </SliderTrack>
<SliderThumb border={'3px solid'} borderColor={'blue.500'}></SliderThumb> <SliderThumb border={'3px solid'} borderColor={'primary.500'}></SliderThumb>
</Slider> </Slider>
); );
}; };
......
...@@ -55,10 +55,10 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => { ...@@ -55,10 +55,10 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
whiteSpace={'nowrap'} whiteSpace={'nowrap'}
{...(activeId === item.id {...(activeId === item.id
? { ? {
color: 'blue.600', color: 'primary.600',
cursor: 'default', cursor: 'default',
fontWeight: 'bold', fontWeight: 'bold',
borderBottomColor: 'blue.600' borderBottomColor: 'primary.600'
} }
: { : {
cursor: 'pointer' cursor: 'pointer'
......
...@@ -10,9 +10,9 @@ const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => { ...@@ -10,9 +10,9 @@ const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
const theme = useMemo(() => { const theme = useMemo(() => {
const map = { const map = {
blue: { blue: {
borderColor: 'blue.500', borderColor: 'primary.500',
bg: '#F2FBFF', bg: '#F2FBFF',
color: 'blue.600' color: 'primary.600'
}, },
green: { green: {
borderColor: '#67c13b', borderColor: '#67c13b',
......
...@@ -43,13 +43,13 @@ const MyRadio = ({ ...@@ -43,13 +43,13 @@ const MyRadio = ({
position={'relative'} position={'relative'}
{...(value === item.value {...(value === item.value
? { ? {
borderColor: 'blue.400', borderColor: 'primary.400',
bg: 'blue.50' bg: 'primary.50'
} }
: { : {
bg: 'myWhite.300', bg: 'myWhite.300',
_hover: { _hover: {
borderColor: 'blue.400' borderColor: 'primary.400'
} }
})} })}
_after={{ _after={{
...@@ -66,7 +66,7 @@ const MyRadio = ({ ...@@ -66,7 +66,7 @@ const MyRadio = ({
...(value === item.value ...(value === item.value
? { ? {
border: '5px solid', border: '5px solid',
borderColor: 'blue.600' borderColor: 'primary.600'
} }
: { : {
border: '2px solid', border: '2px solid',
......
...@@ -52,7 +52,7 @@ const TagTextarea = ({ defaultValues, onUpdate, ...props }: Props) => { ...@@ -52,7 +52,7 @@ const TagTextarea = ({ defaultValues, onUpdate, ...props }: Props) => {
bg={'myWhite.600'} bg={'myWhite.600'}
{...(focus && { {...(focus && {
boxShadow: '0px 0px 4px #A8DBFF', boxShadow: '0px 0px 4px #A8DBFF',
borderColor: 'blue.500' borderColor: 'primary.500'
})} })}
{...props} {...props}
onClick={() => { onClick={() => {
...@@ -64,7 +64,7 @@ const TagTextarea = ({ defaultValues, onUpdate, ...props }: Props) => { ...@@ -64,7 +64,7 @@ const TagTextarea = ({ defaultValues, onUpdate, ...props }: Props) => {
> >
<Flex alignItems={'center'} gap={2} flexWrap={'wrap'}> <Flex alignItems={'center'} gap={2} flexWrap={'wrap'}>
{tags.map((tag, i) => ( {tags.map((tag, i) => (
<Tag key={tag} colorScheme="blue" onClick={(e) => e.stopPropagation()}> <Tag key={tag} colorScheme="primary" onClick={(e) => e.stopPropagation()}>
<TagLabel>{tag}</TagLabel> <TagLabel>{tag}</TagLabel>
<TagCloseButton <TagCloseButton
onClick={() => { onClick={() => {
......
...@@ -66,7 +66,7 @@ const AIChatSettingsModal = ({ ...@@ -66,7 +66,7 @@ const AIChatSettingsModal = ({
fontSize: ['sm', 'md'] fontSize: ['sm', 'md']
}; };
const selectTemplateBtn: BoxProps = { const selectTemplateBtn: BoxProps = {
color: 'blue.500', color: 'primary.500',
cursor: 'pointer' cursor: 'pointer'
}; };
...@@ -229,7 +229,7 @@ const AIChatSettingsModal = ({ ...@@ -229,7 +229,7 @@ const AIChatSettingsModal = ({
)} )}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} onClick={onClose}> <Button variant={'whiteBase'} onClick={onClose}>
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button ml={4} onClick={handleSubmit(onSuccess)}> <Button ml={4} onClick={handleSubmit(onSuccess)}>
......
...@@ -141,7 +141,7 @@ const DatasetParamsModal = ({ ...@@ -141,7 +141,7 @@ const DatasetParamsModal = ({
)} )}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common.Close')} {t('common.Close')}
</Button> </Button>
<Button <Button
......
...@@ -82,7 +82,7 @@ export const DatasetSelectModal = ({ ...@@ -82,7 +82,7 @@ export const DatasetSelectModal = ({
p={3} p={3}
border={theme.borders.base} border={theme.borders.base}
boxShadow={'sm'} boxShadow={'sm'}
bg={'blue.200'} bg={'primary.200'}
> >
<Flex alignItems={'center'} h={'38px'}> <Flex alignItems={'center'} h={'38px'}>
<Avatar src={item.avatar} w={['24px', '28px']}></Avatar> <Avatar src={item.avatar} w={['24px', '28px']}></Avatar>
......
...@@ -104,9 +104,9 @@ const ChatTest = ( ...@@ -104,9 +104,9 @@ const ChatTest = (
<MyTooltip label={'重置'}> <MyTooltip label={'重置'}>
<IconButton <IconButton
className="chat" className="chat"
size={'sm'} size={'smSquare'}
icon={<MyIcon name={'clear'} w={'14px'} />} icon={<MyIcon name={'clear'} w={'14px'} />}
variant={'base'} variant={'whiteDanger'}
borderRadius={'md'} borderRadius={'md'}
aria-label={'delete'} aria-label={'delete'}
onClick={(e) => { onClick={(e) => {
......
...@@ -48,7 +48,7 @@ export type useFlowProviderStoreType = { ...@@ -48,7 +48,7 @@ export type useFlowProviderStoreType = {
onDelNode: (nodeId: string) => void; onDelNode: (nodeId: string) => void;
onChangeNode: (e: FlowNodeChangeProps) => void; onChangeNode: (e: FlowNodeChangeProps) => void;
onCopyNode: (nodeId: string) => void; onCopyNode: (nodeId: string) => void;
onResetNode: (id: string, module: FlowModuleTemplateType) => void; onResetNode: (e: { id: string; module: FlowModuleTemplateType }) => void;
onDelEdge: (e: { onDelEdge: (e: {
moduleId: string; moduleId: string;
sourceHandle?: string | undefined; sourceHandle?: string | undefined;
...@@ -58,6 +58,13 @@ export type useFlowProviderStoreType = { ...@@ -58,6 +58,13 @@ export type useFlowProviderStoreType = {
onConnect: ({ connect }: { connect: Connection }) => any; onConnect: ({ connect }: { connect: Connection }) => any;
initData: (modules: ModuleItemType[]) => void; initData: (modules: ModuleItemType[]) => void;
}; };
type requestEventType =
| 'onChangeNode'
| 'onCopyNode'
| 'onResetNode'
| 'onDelNode'
| 'onDelConnect'
| 'setNodes';
const StateContext = createContext<useFlowProviderStoreType>({ const StateContext = createContext<useFlowProviderStoreType>({
reactFlowWrapper: null, reactFlowWrapper: null,
...@@ -107,7 +114,7 @@ const StateContext = createContext<useFlowProviderStoreType>({ ...@@ -107,7 +114,7 @@ const StateContext = createContext<useFlowProviderStoreType>({
initData: function (modules: ModuleItemType[]): void { initData: function (modules: ModuleItemType[]): void {
throw new Error('Function not implemented.'); throw new Error('Function not implemented.');
}, },
onResetNode: function (id: string, module: FlowModuleTemplateType): void { onResetNode: function (e): void {
throw new Error('Function not implemented.'); throw new Error('Function not implemented.');
} }
}); });
...@@ -350,7 +357,7 @@ export const FlowProvider = ({ ...@@ -350,7 +357,7 @@ export const FlowProvider = ({
// reset a node data. delete edge and replace it // reset a node data. delete edge and replace it
const onResetNode = useCallback( const onResetNode = useCallback(
(id: string, module: FlowModuleTemplateType) => { ({ id, module }: { id: string; module: FlowModuleTemplateType }) => {
setNodes((state) => setNodes((state) =>
state.map((node) => { state.map((node) => {
if (node.id === id) { if (node.id === id) {
...@@ -379,8 +386,7 @@ export const FlowProvider = ({ ...@@ -379,8 +386,7 @@ export const FlowProvider = ({
const initData = useCallback( const initData = useCallback(
(modules: ModuleItemType[]) => { (modules: ModuleItemType[]) => {
const edges = appModule2FlowEdge({ const edges = appModule2FlowEdge({
modules, modules
onDelete: onDelConnect
}); });
setEdges(edges); setEdges(edges);
...@@ -388,19 +394,54 @@ export const FlowProvider = ({ ...@@ -388,19 +394,54 @@ export const FlowProvider = ({
onFixView(); onFixView();
}, },
[onDelConnect, setEdges, setNodes, onFixView] [setEdges, setNodes, onFixView]
); );
// use eventbus to avoid refresh ReactComponents // use eventbus to avoid refresh ReactComponents
useEffect(() => { useEffect(() => {
const update = (e: FlowNodeChangeProps) => { eventBus.on(
onChangeNode(e); EventNameEnum.requestFlowEvent,
({ type, data }: { type: requestEventType; data: any }) => {
switch (type) {
case 'onChangeNode':
onChangeNode(data);
return;
case 'onCopyNode':
onCopyNode(data);
return;
case 'onResetNode':
onResetNode(data);
return;
case 'onDelNode':
onDelNode(data);
return;
case 'onDelConnect':
onDelConnect(data);
return;
case 'setNodes':
setNodes(data);
return;
}
}
);
return () => {
eventBus.off(EventNameEnum.requestFlowEvent);
}; };
eventBus.on(EventNameEnum.updaterNode, update); }, []);
useEffect(() => {
eventBus.on(EventNameEnum.requestFlowStore, () => {
eventBus.emit('receiveFlowStore', {
nodes,
edges,
mode,
filterAppIds,
reactFlowWrapper
});
});
return () => { return () => {
eventBus.off(EventNameEnum.updaterNode); eventBus.off(EventNameEnum.requestFlowStore);
}; };
}, [onChangeNode]); }, [edges, filterAppIds, mode, nodes]);
const value = { const value = {
reactFlowWrapper, reactFlowWrapper,
...@@ -429,5 +470,53 @@ export const FlowProvider = ({ ...@@ -429,5 +470,53 @@ export const FlowProvider = ({
export default React.memo(FlowProvider); export default React.memo(FlowProvider);
export const onChangeNode = (e: FlowNodeChangeProps) => { export const onChangeNode = (e: FlowNodeChangeProps) => {
eventBus.emit(EventNameEnum.updaterNode, e); eventBus.emit(EventNameEnum.requestFlowEvent, {
type: 'onChangeNode',
data: e
});
}; };
export const onCopyNode = (nodeId: string) => {
eventBus.emit(EventNameEnum.requestFlowEvent, {
type: 'onCopyNode',
data: nodeId
});
};
export const onResetNode = (e: Parameters<useFlowProviderStoreType['onResetNode']>[0]) => {
eventBus.emit(EventNameEnum.requestFlowEvent, {
type: 'onResetNode',
data: e
});
};
export const onDelNode = (nodeId: string) => {
eventBus.emit(EventNameEnum.requestFlowEvent, {
type: 'onDelNode',
data: nodeId
});
};
export const onDelConnect = (e: Parameters<useFlowProviderStoreType['onDelConnect']>[0]) => {
eventBus.emit(EventNameEnum.requestFlowEvent, {
type: 'onDelConnect',
data: e
});
};
export const onSetNodes = (e: useFlowProviderStoreType['nodes']) => {
eventBus.emit(EventNameEnum.requestFlowEvent, {
type: 'setNodes',
data: e
});
};
export const getFlowStore = () =>
new Promise<{
nodes: useFlowProviderStoreType['nodes'];
edges: useFlowProviderStoreType['edges'];
mode: useFlowProviderStoreType['mode'];
filterAppIds: useFlowProviderStoreType['filterAppIds'];
reactFlowWrapper: useFlowProviderStoreType['reactFlowWrapper'];
}>((resolve) => {
eventBus.on('receiveFlowStore', (data: any) => {
resolve(data);
eventBus.off('receiveFlowStore');
});
eventBus.emit(EventNameEnum.requestFlowStore);
});
...@@ -3,24 +3,16 @@ import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react'; ...@@ -3,24 +3,16 @@ import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useFlowProviderStore, type useFlowProviderStoreType } from './FlowProvider'; import { useFlowProviderStore } from './FlowProvider';
type Props = { type Props = {
onClose: () => void; onClose: () => void;
}; };
const ImportSettings = ({ const ImportSettings = ({ onClose }: Props) => {
onClose,
setNodes,
setEdges,
initData
}: Props & {
setNodes: useFlowProviderStoreType['setNodes'];
setEdges: useFlowProviderStoreType['setEdges'];
initData: useFlowProviderStoreType['initData'];
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { toast } = useToast(); const { toast } = useToast();
const { setNodes, setEdges, initData } = useFlowProviderStore();
const [value, setValue] = useState(''); const [value, setValue] = useState('');
return ( return (
...@@ -41,7 +33,7 @@ const ImportSettings = ({ ...@@ -41,7 +33,7 @@ const ImportSettings = ({
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button
variant="base" variant="whiteBase"
onClick={() => { onClick={() => {
if (!value) { if (!value) {
return onClose(); return onClose();
...@@ -68,8 +60,4 @@ const ImportSettings = ({ ...@@ -68,8 +60,4 @@ const ImportSettings = ({
); );
}; };
export default React.memo(function (props: Props) { export default React.memo(ImportSettings);
const { setNodes, setEdges, initData } = useFlowProviderStore();
return <ImportSettings {...props} setNodes={setNodes} setEdges={setEdges} initData={initData} />;
});
...@@ -7,11 +7,10 @@ import type { ...@@ -7,11 +7,10 @@ import type {
import { useViewport, XYPosition } from 'reactflow'; import { useViewport, XYPosition } from 'reactflow';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import { useFlowProviderStore, type useFlowProviderStoreType } from './FlowProvider'; import { getFlowStore, onSetNodes } from './FlowProvider';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import { appModule2FlowNode } from '@/utils/adapt'; import { appModule2FlowNode } from '@/utils/adapt';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import EmptyTip from '@/components/EmptyTip'; import EmptyTip from '@/components/EmptyTip';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
...@@ -19,7 +18,6 @@ import { getPreviewPluginModule } from '@/web/core/plugin/api'; ...@@ -19,7 +18,6 @@ import { getPreviewPluginModule } from '@/web/core/plugin/api';
import { useToast } from '@/web/common/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils'; import { getErrText } from '@fastgpt/global/common/error/utils';
import { moduleTemplatesList } from '@/web/core/modules/template/system'; import { moduleTemplatesList } from '@/web/core/modules/template/system';
import { ModuleTemplateTypeEnum } from '@fastgpt/global/core/module/constants';
export type ModuleTemplateProps = { export type ModuleTemplateProps = {
templates: FlowModuleTemplateType[]; templates: FlowModuleTemplateType[];
...@@ -32,20 +30,9 @@ type ModuleTemplateListProps = ModuleTemplateProps & { ...@@ -32,20 +30,9 @@ type ModuleTemplateListProps = ModuleTemplateProps & {
type RenderListProps = { type RenderListProps = {
templates: FlowModuleTemplateType[]; templates: FlowModuleTemplateType[];
onClose: () => void; onClose: () => void;
setNodes: useFlowProviderStoreType['setNodes'];
reactFlowWrapper: useFlowProviderStoreType['reactFlowWrapper'];
}; };
const ModuleTemplateList = ({ const ModuleTemplateList = ({ templates, isOpen, onClose }: ModuleTemplateListProps) => {
templates,
isOpen,
onClose,
setNodes,
reactFlowWrapper
}: ModuleTemplateListProps & {
setNodes: useFlowProviderStoreType['setNodes'];
reactFlowWrapper: useFlowProviderStoreType['reactFlowWrapper'];
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
...@@ -77,31 +64,16 @@ const ModuleTemplateList = ({ ...@@ -77,31 +64,16 @@ const ModuleTemplateList = ({
transition={'.2s ease'} transition={'.2s ease'}
userSelect={'none'} userSelect={'none'}
> >
<RenderList <RenderList templates={templates} onClose={onClose} />
templates={templates}
onClose={onClose}
setNodes={setNodes}
reactFlowWrapper={reactFlowWrapper}
/>
</Flex> </Flex>
</> </>
); );
}; };
export default React.memo(function (props: ModuleTemplateListProps) { export default React.memo(ModuleTemplateList);
const { setNodes, reactFlowWrapper } = useFlowProviderStore();
return <ModuleTemplateList {...props} setNodes={setNodes} reactFlowWrapper={reactFlowWrapper} />; const RenderList = React.memo(function RenderList({ templates, onClose }: RenderListProps) {
});
const RenderList = React.memo(function RenderList({
templates,
onClose,
setNodes,
reactFlowWrapper
}: RenderListProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter();
const { isPc } = useSystemStore(); const { isPc } = useSystemStore();
const { x, y, zoom } = useViewport(); const { x, y, zoom } = useViewport();
const { setLoading } = useSystemStore(); const { setLoading } = useSystemStore();
...@@ -119,6 +91,7 @@ const RenderList = React.memo(function RenderList({ ...@@ -119,6 +91,7 @@ const RenderList = React.memo(function RenderList({
const onAddNode = useCallback( const onAddNode = useCallback(
async ({ template, position }: { template: FlowModuleTemplateType; position: XYPosition }) => { async ({ template, position }: { template: FlowModuleTemplateType; position: XYPosition }) => {
const { reactFlowWrapper, nodes } = await getFlowStore();
if (!reactFlowWrapper?.current) return; if (!reactFlowWrapper?.current) return;
const templateModule = await (async () => { const templateModule = await (async () => {
...@@ -145,8 +118,8 @@ const RenderList = React.memo(function RenderList({ ...@@ -145,8 +118,8 @@ const RenderList = React.memo(function RenderList({
const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100; const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100;
const mouseY = (position.y - reactFlowBounds.top - y) / zoom; const mouseY = (position.y - reactFlowBounds.top - y) / zoom;
setNodes((state) => onSetNodes(
state.concat( nodes.concat(
appModule2FlowNode({ appModule2FlowNode({
item: { item: {
...templateModule, ...templateModule,
...@@ -157,7 +130,7 @@ const RenderList = React.memo(function RenderList({ ...@@ -157,7 +130,7 @@ const RenderList = React.memo(function RenderList({
) )
); );
}, },
[reactFlowWrapper, setLoading, setNodes, t, toast, x, y, zoom] [setLoading, t, toast, x, y, zoom]
); );
return templates.length === 0 ? ( return templates.length === 0 ? (
......
...@@ -60,7 +60,7 @@ const SelectAppModal = ({ ...@@ -60,7 +60,7 @@ const SelectAppModal = ({
cursor={'pointer'} cursor={'pointer'}
{...(selectedApps.includes(app._id) {...(selectedApps.includes(app._id)
? { ? {
bg: 'blue.100', bg: 'primary.100',
onClick: () => { onClick: () => {
setSelectedApps(selectedApps.filter((e) => e !== app._id)); setSelectedApps(selectedApps.filter((e) => e !== app._id));
} }
...@@ -83,7 +83,7 @@ const SelectAppModal = ({ ...@@ -83,7 +83,7 @@ const SelectAppModal = ({
))} ))}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} onClick={onClose}> <Button variant={'whiteBase'} onClick={onClose}>
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button <Button
......
import React from 'react'; import React from 'react';
import { import { BezierEdge, getBezierPath, EdgeLabelRenderer, EdgeProps } from 'reactflow';
BezierEdge, import { onDelConnect } from '../../FlowProvider';
getBezierPath,
EdgeLabelRenderer,
EdgeProps,
getSmoothStepPath
} from 'reactflow';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
const ButtonEdge = ( const ButtonEdge = (props: EdgeProps) => {
props: EdgeProps<{
onDelete: (id: string) => void;
}>
) => {
const { const {
id, id,
sourceX, sourceX,
...@@ -22,7 +13,6 @@ const ButtonEdge = ( ...@@ -22,7 +13,6 @@ const ButtonEdge = (
targetY, targetY,
sourcePosition, sourcePosition,
targetPosition, targetPosition,
data,
selected, selected,
style = {} style = {}
} = props; } = props;
...@@ -67,12 +57,12 @@ const ButtonEdge = ( ...@@ -67,12 +57,12 @@ const ButtonEdge = (
_hover={{ _hover={{
boxShadow: '0 0 6px 2px rgba(0, 0, 0, 0.08)' boxShadow: '0 0 6px 2px rgba(0, 0, 0, 0.08)'
}} }}
onClick={() => data?.onDelete(id)} onClick={() => onDelConnect(id)}
> >
<MyIcon <MyIcon
name="closeSolid" name="closeSolid"
w={'100%'} w={'100%'}
color={selected ? 'blue.700' : 'myGray.500'} color={selected ? 'primary.700' : 'myGray.500'}
></MyIcon> ></MyIcon>
</Flex> </Flex>
</EdgeLabelRenderer> </EdgeLabelRenderer>
......
...@@ -133,7 +133,8 @@ const TTSSelect = ({ ...@@ -133,7 +133,8 @@ const TTSSelect = ({
<Image src="/icon/speaking.gif" w={'24px'} alt={''} /> <Image src="/icon/speaking.gif" w={'24px'} alt={''} />
<Button <Button
ml={2} ml={2}
variant={'gray'} variant={'grayBase'}
color={'primary.600'}
isLoading={audioLoading} isLoading={audioLoading}
leftIcon={<MyIcon name={'core/chat/stopSpeech'} w={'16px'} />} leftIcon={<MyIcon name={'core/chat/stopSpeech'} w={'16px'} />}
onClick={() => { onClick={() => {
......
...@@ -289,7 +289,7 @@ const VariableEdit = ({ ...@@ -289,7 +289,7 @@ const VariableEdit = ({
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onCloseEdit}> <Button variant={'whiteBase'} mr={3} onClick={onCloseEdit}>
{t('common.Close')} {t('common.Close')}
</Button> </Button>
<Button <Button
......
...@@ -6,7 +6,7 @@ import Container from '../modules/Container'; ...@@ -6,7 +6,7 @@ import Container from '../modules/Container';
import RenderInput from '../render/RenderInput'; import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../render/RenderOutput';
const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeAnswer = React.memo(function NodeAnswer({ data }: { data: FlowModuleItemType }) {
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
return ( return (
<NodeCard minW={'400px'} {...data}> <NodeCard minW={'400px'} {...data}>
...@@ -16,5 +16,7 @@ const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -16,5 +16,7 @@ const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => {
</Container> </Container>
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodeAnswer); export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeAnswer data={data} />;
}
...@@ -17,7 +17,7 @@ import SourceHandle from '../render/SourceHandle'; ...@@ -17,7 +17,7 @@ import SourceHandle from '../render/SourceHandle';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { onChangeNode } from '../../FlowProvider'; import { onChangeNode } from '../../FlowProvider';
const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeCQNode = React.memo(function NodeCQNode({ data }: { data: FlowModuleItemType }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { moduleId, inputs } = data; const { moduleId, inputs } = data;
...@@ -136,5 +136,7 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -136,5 +136,7 @@ const NodeCQNode = ({ data }: NodeProps<FlowModuleItemType>) => {
</Container> </Container>
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodeCQNode); export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeCQNode data={data} />;
}
...@@ -3,7 +3,10 @@ import { NodeProps } from 'reactflow'; ...@@ -3,7 +3,10 @@ import { NodeProps } from 'reactflow';
import NodeCard from '../render/NodeCard'; import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d'; import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
const NodeAnswer = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeAnswer = React.memo(function NodeAnswer({ data }: { data: FlowModuleItemType }) {
return <NodeCard {...data}></NodeCard>; return <NodeCard {...data}></NodeCard>;
}; });
export default React.memo(NodeAnswer);
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeAnswer data={data} />;
}
...@@ -73,7 +73,7 @@ const ExtractFieldModal = ({ ...@@ -73,7 +73,7 @@ const ExtractFieldModal = ({
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common.Close')} {t('common.Close')}
</Button> </Button>
<Button onClick={handleSubmit(onSubmit)}>{t('common.Confirm')}</Button> <Button onClick={handleSubmit(onSubmit)}>{t('common.Confirm')}</Button>
......
...@@ -17,7 +17,7 @@ import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constan ...@@ -17,7 +17,7 @@ import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constan
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants'; import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { onChangeNode } from '../../../FlowProvider'; import { onChangeNode } from '../../../FlowProvider';
const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeExtract = React.memo(function NodeExtract({ data }: { data: FlowModuleItemType }) {
const { inputs, outputs, moduleId } = data; const { inputs, outputs, moduleId } = data;
const { t } = useTranslation(); const { t } = useTranslation();
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>(); const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
...@@ -39,7 +39,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -39,7 +39,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
<Box pt={2}> <Box pt={2}>
<Box position={'absolute'} top={0} right={0}> <Box position={'absolute'} top={0} right={0}>
<Button <Button
variant={'base'} variant={'whitePrimary'}
leftIcon={<AddIcon fontSize={'10px'} />} leftIcon={<AddIcon fontSize={'10px'} />}
onClick={() => setEditExtractField(defaultField)} onClick={() => setEditExtractField(defaultField)}
> >
...@@ -183,6 +183,8 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -183,6 +183,8 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
)} )}
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodeExtract); export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeExtract data={data} />;
}
...@@ -17,7 +17,7 @@ import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants'; ...@@ -17,7 +17,7 @@ import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeHttp = React.memo(function NodeHttp({ data }: { data: FlowModuleItemType }) {
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
return ( return (
...@@ -31,5 +31,7 @@ const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -31,5 +31,7 @@ const NodeHttp = ({ data }: NodeProps<FlowModuleItemType>) => {
</Container> </Container>
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodeHttp); export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeHttp data={data} />;
}
...@@ -41,7 +41,11 @@ const createEditField = { ...@@ -41,7 +41,11 @@ const createEditField = {
inputType: true inputType: true
}; };
const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { const NodePluginInput = React.memo(function NodePluginInput({
data
}: {
data: FlowModuleItemType;
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
const [createField, setCreateField] = useState<EditNodeFieldType>(); const [createField, setCreateField] = useState<EditNodeFieldType>();
...@@ -65,7 +69,7 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -65,7 +69,7 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
w={'14px'} w={'14px'}
cursor={'pointer'} cursor={'pointer'}
mr={3} mr={3}
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
onClick={() => onClick={() =>
setEditField({ setEditField({
inputType: item.type, inputType: item.type,
...@@ -121,7 +125,7 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -121,7 +125,7 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
))} ))}
<Box textAlign={'right'} mt={5}> <Box textAlign={'right'} mt={5}>
<Button <Button
variant={'base'} variant={'whitePrimary'}
leftIcon={<SmallAddIcon />} leftIcon={<SmallAddIcon />}
onClick={() => { onClick={() => {
setCreateField(defaultCreateField); setCreateField(defaultCreateField);
...@@ -253,5 +257,7 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -253,5 +257,7 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
)} )}
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodePluginInput); export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodePluginInput data={data} />;
}
...@@ -42,7 +42,11 @@ const createEditField = { ...@@ -42,7 +42,11 @@ const createEditField = {
inputType: false inputType: false
}; };
const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { const NodePluginOutput = React.memo(function NodePluginOutput({
data
}: {
data: FlowModuleItemType;
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
const [createField, setCreateField] = useState<EditNodeFieldType>(); const [createField, setCreateField] = useState<EditNodeFieldType>();
...@@ -84,7 +88,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -84,7 +88,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
w={'14px'} w={'14px'}
cursor={'pointer'} cursor={'pointer'}
ml={3} ml={3}
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
onClick={() => onClick={() =>
setEditField({ setEditField({
inputType: item.type, inputType: item.type,
...@@ -121,7 +125,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -121,7 +125,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
))} ))}
<Box textAlign={'left'} mt={5}> <Box textAlign={'left'} mt={5}>
<Button <Button
variant={'base'} variant={'whitePrimary'}
leftIcon={<SmallAddIcon />} leftIcon={<SmallAddIcon />}
onClick={() => { onClick={() => {
setCreateField(defaultCreateField); setCreateField(defaultCreateField);
...@@ -233,5 +237,8 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -233,5 +237,8 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
)} )}
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodePluginOutput);
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodePluginOutput data={data} />;
}
...@@ -6,7 +6,11 @@ import Container from '../modules/Container'; ...@@ -6,7 +6,11 @@ import Container from '../modules/Container';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../render/RenderOutput';
const QuestionInputNode = ({ data }: NodeProps<FlowModuleItemType>) => { const QuestionInputNode = React.memo(function QuestionInputNode({
data
}: {
data: FlowModuleItemType;
}) {
const { moduleId, outputs } = data; const { moduleId, outputs } = data;
return ( return (
...@@ -16,5 +20,8 @@ const QuestionInputNode = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -16,5 +20,8 @@ const QuestionInputNode = ({ data }: NodeProps<FlowModuleItemType>) => {
</Container> </Container>
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(QuestionInputNode);
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <QuestionInputNode data={data} />;
}
...@@ -7,7 +7,7 @@ import Container from '../modules/Container'; ...@@ -7,7 +7,7 @@ import Container from '../modules/Container';
import RenderInput from '../render/RenderInput'; import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../render/RenderOutput';
const NodeRunAPP = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeRunAPP = React.memo(function NodeRunAPP({ data }: { data: FlowModuleItemType }) {
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
return ( return (
...@@ -21,5 +21,7 @@ const NodeRunAPP = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -21,5 +21,7 @@ const NodeRunAPP = ({ data }: NodeProps<FlowModuleItemType>) => {
</Container> </Container>
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodeRunAPP); export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeRunAPP data={data} />;
}
...@@ -7,7 +7,7 @@ import Container from '../modules/Container'; ...@@ -7,7 +7,7 @@ import Container from '../modules/Container';
import RenderInput from '../render/RenderInput'; import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../render/RenderOutput';
const NodeSimple = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeSimple = React.memo(function NodeSimple({ data }: { data: FlowModuleItemType }) {
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
return ( return (
...@@ -30,5 +30,7 @@ const NodeSimple = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -30,5 +30,7 @@ const NodeSimple = ({ data }: NodeProps<FlowModuleItemType>) => {
)} )}
</NodeCard> </NodeCard>
); );
}; });
export default React.memo(NodeSimple); export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeSimple data={data} />;
}
...@@ -30,7 +30,7 @@ import QGSwitch from '@/components/core/module/Flow/components/modules/QGSwitch' ...@@ -30,7 +30,7 @@ import QGSwitch from '@/components/core/module/Flow/components/modules/QGSwitch'
import TTSSelect from '@/components/core/module/Flow/components/modules/TTSSelect'; import TTSSelect from '@/components/core/module/Flow/components/modules/TTSSelect';
import { splitGuideModule } from '@fastgpt/global/core/module/utils'; import { splitGuideModule } from '@fastgpt/global/core/module/utils';
const NodeUserGuide = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeUserGuide = React.memo(function NodeUserGuide({ data }: { data: FlowModuleItemType }) {
const theme = useTheme(); const theme = useTheme();
return ( return (
<> <>
...@@ -50,9 +50,11 @@ const NodeUserGuide = ({ data }: NodeProps<FlowModuleItemType>) => { ...@@ -50,9 +50,11 @@ const NodeUserGuide = ({ data }: NodeProps<FlowModuleItemType>) => {
</NodeCard> </NodeCard>
</> </>
); );
}; });
export default React.memo(NodeUserGuide);
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeUserGuide data={data} />;
}
export function WelcomeText({ data }: { data: FlowModuleItemType }) { export function WelcomeText({ data }: { data: FlowModuleItemType }) {
const { inputs, moduleId } = data; const { inputs, moduleId } = data;
......
...@@ -221,7 +221,7 @@ const FieldEditModal = ({ ...@@ -221,7 +221,7 @@ const FieldEditModal = ({
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common.Close')} {t('common.Close')}
</Button> </Button>
<Button <Button
......
...@@ -8,11 +8,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons'; ...@@ -8,11 +8,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useEditTitle } from '@/web/common/hooks/useEditTitle'; import { useEditTitle } from '@/web/common/hooks/useEditTitle';
import { useToast } from '@/web/common/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { import { onChangeNode, onCopyNode, onResetNode, onDelNode } from '../../FlowProvider';
useFlowProviderStore,
onChangeNode,
type useFlowProviderStoreType
} from '../../FlowProvider';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants'; import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
...@@ -27,13 +23,7 @@ type Props = FlowModuleItemType & { ...@@ -27,13 +23,7 @@ type Props = FlowModuleItemType & {
isPreview?: boolean; isPreview?: boolean;
}; };
const NodeCard = ( const NodeCard = (props: Props) => {
props: Props & {
onCopyNode: useFlowProviderStoreType['onCopyNode'];
onResetNode: useFlowProviderStoreType['onResetNode'];
onDelNode: useFlowProviderStoreType['onDelNode'];
}
) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { const {
children, children,
...@@ -44,11 +34,9 @@ const NodeCard = ( ...@@ -44,11 +34,9 @@ const NodeCard = (
moduleId, moduleId,
flowType, flowType,
inputs, inputs,
isPreview, isPreview
onCopyNode,
onResetNode,
onDelNode
} = props; } = props;
const theme = useTheme(); const theme = useTheme();
const { toast } = useToast(); const { toast } = useToast();
const { setLoading } = useSystemStore(); const { setLoading } = useSystemStore();
...@@ -77,7 +65,10 @@ const NodeCard = ( ...@@ -77,7 +65,10 @@ const NodeCard = (
try { try {
setLoading(true); setLoading(true);
const pluginModule = await getPreviewPluginModule(pluginId); const pluginModule = await getPreviewPluginModule(pluginId);
onResetNode(moduleId, pluginModule); onResetNode({
id: moduleId,
module: pluginModule
});
} catch (e) { } catch (e) {
return toast({ return toast({
status: 'error', status: 'error',
...@@ -130,20 +121,7 @@ const NodeCard = ( ...@@ -130,20 +121,7 @@ const NodeCard = (
onClick: () => {} onClick: () => {}
} }
], ],
[ [flowType, inputs, moduleId, name, onOpenModal, openConfirm, setLoading, t, toast]
flowType,
inputs,
moduleId,
name,
onCopyNode,
onDelNode,
onOpenModal,
onResetNode,
openConfirm,
setLoading,
t,
toast
]
); );
return ( return (
...@@ -198,10 +176,4 @@ const NodeCard = ( ...@@ -198,10 +176,4 @@ const NodeCard = (
); );
}; };
export default React.memo(function (props: Props) { export default React.memo(NodeCard);
const { onCopyNode, onResetNode, onDelNode } = useFlowProviderStore();
return (
<NodeCard {...props} onCopyNode={onCopyNode} onResetNode={onResetNode} onDelNode={onDelNode} />
);
});
import { EditNodeFieldType, FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type'; import { EditNodeFieldType, FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { import { onChangeNode, useFlowProviderStoreType } from '../../../FlowProvider';
onChangeNode,
useFlowProviderStore,
useFlowProviderStoreType
} from '../../../FlowProvider';
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
...@@ -20,16 +16,10 @@ const FieldEditModal = dynamic(() => import('../FieldEditModal')); ...@@ -20,16 +16,10 @@ const FieldEditModal = dynamic(() => import('../FieldEditModal'));
type Props = FlowNodeInputItemType & { type Props = FlowNodeInputItemType & {
moduleId: string; moduleId: string;
inputKey: string; inputKey: string;
mode: useFlowProviderStoreType['mode'];
}; };
const InputLabel = ({ const InputLabel = ({ moduleId, inputKey, mode, ...item }: Props) => {
moduleId,
inputKey,
mode,
...item
}: Props & {
mode: useFlowProviderStoreType['mode'];
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { const {
required = false, required = false,
...@@ -41,6 +31,7 @@ const InputLabel = ({ ...@@ -41,6 +31,7 @@ const InputLabel = ({
showTargetInApp, showTargetInApp,
showTargetInPlugin showTargetInPlugin
} = item; } = item;
const [editField, setEditField] = useState<EditNodeFieldType>(); const [editField, setEditField] = useState<EditNodeFieldType>();
const targetHandle = useMemo(() => { const targetHandle = useMemo(() => {
...@@ -81,7 +72,7 @@ const InputLabel = ({ ...@@ -81,7 +72,7 @@ const InputLabel = ({
w={'14px'} w={'14px'}
cursor={'pointer'} cursor={'pointer'}
ml={3} ml={3}
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
onClick={() => onClick={() =>
setEditField({ setEditField({
inputType: type, inputType: type,
...@@ -153,8 +144,4 @@ const InputLabel = ({ ...@@ -153,8 +144,4 @@ const InputLabel = ({
); );
}; };
export default React.memo(function (props: Props) { export default React.memo(InputLabel);
const { mode } = useFlowProviderStore();
return <InputLabel {...props} mode={mode} />;
});
import React, { useMemo } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import type { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type'; import type { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
import { Box } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant'; import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant';
...@@ -6,7 +6,7 @@ import dynamic from 'next/dynamic'; ...@@ -6,7 +6,7 @@ import dynamic from 'next/dynamic';
import InputLabel from './Label'; import InputLabel from './Label';
import type { RenderInputProps } from './type.d'; import type { RenderInputProps } from './type.d';
import { useFlowProviderStore, type useFlowProviderStoreType } from '../../../FlowProvider'; import { getFlowStore, type useFlowProviderStoreType } from '../../../FlowProvider';
const RenderList: { const RenderList: {
types: `${FlowNodeInputTypeEnum}`[]; types: `${FlowNodeInputTypeEnum}`[];
...@@ -71,14 +71,9 @@ type Props = { ...@@ -71,14 +71,9 @@ type Props = {
moduleId: string; moduleId: string;
CustomComponent?: Record<string, (e: FlowNodeInputItemType) => React.ReactNode>; CustomComponent?: Record<string, (e: FlowNodeInputItemType) => React.ReactNode>;
}; };
const RenderInput = ({ const RenderInput = ({ flowInputList, moduleId, CustomComponent = {} }: Props) => {
flowInputList, const [mode, setMode] = useState<useFlowProviderStoreType['mode']>('app');
moduleId,
CustomComponent = {},
mode
}: Props & {
mode: useFlowProviderStoreType['mode'];
}) => {
const sortInputs = useMemo( const sortInputs = useMemo(
() => () =>
flowInputList.sort((a, b) => { flowInputList.sort((a, b) => {
...@@ -108,6 +103,13 @@ const RenderInput = ({ ...@@ -108,6 +103,13 @@ const RenderInput = ({
[mode, sortInputs] [mode, sortInputs]
); );
useEffect(() => {
async () => {
const { mode } = await getFlowStore();
setMode(mode);
};
}, []);
return ( return (
<> <>
{filterInputs.map((input) => { {filterInputs.map((input) => {
...@@ -124,7 +126,9 @@ const RenderInput = ({ ...@@ -124,7 +126,9 @@ const RenderInput = ({
return ( return (
input.type !== FlowNodeInputTypeEnum.hidden && ( input.type !== FlowNodeInputTypeEnum.hidden && (
<Box key={input.key} _notLast={{ mb: 7 }} position={'relative'}> <Box key={input.key} _notLast={{ mb: 7 }} position={'relative'}>
{!!input.label && <InputLabel moduleId={moduleId} inputKey={input.key} {...input} />} {!!input.label && (
<InputLabel moduleId={moduleId} inputKey={input.key} mode={mode} {...input} />
)}
{!!RenderComponent && ( {!!RenderComponent && (
<Box mt={2} className={'nodrag'}> <Box mt={2} className={'nodrag'}>
{RenderComponent} {RenderComponent}
...@@ -138,7 +142,4 @@ const RenderInput = ({ ...@@ -138,7 +142,4 @@ const RenderInput = ({
); );
}; };
export default React.memo(function (props: Props) { export default React.memo(RenderInput);
const { mode } = useFlowProviderStore();
return <RenderInput {...props} mode={mode} />;
});
...@@ -16,7 +16,7 @@ const AddInputParam = ({ inputs = [], item, moduleId }: RenderInputProps) => { ...@@ -16,7 +16,7 @@ const AddInputParam = ({ inputs = [], item, moduleId }: RenderInputProps) => {
return ( return (
<> <>
<Button <Button
variant={'base'} variant={'whitePrimary'}
leftIcon={<SmallAddIcon />} leftIcon={<SmallAddIcon />}
onClick={() => { onClick={() => {
setEditField(item.defaultEditField || {}); setEditField(item.defaultEditField || {});
......
...@@ -26,7 +26,7 @@ const AiSettingRender = ({ inputs = [], moduleId }: RenderInputProps) => { ...@@ -26,7 +26,7 @@ const AiSettingRender = ({ inputs = [], moduleId }: RenderInputProps) => {
return ( return (
<> <>
<Button <Button
variant={'base'} variant={'whitePrimary'}
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />} leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
onClick={onOpenAIChatSetting} onClick={onOpenAIChatSetting}
> >
......
import React from 'react'; import React, { useEffect, useState } from 'react';
import type { RenderInputProps } from '../type'; import type { RenderInputProps } from '../type';
import { import { getFlowStore, onChangeNode, useFlowProviderStoreType } from '../../../../FlowProvider';
onChangeNode,
useFlowProviderStore,
type useFlowProviderStoreType
} from '../../../../FlowProvider';
import { Box, Button, Flex, useDisclosure, useTheme } from '@chakra-ui/react'; import { Box, Button, Flex, useDisclosure, useTheme } from '@chakra-ui/react';
import { SelectAppItemType } from '@fastgpt/global/core/module/type'; import { SelectAppItemType } from '@fastgpt/global/core/module/type';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import SelectAppModal from '../../../../SelectAppModal'; import SelectAppModal from '../../../../SelectAppModal';
const SelectAppRender = ({ const SelectAppRender = ({ item, moduleId }: RenderInputProps) => {
item,
moduleId,
filterAppIds
}: RenderInputProps & {
filterAppIds: useFlowProviderStoreType['filterAppIds'];
}) => {
const theme = useTheme(); const theme = useTheme();
const [filterAppIds, setFilterAppIds] = useState<useFlowProviderStoreType['filterAppIds']>([]);
const { const {
isOpen: isOpenSelectApp, isOpen: isOpenSelectApp,
...@@ -27,11 +18,18 @@ const SelectAppRender = ({ ...@@ -27,11 +18,18 @@ const SelectAppRender = ({
const value = item.value as SelectAppItemType | undefined; const value = item.value as SelectAppItemType | undefined;
useEffect(() => {
async () => {
const { filterAppIds } = await getFlowStore();
setFilterAppIds(filterAppIds);
};
}, []);
return ( return (
<> <>
<Box onClick={onOpenSelectApp}> <Box onClick={onOpenSelectApp}>
{!value ? ( {!value ? (
<Button variant={'base'} w={'100%'}> <Button variant={'whitePrimary'} w={'100%'}>
选择应用 选择应用
</Button> </Button>
) : ( ) : (
...@@ -66,7 +64,4 @@ const SelectAppRender = ({ ...@@ -66,7 +64,4 @@ const SelectAppRender = ({
); );
}; };
export default React.memo(function (props: RenderInputProps) { export default React.memo(SelectAppRender);
const { filterAppIds } = useFlowProviderStore();
return <SelectAppRender {...props} filterAppIds={filterAppIds} />;
});
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import type { RenderInputProps } from '../type'; import type { RenderInputProps } from '../type';
import { onChangeNode, useFlowProviderStore } from '../../../../FlowProvider'; import { getFlowStore, onChangeNode, useFlowProviderStoreType } from '../../../../FlowProvider';
import { Button, useDisclosure } from '@chakra-ui/react'; import { Button, useDisclosure } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constant'; import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constant';
...@@ -11,7 +11,7 @@ import MyIcon from '@/components/Icon'; ...@@ -11,7 +11,7 @@ import MyIcon from '@/components/Icon';
import DatasetParamsModal from '@/components/core/module/DatasetParamsModal'; import DatasetParamsModal from '@/components/core/module/DatasetParamsModal';
const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => { const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
const { nodes } = useFlowProviderStore(); const [nodes, setNodes] = useState<useFlowProviderStoreType['nodes']>([]);
const { t } = useTranslation(); const { t } = useTranslation();
const [data, setData] = useState({ const [data, setData] = useState({
...@@ -51,10 +51,17 @@ const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => { ...@@ -51,10 +51,17 @@ const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
}); });
}, [inputs]); }, [inputs]);
useEffect(() => {
async () => {
const { nodes } = await getFlowStore();
setNodes(nodes);
};
}, []);
return ( return (
<> <>
<Button <Button
variant={'base'} variant={'whitePrimary'}
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />} leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
onClick={onOpen} onClick={onOpen}
> >
......
...@@ -41,7 +41,7 @@ const OutputLabel = ({ ...@@ -41,7 +41,7 @@ const OutputLabel = ({
w={'14px'} w={'14px'}
cursor={'pointer'} cursor={'pointer'}
mr={3} mr={3}
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
onClick={() => onClick={() =>
setEditField({ setEditField({
key: outputKey, key: outputKey,
......
...@@ -17,7 +17,7 @@ const AddOutputParam = ({ outputs = [], item, moduleId }: RenderOutputProps) => ...@@ -17,7 +17,7 @@ const AddOutputParam = ({ outputs = [], item, moduleId }: RenderOutputProps) =>
return ( return (
<Box textAlign={'right'}> <Box textAlign={'right'}>
<Button <Button
variant={'base'} variant={'whitePrimary'}
leftIcon={<SmallAddIcon />} leftIcon={<SmallAddIcon />}
onClick={() => { onClick={() => {
setEditField(item.defaultEditField || {}); setEditField(item.defaultEditField || {});
......
...@@ -28,7 +28,7 @@ const SourceHandle = ({ handleKey, valueType, ...props }: Props) => { ...@@ -28,7 +28,7 @@ const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
<Box <Box
position={'absolute'} position={'absolute'}
top={'50%'} top={'50%'}
right={'-16px'} right={'-18px'}
transform={'translate(50%,-50%)'} transform={'translate(50%,-50%)'}
{...props} {...props}
> >
...@@ -40,8 +40,8 @@ const SourceHandle = ({ handleKey, valueType, ...props }: Props) => { ...@@ -40,8 +40,8 @@ const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
> >
<Handle <Handle
style={{ style={{
width: '12px', width: '14px',
height: '12px', height: '14px',
...valueStyle ...valueStyle
}} }}
type="source" type="source"
......
...@@ -9,10 +9,9 @@ import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants'; ...@@ -9,10 +9,9 @@ import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
interface Props extends BoxProps { interface Props extends BoxProps {
handleKey: string; handleKey: string;
valueType?: `${ModuleIOValueTypeEnum}`; valueType?: `${ModuleIOValueTypeEnum}`;
onConnect?: OnConnect;
} }
const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => { const TargetHandle = ({ handleKey, valueType, ...props }: Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const valType = valueType ?? ModuleIOValueTypeEnum.any; const valType = valueType ?? ModuleIOValueTypeEnum.any;
...@@ -28,7 +27,7 @@ const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => { ...@@ -28,7 +27,7 @@ const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
<Box <Box
position={'absolute'} position={'absolute'}
top={'50%'} top={'50%'}
left={'-16px'} left={'-18px'}
transform={'translate(50%,-50%)'} transform={'translate(50%,-50%)'}
{...props} {...props}
> >
...@@ -40,8 +39,8 @@ const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => { ...@@ -40,8 +39,8 @@ const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
> >
<Handle <Handle
style={{ style={{
width: '12px', width: '14px',
height: '12px', height: '14px',
...valueStyle ...valueStyle
}} }}
type="target" type="target"
......
...@@ -11,7 +11,6 @@ import ModuleTemplateList, { type ModuleTemplateProps } from './ModuleTemplateLi ...@@ -11,7 +11,6 @@ import ModuleTemplateList, { type ModuleTemplateProps } from './ModuleTemplateLi
import { useFlowProviderStore } from './FlowProvider'; import { useFlowProviderStore } from './FlowProvider';
import 'reactflow/dist/style.css'; import 'reactflow/dist/style.css';
import type { ModuleItemType } from '@fastgpt/global/core/module/type.d';
const NodeSimple = dynamic(() => import('./components/nodes/NodeSimple')); const NodeSimple = dynamic(() => import('./components/nodes/NodeSimple'));
const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = { const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
...@@ -34,106 +33,96 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = { ...@@ -34,106 +33,96 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
const edgeTypes = { const edgeTypes = {
[EDGE_TYPE]: ButtonEdge [EDGE_TYPE]: ButtonEdge
}; };
type Props = {
modules: ModuleItemType[];
Header: React.ReactNode;
} & ModuleTemplateProps;
const Container = React.memo(function Container(props: Props) { const Container = React.memo(function Container() {
const { modules = [], Header, templates } = props; const { reactFlowWrapper, nodes, onNodesChange, edges, onEdgesChange, onConnect } =
useFlowProviderStore();
return (
<ReactFlow
ref={reactFlowWrapper}
fitView
nodes={nodes}
edges={edges}
minZoom={0.1}
maxZoom={1.5}
defaultEdgeOptions={{
animated: true,
zIndex: 0
}}
elevateEdgesOnSelect
connectionLineStyle={{ strokeWidth: 2, stroke: '#5A646Es' }}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={(connect) => {
connect.sourceHandle &&
connect.targetHandle &&
onConnect({
connect
});
}}
>
<Background />
<Controls position={'bottom-right'} style={{ display: 'flex' }} showInteractive={false} />
</ReactFlow>
);
});
const Flow = ({
Header,
templates,
...data
}: ModuleTemplateProps & { Header: React.ReactNode }) => {
const { const {
isOpen: isOpenTemplate, isOpen: isOpenTemplate,
onOpen: onOpenTemplate, onOpen: onOpenTemplate,
onClose: onCloseTemplate onClose: onCloseTemplate
} = useDisclosure(); } = useDisclosure();
const { reactFlowWrapper, nodes, onNodesChange, edges, onEdgesChange, onConnect, initData } =
useFlowProviderStore();
useEffect(() => {
initData(JSON.parse(JSON.stringify(modules)));
}, [modules.length]);
return (
<>
{/* header */}
{Header}
<Box
minH={'400px'}
flex={'1 0 0'}
w={'100%'}
h={0}
position={'relative'}
onContextMenu={(e) => {
e.preventDefault();
return false;
}}
>
{/* open module template */}
<IconButton
position={'absolute'}
top={5}
left={5}
w={'38px'}
h={'38px'}
borderRadius={'50%'}
icon={<SmallCloseIcon fontSize={'26px'} />}
transform={isOpenTemplate ? '' : 'rotate(135deg)'}
transition={'0.2s ease'}
aria-label={''}
zIndex={1}
boxShadow={'2px 2px 6px #85b1ff'}
onClick={() => {
isOpenTemplate ? onCloseTemplate() : onOpenTemplate();
}}
/>
<ReactFlow
ref={reactFlowWrapper}
fitView
nodes={nodes}
edges={edges}
minZoom={0.1}
maxZoom={1.5}
defaultEdgeOptions={{
animated: true,
zIndex: 0
}}
elevateEdgesOnSelect
connectionLineStyle={{ strokeWidth: 2, stroke: '#5A646Es' }}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={(connect) => {
connect.sourceHandle &&
connect.targetHandle &&
onConnect({
connect
});
}}
>
<Background />
<Controls position={'bottom-right'} style={{ display: 'flex' }} showInteractive={false} />
</ReactFlow>
<ModuleTemplateList
templates={templates}
isOpen={isOpenTemplate}
onClose={onCloseTemplate}
/>
</Box>
</>
);
});
const Flow = (data: Props) => {
return ( return (
<Box h={'100%'} position={'fixed'} zIndex={999} top={0} left={0} right={0} bottom={0}> <Box h={'100%'} position={'fixed'} zIndex={999} top={0} left={0} right={0} bottom={0}>
<ReactFlowProvider> <ReactFlowProvider>
<Flex h={'100%'} flexDirection={'column'} bg={'#fff'}> <Flex h={'100%'} flexDirection={'column'} bg={'#fff'}>
<Container {...data} /> {Header}
<Box
minH={'400px'}
flex={'1 0 0'}
w={'100%'}
h={0}
position={'relative'}
onContextMenu={(e) => {
e.preventDefault();
return false;
}}
>
{/* open module template */}
<IconButton
position={'absolute'}
top={5}
left={5}
size={'mdSquare'}
borderRadius={'50%'}
icon={<SmallCloseIcon fontSize={'26px'} />}
transform={isOpenTemplate ? '' : 'rotate(135deg)'}
transition={'0.2s ease'}
aria-label={''}
zIndex={1}
boxShadow={'2px 2px 6px #85b1ff'}
onClick={() => {
isOpenTemplate ? onCloseTemplate() : onOpenTemplate();
}}
/>
<Container {...data} />
<ModuleTemplateList
templates={templates}
isOpen={isOpenTemplate}
onClose={onCloseTemplate}
/>
</Box>
</Flex> </Flex>
</ReactFlowProvider> </ReactFlowProvider>
</Box> </Box>
......
...@@ -88,7 +88,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => { ...@@ -88,7 +88,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
href={feConfigs.openAPIDocUrl || getDocPath('/docs/development/openapi')} href={feConfigs.openAPIDocUrl || getDocPath('/docs/development/openapi')}
target={'_blank'} target={'_blank'}
ml={1} ml={1}
color={'blue.500'} color={'primary.500'}
> >
查看文档 查看文档
</Link> </Link>
...@@ -119,7 +119,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => { ...@@ -119,7 +119,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
<Button <Button
ml={3} ml={3}
leftIcon={<AddIcon fontSize={'md'} />} leftIcon={<AddIcon fontSize={'md'} />}
variant={'base'} variant={'whitePrimary'}
onClick={() => onClick={() =>
setEditData({ setEditData({
...defaultEditData, ...defaultEditData,
...@@ -254,7 +254,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => { ...@@ -254,7 +254,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
</Flex> </Flex>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant="base" onClick={() => setApiKey('')}> <Button variant="whiteBase" onClick={() => setApiKey('')}>
好的 好的
</Button> </Button>
</ModalFooter> </ModalFooter>
...@@ -358,7 +358,7 @@ function EditKeyModal({ ...@@ -358,7 +358,7 @@ function EditKeyModal({
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('Cancel')} {t('Cancel')}
</Button> </Button>
......
...@@ -12,7 +12,7 @@ const PermissionIconText = ({ ...@@ -12,7 +12,7 @@ const PermissionIconText = ({
return PermissionTypeMap[permission] ? ( return PermissionTypeMap[permission] ? (
<Flex alignItems={'center'} {...props}> <Flex alignItems={'center'} {...props}>
<MyIcon name={PermissionTypeMap[permission]?.iconLight as any} w={'14px'} /> <MyIcon name={PermissionTypeMap[permission]?.iconLight as any} w={'14px'} />
<Box ml={'1px'}>{t(PermissionTypeMap[permission]?.label)}</Box> <Box ml={'2px'}>{t(PermissionTypeMap[permission]?.label)}</Box>
</Flex> </Flex>
) : null; ) : null;
}; };
......
...@@ -135,7 +135,7 @@ function EditModal({ ...@@ -135,7 +135,7 @@ function EditModal({
{!!defaultData.id ? ( {!!defaultData.id ? (
<> <>
<Box flex={1} /> <Box flex={1} />
<Button variant={'base'} mr={3} onClick={onClose}> <Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common.Close')} {t('common.Close')}
</Button> </Button>
<Button isLoading={updating} onClick={handleSubmit((data) => onclickUpdate(data))}> <Button isLoading={updating} onClick={handleSubmit((data) => onclickUpdate(data))}>
......
...@@ -156,7 +156,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => { ...@@ -156,7 +156,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
<MyIcon <MyIcon
name={'common/addCircleLight'} name={'common/addCircleLight'}
w={['16px', '18px']} w={['16px', '18px']}
color={'blue.500'} color={'primary.500'}
cursor={'pointer'} cursor={'pointer'}
/> />
} }
...@@ -177,7 +177,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => { ...@@ -177,7 +177,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
gap={3} gap={3}
{...(userInfo?.team?.teamId === team.teamId {...(userInfo?.team?.teamId === team.teamId
? { ? {
bg: 'blue.200' bg: 'primary.200'
} }
: { : {
_hover: { _hover: {
...@@ -198,9 +198,13 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => { ...@@ -198,9 +198,13 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
{team.teamName} {team.teamName}
</Box> </Box>
{userInfo?.team?.teamId === team.teamId ? ( {userInfo?.team?.teamId === team.teamId ? (
<MyIcon name={'common/tickFill'} w={'16px'} color={'blue.500'} /> <MyIcon name={'common/tickFill'} w={'16px'} color={'primary.500'} />
) : ( ) : (
<Button size={'xs'} variant={'base'} onClick={() => onSwitchTeam(team.teamId)}> <Button
size={'xs'}
variant={'whitePrimary'}
onClick={() => onSwitchTeam(team.teamId)}
>
{t('user.team.Check Team')} {t('user.team.Check Team')}
</Button> </Button>
)} )}
...@@ -235,7 +239,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => { ...@@ -235,7 +239,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
ml={2} ml={2}
cursor={'pointer'} cursor={'pointer'}
_hover={{ _hover={{
color: 'blue.500' color: 'primary.500'
}} }}
onClick={() => { onClick={() => {
if (!userInfo?.team) return; if (!userInfo?.team) return;
...@@ -256,11 +260,11 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => { ...@@ -256,11 +260,11 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
</Box> </Box>
{userInfo.team.role === TeamMemberRoleEnum.owner && ( {userInfo.team.role === TeamMemberRoleEnum.owner && (
<Button <Button
variant={'base'} variant={'whitePrimary'}
size="sm" size="sm"
borderRadius={'md'} borderRadius={'md'}
ml={3} ml={3}
leftIcon={<MyIcon name={'common/inviteLight'} w={'14px'} color={'blue.500'} />} leftIcon={<MyIcon name={'common/inviteLight'} w={'14px'} color={'primary.500'} />}
onClick={() => { onClick={() => {
if (userInfo.team.maxSize <= members.length) { if (userInfo.team.maxSize <= members.length) {
toast({ toast({
...@@ -278,12 +282,16 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => { ...@@ -278,12 +282,16 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
<Box flex={1} /> <Box flex={1} />
{userInfo.team.role !== TeamMemberRoleEnum.owner && ( {userInfo.team.role !== TeamMemberRoleEnum.owner && (
<Button <Button
variant={'base'} variant={'whitePrimary'}
size="sm" size="sm"
borderRadius={'md'} borderRadius={'md'}
ml={3} ml={3}
leftIcon={ leftIcon={
<MyIcon name={'support/account/loginoutLight'} w={'14px'} color={'blue.500'} /> <MyIcon
name={'support/account/loginoutLight'}
w={'14px'}
color={'primary.500'}
/>
} }
onClick={() => { onClick={() => {
openLeaveConfirm(() => onLeaveTeam(userInfo?.team?.teamId))(); openLeaveConfirm(() => onLeaveTeam(userInfo?.team?.teamId))();
...@@ -335,7 +343,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => { ...@@ -335,7 +343,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
name={'edit'} name={'edit'}
cursor={'pointer'} cursor={'pointer'}
w="14px" w="14px"
_hover={{ color: 'blue.500' }} _hover={{ color: 'primary.500' }}
/> />
</MenuButton> </MenuButton>
} }
......
...@@ -19,7 +19,7 @@ const TeamMenu = () => { ...@@ -19,7 +19,7 @@ const TeamMenu = () => {
return ( return (
<Button <Button
variant={'base'} variant={'whitePrimary'}
userSelect={'none'} userSelect={'none'}
w={'100%'} w={'100%'}
display={'block'} display={'block'}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment