mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 02:12:38 +00:00
v4.6.5 (#620)
This commit is contained in:
@@ -288,7 +288,7 @@ async function initPgData() {
|
||||
const limit = 10;
|
||||
// add column
|
||||
try {
|
||||
await Promise.all([
|
||||
await Promise.allSettled([
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN team_id VARCHAR(50);`),
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN tmb_id VARCHAR(50);`),
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN user_id DROP NOT NULL;`)
|
||||
|
@@ -2,79 +2,15 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import { uploadFile } from '@fastgpt/service/common/file/gridfs/controller';
|
||||
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||
|
||||
const nanoid = customAlphabet('1234567890abcdef', 12);
|
||||
|
||||
type FileType = {
|
||||
fieldname: string;
|
||||
originalname: string;
|
||||
encoding: string;
|
||||
mimetype: string;
|
||||
filename: string;
|
||||
path: string;
|
||||
size: number;
|
||||
};
|
||||
import { getUploadModel } from '@fastgpt/service/common/file/upload/multer';
|
||||
|
||||
/**
|
||||
* Creates the multer uploader
|
||||
*/
|
||||
const maxSize = 500 * 1024 * 1024;
|
||||
class UploadModel {
|
||||
uploader = multer({
|
||||
limits: {
|
||||
fieldSize: maxSize
|
||||
},
|
||||
preservePath: true,
|
||||
storage: multer.diskStorage({
|
||||
filename: (_req, file, cb) => {
|
||||
const { ext } = path.parse(decodeURIComponent(file.originalname));
|
||||
cb(null, nanoid() + ext);
|
||||
}
|
||||
})
|
||||
}).any();
|
||||
|
||||
async doUpload(req: NextApiRequest, res: NextApiResponse) {
|
||||
return new Promise<{
|
||||
files: FileType[];
|
||||
bucketName: `${BucketNameEnum}`;
|
||||
metadata: Record<string, any>;
|
||||
}>((resolve, reject) => {
|
||||
// @ts-ignore
|
||||
this.uploader(req, res, (error) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
resolve({
|
||||
...req.body,
|
||||
files:
|
||||
// @ts-ignore
|
||||
req.files?.map((file) => ({
|
||||
...file,
|
||||
originalname: decodeURIComponent(file.originalname)
|
||||
})) || [],
|
||||
metadata: (() => {
|
||||
if (!req.body?.metadata) return {};
|
||||
try {
|
||||
return JSON.parse(req.body.metadata);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
return {};
|
||||
}
|
||||
})()
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const upload = new UploadModel();
|
||||
const upload = getUploadModel({
|
||||
maxSize: 500 * 1024 * 1024
|
||||
});
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -82,6 +18,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
const { userId, teamId, tmbId } = await authCert({ req, authToken: true });
|
||||
const { files, bucketName, metadata } = await upload.doUpload(req, res);
|
||||
|
||||
if (!bucketName) {
|
||||
throw new Error('bucketName is empty');
|
||||
}
|
||||
|
||||
const upLoadResults = await Promise.all(
|
||||
files.map((file) =>
|
||||
uploadFile({
|
||||
|
@@ -4,7 +4,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { UrlFetchParams, UrlFetchResponse } from '@fastgpt/global/common/file/api.d';
|
||||
import { urlsFetch } from '@fastgpt/global/common/file/tools';
|
||||
import { urlsFetch } from '@fastgpt/service/common/string/cheerio';
|
||||
|
||||
const fetchContent = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
try {
|
||||
|
@@ -53,7 +53,7 @@ function simpleChatTemplate({
|
||||
key: 'userChatInput',
|
||||
type: 'systemInput',
|
||||
label: '用户问题',
|
||||
connected: true
|
||||
connected: false
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
@@ -95,7 +95,7 @@ function simpleChatTemplate({
|
||||
label: '对话模型',
|
||||
required: true,
|
||||
value: formData.aiSettings.model,
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'temperature',
|
||||
@@ -115,7 +115,7 @@ function simpleChatTemplate({
|
||||
value: 10
|
||||
}
|
||||
],
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'maxToken',
|
||||
@@ -135,7 +135,7 @@ function simpleChatTemplate({
|
||||
value: 4000
|
||||
}
|
||||
],
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'isResponseAnswerText',
|
||||
@@ -143,21 +143,21 @@ function simpleChatTemplate({
|
||||
label: '返回AI内容',
|
||||
valueType: 'boolean',
|
||||
value: true,
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quoteTemplate',
|
||||
type: 'hidden',
|
||||
label: '引用内容模板',
|
||||
valueType: 'string',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quotePrompt',
|
||||
type: 'hidden',
|
||||
label: '引用内容提示词',
|
||||
valueType: 'string',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'aiSettings',
|
||||
@@ -176,7 +176,7 @@ function simpleChatTemplate({
|
||||
placeholder:
|
||||
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}',
|
||||
value: formData.aiSettings.systemPrompt,
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quoteQA',
|
||||
@@ -191,7 +191,7 @@ function simpleChatTemplate({
|
||||
type: 'target',
|
||||
label: 'core.module.input.label.chat history',
|
||||
valueType: 'chatHistory',
|
||||
connected: true,
|
||||
connected: false,
|
||||
value: 8
|
||||
},
|
||||
{
|
||||
@@ -292,21 +292,21 @@ function datasetTemplate({
|
||||
value: formData.dataset.datasets,
|
||||
type: FlowNodeInputTypeEnum.custom,
|
||||
label: '关联的知识库',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'similarity',
|
||||
value: 0.1,
|
||||
type: FlowNodeInputTypeEnum.slider,
|
||||
label: '相关度',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'limit',
|
||||
value: 2000,
|
||||
type: FlowNodeInputTypeEnum.slider,
|
||||
label: '单次搜索上限',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'switch',
|
||||
@@ -403,7 +403,7 @@ function datasetTemplate({
|
||||
label: '对话模型',
|
||||
required: true,
|
||||
value: formData.aiSettings.model,
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'temperature',
|
||||
@@ -423,7 +423,7 @@ function datasetTemplate({
|
||||
value: 10
|
||||
}
|
||||
],
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'maxToken',
|
||||
@@ -443,7 +443,7 @@ function datasetTemplate({
|
||||
value: 4000
|
||||
}
|
||||
],
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'isResponseAnswerText',
|
||||
@@ -451,21 +451,21 @@ function datasetTemplate({
|
||||
label: '返回AI内容',
|
||||
valueType: 'boolean',
|
||||
value: true,
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quoteTemplate',
|
||||
type: 'hidden',
|
||||
label: '引用内容模板',
|
||||
valueType: 'string',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quotePrompt',
|
||||
type: 'hidden',
|
||||
label: '引用内容提示词',
|
||||
valueType: 'string',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'aiSettings',
|
||||
@@ -484,7 +484,7 @@ function datasetTemplate({
|
||||
placeholder:
|
||||
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}',
|
||||
value: formData.aiSettings.systemPrompt,
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quoteQA',
|
||||
@@ -499,7 +499,7 @@ function datasetTemplate({
|
||||
type: 'target',
|
||||
label: 'core.module.input.label.chat history',
|
||||
valueType: 'chatHistory',
|
||||
connected: true,
|
||||
connected: false,
|
||||
value: 8
|
||||
},
|
||||
{
|
||||
|
@@ -39,49 +39,49 @@ function chatModelInput(formData: AppSimpleEditFormType): FlowNodeInputItemType[
|
||||
value: formData.aiSettings.model,
|
||||
type: 'custom',
|
||||
label: '对话模型',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'temperature',
|
||||
value: formData.aiSettings.temperature,
|
||||
type: 'slider',
|
||||
label: '温度',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'maxToken',
|
||||
value: formData.aiSettings.maxToken,
|
||||
type: 'custom',
|
||||
label: '回复上限',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'systemPrompt',
|
||||
value: formData.aiSettings.systemPrompt || '',
|
||||
type: 'textarea',
|
||||
label: '系统提示词',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: ModuleInputKeyEnum.aiChatIsResponseText,
|
||||
value: true,
|
||||
type: 'hidden',
|
||||
label: '返回AI内容',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quoteTemplate',
|
||||
value: formData.aiSettings.quoteTemplate || '',
|
||||
type: 'hidden',
|
||||
label: '引用内容模板',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'quotePrompt',
|
||||
value: formData.aiSettings.quotePrompt || '',
|
||||
type: 'hidden',
|
||||
label: '引用内容提示词',
|
||||
connected: true
|
||||
connected: false
|
||||
},
|
||||
{
|
||||
key: 'switch',
|
||||
@@ -93,7 +93,7 @@ function chatModelInput(formData: AppSimpleEditFormType): FlowNodeInputItemType[
|
||||
key: 'history',
|
||||
type: 'target',
|
||||
label: 'core.module.input.label.chat history',
|
||||
connected: true,
|
||||
connected: false,
|
||||
value: 6
|
||||
},
|
||||
{
|
||||
@@ -118,9 +118,9 @@ function simpleChatTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
inputs: [
|
||||
{
|
||||
key: 'userChatInput',
|
||||
connected: true,
|
||||
connected: false,
|
||||
label: '用户问题',
|
||||
type: 'target'
|
||||
type: 'systemInput'
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
@@ -179,8 +179,8 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
{
|
||||
key: 'userChatInput',
|
||||
label: '用户问题',
|
||||
type: 'target',
|
||||
connected: true
|
||||
type: 'systemInput',
|
||||
connected: false
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
@@ -319,7 +319,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
|
||||
type: FlowNodeInputTypeEnum.textarea,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
label: '回复的内容',
|
||||
connected: true
|
||||
connected: false
|
||||
}
|
||||
],
|
||||
outputs: [],
|
||||
|
@@ -78,12 +78,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
}
|
||||
}
|
||||
},
|
||||
robotBadFeedbackCount: {
|
||||
customFeedbacksCount: {
|
||||
$size: {
|
||||
$filter: {
|
||||
input: '$chatitems',
|
||||
as: 'item',
|
||||
cond: { $ifNull: ['$$item.robotBadFeedback', false] }
|
||||
cond: { $gt: [{ $size: { $ifNull: ['$$item.customFeedbacks', []] } }, 0] }
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -102,7 +102,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
$sort: {
|
||||
userBadFeedbackCount: -1,
|
||||
userGoodFeedbackCount: -1,
|
||||
robotBadFeedbackCount: -1,
|
||||
customFeedbacksCount: -1,
|
||||
updateTime: -1
|
||||
}
|
||||
},
|
||||
@@ -118,7 +118,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
messageCount: { $size: '$chatitems' },
|
||||
userGoodFeedbackCount: 1,
|
||||
userBadFeedbackCount: 1,
|
||||
robotBadFeedbackCount: 1,
|
||||
customFeedbacksCount: 1,
|
||||
markCount: 1
|
||||
}
|
||||
}
|
||||
|
@@ -4,22 +4,29 @@ import { connectToDatabase } from '@/service/mongo';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import type { AdminUpdateFeedbackParams } from '@/global/core/chat/api.d';
|
||||
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||
import { autChatCrud } from '@/service/support/permission/auth/chat';
|
||||
|
||||
/* 初始化我的聊天框,需要身份验证 */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { chatItemId, datasetId, dataId, q, a } = req.body as AdminUpdateFeedbackParams;
|
||||
const { appId, chatId, chatItemId, datasetId, dataId, q, a } =
|
||||
req.body as AdminUpdateFeedbackParams;
|
||||
|
||||
if (!chatItemId || !datasetId || !dataId || !q) {
|
||||
throw new Error('missing parameter');
|
||||
}
|
||||
|
||||
const { userId } = await authCert({ req, authToken: true });
|
||||
await autChatCrud({
|
||||
req,
|
||||
authToken: true,
|
||||
appId,
|
||||
chatId,
|
||||
per: 'r'
|
||||
});
|
||||
|
||||
await MongoChatItem.findOneAndUpdate(
|
||||
{
|
||||
userId,
|
||||
dataId: chatItemId
|
||||
},
|
||||
{
|
||||
|
47
projects/app/src/pages/api/core/chat/feedback/closeCustom.ts
Normal file
47
projects/app/src/pages/api/core/chat/feedback/closeCustom.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import type {
|
||||
AdminUpdateFeedbackParams,
|
||||
CloseCustomFeedbackParams
|
||||
} from '@/global/core/chat/api.d';
|
||||
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||
import { autChatCrud } from '@/service/support/permission/auth/chat';
|
||||
|
||||
/* 初始化我的聊天框,需要身份验证 */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { appId, chatId, chatItemId, index } = req.body as CloseCustomFeedbackParams;
|
||||
|
||||
if (!chatItemId || !appId || !chatId || !chatItemId) {
|
||||
throw new Error('missing parameter');
|
||||
}
|
||||
|
||||
await autChatCrud({
|
||||
req,
|
||||
authToken: true,
|
||||
appId,
|
||||
chatId,
|
||||
per: 'r'
|
||||
});
|
||||
await authCert({ req, authToken: true });
|
||||
|
||||
await MongoChatItem.findOneAndUpdate(
|
||||
{ dataId: chatItemId },
|
||||
{ $unset: { [`customFeedbacks.${index}`]: 1 } }
|
||||
);
|
||||
await MongoChatItem.findOneAndUpdate(
|
||||
{ dataId: chatItemId },
|
||||
{ $pull: { customFeedbacks: null } }
|
||||
);
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
@@ -14,7 +14,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
try {
|
||||
await connectToDatabase();
|
||||
|
||||
let { appId, chatId } = req.query as InitChatProps;
|
||||
let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
|
||||
|
||||
if (!appId) {
|
||||
return jsonRes(res, {
|
||||
@@ -43,7 +43,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
const { history } = await getChatItems({
|
||||
chatId,
|
||||
limit: 30,
|
||||
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback robotBadFeedback ${ModuleOutputKeyEnum.responseData}`
|
||||
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
|
||||
ModuleOutputKeyEnum.responseData
|
||||
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
|
||||
});
|
||||
|
||||
jsonRes<InitChatResponse>(res, {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||
|
||||
type Props = HttpBodyType<{
|
||||
input: string;
|
||||
@@ -13,6 +14,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
data: { input, rule = '' }
|
||||
} = req.body as Props;
|
||||
|
||||
await authRequestFromLocal({ req });
|
||||
|
||||
const result = (() => {
|
||||
if (typeof input === 'string') {
|
||||
const defaultReg: any[] = [
|
||||
|
52
projects/app/src/pages/api/plugins/customFeedback/index.ts
Normal file
52
projects/app/src/pages/api/plugins/customFeedback/index.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
|
||||
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||
|
||||
type Props = HttpBodyType<{
|
||||
defaultFeedback: string;
|
||||
customFeedback: string;
|
||||
}>;
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
const {
|
||||
chatId,
|
||||
responseChatItemId: chatItemId,
|
||||
data: { defaultFeedback, customFeedback }
|
||||
} = req.body as Props;
|
||||
|
||||
await authRequestFromLocal({ req });
|
||||
|
||||
const feedback = customFeedback || defaultFeedback;
|
||||
|
||||
if (!feedback) {
|
||||
return res.json({
|
||||
response: ''
|
||||
});
|
||||
}
|
||||
|
||||
// wait the chat finish
|
||||
setTimeout(() => {
|
||||
addCustomFeedbacks({
|
||||
chatId,
|
||||
chatItemId,
|
||||
feedbacks: [feedback]
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
if (!chatId || !chatItemId) {
|
||||
return res.json({
|
||||
response: `\\n\\n**自动反馈调试**: ${feedback}\\n\\n`
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
response: ''
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
res.status(500).send(getErrText(err));
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||
|
||||
type Props = HttpBodyType<{
|
||||
text: string;
|
||||
@@ -14,6 +15,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
data: { text, ...obj }
|
||||
} = req.body as Props;
|
||||
|
||||
await authRequestFromLocal({ req });
|
||||
|
||||
const textResult = replaceVariable(text, obj);
|
||||
|
||||
res.json({
|
||||
|
@@ -195,12 +195,14 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
// get and concat history
|
||||
const { history } = await getChatItems({ chatId, limit: 30, field: `dataId obj value` });
|
||||
const concatHistories = history.concat(chatMessages);
|
||||
const responseChatItemId: string | undefined = messages[messages.length - 1].dataId;
|
||||
|
||||
/* start flow controller */
|
||||
const { responseData, answerText } = await dispatchModules({
|
||||
res,
|
||||
appId: String(app._id),
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
modules: app.modules,
|
||||
user,
|
||||
teamId: user.team.teamId,
|
||||
@@ -237,7 +239,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
content: [
|
||||
question,
|
||||
{
|
||||
dataId: messages[messages.length - 1].dataId,
|
||||
dataId: responseChatItemId,
|
||||
obj: ChatRoleEnum.AI,
|
||||
value: answerText,
|
||||
responseData
|
||||
|
@@ -29,6 +29,7 @@ import Tag from '@/components/Tag';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import DateRangePicker, { type DateRangeType } from '@/components/DateRangePicker';
|
||||
import { addDays } from 'date-fns';
|
||||
import MyBox from '@/components/common/MyBox';
|
||||
|
||||
const Logs = ({ appId }: { appId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -96,6 +97,7 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
<Th>{t('app.Logs Title')}</Th>
|
||||
<Th>{t('app.Logs Message Total')}</Th>
|
||||
<Th>{t('app.Feedback Count')}</Th>
|
||||
<Th>{t('core.app.feedback.Custom feedback')}</Th>
|
||||
<Th>{t('app.Mark Count')}</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
@@ -158,7 +160,9 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
{item.userBadFeedbackCount}
|
||||
</Flex>
|
||||
)}
|
||||
{!item?.userGoodFeedbackCount && !item?.userBadFeedbackCount && <>-</>}
|
||||
</Td>
|
||||
<Td>{item.customFeedbacksCount || '-'}</Td>
|
||||
<Td>{item.markCount}</Td>
|
||||
</Tr>
|
||||
))}
|
||||
@@ -208,7 +212,7 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
|
||||
export default React.memo(Logs);
|
||||
|
||||
function DetailLogsModal({
|
||||
const DetailLogsModal = ({
|
||||
appId,
|
||||
chatId,
|
||||
onClose
|
||||
@@ -216,14 +220,14 @@ function DetailLogsModal({
|
||||
appId: string;
|
||||
chatId: string;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
}) => {
|
||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||
const { isPc } = useSystemStore();
|
||||
const theme = useTheme();
|
||||
|
||||
const { data: chat } = useQuery(
|
||||
const { data: chat, isFetching } = useQuery(
|
||||
['getChatDetail', chatId],
|
||||
() => getInitChatInfo({ appId, chatId }),
|
||||
() => getInitChatInfo({ appId, chatId, loadCustomFeedbacks: true }),
|
||||
{
|
||||
onSuccess(res) {
|
||||
const history = res.history.map((item) => ({
|
||||
@@ -249,9 +253,11 @@ function DetailLogsModal({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
zIndex={3}
|
||||
<MyBox
|
||||
isLoading={isFetching}
|
||||
display={'flex'}
|
||||
flexDirection={'column'}
|
||||
zIndex={3}
|
||||
position={['fixed', 'absolute']}
|
||||
top={[0, '2%']}
|
||||
right={0}
|
||||
@@ -325,8 +331,8 @@ function DetailLogsModal({
|
||||
chatId={chatId}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyBox>
|
||||
<Box zIndex={2} position={'fixed'} top={0} left={0} bottom={0} right={0} onClick={onClose} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@@ -189,7 +189,7 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
|
||||
w={'16px'}
|
||||
color={'myGray.600'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'myBlue.600' }}
|
||||
_hover={{ color: 'blue.500' }}
|
||||
onClick={() => {
|
||||
copyData(wayMap[getValues('usingWay')].code);
|
||||
}}
|
||||
|
@@ -77,7 +77,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
</Box>
|
||||
<Button
|
||||
variant={'base'}
|
||||
colorScheme={'myBlue'}
|
||||
colorScheme={'blue'}
|
||||
size={['sm', 'md']}
|
||||
{...(shareChatList.length >= 10
|
||||
? {
|
||||
|
@@ -548,7 +548,7 @@ function Settings({ appId }: { appId: string }) {
|
||||
mt={2}
|
||||
px={5}
|
||||
py={4}
|
||||
bg={'myBlue.100'}
|
||||
bg={'blue.50'}
|
||||
position={'relative'}
|
||||
>
|
||||
<Flex alignItems={'center'} py={2}>
|
||||
|
@@ -139,7 +139,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
h={'28px'}
|
||||
|
@@ -61,7 +61,7 @@ const ShareModelList = ({
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
color={model.isCollection ? 'myBlue.700' : 'blackAlpha.700'}
|
||||
color={model.isCollection ? 'blue.600' : 'blackAlpha.700'}
|
||||
onClick={() => onclickCollection(model._id)}
|
||||
>
|
||||
<MyIcon
|
||||
|
@@ -154,7 +154,7 @@ const ChatHistorySlider = ({
|
||||
variant={'base'}
|
||||
flex={1}
|
||||
h={'100%'}
|
||||
color={'myBlue.700'}
|
||||
color={'blue.600'}
|
||||
borderRadius={'xl'}
|
||||
leftIcon={<MyIcon name={'chat'} w={'16px'} />}
|
||||
overflow={'hidden'}
|
||||
@@ -201,8 +201,8 @@ const ChatHistorySlider = ({
|
||||
bg={item.top ? '#E6F6F6 !important' : ''}
|
||||
{...(item.id === activeChatId
|
||||
? {
|
||||
backgroundColor: 'myBlue.100 !important',
|
||||
color: 'myBlue.700'
|
||||
backgroundColor: 'blue.50 !important',
|
||||
color: 'blue.600'
|
||||
}
|
||||
: {
|
||||
onClick: () => {
|
||||
@@ -290,8 +290,8 @@ const ChatHistorySlider = ({
|
||||
alignItems={'center'}
|
||||
{...(item._id === appId
|
||||
? {
|
||||
backgroundColor: 'myBlue.100 !important',
|
||||
color: 'myBlue.700'
|
||||
backgroundColor: 'blue.50 !important',
|
||||
color: 'blue.600'
|
||||
}
|
||||
: {
|
||||
onClick: () => {
|
||||
@@ -325,7 +325,7 @@ const ChatHistorySlider = ({
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
h={'28px'}
|
||||
|
@@ -28,7 +28,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
h={'28px'}
|
||||
|
@@ -311,7 +311,7 @@ const CollectionCard = () => {
|
||||
target="_blank"
|
||||
mr={2}
|
||||
textDecoration={'underline'}
|
||||
color={'myBlue.700'}
|
||||
color={'blue.600'}
|
||||
>
|
||||
{datasetDetail.websiteConfig.url}
|
||||
</Link>
|
||||
@@ -371,7 +371,7 @@ const CollectionCard = () => {
|
||||
Button={
|
||||
<MenuButton
|
||||
_hover={{
|
||||
color: 'myBlue.600'
|
||||
color: 'blue.500'
|
||||
}}
|
||||
fontSize={['sm', 'md']}
|
||||
>
|
||||
@@ -381,7 +381,7 @@ const CollectionCard = () => {
|
||||
py={2}
|
||||
borderRadius={'md'}
|
||||
cursor={'pointer'}
|
||||
bg={'myBlue.600'}
|
||||
bg={'blue.500'}
|
||||
overflow={'hidden'}
|
||||
color={'white'}
|
||||
h={['28px', '35px']}
|
||||
@@ -489,7 +489,7 @@ const CollectionCard = () => {
|
||||
data-drag-id={
|
||||
collection.type === DatasetCollectionTypeEnum.folder ? collection._id : undefined
|
||||
}
|
||||
bg={dragTargetId === collection._id ? 'myBlue.200' : ''}
|
||||
bg={dragTargetId === collection._id ? 'blue.100' : ''}
|
||||
userSelect={'none'}
|
||||
onDragStart={(e) => {
|
||||
setDragStartId(collection._id);
|
||||
@@ -579,7 +579,7 @@ const CollectionCard = () => {
|
||||
h={'22px'}
|
||||
borderRadius={'md'}
|
||||
_hover={{
|
||||
color: 'myBlue.600',
|
||||
color: 'blue.500',
|
||||
'& .icon': {
|
||||
bg: 'myGray.100'
|
||||
}
|
||||
|
@@ -163,7 +163,7 @@ const DataCard = () => {
|
||||
<Flex alignItems={'center'}>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={['14px', '18px']} color={'myBlue.600'} />}
|
||||
icon={<MyIcon name={'backFill'} w={['14px', '18px']} color={'blue.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
size={'sm'}
|
||||
|
@@ -182,7 +182,7 @@ const FileSelect = ({
|
||||
|
||||
if (text) {
|
||||
text = simpleText(text);
|
||||
const splitRes = splitText2Chunks({
|
||||
const { chunks, tokens } = splitText2Chunks({
|
||||
text,
|
||||
chunkLen,
|
||||
overlapRatio
|
||||
@@ -193,10 +193,10 @@ const FileSelect = ({
|
||||
filename: file.name,
|
||||
icon,
|
||||
rawText: text,
|
||||
tokens: splitRes.tokens,
|
||||
tokens,
|
||||
type: DatasetCollectionTypeEnum.file,
|
||||
fileId,
|
||||
chunks: splitRes.chunks.map((chunk) => ({
|
||||
chunks: chunks.map((chunk) => ({
|
||||
q: chunk,
|
||||
a: ''
|
||||
}))
|
||||
@@ -219,7 +219,7 @@ const FileSelect = ({
|
||||
const onUrlFetch = useCallback(
|
||||
(e: UrlFetchResponse) => {
|
||||
const result: FileItemType[] = e.map<FileItemType>(({ url, content }) => {
|
||||
const splitRes = splitText2Chunks({
|
||||
const { chunks, tokens } = splitText2Chunks({
|
||||
text: content,
|
||||
chunkLen,
|
||||
overlapRatio
|
||||
@@ -229,10 +229,10 @@ const FileSelect = ({
|
||||
filename: url,
|
||||
icon: '/imgs/files/link.svg',
|
||||
rawText: content,
|
||||
tokens: splitRes.tokens,
|
||||
tokens,
|
||||
type: DatasetCollectionTypeEnum.link,
|
||||
rawLink: url,
|
||||
chunks: splitRes.chunks.map((chunk) => ({
|
||||
chunks: chunks.map((chunk) => ({
|
||||
q: chunk,
|
||||
a: ''
|
||||
}))
|
||||
@@ -259,7 +259,7 @@ const FileSelect = ({
|
||||
metadata: { datasetId: datasetDetail._id }
|
||||
});
|
||||
|
||||
const splitRes = splitText2Chunks({
|
||||
const { chunks, tokens } = splitText2Chunks({
|
||||
text: content,
|
||||
chunkLen,
|
||||
overlapRatio
|
||||
@@ -271,10 +271,10 @@ const FileSelect = ({
|
||||
filename,
|
||||
icon: '/imgs/files/txt.svg',
|
||||
rawText: content,
|
||||
tokens: splitRes.tokens,
|
||||
tokens,
|
||||
type: DatasetCollectionTypeEnum.file,
|
||||
fileId: fileIds[0],
|
||||
chunks: splitRes.chunks.map((chunk) => ({
|
||||
chunks: chunks.map((chunk) => ({
|
||||
q: chunk,
|
||||
a: ''
|
||||
}))
|
||||
@@ -352,7 +352,7 @@ const FileSelect = ({
|
||||
ml: 1,
|
||||
as: 'span',
|
||||
cursor: 'pointer',
|
||||
color: 'myBlue.700',
|
||||
color: 'blue.600',
|
||||
_hover: {
|
||||
textDecoration: 'underline'
|
||||
}
|
||||
@@ -417,7 +417,7 @@ const FileSelect = ({
|
||||
mt={1}
|
||||
cursor={'pointer'}
|
||||
textDecoration={'underline'}
|
||||
color={'myBlue.600'}
|
||||
color={'blue.500'}
|
||||
fontSize={'12px'}
|
||||
onClick={() =>
|
||||
fileDownload({
|
||||
|
@@ -195,7 +195,7 @@ const Provider = ({
|
||||
|
||||
setFiles((state) =>
|
||||
state.map((file) => {
|
||||
const splitRes = splitText2Chunks({
|
||||
const { chunks, tokens } = splitText2Chunks({
|
||||
text: file.rawText,
|
||||
chunkLen,
|
||||
overlapRatio: chunkOverlapRatio
|
||||
@@ -203,8 +203,8 @@ const Provider = ({
|
||||
|
||||
return {
|
||||
...file,
|
||||
tokens: splitRes.tokens,
|
||||
chunks: splitRes.chunks.map((chunk) => ({
|
||||
tokens,
|
||||
chunks: chunks.map((chunk) => ({
|
||||
q: chunk,
|
||||
a: ''
|
||||
}))
|
||||
@@ -475,7 +475,7 @@ export const SelectorContainer = ({
|
||||
position={'relative'}
|
||||
alignItems={'center'}
|
||||
_hover={{
|
||||
bg: 'myBlue.100',
|
||||
bg: 'blue.50',
|
||||
'& .delete': {
|
||||
display: 'block'
|
||||
}
|
||||
|
@@ -313,7 +313,7 @@ const InputDataModal = ({
|
||||
borderColor={'transparent'}
|
||||
px={0}
|
||||
_focus={{
|
||||
borderColor: 'myBlue.400',
|
||||
borderColor: 'blue.400',
|
||||
px: 3
|
||||
}}
|
||||
placeholder={t('dataset.data.Index Placeholder')}
|
||||
@@ -332,7 +332,7 @@ const InputDataModal = ({
|
||||
border={theme.borders.base}
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
bg: 'myBlue.100'
|
||||
bg: 'blue.50'
|
||||
}}
|
||||
minH={'100px'}
|
||||
onClick={() =>
|
||||
|
@@ -102,10 +102,10 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
py={4}
|
||||
borderRight={['none', theme.borders.base]}
|
||||
>
|
||||
<Box border={'2px solid'} borderColor={'myBlue.600'} p={3} mx={4} borderRadius={'md'}>
|
||||
<Box border={'2px solid'} borderColor={'blue.500'} p={3} mx={4} borderRadius={'md'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box fontSize={'sm'} fontWeight={'bold'} flex={1}>
|
||||
<MyIcon mr={2} name={'text'} w={'18px'} h={'18px'} color={'myBlue.700'} />
|
||||
<MyIcon mr={2} name={'text'} w={'18px'} h={'18px'} color={'blue.600'} />
|
||||
{t('core.dataset.test.Test Text')}
|
||||
</Box>
|
||||
<Button
|
||||
|
@@ -181,7 +181,7 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
h={'28px'}
|
||||
|
@@ -79,7 +79,7 @@ const MoveModal = ({
|
||||
: {
|
||||
cursor: 'pointer',
|
||||
_hover: {
|
||||
color: 'myBlue.600'
|
||||
color: 'blue.500'
|
||||
},
|
||||
onClick: () => {
|
||||
setParentId(item.parentId);
|
||||
|
@@ -163,7 +163,7 @@ const Kb = () => {
|
||||
Button={
|
||||
<MenuButton
|
||||
_hover={{
|
||||
color: 'myBlue.600'
|
||||
color: 'blue.500'
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
@@ -221,7 +221,7 @@ const Kb = () => {
|
||||
boxShadow={'none'}
|
||||
position={'relative'}
|
||||
data-drag-id={dataset.type === DatasetTypeEnum.folder ? dataset._id : undefined}
|
||||
borderColor={dragTargetId === dataset._id ? 'myBlue.600' : ''}
|
||||
borderColor={dragTargetId === dataset._id ? 'blue.500' : ''}
|
||||
draggable
|
||||
onDragStart={(e) => {
|
||||
setDragStartId(dataset._id);
|
||||
@@ -287,7 +287,7 @@ const Kb = () => {
|
||||
h={'22px'}
|
||||
borderRadius={'md'}
|
||||
_hover={{
|
||||
color: 'myBlue.600',
|
||||
color: 'blue.500',
|
||||
'& .icon': {
|
||||
bg: 'myGray.100'
|
||||
}
|
||||
|
@@ -158,7 +158,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
float={'right'}
|
||||
fontSize="sm"
|
||||
mt={2}
|
||||
color={'myBlue.600'}
|
||||
color={'blue.500'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ textDecoration: 'underline' }}
|
||||
onClick={() => setPageType('login')}
|
||||
|
@@ -125,7 +125,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
</FormControl>
|
||||
{feConfigs?.show_register && (
|
||||
<>
|
||||
<Flex align={'center'} justifyContent={'space-between'} mt={3} color={'myBlue.600'}>
|
||||
<Flex align={'center'} justifyContent={'space-between'} mt={3} color={'blue.500'}>
|
||||
<Box
|
||||
cursor={'pointer'}
|
||||
_hover={{ textDecoration: 'underline' }}
|
||||
@@ -149,7 +149,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
<Link
|
||||
href={getDocPath('/docs/agreement/disclaimer/')}
|
||||
target={'_blank'}
|
||||
color={'myBlue.600'}
|
||||
color={'blue.500'}
|
||||
>
|
||||
免责声明
|
||||
</Link>
|
||||
|
@@ -172,7 +172,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
float={'right'}
|
||||
fontSize="sm"
|
||||
mt={2}
|
||||
color={'myBlue.600'}
|
||||
color={'blue.500'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ textDecoration: 'underline' }}
|
||||
onClick={() => setPageType('login')}
|
||||
|
@@ -116,7 +116,7 @@ const Login = () => {
|
||||
{feConfigs?.concatMd && (
|
||||
<Box
|
||||
fontWeight={'bold'}
|
||||
color={'myBlue.700'}
|
||||
color={'blue.600'}
|
||||
cursor={'pointer'}
|
||||
position={'absolute'}
|
||||
right={5}
|
||||
|
@@ -88,7 +88,7 @@ const MyModules = () => {
|
||||
aria-label={'delete'}
|
||||
display={['', 'none']}
|
||||
_hover={{
|
||||
bg: 'myBlue.200'
|
||||
bg: 'blue.100'
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
Reference in New Issue
Block a user