This commit is contained in:
Archer
2023-12-18 16:24:50 +08:00
committed by GitHub
parent d33c99f564
commit 703583fff7
130 changed files with 3418 additions and 2579 deletions

View File

@@ -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;`)

View File

@@ -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({

View File

@@ -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 {

View File

@@ -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
},
{

View File

@@ -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: [],

View File

@@ -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
}
}

View File

@@ -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
},
{

View 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
});
}
}

View File

@@ -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, {

View File

@@ -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[] = [

View 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));
}
}

View File

@@ -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({

View File

@@ -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