mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 02:12:38 +00:00
v4.5 (#403)
This commit is contained in:
@@ -32,8 +32,6 @@ function Error() {
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context: any) {
|
||||
console.log('[render error]: ', context);
|
||||
|
||||
return {
|
||||
props: { ...(await serviceSideProps(context)) }
|
||||
};
|
||||
|
@@ -3,7 +3,7 @@ import { connectToDatabase } from '@/service/mongo';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { sseErrRes } from '@/service/response';
|
||||
import { sseResponseEventEnum } from '@/constants/chat';
|
||||
import { sseResponse } from '@/service/utils/tools';
|
||||
import { responseWrite } from '@fastgpt/common/tools/stream';
|
||||
import { AppModuleItemType } from '@/types/app';
|
||||
import { dispatchModules } from '@/pages/api/v1/chat/completions';
|
||||
import { pushChatBill } from '@/service/common/bill/push';
|
||||
@@ -59,12 +59,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
detail: true
|
||||
});
|
||||
|
||||
sseResponse({
|
||||
responseWrite({
|
||||
res,
|
||||
event: sseResponseEventEnum.answer,
|
||||
data: '[DONE]'
|
||||
});
|
||||
sseResponse({
|
||||
responseWrite({
|
||||
res,
|
||||
event: sseResponseEventEnum.appStreamResponse,
|
||||
data: JSON.stringify(responseData)
|
||||
|
@@ -6,7 +6,8 @@ import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { ChatItemType } from '@/types/chat';
|
||||
import { authApp } from '@/service/utils/auth';
|
||||
import type { ChatSchema } from '@/types/mongoSchema';
|
||||
import { getChatModelNameList, getGuideModule } from '@/components/ChatBox/utils';
|
||||
import { getGuideModule } from '@/components/ChatBox/utils';
|
||||
import { getChatModelNameListByModules } from '@/service/core/app/module';
|
||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||
|
||||
/* 初始化我的聊天框,需要身份验证 */
|
||||
@@ -83,7 +84,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
appId,
|
||||
app: {
|
||||
userGuideModule: getGuideModule(app.modules),
|
||||
chatModels: getChatModelNameList(app.modules),
|
||||
chatModels: getChatModelNameListByModules(app.modules),
|
||||
name: app.name,
|
||||
avatar: app.avatar,
|
||||
intro: app.intro,
|
||||
|
@@ -12,6 +12,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
const { userId } = await authUser({ req, authToken: true, authApiKey: true });
|
||||
|
||||
const qaModel = global.qaModels[0];
|
||||
|
||||
const { _id } = await Bill.create({
|
||||
userId,
|
||||
appName: name,
|
||||
@@ -25,7 +27,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
},
|
||||
{
|
||||
moduleName: 'QA 拆分',
|
||||
model: global.qaModel.name,
|
||||
model: qaModel?.name,
|
||||
amount: 0,
|
||||
tokenLen: 0
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ import { connectToDatabase } from '@/service/mongo';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import type { CreateQuestionGuideParams } from '@/global/core/api/aiReq.d';
|
||||
import { pushQuestionGuideBill } from '@/service/common/bill/push';
|
||||
import { defaultQGModel } from '@/pages/api/system/getInitData';
|
||||
import { createQuestionGuide } from '@fastgpt/core/ai/functions/createQuestionGuide';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
@@ -23,9 +22,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
throw new Error('user not found');
|
||||
}
|
||||
|
||||
const qgModel = global.qgModels[0];
|
||||
|
||||
const { result, tokens } = await createQuestionGuide({
|
||||
messages,
|
||||
model: (global.qgModel || defaultQGModel).model
|
||||
model: qgModel.model
|
||||
});
|
||||
|
||||
jsonRes(res, {
|
||||
|
@@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDataset } from '@fastgpt/core/dataset/schema';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { getVectorModel } from '@/service/utils/data';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import type { DatasetsItemType } from '@/types/core/dataset';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { PgClient } from '@/service/pg';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import { PgDatasetTableName } from '@/constants/plugin';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
|
||||
|
@@ -8,7 +8,7 @@ import { findAllChildrenIds } from '../delete';
|
||||
import QueryStream from 'pg-query-stream';
|
||||
import { PgClient } from '@/service/pg';
|
||||
import { addLog } from '@/service/utils/tools';
|
||||
import { responseWriteController } from '@/service/common/stream';
|
||||
import { responseWriteController } from '@fastgpt/common/tools/stream';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
|
@@ -7,10 +7,10 @@ import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authDataset } from '@/service/utils/auth';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import { PgDatasetTableName } from '@/constants/plugin';
|
||||
import { insertData2Dataset, PgClient } from '@/service/pg';
|
||||
import { getVectorModel } from '@/service/utils/data';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||
import { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||
import { countPromptTokens } from '@/utils/common/tiktoken';
|
||||
|
@@ -5,15 +5,15 @@ import { connectToDatabase, TrainingData } from '@/service/mongo';
|
||||
import { MongoDataset } from '@fastgpt/core/dataset/schema';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { authDataset } from '@/service/utils/auth';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import { TrainingModeEnum } from '@/constants/plugin';
|
||||
import { startQueue } from '@/service/utils/tools';
|
||||
import { getVectorModel } from '@/service/utils/data';
|
||||
import { DatasetDataItemType } from '@/types/core/dataset/data';
|
||||
import { countPromptTokens } from '@/utils/common/tiktoken';
|
||||
import type { PushDataResponse } from '@/global/core/api/datasetRes.d';
|
||||
import type { PushDataProps } from '@/global/core/api/datasetReq.d';
|
||||
import { authFileIdValid } from '@/service/dataset/auth';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
|
||||
const modeMap = {
|
||||
[TrainingModeEnum.index]: true,
|
||||
@@ -71,7 +71,7 @@ export async function pushDataToKb({
|
||||
if (mode === TrainingModeEnum.index) {
|
||||
const vectorModel = (await MongoDataset.findById(kbId, 'vectorModel'))?.vectorModel;
|
||||
|
||||
return getVectorModel(vectorModel || global.vectorModels[0].model);
|
||||
return getVectorModel(vectorModel);
|
||||
}
|
||||
return global.vectorModels[0];
|
||||
})()
|
||||
@@ -79,7 +79,7 @@ export async function pushDataToKb({
|
||||
|
||||
const modeMaxToken = {
|
||||
[TrainingModeEnum.index]: vectorModel.maxToken * 1.5,
|
||||
[TrainingModeEnum.qa]: global.qaModel.maxToken * 0.8
|
||||
[TrainingModeEnum.qa]: global.qaModels[0].maxToken * 0.8
|
||||
};
|
||||
|
||||
// filter repeat or equal content
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { PgClient } from '@/service/pg';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDataset } from '@fastgpt/core/dataset/schema';
|
||||
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { getVectorModel } from '@/service/utils/data';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import { MongoDataset } from '@fastgpt/core/dataset/schema';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { getVectorModel } from '@/service/utils/data';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import type { DatasetsItemType } from '@/types/core/dataset';
|
||||
import { DatasetTypeEnum } from '@fastgpt/core/dataset/constant';
|
||||
import { MongoDataset } from '@fastgpt/core/dataset/schema';
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { PgClient } from '@/service/pg';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import { getVector } from '../../openapi/plugin/vector';
|
||||
import { PgDatasetTableName } from '@/constants/plugin';
|
||||
import { MongoDataset } from '@fastgpt/core/dataset/schema';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { authBalanceByUid, authUser } from '@fastgpt/support/user/auth';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import { getAIApi } from '@fastgpt/core/ai/config';
|
||||
import { pushGenerateVectorBill } from '@/service/common/bill/push';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import ChatCompletion from '@/pages/api/v1/chat/completions';
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
@@ -6,8 +6,9 @@ import { MongoUser } from '@fastgpt/support/user/schema';
|
||||
import type { InitShareChatResponse } from '@/global/support/api/outLinkRes.d';
|
||||
import { authApp } from '@/service/utils/auth';
|
||||
import { HUMAN_ICON } from '@/constants/chat';
|
||||
import { getChatModelNameList, getGuideModule } from '@/components/ChatBox/utils';
|
||||
import { getGuideModule } from '@/components/ChatBox/utils';
|
||||
import { authShareChatInit } from '@fastgpt/support/outLink/auth';
|
||||
import { getChatModelNameListByModules } from '@/service/core/app/module';
|
||||
|
||||
/* init share chat window */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -51,7 +52,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
userAvatar: user?.avatar || HUMAN_ICON,
|
||||
app: {
|
||||
userGuideModule: getGuideModule(app.modules),
|
||||
chatModels: getChatModelNameList(app.modules),
|
||||
chatModels: getChatModelNameListByModules(app.modules),
|
||||
name: app.name,
|
||||
avatar: app.avatar,
|
||||
intro: app.intro
|
||||
|
@@ -4,10 +4,23 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { readFileSync } from 'fs';
|
||||
import type { InitDateResponse } from '@/global/common/api/systemRes';
|
||||
import type { VectorModelItemType, FunctionModelItemType } from '@/types/model';
|
||||
import { formatPrice } from '@fastgpt/common/bill';
|
||||
import { getTikTokenEnc } from '@/utils/common/tiktoken';
|
||||
import { initHttpAgent } from '@fastgpt/core/init';
|
||||
import {
|
||||
defaultChatModels,
|
||||
defaultQAModels,
|
||||
defaultCQModels,
|
||||
defaultExtractModels,
|
||||
defaultQGModels,
|
||||
defaultVectorModels
|
||||
} from '@/constants/model';
|
||||
import {
|
||||
ChatModelItemType,
|
||||
FunctionModelItemType,
|
||||
LLMModelItemType,
|
||||
VectorModelItemType
|
||||
} from '@/types/model';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
getInitConfig();
|
||||
@@ -17,7 +30,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
data: {
|
||||
feConfigs: global.feConfigs,
|
||||
chatModels: global.chatModels,
|
||||
qaModel: global.qaModel,
|
||||
qaModels: global.qaModels,
|
||||
cqModels: global.cqModels,
|
||||
extractModels: global.extractModels,
|
||||
qgModels: global.qgModels,
|
||||
vectorModels: global.vectorModels,
|
||||
priceMd: global.priceMd,
|
||||
systemVersion: global.systemVersion || '0.0.0'
|
||||
@@ -42,72 +58,6 @@ const defaultFeConfigs: FeConfigsType = {
|
||||
},
|
||||
scripts: []
|
||||
};
|
||||
const defaultChatModels = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo',
|
||||
name: 'GPT35-4k',
|
||||
contextMaxToken: 4000,
|
||||
quoteMaxToken: 2400,
|
||||
maxTemperature: 1.2,
|
||||
price: 0
|
||||
},
|
||||
{
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
contextMaxToken: 16000,
|
||||
quoteMaxToken: 8000,
|
||||
maxTemperature: 1.2,
|
||||
price: 0
|
||||
},
|
||||
{
|
||||
model: 'gpt-4',
|
||||
name: 'GPT4-8k',
|
||||
contextMaxToken: 8000,
|
||||
quoteMaxToken: 4000,
|
||||
maxTemperature: 1.2,
|
||||
price: 0
|
||||
}
|
||||
];
|
||||
const defaultQAModel = {
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
maxToken: 16000,
|
||||
price: 0
|
||||
};
|
||||
export const defaultExtractModel: FunctionModelItemType = {
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
maxToken: 16000,
|
||||
price: 0,
|
||||
prompt: '',
|
||||
functionCall: true
|
||||
};
|
||||
export const defaultCQModel: FunctionModelItemType = {
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'GPT35-16k',
|
||||
maxToken: 16000,
|
||||
price: 0,
|
||||
prompt: '',
|
||||
functionCall: true
|
||||
};
|
||||
export const defaultQGModel: FunctionModelItemType = {
|
||||
model: 'gpt-3.5-turbo',
|
||||
name: 'FastAI-4k',
|
||||
maxToken: 4000,
|
||||
price: 1.5,
|
||||
prompt: '',
|
||||
functionCall: false
|
||||
};
|
||||
|
||||
const defaultVectorModels: VectorModelItemType[] = [
|
||||
{
|
||||
model: 'text-embedding-ada-002',
|
||||
name: 'Embedding-2',
|
||||
price: 0,
|
||||
defaultToken: 500,
|
||||
maxToken: 3000
|
||||
}
|
||||
];
|
||||
|
||||
export function initGlobal() {
|
||||
// init tikToken
|
||||
@@ -127,7 +77,16 @@ export function getInitConfig() {
|
||||
|
||||
const filename =
|
||||
process.env.NODE_ENV === 'development' ? 'data/config.local.json' : '/app/data/config.json';
|
||||
const res = JSON.parse(readFileSync(filename, 'utf-8'));
|
||||
const res = JSON.parse(readFileSync(filename, 'utf-8')) as {
|
||||
FeConfig: FeConfigsType;
|
||||
SystemParams: SystemEnvType;
|
||||
ChatModels: ChatModelItemType[];
|
||||
QAModels: LLMModelItemType[];
|
||||
CQModels: FunctionModelItemType[];
|
||||
ExtractModels: FunctionModelItemType[];
|
||||
QGModels: LLMModelItemType[];
|
||||
VectorModels: VectorModelItemType[];
|
||||
};
|
||||
|
||||
console.log(`System Version: ${global.systemVersion}`);
|
||||
|
||||
@@ -137,11 +96,13 @@ export function getInitConfig() {
|
||||
? { ...defaultSystemEnv, ...res.SystemParams }
|
||||
: defaultSystemEnv;
|
||||
global.feConfigs = res.FeConfig ? { ...defaultFeConfigs, ...res.FeConfig } : defaultFeConfigs;
|
||||
|
||||
global.chatModels = res.ChatModels || defaultChatModels;
|
||||
global.qaModel = res.QAModel || defaultQAModel;
|
||||
global.extractModel = res.ExtractModel || defaultExtractModel;
|
||||
global.cqModel = res.CQModel || defaultCQModel;
|
||||
global.qgModel = res.QGModel || defaultQGModel;
|
||||
global.qaModels = res.QAModels || defaultQAModels;
|
||||
global.cqModels = res.CQModels || defaultCQModels;
|
||||
global.extractModels = res.ExtractModels || defaultExtractModels;
|
||||
global.qgModels = res.QGModels || defaultQGModels;
|
||||
|
||||
global.vectorModels = res.VectorModels || defaultVectorModels;
|
||||
} catch (error) {
|
||||
setDefaultData();
|
||||
@@ -152,13 +113,27 @@ export function getInitConfig() {
|
||||
export function setDefaultData() {
|
||||
global.systemEnv = defaultSystemEnv;
|
||||
global.feConfigs = defaultFeConfigs;
|
||||
|
||||
global.chatModels = defaultChatModels;
|
||||
global.qaModel = defaultQAModel;
|
||||
global.qaModels = defaultQAModels;
|
||||
global.cqModels = defaultCQModels;
|
||||
global.extractModels = defaultExtractModels;
|
||||
global.qgModels = defaultQGModels;
|
||||
|
||||
global.vectorModels = defaultVectorModels;
|
||||
global.extractModel = defaultExtractModel;
|
||||
global.cqModel = defaultCQModel;
|
||||
global.qgModel = defaultQGModel;
|
||||
global.priceMd = '';
|
||||
|
||||
console.log('use default config');
|
||||
console.log({
|
||||
feConfigs: defaultFeConfigs,
|
||||
systemEnv: defaultSystemEnv,
|
||||
chatModels: defaultChatModels,
|
||||
qaModels: defaultQAModels,
|
||||
cqModels: defaultCQModels,
|
||||
extractModels: defaultExtractModels,
|
||||
qgModels: defaultQGModels,
|
||||
vectorModels: defaultVectorModels
|
||||
});
|
||||
}
|
||||
|
||||
export function getSystemVersion() {
|
||||
@@ -187,10 +162,18 @@ ${global.vectorModels
|
||||
${global.chatModels
|
||||
?.map((item) => `| 对话-${item.name} | ${formatPrice(item.price, 1000)} |`)
|
||||
.join('\n')}
|
||||
| 文件QA拆分 | ${formatPrice(global.qaModel?.price, 1000)} |
|
||||
| 高级编排 - 问题分类 | ${formatPrice(global.cqModel?.price, 1000)} |
|
||||
| 高级编排 - 内容提取 | ${formatPrice(global.extractModel?.price, 1000)} |
|
||||
| 下一步指引 | ${formatPrice(global.qgModel?.price, 1000)} |
|
||||
${global.qaModels
|
||||
?.map((item) => `| 文件QA拆分-${item.name} | ${formatPrice(item.price, 1000)} |`)
|
||||
.join('\n')}
|
||||
${global.cqModels
|
||||
?.map((item) => `| 问题分类-${item.name} | ${formatPrice(item.price, 1000)} |`)
|
||||
.join('\n')}
|
||||
${global.extractModels
|
||||
?.map((item) => `| 内容提取-${item.name} | ${formatPrice(item.price, 1000)} |`)
|
||||
.join('\n')}
|
||||
${global.qgModels
|
||||
?.map((item) => `| 下一步指引-${item.name} | ${formatPrice(item.price, 1000)} |`)
|
||||
.join('\n')}
|
||||
`;
|
||||
console.log(global.priceMd);
|
||||
}
|
||||
|
@@ -2,8 +2,8 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { MongoUser } from '@fastgpt/support/user/schema';
|
||||
import { setCookie } from '@/service/utils/tools';
|
||||
import { generateToken } from '@fastgpt/support/user/tools';
|
||||
import { setCookie } from '@fastgpt/support/user/auth';
|
||||
import { generateToken } from '@fastgpt/support/user/auth';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { clearCookie } from '@/service/utils/tools';
|
||||
import { clearCookie } from '@fastgpt/support/user/auth';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
|
@@ -3,7 +3,8 @@ import { authApp } from '@/service/utils/auth';
|
||||
import { authUser } from '@fastgpt/support/user/auth';
|
||||
import { AuthUserTypeEnum } from '@fastgpt/support/user/auth';
|
||||
import { sseErrRes, jsonRes } from '@/service/response';
|
||||
import { addLog, withNextCors } from '@/service/utils/tools';
|
||||
import { addLog } from '@/service/utils/tools';
|
||||
import { withNextCors } from '@fastgpt/common/tools/nextjs';
|
||||
import { ChatRoleEnum, ChatSourceEnum, sseResponseEventEnum } from '@/constants/chat';
|
||||
import {
|
||||
dispatchHistory,
|
||||
@@ -21,7 +22,7 @@ import type { MessageItemType } from '@/types/core/chat/type';
|
||||
import { gptMessage2ChatType, textAdaptGptResponse } from '@/utils/adapt';
|
||||
import { getChatHistory } from './getHistory';
|
||||
import { saveChat } from '@/service/utils/chat/saveChat';
|
||||
import { sseResponse } from '@/service/utils/tools';
|
||||
import { responseWrite } from '@fastgpt/common/tools/stream';
|
||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||
import { FlowModuleTypeEnum, initModuleType } from '@/constants/flow';
|
||||
import { AppModuleItemType, RunningModuleItemType } from '@/types/app';
|
||||
@@ -217,7 +218,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
const feResponseData = isOwner ? responseData : selectShareResponse({ responseData });
|
||||
|
||||
if (stream) {
|
||||
sseResponse({
|
||||
responseWrite({
|
||||
res,
|
||||
event: detail ? sseResponseEventEnum.answer : undefined,
|
||||
data: textAdaptGptResponse({
|
||||
@@ -225,14 +226,14 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
finish_reason: 'stop'
|
||||
})
|
||||
});
|
||||
sseResponse({
|
||||
responseWrite({
|
||||
res,
|
||||
event: detail ? sseResponseEventEnum.answer : undefined,
|
||||
data: '[DONE]'
|
||||
});
|
||||
|
||||
if (responseDetail && detail) {
|
||||
sseResponse({
|
||||
responseWrite({
|
||||
res,
|
||||
event: sseResponseEventEnum.appStreamResponse,
|
||||
data: JSON.stringify(feResponseData)
|
||||
@@ -323,13 +324,16 @@ export async function dispatchModules({
|
||||
let chatAnswerText = ''; // AI answer
|
||||
let runningTime = Date.now();
|
||||
|
||||
function pushStore({
|
||||
answerText = '',
|
||||
responseData
|
||||
}: {
|
||||
answerText?: string;
|
||||
responseData?: ChatHistoryItemResType | ChatHistoryItemResType[];
|
||||
}) {
|
||||
function pushStore(
|
||||
{ inputs = [] }: RunningModuleItemType,
|
||||
{
|
||||
answerText = '',
|
||||
responseData
|
||||
}: {
|
||||
answerText?: string;
|
||||
responseData?: ChatHistoryItemResType | ChatHistoryItemResType[];
|
||||
}
|
||||
) {
|
||||
const time = Date.now();
|
||||
if (responseData) {
|
||||
if (Array.isArray(responseData)) {
|
||||
@@ -342,7 +346,12 @@ export async function dispatchModules({
|
||||
}
|
||||
}
|
||||
runningTime = time;
|
||||
chatAnswerText += answerText;
|
||||
|
||||
const isResponseAnswerText =
|
||||
inputs.find((item) => item.key === SystemInputEnum.isResponseAnswerText)?.value ?? true;
|
||||
if (isResponseAnswerText) {
|
||||
chatAnswerText += answerText;
|
||||
}
|
||||
}
|
||||
function moduleInput(
|
||||
module: RunningModuleItemType,
|
||||
@@ -376,7 +385,7 @@ export async function dispatchModules({
|
||||
module: RunningModuleItemType,
|
||||
result: Record<string, any> = {}
|
||||
): Promise<any> {
|
||||
pushStore(result);
|
||||
pushStore(module, result);
|
||||
return Promise.all(
|
||||
module.outputs.map((outputItem) => {
|
||||
if (result[outputItem.key] === undefined) return;
|
||||
@@ -505,7 +514,7 @@ export function responseStatus({
|
||||
name?: string;
|
||||
}) {
|
||||
if (!name) return;
|
||||
sseResponse({
|
||||
responseWrite({
|
||||
res,
|
||||
event: sseResponseEventEnum.moduleStatus,
|
||||
data: JSON.stringify({
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { EditFormType } from '@/utils/app';
|
||||
@@ -11,43 +11,65 @@ import {
|
||||
Link,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Switch,
|
||||
Textarea
|
||||
} from '@chakra-ui/react';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { defaultQuotePrompt, defaultQuoteTemplate } from '@/global/core/prompt/AIChat';
|
||||
import { feConfigs } from '@/web/common/store/static';
|
||||
import { Prompt_QuotePromptList, Prompt_QuoteTemplateList } from '@/global/core/prompt/AIChat';
|
||||
import { chatModelList, feConfigs } from '@/web/common/store/static';
|
||||
import MySlider from '@/components/Slider';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { PromptTemplateItem } from '@fastgpt/core/ai/type';
|
||||
|
||||
const PromptTemplate = dynamic(() => import('@/components/PromptTemplate'));
|
||||
|
||||
const AIChatSettingsModal = ({
|
||||
isAdEdit,
|
||||
onClose,
|
||||
onSuccess,
|
||||
defaultData
|
||||
}: {
|
||||
isAdEdit?: boolean;
|
||||
onClose: () => void;
|
||||
onSuccess: (e: EditFormType['chatModel']) => void;
|
||||
defaultData: EditFormType['chatModel'];
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const { register, handleSubmit } = useForm({
|
||||
const { register, handleSubmit, getValues, setValue } = useForm({
|
||||
defaultValues: defaultData
|
||||
});
|
||||
|
||||
const [selectTemplateData, setSelectTemplateData] = useState<{
|
||||
title: string;
|
||||
key: 'quoteTemplate' | 'quotePrompt';
|
||||
templates: PromptTemplateItem[];
|
||||
}>();
|
||||
|
||||
const tokenLimit = useMemo(() => {
|
||||
return chatModelList.find((item) => item.model === getValues('model'))?.maxToken || 4000;
|
||||
}, [getValues, refresh]);
|
||||
|
||||
const LabelStyles: BoxProps = {
|
||||
fontWeight: 'bold',
|
||||
mb: 1,
|
||||
fontSize: ['sm', 'md']
|
||||
};
|
||||
const selectTemplateBtn: BoxProps = {
|
||||
color: 'myBlue.600',
|
||||
cursor: 'pointer'
|
||||
};
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen
|
||||
title={
|
||||
<Flex alignItems={'flex-end'}>
|
||||
{t('app.Quote Prompt Settings')}
|
||||
{t('app.AI Settings')}
|
||||
{feConfigs?.show_doc && (
|
||||
<Link
|
||||
href={'https://doc.fastgpt.run/docs/use-cases/prompt/'}
|
||||
href={'https://doc.fastgpt.run/docs/use-cases/ai_settings/'}
|
||||
target={'_blank'}
|
||||
ml={1}
|
||||
textDecoration={'underline'}
|
||||
@@ -59,39 +81,134 @@ const AIChatSettingsModal = ({
|
||||
)}
|
||||
</Flex>
|
||||
}
|
||||
isCentered
|
||||
w={'700px'}
|
||||
h={['90vh', 'auto']}
|
||||
>
|
||||
<ModalBody>
|
||||
<ModalBody flex={['1 0 0', 'auto']} overflowY={'auto'}>
|
||||
{isAdEdit && (
|
||||
<Flex alignItems={'center'}>
|
||||
<Box {...LabelStyles} w={'80px'}>
|
||||
返回AI内容
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<Switch
|
||||
isChecked={getValues(SystemInputEnum.isResponseAnswerText)}
|
||||
size={'lg'}
|
||||
onChange={(e) => {
|
||||
const value = e.target.checked;
|
||||
setValue(SystemInputEnum.isResponseAnswerText, value);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
<Flex alignItems={'center'} mb={10} mt={isAdEdit ? 8 : 5}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
温度
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '严谨', value: 0 },
|
||||
{ label: '发散', value: 10 }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={0}
|
||||
max={10}
|
||||
value={getValues('temperature')}
|
||||
onChange={(e) => {
|
||||
setValue('temperature', e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} mt={12} mb={10}>
|
||||
<Box {...LabelStyles} mr={2} w={'80px'}>
|
||||
回复上限
|
||||
</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${tokenLimit}`, value: tokenLimit }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={getValues('maxToken')}
|
||||
onChange={(val) => {
|
||||
setValue('maxToken', val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Box>
|
||||
<Box {...LabelStyles}>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
引用内容模板
|
||||
<MyTooltip
|
||||
label={t('template.Quote Content Tip', { default: defaultQuoteTemplate })}
|
||||
label={t('template.Quote Content Tip', {
|
||||
default: Prompt_QuoteTemplateList[0].value
|
||||
})}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} />
|
||||
<Box
|
||||
{...selectTemplateBtn}
|
||||
onClick={() =>
|
||||
setSelectTemplateData({
|
||||
title: '选择引用内容模板',
|
||||
key: 'quoteTemplate',
|
||||
templates: Prompt_QuoteTemplateList
|
||||
})
|
||||
}
|
||||
>
|
||||
选择模板
|
||||
</Box>
|
||||
</Flex>
|
||||
<Textarea
|
||||
rows={4}
|
||||
placeholder={t('template.Quote Content Tip', { default: defaultQuoteTemplate }) || ''}
|
||||
rows={6}
|
||||
placeholder={
|
||||
t('template.Quote Content Tip', { default: Prompt_QuoteTemplateList[0].value }) || ''
|
||||
}
|
||||
borderColor={'myGray.100'}
|
||||
{...register('quoteTemplate')}
|
||||
/>
|
||||
</Box>
|
||||
<Box mt={4}>
|
||||
<Box {...LabelStyles}>
|
||||
<Flex {...LabelStyles} mb={1}>
|
||||
引用内容提示词
|
||||
<MyTooltip
|
||||
label={t('template.Quote Prompt Tip', { default: defaultQuotePrompt })}
|
||||
label={t('template.Quote Prompt Tip', { default: Prompt_QuotePromptList[0].value })}
|
||||
forceShow
|
||||
>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} />
|
||||
<Box
|
||||
{...selectTemplateBtn}
|
||||
onClick={() =>
|
||||
setSelectTemplateData({
|
||||
title: '选择引用提示词模板',
|
||||
key: 'quotePrompt',
|
||||
templates: Prompt_QuotePromptList
|
||||
})
|
||||
}
|
||||
>
|
||||
选择模板
|
||||
</Box>
|
||||
</Flex>
|
||||
<Textarea
|
||||
rows={6}
|
||||
placeholder={t('template.Quote Prompt Tip', { default: defaultQuotePrompt }) || ''}
|
||||
rows={11}
|
||||
placeholder={
|
||||
t('template.Quote Prompt Tip', { default: Prompt_QuotePromptList[0].value }) || ''
|
||||
}
|
||||
borderColor={'myGray.100'}
|
||||
{...register('quotePrompt')}
|
||||
/>
|
||||
@@ -105,6 +222,14 @@ const AIChatSettingsModal = ({
|
||||
{t('Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
{!!selectTemplateData && (
|
||||
<PromptTemplate
|
||||
title={selectTemplateData.title}
|
||||
templates={selectTemplateData.templates}
|
||||
onClose={() => setSelectTemplateData(undefined)}
|
||||
onSuccess={(e) => setValue(selectTemplateData.key, e)}
|
||||
/>
|
||||
)}
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
@@ -0,0 +1,229 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react';
|
||||
import { SmallCloseIcon } from '@chakra-ui/icons';
|
||||
import { FlowInputItemTypeEnum } from '@/constants/flow';
|
||||
import { FlowOutputTargetItemType } from '@/types/core/app/flow';
|
||||
import { AppModuleItemType } from '@/types/app';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import type { AppSchema } from '@/types/mongoSchema';
|
||||
import { useUserStore } from '@/web/support/store/user';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import { AppTypeEnum } from '@/constants/app';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import ChatTest, { type ChatTestComponentRef } from './ChatTest';
|
||||
import { useFlowStore } from './Provider';
|
||||
|
||||
const ImportSettings = dynamic(() => import('./ImportSettings'));
|
||||
|
||||
type Props = { app: AppSchema; onCloseSettings: () => void };
|
||||
|
||||
const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
app,
|
||||
ChatTestRef,
|
||||
testModules,
|
||||
setTestModules,
|
||||
onCloseSettings
|
||||
}: Props & {
|
||||
ChatTestRef: React.RefObject<ChatTestComponentRef>;
|
||||
testModules?: AppModuleItemType[];
|
||||
setTestModules: React.Dispatch<AppModuleItemType[] | undefined>;
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { copyData } = useCopyData();
|
||||
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
||||
const { updateAppDetail } = useUserStore();
|
||||
|
||||
const { nodes, edges, onFixView } = useFlowStore();
|
||||
|
||||
const flow2AppModules = useCallback(() => {
|
||||
const modules: AppModuleItemType[] = nodes.map((item) => ({
|
||||
moduleId: item.data.moduleId,
|
||||
name: item.data.name,
|
||||
flowType: item.data.flowType,
|
||||
showStatus: item.data.showStatus,
|
||||
position: item.position,
|
||||
inputs: item.data.inputs.map((item) => ({
|
||||
...item,
|
||||
connected: item.connected ?? item.type !== FlowInputItemTypeEnum.target
|
||||
})),
|
||||
outputs: item.data.outputs.map((item) => ({
|
||||
...item,
|
||||
targets: [] as FlowOutputTargetItemType[]
|
||||
}))
|
||||
}));
|
||||
|
||||
// update inputs and outputs
|
||||
modules.forEach((module) => {
|
||||
module.inputs.forEach((input) => {
|
||||
input.connected =
|
||||
input.connected ||
|
||||
!!edges.find(
|
||||
(edge) => edge.target === module.moduleId && edge.targetHandle === input.key
|
||||
);
|
||||
});
|
||||
module.outputs.forEach((output) => {
|
||||
output.targets = edges
|
||||
.filter(
|
||||
(edge) =>
|
||||
edge.source === module.moduleId &&
|
||||
edge.sourceHandle === output.key &&
|
||||
edge.targetHandle
|
||||
)
|
||||
.map((edge) => ({
|
||||
moduleId: edge.target,
|
||||
key: edge.targetHandle || ''
|
||||
}));
|
||||
});
|
||||
});
|
||||
return modules;
|
||||
}, [edges, nodes]);
|
||||
|
||||
const { mutate: onclickSave, isLoading } = useRequest({
|
||||
mutationFn: () => {
|
||||
const modules = flow2AppModules();
|
||||
// check required connect
|
||||
for (let i = 0; i < modules.length; i++) {
|
||||
const item = modules[i];
|
||||
if (item.inputs.find((input) => input.required && !input.connected)) {
|
||||
return Promise.reject(`【${item.name}】存在未连接的必填输入`);
|
||||
}
|
||||
if (item.inputs.find((input) => input.valueCheck && !input.valueCheck(input.value))) {
|
||||
return Promise.reject(`【${item.name}】存在为填写的必填项`);
|
||||
}
|
||||
}
|
||||
|
||||
return updateAppDetail(app._id, {
|
||||
modules: modules,
|
||||
type: AppTypeEnum.advanced
|
||||
});
|
||||
},
|
||||
successToast: '保存配置成功',
|
||||
errorToast: '保存配置异常',
|
||||
onSuccess() {
|
||||
ChatTestRef.current?.resetChatTest();
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
py={3}
|
||||
px={[2, 5, 8]}
|
||||
borderBottom={theme.borders.base}
|
||||
alignItems={'center'}
|
||||
userSelect={'none'}
|
||||
>
|
||||
<MyTooltip label={'返回'} offset={[10, 10]}>
|
||||
<IconButton
|
||||
size={'sm'}
|
||||
icon={<MyIcon name={'back'} w={'14px'} />}
|
||||
borderRadius={'md'}
|
||||
borderColor={'myGray.300'}
|
||||
variant={'base'}
|
||||
aria-label={''}
|
||||
onClick={() => {
|
||||
onCloseSettings();
|
||||
onFixView();
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<Box ml={[3, 6]} fontSize={['md', '2xl']} flex={1}>
|
||||
{app.name}
|
||||
</Box>
|
||||
|
||||
<MyTooltip label={t('app.Import Configs')}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'importLight'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
variant={'base'}
|
||||
aria-label={'save'}
|
||||
onClick={onOpenImport}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<MyTooltip label={t('app.Export Configs')}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'export'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
variant={'base'}
|
||||
aria-label={'save'}
|
||||
onClick={() =>
|
||||
copyData(
|
||||
JSON.stringify(flow2AppModules(), null, 2),
|
||||
t('app.Export Config Successful')
|
||||
)
|
||||
}
|
||||
/>
|
||||
</MyTooltip>
|
||||
|
||||
{testModules ? (
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<SmallCloseIcon fontSize={'25px'} />}
|
||||
variant={'base'}
|
||||
color={'myGray.600'}
|
||||
borderRadius={'lg'}
|
||||
aria-label={''}
|
||||
onClick={() => setTestModules(undefined)}
|
||||
/>
|
||||
) : (
|
||||
<MyTooltip label={'测试对话'}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'chat'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
aria-label={'save'}
|
||||
variant={'base'}
|
||||
onClick={() => {
|
||||
setTestModules(flow2AppModules());
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
)}
|
||||
|
||||
<MyTooltip label={'保存配置'}>
|
||||
<IconButton
|
||||
icon={<MyIcon name={'save'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
isLoading={isLoading}
|
||||
aria-label={'save'}
|
||||
onClick={onclickSave}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
const Header = (props: Props) => {
|
||||
const { app } = props;
|
||||
const ChatTestRef = useRef<ChatTestComponentRef>(null);
|
||||
|
||||
const [testModules, setTestModules] = useState<AppModuleItemType[]>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<RenderHeaderContainer
|
||||
{...props}
|
||||
ChatTestRef={ChatTestRef}
|
||||
testModules={testModules}
|
||||
setTestModules={setTestModules}
|
||||
/>
|
||||
<ChatTest
|
||||
ref={ChatTestRef}
|
||||
modules={testModules}
|
||||
app={app}
|
||||
onClose={() => setTestModules(undefined)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Header);
|
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
@@ -7,11 +7,8 @@ import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
|
||||
import { useFlowStore } from '../Provider';
|
||||
|
||||
const NodeChat = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} {...data}>
|
||||
|
@@ -5,14 +5,11 @@ import {
|
||||
type EdgeChange,
|
||||
useNodesState,
|
||||
useEdgesState,
|
||||
XYPosition,
|
||||
useViewport,
|
||||
Connection,
|
||||
addEdge
|
||||
} from 'reactflow';
|
||||
import type {
|
||||
FlowModuleItemType,
|
||||
FlowModuleTemplateType,
|
||||
FlowOutputTargetItemType,
|
||||
FlowModuleItemChangeProps
|
||||
} from '@/types/core/app/flow';
|
||||
@@ -44,7 +41,6 @@ export type useFlowStoreType = {
|
||||
setEdges: Dispatch<SetStateAction<Edge<any>[]>>;
|
||||
onEdgesChange: OnChange<EdgeChange>;
|
||||
onFixView: () => void;
|
||||
onAddNode: (e: { template: FlowModuleTemplateType; position: XYPosition }) => void;
|
||||
onDelNode: (nodeId: string) => void;
|
||||
onChangeNode: (e: FlowModuleItemChangeProps) => void;
|
||||
onCopyNode: (nodeId: string) => void;
|
||||
@@ -80,9 +76,7 @@ const StateContext = createContext<useFlowStoreType>({
|
||||
onFixView: function (): void {
|
||||
return;
|
||||
},
|
||||
onAddNode: function (e: { template: FlowModuleTemplateType; position: XYPosition }): void {
|
||||
return;
|
||||
},
|
||||
|
||||
onDelNode: function (nodeId: string): void {
|
||||
return;
|
||||
},
|
||||
@@ -117,7 +111,6 @@ export const FlowProvider = ({ appId, children }: { appId: string; children: Rea
|
||||
const { toast } = useToast();
|
||||
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowModuleItemType>([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const { x, y, zoom } = useViewport();
|
||||
|
||||
const onFixView = useCallback(() => {
|
||||
const btn = document.querySelector('.react-flow__controls-fitview') as HTMLButtonElement;
|
||||
@@ -205,27 +198,6 @@ export const FlowProvider = ({ appId, children }: { appId: string; children: Rea
|
||||
[nodes, onDelConnect, setEdges, t, toast]
|
||||
);
|
||||
|
||||
const onAddNode = useCallback(
|
||||
({ template, position }: { template: FlowModuleTemplateType; position: XYPosition }) => {
|
||||
if (!reactFlowWrapper.current) return;
|
||||
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||
const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100;
|
||||
const mouseY = (position.y - reactFlowBounds.top - y) / zoom;
|
||||
setNodes((state) =>
|
||||
state.concat(
|
||||
appModule2FlowNode({
|
||||
item: {
|
||||
...template,
|
||||
moduleId: nanoid(),
|
||||
position: { x: mouseX, y: mouseY }
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
[setNodes, x, y, zoom]
|
||||
);
|
||||
|
||||
const onDelNode = useCallback(
|
||||
(nodeId: string) => {
|
||||
setNodes((state) => state.filter((item) => item.id !== nodeId));
|
||||
@@ -338,7 +310,6 @@ export const FlowProvider = ({ appId, children }: { appId: string; children: Rea
|
||||
setEdges,
|
||||
onEdgesChange,
|
||||
onFixView,
|
||||
onAddNode,
|
||||
onDelNode,
|
||||
onChangeNode,
|
||||
onCopyNode,
|
||||
|
@@ -1,24 +1,20 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { ModuleTemplates } from '@/constants/flow/ModuleTemplate';
|
||||
import { FlowModuleItemType, FlowModuleTemplateType } from '@/types/core/app/flow';
|
||||
import type { Node } from 'reactflow';
|
||||
import { FlowModuleTemplateType } from '@/types/core/app/flow';
|
||||
import { useViewport, XYPosition } from 'reactflow';
|
||||
import { useGlobalStore } from '@/web/common/store/global';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||
import { useFlowStore } from './Provider';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { appModule2FlowNode } from '@/utils/adapt';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
|
||||
const ModuleTemplateList = ({
|
||||
nodes,
|
||||
isOpen,
|
||||
onClose
|
||||
}: {
|
||||
nodes?: Node<FlowModuleItemType>[];
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { onAddNode } = useFlowStore();
|
||||
const ModuleTemplateList = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) => {
|
||||
const { nodes, setNodes, reactFlowWrapper } = useFlowStore();
|
||||
const { isPc } = useGlobalStore();
|
||||
const { x, y, zoom } = useViewport();
|
||||
|
||||
const filterTemplates = useMemo(() => {
|
||||
const guideModulesIndex = ModuleTemplates.findIndex((item) => item.label === '引导模块');
|
||||
@@ -47,6 +43,28 @@ const ModuleTemplateList = ({
|
||||
];
|
||||
}, [nodes]);
|
||||
|
||||
const onAddNode = useCallback(
|
||||
({ template, position }: { template: FlowModuleTemplateType; position: XYPosition }) => {
|
||||
if (!reactFlowWrapper?.current) return;
|
||||
|
||||
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||
const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100;
|
||||
const mouseY = (position.y - reactFlowBounds.top - y) / zoom;
|
||||
setNodes((state) =>
|
||||
state.concat(
|
||||
appModule2FlowNode({
|
||||
item: {
|
||||
...template,
|
||||
moduleId: nanoid(),
|
||||
position: { x: mouseX, y: mouseY }
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
[reactFlowWrapper, setNodes, x, y, zoom]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
|
@@ -32,6 +32,7 @@ import { formatPrice } from '@fastgpt/common/bill';
|
||||
import { useDatasetStore } from '@/web/core/store/dataset';
|
||||
import { SelectedDatasetType } from '@/types/core/dataset';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { LLMModelItemType } from '@/types/model';
|
||||
|
||||
const SetInputFieldModal = dynamic(() => import('../modules/SetInputFieldModal'));
|
||||
const SelectAppModal = dynamic(() => import('../../../SelectAppModal'));
|
||||
@@ -186,8 +187,8 @@ const RenderInput = ({
|
||||
{item.type === FlowInputItemTypeEnum.selectApp && (
|
||||
<SelectAppRender item={item} moduleId={moduleId} />
|
||||
)}
|
||||
{item.type === FlowInputItemTypeEnum.quoteList && (
|
||||
<QuoteListRender inputs={sortInputs} item={item} moduleId={moduleId} />
|
||||
{item.type === FlowInputItemTypeEnum.aiSettings && (
|
||||
<AISetting inputs={sortInputs} item={item} moduleId={moduleId} />
|
||||
)}
|
||||
{item.type === FlowInputItemTypeEnum.maxToken && (
|
||||
<MaxTokenRender inputs={sortInputs} item={item} moduleId={moduleId} />
|
||||
@@ -343,7 +344,7 @@ var SliderRender = React.memo(function SliderRender({ item, moduleId }: RenderPr
|
||||
);
|
||||
});
|
||||
|
||||
var QuoteListRender = React.memo(function QuoteListRender({ inputs = [], moduleId }: RenderProps) {
|
||||
var AISetting = React.memo(function AISetting({ inputs = [], moduleId }: RenderProps) {
|
||||
const { onChangeNode } = useFlowStore();
|
||||
const { t } = useTranslation();
|
||||
const chatModulesData = useMemo(() => {
|
||||
@@ -367,10 +368,11 @@ var QuoteListRender = React.memo(function QuoteListRender({ inputs = [], moduleI
|
||||
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
|
||||
onClick={onOpenAIChatSetting}
|
||||
>
|
||||
{t('app.Quote Prompt Settings')}
|
||||
{t('app.AI Settings')}
|
||||
</Button>
|
||||
{isOpenAIChatSetting && (
|
||||
<AIChatSettingsModal
|
||||
isAdEdit
|
||||
onClose={onCloseAIChatSetting}
|
||||
onSuccess={(e) => {
|
||||
for (let key in e) {
|
||||
@@ -404,7 +406,7 @@ var MaxTokenRender = React.memo(function MaxTokenRender({
|
||||
const { onChangeNode } = useFlowStore();
|
||||
const model = inputs.find((item) => item.key === 'model')?.value;
|
||||
const modelData = chatModelList.find((item) => item.model === model);
|
||||
const maxToken = modelData ? modelData.contextMaxToken : 4000;
|
||||
const maxToken = modelData ? modelData.maxToken : 4000;
|
||||
const markList = [
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${maxToken}`, value: maxToken }
|
||||
@@ -441,8 +443,42 @@ var SelectChatModelRender = React.memo(function SelectChatModelRender({
|
||||
moduleId
|
||||
}: RenderProps) {
|
||||
const { onChangeNode } = useFlowStore();
|
||||
const modelList = (item.customData?.() as LLMModelItemType[]) || chatModelList || [];
|
||||
|
||||
const list = chatModelList.map((item) => {
|
||||
function onChangeModel(e: string) {
|
||||
{
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
|
||||
// update max tokens
|
||||
const model = modelList.find((item) => item.model === e) || modelList[0];
|
||||
if (!model) return;
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
key: 'maxToken',
|
||||
value: {
|
||||
...inputs.find((input) => input.key === 'maxToken'),
|
||||
markList: [
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${model.maxToken}`, value: model.maxToken }
|
||||
],
|
||||
max: model.maxToken,
|
||||
value: model.maxToken / 2
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const list = modelList.map((item) => {
|
||||
const priceStr = `(${formatPrice(item.price, 1000)}元/1k Tokens)`;
|
||||
|
||||
return {
|
||||
@@ -451,43 +487,11 @@ var SelectChatModelRender = React.memo(function SelectChatModelRender({
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<MySelect
|
||||
width={'100%'}
|
||||
value={item.value}
|
||||
list={list}
|
||||
onchange={(e) => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
if (!item.value && list.length > 0) {
|
||||
onChangeModel(list[0].value);
|
||||
}
|
||||
|
||||
// update max tokens
|
||||
const model = chatModelList.find((item) => item.model === e) || chatModelList[0];
|
||||
if (!model) return;
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
key: 'maxToken',
|
||||
value: {
|
||||
...inputs.find((input) => input.key === 'maxToken'),
|
||||
markList: [
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${model.contextMaxToken}`, value: model.contextMaxToken }
|
||||
],
|
||||
max: model.contextMaxToken,
|
||||
value: model.contextMaxToken / 2
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return <MySelect width={'100%'} value={item.value} list={list} onchange={onChangeModel} />;
|
||||
});
|
||||
|
||||
var SelectDatasetRender = React.memo(function SelectDatasetRender({ item, moduleId }: RenderProps) {
|
||||
|
@@ -25,6 +25,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import TemplateList from './components/TemplateList';
|
||||
import ChatTest, { type ChatTestComponentRef } from './components/ChatTest';
|
||||
import FlowProvider, { useFlowStore } from './components/Provider';
|
||||
import Header from './components/Header';
|
||||
|
||||
const ImportSettings = dynamic(() => import('./components/ImportSettings'));
|
||||
const NodeChat = dynamic(() => import('./components/Nodes/NodeChat'));
|
||||
@@ -62,187 +63,7 @@ const edgeTypes = {
|
||||
};
|
||||
type Props = { app: AppSchema; onCloseSettings: () => void };
|
||||
|
||||
function FlowHeader({ app, onCloseSettings }: Props & {}) {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { copyData } = useCopyData();
|
||||
const ChatTestRef = useRef<ChatTestComponentRef>(null);
|
||||
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
||||
const { updateAppDetail } = useUserStore();
|
||||
const { nodes, edges, onFixView } = useFlowStore();
|
||||
|
||||
const [testModules, setTestModules] = useState<AppModuleItemType[]>();
|
||||
|
||||
const flow2AppModules = useCallback(() => {
|
||||
const modules: AppModuleItemType[] = nodes.map((item) => ({
|
||||
moduleId: item.data.moduleId,
|
||||
name: item.data.name,
|
||||
flowType: item.data.flowType,
|
||||
showStatus: item.data.showStatus,
|
||||
position: item.position,
|
||||
inputs: item.data.inputs.map((item) => ({
|
||||
...item,
|
||||
connected: item.connected ?? item.type !== FlowInputItemTypeEnum.target
|
||||
})),
|
||||
outputs: item.data.outputs.map((item) => ({
|
||||
...item,
|
||||
targets: [] as FlowOutputTargetItemType[]
|
||||
}))
|
||||
}));
|
||||
|
||||
// update inputs and outputs
|
||||
modules.forEach((module) => {
|
||||
module.inputs.forEach((input) => {
|
||||
input.connected =
|
||||
input.connected ||
|
||||
!!edges.find(
|
||||
(edge) => edge.target === module.moduleId && edge.targetHandle === input.key
|
||||
);
|
||||
});
|
||||
module.outputs.forEach((output) => {
|
||||
output.targets = edges
|
||||
.filter(
|
||||
(edge) =>
|
||||
edge.source === module.moduleId &&
|
||||
edge.sourceHandle === output.key &&
|
||||
edge.targetHandle
|
||||
)
|
||||
.map((edge) => ({
|
||||
moduleId: edge.target,
|
||||
key: edge.targetHandle || ''
|
||||
}));
|
||||
});
|
||||
});
|
||||
return modules;
|
||||
}, [edges, nodes]);
|
||||
|
||||
const { mutate: onclickSave, isLoading } = useRequest({
|
||||
mutationFn: () => {
|
||||
const modules = flow2AppModules();
|
||||
// check required connect
|
||||
for (let i = 0; i < modules.length; i++) {
|
||||
const item = modules[i];
|
||||
if (item.inputs.find((input) => input.required && !input.connected)) {
|
||||
return Promise.reject(`【${item.name}】存在未连接的必填输入`);
|
||||
}
|
||||
if (item.inputs.find((input) => input.valueCheck && !input.valueCheck(input.value))) {
|
||||
return Promise.reject(`【${item.name}】存在为填写的必填项`);
|
||||
}
|
||||
}
|
||||
|
||||
return updateAppDetail(app._id, {
|
||||
modules: modules,
|
||||
type: AppTypeEnum.advanced
|
||||
});
|
||||
},
|
||||
successToast: '保存配置成功',
|
||||
errorToast: '保存配置异常',
|
||||
onSuccess() {
|
||||
ChatTestRef.current?.resetChatTest();
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
py={3}
|
||||
px={[2, 5, 8]}
|
||||
borderBottom={theme.borders.base}
|
||||
alignItems={'center'}
|
||||
userSelect={'none'}
|
||||
>
|
||||
<MyTooltip label={'返回'} offset={[10, 10]}>
|
||||
<IconButton
|
||||
size={'sm'}
|
||||
icon={<MyIcon name={'back'} w={'14px'} />}
|
||||
borderRadius={'md'}
|
||||
borderColor={'myGray.300'}
|
||||
variant={'base'}
|
||||
aria-label={''}
|
||||
onClick={() => {
|
||||
onCloseSettings();
|
||||
onFixView();
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<Box ml={[3, 6]} fontSize={['md', '2xl']} flex={1}>
|
||||
{app.name}
|
||||
</Box>
|
||||
|
||||
<MyTooltip label={t('app.Import Configs')}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'importLight'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
variant={'base'}
|
||||
aria-label={'save'}
|
||||
onClick={onOpenImport}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<MyTooltip label={t('app.Export Configs')}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'export'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
variant={'base'}
|
||||
aria-label={'save'}
|
||||
onClick={() =>
|
||||
copyData(
|
||||
JSON.stringify(flow2AppModules(), null, 2),
|
||||
t('app.Export Config Successful')
|
||||
)
|
||||
}
|
||||
/>
|
||||
</MyTooltip>
|
||||
|
||||
{testModules ? (
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<SmallCloseIcon fontSize={'25px'} />}
|
||||
variant={'base'}
|
||||
color={'myGray.600'}
|
||||
borderRadius={'lg'}
|
||||
aria-label={''}
|
||||
onClick={() => setTestModules(undefined)}
|
||||
/>
|
||||
) : (
|
||||
<MyTooltip label={'测试对话'}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'chat'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
aria-label={'save'}
|
||||
variant={'base'}
|
||||
onClick={() => {
|
||||
setTestModules(flow2AppModules());
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
)}
|
||||
|
||||
<MyTooltip label={'保存配置'}>
|
||||
<IconButton
|
||||
icon={<MyIcon name={'save'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
isLoading={isLoading}
|
||||
aria-label={'save'}
|
||||
onClick={onclickSave}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
||||
<ChatTest
|
||||
ref={ChatTestRef}
|
||||
modules={testModules}
|
||||
app={app}
|
||||
onClose={() => setTestModules(undefined)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
const Header = React.memo(FlowHeader);
|
||||
|
||||
const AppEdit = (props: Props) => {
|
||||
const AppEdit = React.memo(function AppEdit(props: Props) {
|
||||
const { app } = props;
|
||||
|
||||
const {
|
||||
@@ -261,7 +82,7 @@ const AppEdit = (props: Props) => {
|
||||
return (
|
||||
<>
|
||||
{/* header */}
|
||||
<Header {...props} />
|
||||
<Header app={app} onCloseSettings={props.onCloseSettings} />
|
||||
<Box
|
||||
minH={'400px'}
|
||||
flex={'1 0 0'}
|
||||
@@ -318,11 +139,11 @@ const AppEdit = (props: Props) => {
|
||||
<Controls position={'bottom-right'} style={{ display: 'flex' }} showInteractive={false} />
|
||||
</ReactFlow>
|
||||
|
||||
<TemplateList isOpen={isOpenTemplate} nodes={nodes} onClose={onCloseTemplate} />
|
||||
<TemplateList isOpen={isOpenTemplate} onClose={onCloseTemplate} />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
const Flow = (data: Props) => {
|
||||
return (
|
||||
|
@@ -34,7 +34,6 @@ import { chatModelList } from '@/web/common/store/static';
|
||||
import { formatPrice } from '@fastgpt/common/bill/index';
|
||||
import {
|
||||
ChatModelSystemTip,
|
||||
ChatModelLimitTip,
|
||||
welcomeTextTip,
|
||||
questionGuideTip
|
||||
} from '@/constants/flow/ModuleTemplate';
|
||||
@@ -128,12 +127,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
label: `${item.name} (${formatPrice(item.price, 1000)} 元/1k tokens)`
|
||||
}));
|
||||
}, [refresh]);
|
||||
const tokenLimit = useMemo(() => {
|
||||
return (
|
||||
chatModelList.find((item) => item.model === getValues('chatModel.model'))?.contextMaxToken ||
|
||||
4000
|
||||
);
|
||||
}, [getValues, refresh]);
|
||||
|
||||
const selectedKbList = useMemo(
|
||||
() => allDatasets.filter((item) => kbList.find((kb) => kb.kbId === item._id)),
|
||||
[allDatasets, kbList]
|
||||
@@ -411,6 +405,10 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
<Box ml={2} flex={1}>
|
||||
AI 配置
|
||||
</Box>
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
|
||||
<MyIcon mr={1} name={'settingLight'} w={'14px'} />
|
||||
高级配置
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Flex alignItems={'center'} mt={5}>
|
||||
@@ -424,7 +422,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
setValue('chatModel.model', val);
|
||||
const maxToken =
|
||||
chatModelList.find((item) => item.model === getValues('chatModel.model'))
|
||||
?.contextMaxToken || 4000;
|
||||
?.maxToken || 4000;
|
||||
const token = maxToken / 2;
|
||||
setValue('chatModel.maxToken', token);
|
||||
setRefresh(!refresh);
|
||||
@@ -432,45 +430,6 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} my={10}>
|
||||
<Box {...LabelStyles}>温度</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '严谨', value: 0 },
|
||||
{ label: '发散', value: 10 }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={0}
|
||||
max={10}
|
||||
value={getValues('chatModel.temperature')}
|
||||
onChange={(e) => {
|
||||
setValue('chatModel.temperature', e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} mt={12} mb={10}>
|
||||
<Box {...LabelStyles}>回复上限</Box>
|
||||
<Box flex={1} ml={'10px'}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: `${tokenLimit}`, value: tokenLimit }
|
||||
]}
|
||||
width={'95%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={getValues('chatModel.maxToken')}
|
||||
onChange={(val) => {
|
||||
setValue('chatModel.maxToken', val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex mt={10} alignItems={'flex-start'}>
|
||||
<Box {...LabelStyles}>
|
||||
提示词
|
||||
@@ -502,10 +461,6 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
<MyIcon name={'edit'} w={'14px'} mr={1} />
|
||||
参数
|
||||
</Flex>
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
|
||||
<MyIcon mr={1} name={'settingLight'} w={'14px'} />
|
||||
提示词
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex mt={1} color={'myGray.600'} fontSize={['sm', 'md']}>
|
||||
相似度: {getValues('kb.searchSimilarity')}, 单次搜索数量: {getValues('kb.searchLimit')},
|
||||
|
@@ -6,7 +6,7 @@ import { useMutation } from '@tanstack/react-query';
|
||||
import { splitText2Chunks } from '@/utils/file';
|
||||
import { getErrText } from '@/utils/tools';
|
||||
import { formatPrice } from '@fastgpt/common/bill/index';
|
||||
import { qaModel } from '@/web/common/store/static';
|
||||
import { qaModelList } from '@/web/common/store/static';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import CloseIcon from '@/components/Icon/close';
|
||||
import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
|
||||
@@ -23,8 +23,9 @@ import { chunksUpload } from '@/web/core/utils/dataset';
|
||||
const fileExtension = '.txt, .doc, .docx, .pdf, .md';
|
||||
|
||||
const QAImport = ({ kbId }: { kbId: string }) => {
|
||||
const unitPrice = qaModel.price || 3;
|
||||
const chunkLen = qaModel.maxToken * 0.45;
|
||||
const qaModel = qaModelList[0];
|
||||
const unitPrice = qaModel?.price || 3;
|
||||
const chunkLen = qaModel?.maxToken * 0.45;
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
@@ -13,9 +13,9 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { postCreateDataset } from '@/web/core/api/dataset';
|
||||
import type { CreateDatasetParams } from '@/global/core/api/datasetReq.d';
|
||||
import { vectorModelList } from '@/web/common/store/static';
|
||||
import MySelect from '@/components/Select';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { vectorModelList } from '@/web/common/store/static';
|
||||
import Tag from '@/components/Tag';
|
||||
|
||||
const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: string }) => {
|
||||
|
Reference in New Issue
Block a user