Publish app - feishu and wecom (#2375)

* feat(app publish): feishu bot (#2290)

* feat: feishu publish channel fe

* feat: enable feishu fe,
feat: feishu token api

* feat: feishu bot

* chore: extract saveChat from projects/app

* chore: remove debug log output

* feat: Basic Info

* chore: feishu bot fe adjusting

* feat: feishu bot docs

* feat: new tmpData collection for all tmpdata

* chore: compress the image

* perf: feishu config

* feat: source name

* perf: text desc

* perf: load system plugins

* perf: chat source

* feat(publish): Wecom bot (#2343)

* chore: Wecom Config

* feat(fe): wecom config fe

* feat: wecom fe

* chore: uses the newest editmodal

* feat: update png; adjust the fe

* chore: adjust fe

* perf: publish app ui

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
Archer
2024-08-13 21:52:18 +08:00
committed by GitHub
parent 7417de74da
commit 0f3418daf5
71 changed files with 1301 additions and 498 deletions

View File

@@ -1,4 +1,9 @@
import axios, { Method, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import axios, {
Method,
InternalAxiosRequestConfig,
AxiosResponse,
AxiosRequestConfig
} from 'axios';
import { FastGPTProUrl } from '../system/constants';
interface ConfigType {
@@ -118,3 +123,9 @@ export function PUT<T = undefined>(url: string, data = {}, config: ConfigType =
export function DELETE<T = undefined>(url: string, data = {}, config: ConfigType = {}): Promise<T> {
return request(url, data, config, 'DELETE');
}
export const plusRequest = (config: AxiosRequestConfig) =>
instance.request({
...config,
baseURL: FastGPTProUrl
});

View File

@@ -61,9 +61,7 @@ const getPluginTemplateById = async (
currentCost: 0
};
} else {
const item = [...global.communityPlugins, ...(await getSystemPluginTemplates())].find(
(plugin) => plugin.id === pluginId
);
const item = getSystemPluginTemplates().find((plugin) => plugin.id === pluginId);
if (!item) return Promise.reject('plugin not found');
return cloneDeep(item);

View File

@@ -0,0 +1,113 @@
import type { AIChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type.d';
import { MongoApp } from '../app/schema';
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import { MongoChatItem } from './chatItemSchema';
import { MongoChat } from './chatSchema';
import { addLog } from '../../common/system/log';
import { mongoSessionRun } from '../../common/mongo/sessionRun';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
import { getAppChatConfig, getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
type Props = {
chatId: string;
appId: string;
teamId: string;
tmbId: string;
nodes: StoreNodeItemType[];
appChatConfig?: AppChatConfigType;
variables?: Record<string, any>;
isUpdateUseTime: boolean;
newTitle: string;
source: `${ChatSourceEnum}`;
shareId?: string;
outLinkUid?: string;
content: [UserChatItemType & { dataId?: string }, AIChatItemType & { dataId?: string }];
metadata?: Record<string, any>;
};
export async function saveChat({
chatId,
appId,
teamId,
tmbId,
nodes,
appChatConfig,
variables,
isUpdateUseTime,
newTitle,
source,
shareId,
outLinkUid,
content,
metadata = {}
}: Props) {
try {
const chat = await MongoChat.findOne(
{
appId,
chatId
},
'_id metadata'
);
const metadataUpdate = {
...chat?.metadata,
...metadata
};
const { welcomeText, variables: variableList } = getAppChatConfig({
chatConfig: appChatConfig,
systemConfigNode: getGuideModule(nodes),
isPublicFetch: false
});
await mongoSessionRun(async (session) => {
await MongoChatItem.insertMany(
content.map((item) => ({
chatId,
teamId,
tmbId,
appId,
...item
})),
{ session }
);
await MongoChat.updateOne(
{
appId,
chatId
},
{
$set: {
teamId,
tmbId,
appId,
chatId,
variableList,
welcomeText,
variables: variables || {},
title: newTitle,
source,
shareId,
outLinkUid,
metadata: metadataUpdate,
updateTime: new Date()
}
},
{
session,
upsert: true
}
);
});
if (isUpdateUseTime) {
await MongoApp.findByIdAndUpdate(appId, {
updateTime: new Date()
});
}
} catch (error) {
addLog.error(`update chat history error`, error);
}
}

View File

@@ -21,6 +21,12 @@ export const dispatchRunCode = async (props: RunCodeType): Promise<RunCodeRespon
params: { codeType, code, [NodeInputKeyEnum.addInputParam]: customVariables }
} = props;
if (!process.env.SANDBOX_URL) {
return {
[NodeOutputKeyEnum.error]: 'Can not find SANDBOX_URL in env'
};
}
const sandBoxRequestUrl = `${process.env.SANDBOX_URL}/sandbox/js`;
try {
const { data: runResult } = await axios.post<{

View File

@@ -1,5 +1,5 @@
import { connectionMongo, getMongoModel, type Model } from '../../common/mongo';
const { Schema, model, models } = connectionMongo;
import { connectionMongo, getMongoModel } from '../../common/mongo';
const { Schema } = connectionMongo;
import { OutLinkSchema as SchemaType } from '@fastgpt/global/support/outLink/type';
import {
TeamCollectionName,
@@ -63,18 +63,7 @@ const OutLinkSchema = new Schema({
}
},
app: {
appId: {
type: String
},
appSecret: {
type: String
},
encryptKey: {
type: String
},
verificationToken: {
type: String
}
type: Object // could be FeishuAppType | WecomAppType | ...
},
immediateResponse: {
type: String

View File

@@ -0,0 +1,18 @@
import { TeamMemberWithUserSchema } from '@fastgpt/global/support/user/team/type';
import { MongoTeamMember } from '../../user/team/teamMemberSchema';
import { checkTeamAIPoints } from '../teamLimit';
import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
export async function getUserChatInfoAndAuthTeamPoints(tmbId: string) {
const tmb = (await MongoTeamMember.findById(tmbId, 'teamId userId').populate(
'userId',
'timezone openaiAccount'
)) as TeamMemberWithUserSchema;
if (!tmb) return Promise.reject(UserErrEnum.unAuthUser);
await checkTeamAIPoints(tmb.teamId);
return {
user: tmb.userId
};
}

View File

@@ -1,5 +1,5 @@
import { AppDetailType } from '@fastgpt/global/core/app/type';
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
import { OutlinkAppType, OutLinkSchema } from '@fastgpt/global/support/outLink/type';
import { parseHeaderCert } from '../controller';
import { MongoOutLink } from '../../outLink/schema';
import { OutLinkErrEnum } from '@fastgpt/global/common/error/code/outLink';
@@ -50,11 +50,15 @@ export async function authOutLinkCrud({
}
/* outLink exist and it app exist */
export async function authOutLinkValid({ shareId }: { shareId?: string }) {
export async function authOutLinkValid<T extends OutlinkAppType = undefined>({
shareId
}: {
shareId?: string;
}) {
if (!shareId) {
return Promise.reject(OutLinkErrEnum.linkUnInvalid);
}
const shareChat = await MongoOutLink.findOne({ shareId });
const shareChat = (await MongoOutLink.findOne({ shareId }).lean()) as OutLinkSchema<T>;
if (!shareChat) {
return Promise.reject(OutLinkErrEnum.linkUnInvalid);

View File

@@ -0,0 +1,49 @@
import {
TmpDataEnum,
TmpDataExpireTime,
TmpDataMetadata,
TmpDataType
} from '@fastgpt/global/support/tmpData/constant';
import { MongoTmpData } from './schema';
import { TmpDataSchema } from '@fastgpt/global/support/tmpData/type';
import { addMilliseconds } from 'date-fns';
function getDataId<T extends TmpDataEnum>(type: T, metadata: TmpDataMetadata<T>) {
return `${type}--${Object.values(metadata).join('--')}`;
}
export async function getTmpData<T extends TmpDataEnum>({
type,
metadata
}: {
type: T;
metadata: TmpDataMetadata<T>;
}) {
return (await MongoTmpData.findOne({
dataId: getDataId(type, metadata)
}).lean()) as TmpDataSchema<TmpDataType<T>> | null;
}
export async function setTmpData<T extends TmpDataEnum>({
type,
metadata,
data
}: {
type: T;
metadata: TmpDataMetadata<T>;
data: TmpDataType<T>;
}) {
return await MongoTmpData.updateOne(
{
dataId: getDataId(type, metadata)
},
{
dataId: getDataId(type, metadata),
data,
expireAt: addMilliseconds(Date.now(), TmpDataExpireTime[type])
},
{
upsert: true
}
);
}

View File

@@ -0,0 +1,28 @@
import { getMongoModel, Schema } from '../../common/mongo';
import type { TmpDataSchema as SchemaType } from '@fastgpt/global/support/tmpData/type';
const collectionName = 'tmp_datas';
const TmpDataSchema = new Schema({
dataId: {
type: String,
required: true,
unique: true
},
data: {
type: Object
},
expireAt: {
type: Date,
required: true
}
});
try {
TmpDataSchema.index({ dataId: -1 });
TmpDataSchema.index({ expireAt: -1 }, { expireAfterSeconds: 5 });
} catch (error) {
console.log(error);
}
export const MongoTmpData = getMongoModel<SchemaType<Object>>(collectionName, TmpDataSchema);