mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-02 12:48:30 +00:00
Extraction schema (#398)
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
import { ERROR_ENUM } from '@/service/errorCode';
|
||||
import { updateApiKeyUsedTime } from './index';
|
||||
import { OpenApi } from './schema';
|
||||
|
||||
export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
||||
if (!apikey) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||
}
|
||||
|
||||
try {
|
||||
const openApi = await OpenApi.findOne({ apiKey: apikey });
|
||||
if (!openApi) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||
}
|
||||
const userId = String(openApi.userId);
|
||||
|
||||
// auth limit
|
||||
if (global.feConfigs?.isPlus) {
|
||||
if (openApi?.limit?.expiredTime && openApi.limit.expiredTime.getTime() < Date.now()) {
|
||||
return Promise.reject(`Key ${openApi.apiKey} is expired`);
|
||||
}
|
||||
|
||||
if (
|
||||
openApi?.limit?.credit &&
|
||||
openApi.limit.credit > -1 &&
|
||||
openApi.usage > openApi.limit.credit
|
||||
) {
|
||||
return Promise.reject(`Key ${openApi.apiKey} is over usage`);
|
||||
}
|
||||
}
|
||||
|
||||
updateApiKeyUsedTime(openApi._id);
|
||||
|
||||
return { apikey, userId, appId: openApi.appId };
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
import { OpenApi } from './schema';
|
||||
|
||||
export async function updateApiKeyUsedTime(id: string) {
|
||||
await OpenApi.findByIdAndUpdate(id, {
|
||||
lastUsedTime: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateApiKeyUsage({ apikey, usage }: { apikey: string; usage: number }) {
|
||||
await OpenApi.findOneAndUpdate(
|
||||
{ apiKey: apikey },
|
||||
{
|
||||
$inc: {
|
||||
usage
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
import { Schema, model, models, Model } from 'mongoose';
|
||||
import { OpenApiSchema } from '@/types/support/openapi';
|
||||
import { PRICE_SCALE } from '@fastgpt/common/bill/constants';
|
||||
import { formatPrice } from '@fastgpt/common/bill/index';
|
||||
|
||||
const OpenApiSchema = new Schema(
|
||||
{
|
||||
userId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'user',
|
||||
required: true
|
||||
},
|
||||
apiKey: {
|
||||
type: String,
|
||||
required: true,
|
||||
get: (val: string) => `******${val.substring(val.length - 4)}`
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
lastUsedTime: {
|
||||
type: Date
|
||||
},
|
||||
appId: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: 'Api Key'
|
||||
},
|
||||
usage: {
|
||||
// total usage. value from bill total
|
||||
type: Number,
|
||||
default: 0,
|
||||
get: (val: number) => formatPrice(val)
|
||||
},
|
||||
limit: {
|
||||
expiredTime: {
|
||||
type: Date
|
||||
},
|
||||
credit: {
|
||||
// value from user settings
|
||||
type: Number,
|
||||
default: -1,
|
||||
set: (val: number) => val * PRICE_SCALE,
|
||||
get: (val: number) => formatPrice(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
toObject: { getters: true }
|
||||
}
|
||||
);
|
||||
|
||||
export const OpenApi: Model<OpenApiSchema> = models['openapi'] || model('openapi', OpenApiSchema);
|
@@ -1,171 +0,0 @@
|
||||
import { PRICE_SCALE } from '@fastgpt/common/bill/constants';
|
||||
import { IpLimit } from '@/service/common/ipLimit/schema';
|
||||
import { authBalanceByUid, AuthUserTypeEnum } from '@/service/utils/auth';
|
||||
import { OutLinkSchema } from '@/types/support/outLink';
|
||||
import { OutLink } from './schema';
|
||||
import axios from 'axios';
|
||||
|
||||
type AuthLinkProps = { ip?: string | null; authToken?: string; question: string };
|
||||
|
||||
export async function authOutLinkChat({
|
||||
shareId,
|
||||
ip,
|
||||
authToken,
|
||||
question
|
||||
}: AuthLinkProps & {
|
||||
shareId: string;
|
||||
}) {
|
||||
// get outLink
|
||||
const outLink = await OutLink.findOne({
|
||||
shareId
|
||||
});
|
||||
|
||||
if (!outLink) {
|
||||
return Promise.reject('分享链接无效');
|
||||
}
|
||||
|
||||
const uid = String(outLink.userId);
|
||||
|
||||
const [user] = await Promise.all([
|
||||
authBalanceByUid(uid), // authBalance
|
||||
...(global.feConfigs?.isPlus ? [authOutLinkLimit({ outLink, ip, authToken, question })] : []) // limit auth
|
||||
]);
|
||||
|
||||
return {
|
||||
user,
|
||||
userId: String(outLink.userId),
|
||||
appId: String(outLink.appId),
|
||||
authType: AuthUserTypeEnum.token,
|
||||
responseDetail: outLink.responseDetail
|
||||
};
|
||||
}
|
||||
|
||||
export async function authOutLinkLimit({
|
||||
outLink,
|
||||
ip,
|
||||
authToken,
|
||||
question
|
||||
}: AuthLinkProps & {
|
||||
outLink: OutLinkSchema;
|
||||
}) {
|
||||
if (!ip || !outLink.limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (outLink.limit.expiredTime && outLink.limit.expiredTime.getTime() < Date.now()) {
|
||||
return Promise.reject('分享链接已过期');
|
||||
}
|
||||
|
||||
if (outLink.limit.credit > -1 && outLink.total > outLink.limit.credit * PRICE_SCALE) {
|
||||
return Promise.reject('链接超出使用限制');
|
||||
}
|
||||
|
||||
// ip limit
|
||||
await (async () => {
|
||||
if (!outLink.limit) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const ipLimit = await IpLimit.findOne({ ip, eventId: outLink._id });
|
||||
|
||||
// first request
|
||||
if (!ipLimit) {
|
||||
return await IpLimit.create({
|
||||
eventId: outLink._id,
|
||||
ip,
|
||||
account: outLink.limit.QPM - 1
|
||||
});
|
||||
}
|
||||
|
||||
// over one minute
|
||||
const diffTime = Date.now() - ipLimit.lastMinute.getTime();
|
||||
if (diffTime >= 60 * 1000) {
|
||||
ipLimit.account = outLink.limit.QPM - 1;
|
||||
ipLimit.lastMinute = new Date();
|
||||
return await ipLimit.save();
|
||||
}
|
||||
|
||||
// over limit
|
||||
if (ipLimit.account <= 0) {
|
||||
return Promise.reject(
|
||||
`每分钟仅能请求 ${outLink.limit.QPM} 次, ${60 - Math.round(diffTime / 1000)}s 后重试~`
|
||||
);
|
||||
}
|
||||
|
||||
// update limit
|
||||
ipLimit.account = ipLimit.account - 1;
|
||||
await ipLimit.save();
|
||||
} catch (error) {}
|
||||
})();
|
||||
|
||||
// url auth. send request
|
||||
await authShareStart({ authToken, tokenUrl: outLink.limit.hookUrl, question });
|
||||
}
|
||||
|
||||
export async function authOutLinkId({ id }: { id: string }) {
|
||||
const outLink = await OutLink.findOne({
|
||||
shareId: id
|
||||
});
|
||||
|
||||
if (!outLink) {
|
||||
return Promise.reject('分享链接无效');
|
||||
}
|
||||
|
||||
return {
|
||||
userId: String(outLink.userId)
|
||||
};
|
||||
}
|
||||
|
||||
type TokenAuthResponseType = {
|
||||
success: boolean;
|
||||
msg?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export const authShareChatInit = async (authToken?: string, tokenUrl?: string) => {
|
||||
if (!tokenUrl || !global.feConfigs?.isPlus) return;
|
||||
try {
|
||||
const { data } = await axios<TokenAuthResponseType>({
|
||||
baseURL: tokenUrl,
|
||||
url: '/shareAuth/init',
|
||||
method: 'POST',
|
||||
data: {
|
||||
token: authToken
|
||||
}
|
||||
});
|
||||
if (data?.success !== true) {
|
||||
return Promise.reject(data?.message || data?.msg || '身份校验失败');
|
||||
}
|
||||
} catch (error) {
|
||||
return Promise.reject('身份校验失败');
|
||||
}
|
||||
};
|
||||
|
||||
export const authShareStart = async ({
|
||||
tokenUrl,
|
||||
authToken,
|
||||
question
|
||||
}: {
|
||||
authToken?: string;
|
||||
question: string;
|
||||
tokenUrl?: string;
|
||||
}) => {
|
||||
if (!tokenUrl || !global.feConfigs?.isPlus) return;
|
||||
try {
|
||||
const { data } = await axios<TokenAuthResponseType>({
|
||||
baseURL: tokenUrl,
|
||||
url: '/shareAuth/start',
|
||||
method: 'POST',
|
||||
data: {
|
||||
token: authToken,
|
||||
question
|
||||
}
|
||||
});
|
||||
|
||||
if (data?.success !== true) {
|
||||
return Promise.reject(data?.message || data?.msg || '身份校验失败');
|
||||
}
|
||||
} catch (error) {
|
||||
return Promise.reject('身份校验失败');
|
||||
}
|
||||
};
|
@@ -1,52 +0,0 @@
|
||||
import { addLog } from '@/service/utils/tools';
|
||||
import { ChatHistoryItemResType } from '@/types/chat';
|
||||
import axios from 'axios';
|
||||
import { OutLink } from './schema';
|
||||
|
||||
export const updateOutLinkUsage = async ({
|
||||
shareId,
|
||||
total
|
||||
}: {
|
||||
shareId: string;
|
||||
total: number;
|
||||
}) => {
|
||||
try {
|
||||
await OutLink.findOneAndUpdate(
|
||||
{ shareId },
|
||||
{
|
||||
$inc: { total },
|
||||
lastTime: new Date()
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
addLog.error('update shareChat error', err);
|
||||
}
|
||||
};
|
||||
|
||||
export const pushResult2Remote = async ({
|
||||
authToken,
|
||||
shareId,
|
||||
responseData
|
||||
}: {
|
||||
authToken?: string;
|
||||
shareId?: string;
|
||||
responseData?: ChatHistoryItemResType[];
|
||||
}) => {
|
||||
if (!shareId || !authToken) return;
|
||||
try {
|
||||
const outLink = await OutLink.findOne({
|
||||
shareId
|
||||
});
|
||||
if (!outLink?.limit?.hookUrl) return;
|
||||
|
||||
axios({
|
||||
method: 'post',
|
||||
baseURL: outLink.limit.hookUrl,
|
||||
url: '/shareAuth/finish',
|
||||
data: {
|
||||
token: authToken,
|
||||
responseData
|
||||
}
|
||||
});
|
||||
} catch (error) {}
|
||||
};
|
@@ -1,58 +0,0 @@
|
||||
import { Schema, model, models, Model } from 'mongoose';
|
||||
import { OutLinkSchema as SchemaType } from '@/types/support/outLink';
|
||||
import { OutLinkTypeEnum } from '@/constants/chat';
|
||||
|
||||
const OutLinkSchema = new Schema({
|
||||
shareId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'user',
|
||||
required: true
|
||||
},
|
||||
appId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'model',
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: OutLinkTypeEnum.share
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
total: {
|
||||
// total amount
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
lastTime: {
|
||||
type: Date
|
||||
},
|
||||
responseDetail: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
limit: {
|
||||
expiredTime: {
|
||||
type: Date
|
||||
},
|
||||
QPM: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
credit: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
hookUrl: {
|
||||
type: String
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const OutLink: Model<SchemaType> = models['outlinks'] || model('outlinks', OutLinkSchema);
|
Reference in New Issue
Block a user