V4.6.9-first commit (#899)
* perf: insert mongo dataset data session * perf: dataset data index * remove delay * rename bill schema * rename bill record * perf: bill table * perf: prompt * perf: sub plan * change the usage count * feat: usage bill * publish usages * doc * 新增团队聊天功能 (#20) * perf: doc * feat 添加标签部分 feat 信息团队标签配置 feat 新增团队同步管理 feat team分享页面 feat 完成team分享页面 feat 实现模糊搜索 style 格式化 fix 修复迷糊匹配 style 样式修改 fix 团队标签功能修复 * fix 修复鉴权功能 * merge 合并代码 * fix 修复引用错误 * fix 修复pr问题 * fix 修复ts格式问题 --------- Co-authored-by: archer <545436317@qq.com> Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> * update extra plan * fix: ts * format * perf: bill field * feat: standard plan * fix: ts * feat 个人账号页面修改 (#22) * feat 添加标签部分 feat 信息团队标签配置 feat 新增团队同步管理 feat team分享页面 feat 完成team分享页面 feat 实现模糊搜索 style 格式化 fix 修复迷糊匹配 style 样式修改 fix 团队标签功能修复 * fix 修复鉴权功能 * merge 合并代码 * fix 修复引用错误 * fix 修复pr问题 * fix 修复ts格式问题 * feat 修改个人账号页 --------- Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> * sub plan page (#23) * fix chunk index; error page text * feat: dataset process Integral prediction * feat: stand plan field * feat: sub plan limit * perf: index * query extension * perf: share link push app name * perf: plan point unit * perf: get sub plan * perf: account page * feat 新增套餐详情弹窗代码 (#24) * merge 合并代码 * fix 新增套餐详情弹框 * fix 修复pr问题 * feat: change http node input to prompt editor (#21) * feat: change http node input to prompt editor * fix * split PromptEditor to HttpInput * Team plans (#25) * perf: pay check * perf: team plan test * plan limit check * replace sensitive text * perf: fix some null * collection null check * perf: plans modal * perf: http module * pacakge (#26) * individuation page and pay modal amount (#27) * feat: individuation page * team chat config * pay modal * plan count and replace invalid chars (#29) * fix: user oneapi * fix: training queue * fix: qa queue * perf: remove space chars * replace invalid chars * change httpinput dropdown menu (#28) * perf: http * reseet free plan * perf: plan code to packages * remove llm config to package * perf: code * perf: faq * fix: get team plan --------- Co-authored-by: yst <77910600+yu-and-liu@users.noreply.github.com> Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
@@ -3,11 +3,25 @@ import { ErrType } from '../errorCode';
|
||||
/* team: 500000 */
|
||||
export enum TeamErrEnum {
|
||||
teamOverSize = 'teamOverSize',
|
||||
unAuthTeam = 'unAuthTeam'
|
||||
unAuthTeam = 'unAuthTeam',
|
||||
aiPointsNotEnough = 'aiPointsNotEnough',
|
||||
datasetSizeNotEnough = 'datasetSizeNotEnough',
|
||||
datasetAmountNotEnough = 'datasetAmountNotEnough',
|
||||
appAmountNotEnough = 'appAmountNotEnough',
|
||||
pluginAmountNotEnough = 'pluginAmountNotEnough',
|
||||
websiteSyncNotEnough = 'websiteSyncNotEnough',
|
||||
reRankNotEnough = 'reRankNotEnough'
|
||||
}
|
||||
const teamErr = [
|
||||
{ statusText: TeamErrEnum.teamOverSize, message: 'error.team.overSize' },
|
||||
{ statusText: TeamErrEnum.unAuthTeam, message: '无权操作该团队' }
|
||||
{ statusText: TeamErrEnum.unAuthTeam, message: '无权操作该团队' },
|
||||
{ statusText: TeamErrEnum.aiPointsNotEnough, message: 'AI积分已用完~' },
|
||||
{ statusText: TeamErrEnum.datasetSizeNotEnough, message: '知识库容量不足,请先扩容~' },
|
||||
{ statusText: TeamErrEnum.datasetAmountNotEnough, message: '知识库数量已达上限~' },
|
||||
{ statusText: TeamErrEnum.appAmountNotEnough, message: '应用数量已达上限~' },
|
||||
{ statusText: TeamErrEnum.pluginAmountNotEnough, message: '插件数量已达上限~' },
|
||||
{ statusText: TeamErrEnum.websiteSyncNotEnough, message: '无权使用Web站点同步~' },
|
||||
{ statusText: TeamErrEnum.reRankNotEnough, message: '无权使用检索重排~' }
|
||||
];
|
||||
export default teamErr.reduce((acc, cur, index) => {
|
||||
return {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { replaceSensitiveLink } from '../string/tools';
|
||||
import { replaceSensitiveText } from '../string/tools';
|
||||
|
||||
export const getErrText = (err: any, def = '') => {
|
||||
const msg: string = typeof err === 'string' ? err : err?.message || def || '';
|
||||
msg && console.log('error =>', msg);
|
||||
return replaceSensitiveLink(msg);
|
||||
return replaceSensitiveText(msg);
|
||||
};
|
||||
|
4
packages/global/common/math/tools.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const formatNumber = (num: number, digit = 1e4) => Math.round(num * digit) / digit;
|
||||
|
||||
export const formatNumber2Million = (num: number) => Math.round(num / 1000000);
|
||||
export const formatNumber2Thousand = (num: number) => Math.round(num / 1000);
|
@@ -2,3 +2,4 @@ import dayjs from 'dayjs';
|
||||
|
||||
export const formatTime2YMDHM = (time?: Date) =>
|
||||
time ? dayjs(time).format('YYYY-MM-DD HH:mm') : '';
|
||||
export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : '');
|
||||
|
@@ -38,10 +38,14 @@ export function replaceVariable(text: string, obj: Record<string, string | numbe
|
||||
return text || '';
|
||||
}
|
||||
|
||||
/* replace sensitive link */
|
||||
export const replaceSensitiveLink = (text: string) => {
|
||||
const urlRegex = /(?<=https?:\/\/)[^\s]+/g;
|
||||
return text.replace(urlRegex, 'xxx');
|
||||
/* replace sensitive text */
|
||||
export const replaceSensitiveText = (text: string) => {
|
||||
// 1. http link
|
||||
text = text.replace(/(?<=https?:\/\/)[^\s]+/g, 'xxx');
|
||||
// 2. nx-xxx 全部替换成xxx
|
||||
text = text.replace(/ns-[\w-]+/g, 'xxx');
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
export const getNanoid = (size = 12) => {
|
||||
|
@@ -30,6 +30,7 @@ export type FastGPTFeConfigsType = {
|
||||
show_pay?: boolean;
|
||||
show_openai_account?: boolean;
|
||||
show_promotion?: boolean;
|
||||
show_team_chat?: boolean;
|
||||
hide_app_flow?: boolean;
|
||||
concatMd?: string;
|
||||
docUrl?: string;
|
||||
|
15
packages/global/core/ai/model.d.ts
vendored
@@ -6,8 +6,7 @@ export type LLMModelItemType = {
|
||||
quoteMaxToken: number;
|
||||
maxTemperature: number;
|
||||
|
||||
inputPrice: number;
|
||||
outputPrice: number;
|
||||
charsPointsPrice: number; // 1k chars=n points
|
||||
|
||||
censor?: boolean;
|
||||
vision?: boolean;
|
||||
@@ -27,8 +26,7 @@ export type VectorModelItemType = {
|
||||
model: string;
|
||||
name: string;
|
||||
defaultToken: number;
|
||||
inputPrice: number;
|
||||
outputPrice: number;
|
||||
charsPointsPrice: number;
|
||||
maxToken: number;
|
||||
weight: number;
|
||||
hidden?: boolean;
|
||||
@@ -38,8 +36,7 @@ export type VectorModelItemType = {
|
||||
export type ReRankModelItemType = {
|
||||
model: string;
|
||||
name: string;
|
||||
inputPrice: number;
|
||||
outputPrice?: number;
|
||||
charsPointsPrice: number;
|
||||
requestUrl?: string;
|
||||
requestAuth?: string;
|
||||
};
|
||||
@@ -47,14 +44,12 @@ export type ReRankModelItemType = {
|
||||
export type AudioSpeechModelType = {
|
||||
model: string;
|
||||
name: string;
|
||||
inputPrice: number;
|
||||
outputPrice?: number;
|
||||
charsPointsPrice: number;
|
||||
voices: { label: string; value: string; bufferId: string }[];
|
||||
};
|
||||
|
||||
export type WhisperModelType = {
|
||||
model: string;
|
||||
name: string;
|
||||
inputPrice: number;
|
||||
outputPrice?: number;
|
||||
charsPointsPrice: number; // 60s = n points
|
||||
};
|
||||
|
@@ -2,14 +2,13 @@ import type { LLMModelItemType, VectorModelItemType } from './model.d';
|
||||
|
||||
export const defaultQAModels: LLMModelItemType[] = [
|
||||
{
|
||||
model: 'gpt-3.5-turbo-16k',
|
||||
name: 'gpt-3.5-turbo-16k',
|
||||
model: 'gpt-3.5-turbo',
|
||||
name: 'gpt-3.5-turbo',
|
||||
maxContext: 16000,
|
||||
maxResponse: 16000,
|
||||
quoteMaxToken: 13000,
|
||||
maxTemperature: 1.2,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
charsPointsPrice: 0,
|
||||
censor: false,
|
||||
vision: false,
|
||||
datasetProcess: true,
|
||||
@@ -26,8 +25,7 @@ export const defaultVectorModels: VectorModelItemType[] = [
|
||||
{
|
||||
model: 'text-embedding-ada-002',
|
||||
name: 'Embedding-2',
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
charsPointsPrice: 0,
|
||||
defaultToken: 500,
|
||||
maxToken: 3000,
|
||||
weight: 100
|
||||
|
1
packages/global/core/app/api.d.ts
vendored
@@ -17,6 +17,7 @@ export interface AppUpdateParams {
|
||||
intro?: string;
|
||||
modules?: AppSchema['modules'];
|
||||
permission?: AppSchema['permission'];
|
||||
teamTags?: AppSchema['teamTags'];
|
||||
}
|
||||
|
||||
export type FormatForm2ModulesProps = {
|
||||
|
3
packages/global/core/app/type.d.ts
vendored
@@ -5,7 +5,7 @@ import type { AIChatModuleProps, DatasetModuleProps } from '../module/node/type.
|
||||
import { VariableInputEnum } from '../module/constants';
|
||||
import { SelectedDatasetType } from '../module/api';
|
||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||
|
||||
import { TeamTagsSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
|
||||
export interface AppSchema {
|
||||
_id: string;
|
||||
userId: string;
|
||||
@@ -20,6 +20,7 @@ export interface AppSchema {
|
||||
modules: ModuleItemType[];
|
||||
permission: `${PermissionTypeEnum}`;
|
||||
inited?: boolean;
|
||||
teamTags: [string];
|
||||
}
|
||||
|
||||
export type AppListItemType = {
|
||||
|
@@ -27,7 +27,8 @@ export enum ChatSourceEnum {
|
||||
test = 'test',
|
||||
online = 'online',
|
||||
share = 'share',
|
||||
api = 'api'
|
||||
api = 'api',
|
||||
team = 'team'
|
||||
}
|
||||
export const ChatSourceMap = {
|
||||
[ChatSourceEnum.test]: {
|
||||
@@ -41,6 +42,9 @@ export const ChatSourceMap = {
|
||||
},
|
||||
[ChatSourceEnum.api]: {
|
||||
name: 'core.chat.logs.api'
|
||||
},
|
||||
[ChatSourceEnum.team]: {
|
||||
name: 'core.chat.logs.team'
|
||||
}
|
||||
};
|
||||
|
||||
|
29
packages/global/core/chat/type.d.ts
vendored
@@ -4,6 +4,7 @@ import { ChatRoleEnum, ChatSourceEnum, ChatStatusEnum } from './constants';
|
||||
import { FlowNodeTypeEnum } from '../module/node/constant';
|
||||
import { ModuleOutputKeyEnum } from '../module/constants';
|
||||
import { AppSchema } from '../app/type';
|
||||
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||
|
||||
export type ChatSchema = {
|
||||
@@ -25,6 +26,23 @@ export type ChatSchema = {
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
|
||||
export type teamInfoType = {
|
||||
avatar: string;
|
||||
balance: number;
|
||||
createTime: string;
|
||||
maxSize: number;
|
||||
name: string;
|
||||
ownerId: string;
|
||||
tagsUrl: string;
|
||||
_id: string;
|
||||
};
|
||||
|
||||
export type chatAppListSchema = {
|
||||
apps: AppType[];
|
||||
teamInfo: teamInfoSchema;
|
||||
uid?: string;
|
||||
};
|
||||
|
||||
export type ChatWithAppSchema = Omit<ChatSchema, 'appId'> & {
|
||||
appId: AppSchema;
|
||||
};
|
||||
@@ -88,15 +106,15 @@ export type ChatHistoryItemType = HistoryItemType & {
|
||||
export type moduleDispatchResType = {
|
||||
// common
|
||||
moduleLogo?: string;
|
||||
price?: number;
|
||||
runningTime?: number;
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
query?: string;
|
||||
textOutput?: string;
|
||||
|
||||
// bill
|
||||
charsLength?: number;
|
||||
model?: string;
|
||||
query?: string;
|
||||
contextTotalLen?: number;
|
||||
textOutput?: string;
|
||||
totalPoints?: number;
|
||||
|
||||
// chat
|
||||
temperature?: number;
|
||||
@@ -111,6 +129,7 @@ export type moduleDispatchResType = {
|
||||
searchUsingReRank?: boolean;
|
||||
extensionModel?: string;
|
||||
extensionResult?: string;
|
||||
extensionCharsLength?: number;
|
||||
|
||||
// cq
|
||||
cqList?: ClassifyQuestionAgentItemType[];
|
||||
|
@@ -71,30 +71,6 @@ export const DatasetCollectionSyncResultMap = {
|
||||
};
|
||||
|
||||
/* ------------ data -------------- */
|
||||
export enum DatasetDataIndexTypeEnum {
|
||||
chunk = 'chunk',
|
||||
qa = 'qa',
|
||||
summary = 'summary',
|
||||
hypothetical = 'hypothetical',
|
||||
custom = 'custom'
|
||||
}
|
||||
export const DatasetDataIndexTypeMap = {
|
||||
[DatasetDataIndexTypeEnum.chunk]: {
|
||||
name: 'dataset.data.indexes.chunk'
|
||||
},
|
||||
[DatasetDataIndexTypeEnum.summary]: {
|
||||
name: 'dataset.data.indexes.summary'
|
||||
},
|
||||
[DatasetDataIndexTypeEnum.hypothetical]: {
|
||||
name: 'dataset.data.indexes.hypothetical'
|
||||
},
|
||||
[DatasetDataIndexTypeEnum.qa]: {
|
||||
name: 'dataset.data.indexes.qa'
|
||||
},
|
||||
[DatasetDataIndexTypeEnum.custom]: {
|
||||
name: 'dataset.data.indexes.custom'
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------ training -------------- */
|
||||
export enum TrainingModeEnum {
|
||||
|
5
packages/global/core/dataset/type.d.ts
vendored
@@ -3,7 +3,6 @@ import { PermissionTypeEnum } from '../../support/permission/constant';
|
||||
import { PushDatasetDataChunkProps } from './api';
|
||||
import {
|
||||
DatasetCollectionTypeEnum,
|
||||
DatasetDataIndexTypeEnum,
|
||||
DatasetStatusEnum,
|
||||
DatasetTypeEnum,
|
||||
SearchScoreTypeEnum,
|
||||
@@ -64,7 +63,6 @@ export type DatasetCollectionSchemaType = {
|
||||
export type DatasetDataIndexItemType = {
|
||||
defaultIndex: boolean;
|
||||
dataId: string; // pg data id
|
||||
type: `${DatasetDataIndexTypeEnum}`;
|
||||
text: string;
|
||||
};
|
||||
export type DatasetDataSchemaType = {
|
||||
@@ -142,6 +140,7 @@ export type DatasetCollectionItemType = CollectionWithDatasetType & {
|
||||
/* ================= data ===================== */
|
||||
export type DatasetDataItemType = {
|
||||
id: string;
|
||||
teamId: string;
|
||||
datasetId: string;
|
||||
collectionId: string;
|
||||
sourceName: string;
|
||||
@@ -173,7 +172,7 @@ export type DatasetFileSchema = {
|
||||
/* ============= search =============== */
|
||||
export type SearchDataResponseItemType = Omit<
|
||||
DatasetDataItemType,
|
||||
'indexes' | 'isOwner' | 'canWrite'
|
||||
'teamId' | 'indexes' | 'isOwner' | 'canWrite'
|
||||
> & {
|
||||
score: { type: `${SearchScoreTypeEnum}`; value: number; index: number }[];
|
||||
// score: number;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { TrainingModeEnum, DatasetCollectionTypeEnum, DatasetDataIndexTypeEnum } from './constants';
|
||||
import { TrainingModeEnum, DatasetCollectionTypeEnum } from './constants';
|
||||
import { getFileIcon } from '../../common/file/icon';
|
||||
import { strIsLink } from '../../common/string/tools';
|
||||
|
||||
@@ -41,7 +41,6 @@ export function getDefaultIndex(props?: { q?: string; a?: string; dataId?: strin
|
||||
const qaStr = `${q}\n${a}`.trim();
|
||||
return {
|
||||
defaultIndex: true,
|
||||
type: a ? DatasetDataIndexTypeEnum.qa : DatasetDataIndexTypeEnum.chunk,
|
||||
text: a ? qaStr : q,
|
||||
dataId
|
||||
};
|
||||
|
@@ -89,9 +89,10 @@ export enum ModuleInputKeyEnum {
|
||||
|
||||
export enum ModuleOutputKeyEnum {
|
||||
// common
|
||||
responseData = 'responseData',
|
||||
moduleDispatchBills = 'moduleDispatchBills',
|
||||
userChatInput = 'userChatInput',
|
||||
finish = 'finish',
|
||||
responseData = 'responseData',
|
||||
history = 'history',
|
||||
answerText = 'answerText', // answer module text key
|
||||
success = 'success',
|
||||
|
@@ -20,9 +20,7 @@ export enum FlowNodeInputTypeEnum {
|
||||
aiSettings = 'aiSettings',
|
||||
|
||||
// ai model select
|
||||
selectChatModel = 'selectChatModel',
|
||||
selectCQModel = 'selectCQModel',
|
||||
selectExtractModel = 'selectExtractModel',
|
||||
selectLLMModel = 'selectLLMModel',
|
||||
|
||||
// dataset special input
|
||||
selectDataset = 'selectDataset',
|
||||
@@ -58,7 +56,7 @@ export enum FlowNodeTypeEnum {
|
||||
pluginModule = 'pluginModule',
|
||||
pluginInput = 'pluginInput',
|
||||
pluginOutput = 'pluginOutput',
|
||||
cfr = 'cfr'
|
||||
queryExtension = 'cfr'
|
||||
|
||||
// abandon
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ export const AiChatModule: FlowModuleTemplateType = {
|
||||
Input_Template_Switch,
|
||||
{
|
||||
key: ModuleInputKeyEnum.aiModel,
|
||||
type: FlowNodeInputTypeEnum.selectChatModel,
|
||||
type: FlowNodeInputTypeEnum.selectLLMModel,
|
||||
label: 'core.module.input.label.aiModel',
|
||||
required: true,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
|
@@ -24,7 +24,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
|
||||
Input_Template_Switch,
|
||||
{
|
||||
key: ModuleInputKeyEnum.aiModel,
|
||||
type: FlowNodeInputTypeEnum.selectCQModel,
|
||||
type: FlowNodeInputTypeEnum.selectLLMModel,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
label: 'core.module.input.label.Classify model',
|
||||
required: true,
|
||||
|
@@ -24,7 +24,7 @@ export const ContextExtractModule: FlowModuleTemplateType = {
|
||||
Input_Template_Switch,
|
||||
{
|
||||
key: ModuleInputKeyEnum.aiModel,
|
||||
type: FlowNodeInputTypeEnum.selectExtractModel,
|
||||
type: FlowNodeInputTypeEnum.selectLLMModel,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
label: 'core.module.input.label.LLM',
|
||||
required: true,
|
||||
|
@@ -85,7 +85,6 @@ export const HttpModule468: FlowModuleTemplateType = {
|
||||
...Input_Template_AddInputParam,
|
||||
editField: {
|
||||
key: true,
|
||||
name: true,
|
||||
description: true,
|
||||
required: true,
|
||||
dataType: true
|
||||
@@ -106,7 +105,6 @@ export const HttpModule468: FlowModuleTemplateType = {
|
||||
...Output_Template_AddOutput,
|
||||
editField: {
|
||||
key: true,
|
||||
name: true,
|
||||
description: true,
|
||||
dataType: true
|
||||
},
|
||||
|
@@ -3,7 +3,7 @@ import {
|
||||
FlowNodeOutputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '../../node/constant';
|
||||
import { FlowModuleTemplateType } from '../../type.d';
|
||||
import { FlowModuleTemplateType } from '../../type';
|
||||
import {
|
||||
ModuleIOValueTypeEnum,
|
||||
ModuleInputKeyEnum,
|
||||
@@ -17,19 +17,19 @@ import {
|
||||
} from '../input';
|
||||
import { Output_Template_UserChatInput } from '../output';
|
||||
|
||||
export const AiCFR: FlowModuleTemplateType = {
|
||||
export const AiQueryExtension: FlowModuleTemplateType = {
|
||||
id: FlowNodeTypeEnum.chatNode,
|
||||
templateType: ModuleTemplateTypeEnum.other,
|
||||
flowType: FlowNodeTypeEnum.cfr,
|
||||
flowType: FlowNodeTypeEnum.queryExtension,
|
||||
avatar: '/imgs/module/cfr.svg',
|
||||
name: 'core.module.template.Query extension',
|
||||
intro: '该模块已合并到知识库搜索参数中,无需单独使用。模块将于2024/3/31弃用,请尽快修改。',
|
||||
intro: 'core.module.template.Query extension intro',
|
||||
showStatus: true,
|
||||
inputs: [
|
||||
Input_Template_Switch,
|
||||
{
|
||||
key: ModuleInputKeyEnum.aiModel,
|
||||
type: FlowNodeInputTypeEnum.selectExtractModel,
|
||||
type: FlowNodeInputTypeEnum.selectLLMModel,
|
||||
label: 'core.module.input.label.aiModel',
|
||||
required: true,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
@@ -39,7 +39,7 @@ export const AiCFR: FlowModuleTemplateType = {
|
||||
{
|
||||
key: ModuleInputKeyEnum.aiSystemPrompt,
|
||||
type: FlowNodeInputTypeEnum.textarea,
|
||||
label: 'core.module.input.label.Background',
|
||||
label: 'core.app.edit.Query extension background prompt',
|
||||
max: 300,
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
description: 'core.app.edit.Query extension background tip',
|
||||
@@ -54,7 +54,8 @@ export const AiCFR: FlowModuleTemplateType = {
|
||||
Output_Template_UserChatInput,
|
||||
{
|
||||
key: ModuleOutputKeyEnum.text,
|
||||
label: 'core.module.output.label.cfr result',
|
||||
label: 'core.module.output.label.query extension result',
|
||||
description: 'core.module.output.description.query extension result',
|
||||
valueType: ModuleIOValueTypeEnum.string,
|
||||
type: FlowNodeOutputTypeEnum.source,
|
||||
targets: []
|
19
packages/global/core/module/type.d.ts
vendored
@@ -1,6 +1,14 @@
|
||||
import { FlowNodeTypeEnum } from './node/constant';
|
||||
import { ModuleIOValueTypeEnum, ModuleTemplateTypeEnum, VariableInputEnum } from './constants';
|
||||
import {
|
||||
ModuleIOValueTypeEnum,
|
||||
ModuleOutputKeyEnum,
|
||||
ModuleTemplateTypeEnum,
|
||||
VariableInputEnum
|
||||
} from './constants';
|
||||
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type';
|
||||
import { UserModelSchema } from 'support/user/type';
|
||||
import { moduleDispatchResType } from '..//chat/type';
|
||||
import { ChatModuleBillType } from '../../support/wallet/bill/type';
|
||||
|
||||
export type FlowModuleTemplateType = {
|
||||
id: string; // module id, unique
|
||||
@@ -105,7 +113,7 @@ export type ChatDispatchProps = {
|
||||
mode: 'test' | 'chat';
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
user: UserType;
|
||||
user: UserModelSchema;
|
||||
appId: string;
|
||||
chatId?: string;
|
||||
responseChatItemId?: string;
|
||||
@@ -116,7 +124,10 @@ export type ChatDispatchProps = {
|
||||
};
|
||||
|
||||
export type ModuleDispatchProps<T> = ChatDispatchProps & {
|
||||
outputs: RunningModuleItemType['outputs'];
|
||||
inputs: RunningModuleItemType['inputs'];
|
||||
module: RunningModuleItemType;
|
||||
params: T;
|
||||
};
|
||||
export type ModuleDispatchResponse<T> = T & {
|
||||
[ModuleOutputKeyEnum.responseData]?: moduleDispatchResType;
|
||||
[ModuleOutputKeyEnum.moduleDispatchBills]?: ChatModuleBillType[];
|
||||
};
|
||||
|
5
packages/global/support/openapi/type.d.ts
vendored
@@ -1,6 +1,5 @@
|
||||
export type OpenApiSchema = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
createTime: Date;
|
||||
@@ -8,9 +7,9 @@ export type OpenApiSchema = {
|
||||
apiKey: string;
|
||||
appId?: string;
|
||||
name: string;
|
||||
usage: number;
|
||||
usagePoints: number;
|
||||
limit?: {
|
||||
expiredTime?: Date;
|
||||
credit?: number;
|
||||
maxUsagePoints: number;
|
||||
};
|
||||
};
|
||||
|
2
packages/global/support/outLink/api.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
import type { HistoryItemType, ChatSiteItemType } from '../../core/chat/type.d';
|
||||
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
|
||||
import { OutLinkSchema } from './type.d';
|
||||
|
||||
export type AuthOutLinkInitProps = {
|
||||
outLinkUid: string;
|
||||
|
4
packages/global/support/outLink/type.d.ts
vendored
@@ -7,14 +7,14 @@ export type OutLinkSchema = {
|
||||
tmbId: string;
|
||||
appId: string;
|
||||
name: string;
|
||||
total: number;
|
||||
usagePoints: number;
|
||||
lastTime: Date;
|
||||
type: `${OutLinkTypeEnum}`;
|
||||
responseDetail: boolean;
|
||||
limit?: {
|
||||
expiredTime?: Date;
|
||||
QPM: number;
|
||||
credit: number;
|
||||
maxUsagePoints: number;
|
||||
hookUrl?: string;
|
||||
};
|
||||
};
|
||||
|
1
packages/global/support/permission/type.d.ts
vendored
@@ -1,7 +1,6 @@
|
||||
import { AuthUserTypeEnum } from './constant';
|
||||
|
||||
export type AuthResponseType = {
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
isOwner: boolean;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
export const TeamCollectionName = 'teams';
|
||||
export const TeamMemberCollectionName = 'team.members';
|
||||
export const TeamTagsCollectionName = 'team.tags';
|
||||
|
||||
export enum TeamMemberRoleEnum {
|
||||
owner = 'owner',
|
||||
|
@@ -15,6 +15,7 @@ export type UpdateTeamProps = {
|
||||
teamId: string;
|
||||
name?: string;
|
||||
avatar?: string;
|
||||
tagsUrl?: string;
|
||||
};
|
||||
|
||||
/* ------------- member ----------- */
|
||||
|
18
packages/global/support/user/team/type.d.ts
vendored
@@ -9,11 +9,23 @@ export type TeamSchema = {
|
||||
createTime: Date;
|
||||
balance: number;
|
||||
maxSize: number;
|
||||
tagsUrl: string;
|
||||
limit: {
|
||||
lastExportDatasetTime: Date;
|
||||
lastWebsiteSyncTime: Date;
|
||||
};
|
||||
};
|
||||
export type tagsType = {
|
||||
label: string,
|
||||
key: string
|
||||
}
|
||||
export type TeamTagsSchema = {
|
||||
_id: string;
|
||||
label: string;
|
||||
teamId: string;
|
||||
key: string;
|
||||
createTime: Date;
|
||||
};
|
||||
|
||||
export type TeamMemberSchema = {
|
||||
_id: string;
|
||||
@@ -26,13 +38,13 @@ export type TeamMemberSchema = {
|
||||
defaultTeam: boolean;
|
||||
};
|
||||
|
||||
export type TeamMemberWithUserSchema = TeamMemberSchema & {
|
||||
export type TeamMemberWithUserSchema = Omit<TeamMemberSchema, 'userId'> & {
|
||||
userId: UserModelSchema;
|
||||
};
|
||||
export type TeamMemberWithTeamSchema = TeamMemberSchema & {
|
||||
export type TeamMemberWithTeamSchema = Omit<TeamMemberSchema, 'teamId'> & {
|
||||
teamId: TeamSchema;
|
||||
};
|
||||
export type TeamMemberWithTeamAndUserSchema = TeamMemberWithTeamSchema & {
|
||||
export type TeamMemberWithTeamAndUserSchema = Omit<TeamMemberWithTeamSchema, 'userId'> & {
|
||||
userId: UserModelSchema;
|
||||
};
|
||||
|
||||
|
1
packages/global/support/user/type.d.ts
vendored
@@ -29,4 +29,5 @@ export type UserType = {
|
||||
promotionRate: UserModelSchema['promotionRate'];
|
||||
openaiAccount: UserModelSchema['openaiAccount'];
|
||||
team: TeamItemType;
|
||||
standardInfo?: standardInfoType;
|
||||
};
|
||||
|
37
packages/global/support/wallet/bill/api.d.ts
vendored
@@ -1,25 +1,18 @@
|
||||
import { BillSourceEnum } from './constants';
|
||||
import { BillListItemCountType, BillListItemType } from './type';
|
||||
|
||||
export type CreateTrainingBillProps = {
|
||||
name: string;
|
||||
datasetId: string;
|
||||
};
|
||||
|
||||
export type ConcatBillProps = BillListItemCountType & {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
billId?: string;
|
||||
total: number;
|
||||
listIndex?: number;
|
||||
};
|
||||
import { BillTypeEnum } from './constants';
|
||||
|
||||
export type CreateBillProps = {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
appName: string;
|
||||
appId?: string;
|
||||
total: number;
|
||||
source: `${BillSourceEnum}`;
|
||||
list: BillListItemType[];
|
||||
type: `${BillTypeEnum}`;
|
||||
|
||||
// balance
|
||||
balance?: number; // read
|
||||
|
||||
month?: number;
|
||||
// extra dataset size
|
||||
extraDatasetSize?: number; // 1k
|
||||
extraPoints?: number; // 100w
|
||||
};
|
||||
export type CreateBillResponse = {
|
||||
billId: string;
|
||||
codeUrl: string;
|
||||
readPrice: number;
|
||||
};
|
||||
|
@@ -1,34 +1,57 @@
|
||||
// model price: xxx/1k tokens
|
||||
// ¥1 = 100000.
|
||||
export const PRICE_SCALE = 100000;
|
||||
|
||||
export enum BillSourceEnum {
|
||||
fastgpt = 'fastgpt',
|
||||
api = 'api',
|
||||
shareLink = 'shareLink',
|
||||
training = 'training',
|
||||
|
||||
export enum BillTypeEnum {
|
||||
balance = 'balance',
|
||||
standSubPlan = 'standSubPlan',
|
||||
extraDatasetSub = 'extraDatasetSub'
|
||||
extraDatasetSub = 'extraDatasetSub',
|
||||
extraPoints = 'extraPoints'
|
||||
}
|
||||
|
||||
export const BillSourceMap = {
|
||||
[BillSourceEnum.fastgpt]: {
|
||||
label: '在线使用'
|
||||
export const billTypeMap = {
|
||||
[BillTypeEnum.balance]: {
|
||||
label: 'support.wallet.subscription.type.balance'
|
||||
},
|
||||
[BillSourceEnum.api]: {
|
||||
label: 'Api'
|
||||
},
|
||||
[BillSourceEnum.shareLink]: {
|
||||
label: '免登录链接'
|
||||
},
|
||||
[BillSourceEnum.training]: {
|
||||
label: 'dataset.Training Name'
|
||||
},
|
||||
[BillSourceEnum.standSubPlan]: {
|
||||
[BillTypeEnum.standSubPlan]: {
|
||||
label: 'support.wallet.subscription.type.standard'
|
||||
},
|
||||
[BillSourceEnum.extraDatasetSub]: {
|
||||
[BillTypeEnum.extraDatasetSub]: {
|
||||
label: 'support.wallet.subscription.type.extraDatasetSize'
|
||||
},
|
||||
[BillTypeEnum.extraPoints]: {
|
||||
label: 'support.wallet.subscription.type.extraPoints'
|
||||
}
|
||||
};
|
||||
|
||||
export enum BillStatusEnum {
|
||||
SUCCESS = 'SUCCESS',
|
||||
REFUND = 'REFUND',
|
||||
NOTPAY = 'NOTPAY',
|
||||
CLOSED = 'CLOSED'
|
||||
}
|
||||
export const billStatusMap = {
|
||||
[BillStatusEnum.SUCCESS]: {
|
||||
label: 'support.wallet.bill.status.success'
|
||||
},
|
||||
[BillStatusEnum.REFUND]: {
|
||||
label: 'support.wallet.bill.status.refund'
|
||||
},
|
||||
[BillStatusEnum.NOTPAY]: {
|
||||
label: 'support.wallet.bill.status.notpay'
|
||||
},
|
||||
[BillStatusEnum.CLOSED]: {
|
||||
label: 'support.wallet.bill.status.closed'
|
||||
}
|
||||
};
|
||||
|
||||
export enum BillPayWayEnum {
|
||||
balance = 'balance',
|
||||
wx = 'wx'
|
||||
}
|
||||
export const billPayWayMap = {
|
||||
[BillPayWayEnum.balance]: {
|
||||
label: 'support.wallet.bill.payWay.balance'
|
||||
},
|
||||
[BillPayWayEnum.wx]: {
|
||||
label: 'support.wallet.bill.payWay.wx'
|
||||
}
|
||||
};
|
||||
|
||||
export const SUB_DATASET_SIZE_RATE = 1000;
|
||||
export const SUB_EXTRA_POINT_RATE = 1000;
|
||||
|
@@ -1,26 +0,0 @@
|
||||
/* bill common */
|
||||
import { PRICE_SCALE } from './constants';
|
||||
import { BillSourceEnum } from './constants';
|
||||
import { AuthUserTypeEnum } from '../../permission/constant';
|
||||
|
||||
/**
|
||||
* dataset price / PRICE_SCALE = real price
|
||||
*/
|
||||
export const formatStorePrice2Read = (val = 0, multiple = 1) => {
|
||||
return Number(((val / PRICE_SCALE) * multiple).toFixed(10));
|
||||
};
|
||||
export const formatModelPrice2Read = (val = 0) => {
|
||||
return Number((val / 1000).toFixed(10));
|
||||
};
|
||||
|
||||
export const getBillSourceByAuthType = ({
|
||||
shareId,
|
||||
authType
|
||||
}: {
|
||||
shareId?: string;
|
||||
authType?: `${AuthUserTypeEnum}`;
|
||||
}) => {
|
||||
if (shareId) return BillSourceEnum.shareLink;
|
||||
if (authType === AuthUserTypeEnum.apikey) return BillSourceEnum.api;
|
||||
return BillSourceEnum.fastgpt;
|
||||
};
|
54
packages/global/support/wallet/bill/type.d.ts
vendored
@@ -1,35 +1,29 @@
|
||||
import { CreateBillProps } from './api';
|
||||
import { BillSourceEnum } from './constants';
|
||||
import { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from '../sub/constants';
|
||||
import { BillPayWayEnum, BillTypeEnum } from './constants';
|
||||
|
||||
export type BillListItemCountType = {
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
charsLength?: number;
|
||||
duration?: number;
|
||||
|
||||
// sub
|
||||
datasetSize?: number;
|
||||
|
||||
// abandon
|
||||
tokenLen?: number;
|
||||
};
|
||||
export type BillListItemType = BillListItemCountType & {
|
||||
moduleName: string;
|
||||
amount: number;
|
||||
model?: string;
|
||||
};
|
||||
|
||||
export type BillSchema = CreateBillProps & {
|
||||
export type BillSchemaType = {
|
||||
_id: string;
|
||||
time: Date;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
createTime: Date;
|
||||
orderId: string;
|
||||
status: 'SUCCESS' | 'REFUND' | 'NOTPAY' | 'CLOSED';
|
||||
type: `${BillTypeEnum}`;
|
||||
price: number;
|
||||
metadata: {
|
||||
payWay: `${BillPayWayEnum}`;
|
||||
subMode?: `${SubModeEnum}`;
|
||||
standSubLevel?: `${StandardSubLevelEnum}`;
|
||||
month?: number;
|
||||
datasetSize?: number;
|
||||
extraPoints?: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type BillItemType = {
|
||||
id: string;
|
||||
// memberName: string;
|
||||
time: Date;
|
||||
appName: string;
|
||||
source: BillSchema['source'];
|
||||
total: number;
|
||||
list: BillSchema['list'];
|
||||
export type ChatModuleBillType = {
|
||||
totalPoints: number;
|
||||
moduleName: string;
|
||||
model?: string;
|
||||
charsLength?: number;
|
||||
};
|
||||
|
3
packages/global/support/wallet/constants.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// model price: xxx/1k tokens
|
||||
// ¥1 = 100000.
|
||||
export const PRICE_SCALE = 100000;
|
@@ -1,41 +0,0 @@
|
||||
export enum PayTypeEnum {
|
||||
balance = 'balance',
|
||||
subStandard = 'subStandard',
|
||||
subExtraDatasetSize = 'subExtraDatasetSize',
|
||||
subExtraPoints = 'subExtraPoints'
|
||||
}
|
||||
export const payTypeMap = {
|
||||
[PayTypeEnum.balance]: {
|
||||
label: 'support.user.team.pay.type.balance'
|
||||
},
|
||||
[PayTypeEnum.subStandard]: {
|
||||
label: 'support.wallet.subscription.type.standard'
|
||||
},
|
||||
[PayTypeEnum.subExtraDatasetSize]: {
|
||||
label: 'support.wallet.subscription.type.extraDatasetSize'
|
||||
},
|
||||
[PayTypeEnum.subExtraPoints]: {
|
||||
label: 'support.wallet.subscription.type.extraPoints'
|
||||
}
|
||||
};
|
||||
|
||||
export enum PayStatusEnum {
|
||||
SUCCESS = 'SUCCESS',
|
||||
REFUND = 'REFUND',
|
||||
NOTPAY = 'NOTPAY',
|
||||
CLOSED = 'CLOSED'
|
||||
}
|
||||
export const payStatusMap = {
|
||||
[PayStatusEnum.SUCCESS]: {
|
||||
label: 'support.user.team.pay.status.success'
|
||||
},
|
||||
[PayStatusEnum.REFUND]: {
|
||||
label: 'support.user.team.pay.status.refund'
|
||||
},
|
||||
[PayStatusEnum.NOTPAY]: {
|
||||
label: 'support.user.team.pay.status.notpay'
|
||||
},
|
||||
[PayStatusEnum.CLOSED]: {
|
||||
label: 'support.user.team.pay.status.closed'
|
||||
}
|
||||
};
|
18
packages/global/support/wallet/pay/type.d.ts
vendored
@@ -1,18 +0,0 @@
|
||||
import { SubModeEnum, SubTypeEnum } from '../sub/constants';
|
||||
import { PayTypeEnum } from './constants';
|
||||
|
||||
export type PaySchema = {
|
||||
_id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
createTime: Date;
|
||||
orderId: string;
|
||||
status: 'SUCCESS' | 'REFUND' | 'NOTPAY' | 'CLOSED';
|
||||
type: `${PayType}`;
|
||||
|
||||
price: number;
|
||||
payWay: 'balance' | 'wx';
|
||||
|
||||
subMetadata: {};
|
||||
};
|
14
packages/global/support/wallet/sub/api.d.ts
vendored
@@ -1,26 +1,14 @@
|
||||
import { StandardSubLevelEnum, SubModeEnum } from './constants';
|
||||
import { TeamSubSchema } from './type.d';
|
||||
|
||||
export type SubDatasetSizeParams = {
|
||||
size: number;
|
||||
};
|
||||
export type StandardSubPlanParams = {
|
||||
level: `${StandardSubLevelEnum}`;
|
||||
mode: `${SubModeEnum}`;
|
||||
};
|
||||
|
||||
export type SubDatasetSizePreviewCheckResponse = {
|
||||
payForNewSub: boolean; // Does this change require payment
|
||||
newSubSize: number; // new sub dataset size
|
||||
alreadySubSize: number; // old sub dataset size
|
||||
payPrice: number; // this change require payment
|
||||
newPlanPrice: number; // the new sub price
|
||||
newSubStartTime: Date;
|
||||
newSubExpiredTime: Date;
|
||||
balanceEnough: boolean; // team balance is enough
|
||||
};
|
||||
export type StandardSubPlanUpdateResponse = {
|
||||
balanceEnough: boolean; // team balance is enough
|
||||
teamBalance: number;
|
||||
payPrice?: number;
|
||||
planPrice: number;
|
||||
planPointPrice: number;
|
||||
|
@@ -1,38 +1,36 @@
|
||||
export const POINTS_SCALE = 10000;
|
||||
|
||||
export enum SubTypeEnum {
|
||||
standard = 'standard',
|
||||
extraDatasetSize = 'extraDatasetSize',
|
||||
extraPoints = 'extraPoints'
|
||||
}
|
||||
|
||||
export const subTypeMap = {
|
||||
[SubTypeEnum.standard]: {
|
||||
label: 'support.wallet.subscription.type.standard'
|
||||
label: 'support.wallet.subscription.type.standard',
|
||||
icon: 'support/account/plans'
|
||||
},
|
||||
[SubTypeEnum.extraDatasetSize]: {
|
||||
label: 'support.wallet.subscription.type.extraDatasetSize'
|
||||
label: 'support.wallet.subscription.type.extraDatasetSize',
|
||||
icon: 'core/dataset/datasetLight'
|
||||
},
|
||||
[SubTypeEnum.extraPoints]: {
|
||||
label: 'support.wallet.subscription.type.extraPoints'
|
||||
label: 'support.wallet.subscription.type.extraPoints',
|
||||
icon: 'core/chat/chatLight'
|
||||
}
|
||||
};
|
||||
|
||||
export enum SubStatusEnum {
|
||||
active = 'active',
|
||||
canceled = 'canceled'
|
||||
expired = 'expired'
|
||||
}
|
||||
export const subStatusMap = {
|
||||
[SubStatusEnum.active]: {
|
||||
label: 'support.wallet.subscription.status.active'
|
||||
},
|
||||
[SubStatusEnum.canceled]: {
|
||||
[SubStatusEnum.expired]: {
|
||||
label: 'support.wallet.subscription.status.canceled'
|
||||
}
|
||||
};
|
||||
export const subSelectMap = {
|
||||
true: SubStatusEnum.active,
|
||||
false: SubStatusEnum.canceled
|
||||
};
|
||||
|
||||
export enum SubModeEnum {
|
||||
month = 'month',
|
||||
@@ -40,11 +38,11 @@ export enum SubModeEnum {
|
||||
}
|
||||
export const subModeMap = {
|
||||
[SubModeEnum.month]: {
|
||||
label: 'support.wallet.subscription.mode.month',
|
||||
label: 'support.wallet.subscription.mode.Month',
|
||||
durationMonth: 1
|
||||
},
|
||||
[SubModeEnum.year]: {
|
||||
label: 'support.wallet.subscription.mode.year',
|
||||
label: 'support.wallet.subscription.mode.Year',
|
||||
durationMonth: 12
|
||||
}
|
||||
};
|
||||
@@ -63,7 +61,7 @@ export const standardSubLevelMap = {
|
||||
},
|
||||
[StandardSubLevelEnum.experience]: {
|
||||
label: 'support.wallet.subscription.standardSubLevel.experience',
|
||||
desc: 'support.wallet.subscription.standardSubLevel.experience desc'
|
||||
desc: ''
|
||||
},
|
||||
[StandardSubLevelEnum.team]: {
|
||||
label: 'support.wallet.subscription.standardSubLevel.team',
|
||||
|
41
packages/global/support/wallet/sub/type.d.ts
vendored
@@ -2,19 +2,19 @@ import { StandardSubLevelEnum, SubModeEnum, SubStatusEnum, SubTypeEnum } from '.
|
||||
|
||||
// Content of plan
|
||||
export type TeamStandardSubPlanItemType = {
|
||||
price: number; // read price
|
||||
pointPrice: number; // read price/ one ten thousand
|
||||
price: number; // read price / month
|
||||
pointPrice: number; // read price/ one thousand
|
||||
totalPoints: number; // n
|
||||
maxTeamMember: number;
|
||||
maxAppAmount: number; // max app or plugin amount
|
||||
maxDatasetAmount: number;
|
||||
chatHistoryStoreDuration: number; // n day
|
||||
maxDatasetSize: number;
|
||||
customApiKey: boolean;
|
||||
customCopyright: boolean; // feature
|
||||
websiteSyncInterval: number; // n hours
|
||||
trainingWeight: number; // 1~4
|
||||
reRankWeight: number; // 1~4
|
||||
totalPoints: number; // n ten thousand
|
||||
permissionCustomApiKey: boolean;
|
||||
permissionCustomCopyright: boolean; // feature
|
||||
permissionWebsiteSync: boolean;
|
||||
permissionReRank: boolean;
|
||||
};
|
||||
|
||||
export type StandSubPlanLevelMapType = Record<
|
||||
@@ -27,6 +27,9 @@ export type SubPlanType = {
|
||||
[SubTypeEnum.extraDatasetSize]: {
|
||||
price: number;
|
||||
};
|
||||
[SubTypeEnum.extraPoints]: {
|
||||
price: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type TeamSubSchema = {
|
||||
@@ -34,40 +37,30 @@ export type TeamSubSchema = {
|
||||
teamId: string;
|
||||
type: `${SubTypeEnum}`;
|
||||
status: `${SubStatusEnum}`;
|
||||
currentMode: `${SubModeEnum}`;
|
||||
nextMode: `${SubModeEnum}`;
|
||||
startTime: Date;
|
||||
expiredTime: Date;
|
||||
price: number;
|
||||
|
||||
currentMode: `${SubModeEnum}`;
|
||||
nextMode: `${SubModeEnum}`;
|
||||
currentSubLevel: `${StandardSubLevelEnum}`;
|
||||
nextSubLevel: `${StandardSubLevelEnum}`;
|
||||
|
||||
pointPrice: number;
|
||||
totalPoints: number;
|
||||
|
||||
currentExtraDatasetSize: number;
|
||||
nextExtraDatasetSize: number;
|
||||
|
||||
currentExtraPoints: number;
|
||||
nextExtraPoints: number;
|
||||
|
||||
surplusPoints: number;
|
||||
|
||||
// abandon
|
||||
datasetStoreAmount?: number;
|
||||
renew?: boolean;
|
||||
currentExtraDatasetSize: number;
|
||||
};
|
||||
|
||||
export type FeTeamSubType = {
|
||||
export type FeTeamPlanStatusType = {
|
||||
[SubTypeEnum.standard]?: TeamSubSchema;
|
||||
[SubTypeEnum.extraDatasetSize]?: TeamSubSchema;
|
||||
[SubTypeEnum.extraPoints]?: TeamSubSchema;
|
||||
standardConstants?: TeamStandardSubPlanItemType;
|
||||
|
||||
standardMaxDatasetSize: number;
|
||||
totalPoints: number;
|
||||
usedPoints: number;
|
||||
|
||||
standardMaxPoints: number;
|
||||
// standard + extra
|
||||
datasetMaxSize: number;
|
||||
usedDatasetSize: number;
|
||||
};
|
||||
|
26
packages/global/support/wallet/usage/api.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import { UsageSourceEnum } from './constants';
|
||||
import { UsageListItemCountType, UsageListItemType } from './type';
|
||||
|
||||
export type CreateTrainingUsageProps = {
|
||||
name: string;
|
||||
datasetId: string;
|
||||
};
|
||||
|
||||
export type ConcatUsageProps = UsageListItemCountType & {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
billId?: string;
|
||||
totalPoints: number;
|
||||
listIndex?: number;
|
||||
};
|
||||
|
||||
export type CreateUsageProps = {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
appName: string;
|
||||
appId?: string;
|
||||
totalPoints: number;
|
||||
// inputTokens: number;
|
||||
source: `${UsageSourceEnum}`;
|
||||
list: UsageListItemType[];
|
||||
};
|
21
packages/global/support/wallet/usage/constants.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export enum UsageSourceEnum {
|
||||
fastgpt = 'fastgpt',
|
||||
api = 'api',
|
||||
shareLink = 'shareLink',
|
||||
training = 'training'
|
||||
}
|
||||
|
||||
export const UsageSourceMap = {
|
||||
[UsageSourceEnum.fastgpt]: {
|
||||
label: '在线使用'
|
||||
},
|
||||
[UsageSourceEnum.api]: {
|
||||
label: 'Api'
|
||||
},
|
||||
[UsageSourceEnum.shareLink]: {
|
||||
label: '免登录链接'
|
||||
},
|
||||
[UsageSourceEnum.training]: {
|
||||
label: 'dataset.Training Name'
|
||||
}
|
||||
};
|
23
packages/global/support/wallet/usage/tools.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/* bill common */
|
||||
import { PRICE_SCALE } from '../constants';
|
||||
import { UsageSourceEnum } from './constants';
|
||||
import { AuthUserTypeEnum } from '../../permission/constant';
|
||||
|
||||
/**
|
||||
* dataset price / PRICE_SCALE = real price
|
||||
*/
|
||||
export const formatStorePrice2Read = (val = 0, multiple = 1) => {
|
||||
return Number(((val / PRICE_SCALE) * multiple).toFixed(10));
|
||||
};
|
||||
|
||||
export const getUsageSourceByAuthType = ({
|
||||
shareId,
|
||||
authType
|
||||
}: {
|
||||
shareId?: string;
|
||||
authType?: `${AuthUserTypeEnum}`;
|
||||
}) => {
|
||||
if (shareId) return UsageSourceEnum.shareLink;
|
||||
if (authType === AuthUserTypeEnum.apikey) return UsageSourceEnum.api;
|
||||
return UsageSourceEnum.fastgpt;
|
||||
};
|
26
packages/global/support/wallet/usage/type.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import { CreateUsageProps } from './api';
|
||||
import { UsageSourceEnum } from './constants';
|
||||
|
||||
export type UsageListItemCountType = {
|
||||
charsLength?: number;
|
||||
duration?: number;
|
||||
};
|
||||
export type UsageListItemType = UsageListItemCountType & {
|
||||
moduleName: string;
|
||||
amount: number;
|
||||
model?: string;
|
||||
};
|
||||
|
||||
export type UsageSchemaType = CreateUsageProps & {
|
||||
_id: string;
|
||||
time: Date;
|
||||
};
|
||||
|
||||
export type UsageItemType = {
|
||||
id: string;
|
||||
time: Date;
|
||||
appName: string;
|
||||
source: UsageSchemaType['source'];
|
||||
totalPoints: number;
|
||||
list: UsageSchemaType['list'];
|
||||
};
|
@@ -3,7 +3,7 @@ import { sseResponseEventEnum } from './constant';
|
||||
import { proxyError, ERROR_RESPONSE, ERROR_ENUM } from '@fastgpt/global/common/error/errorCode';
|
||||
import { addLog } from '../system/log';
|
||||
import { clearCookie } from '../../support/permission/controller';
|
||||
import { replaceSensitiveLink } from '@fastgpt/global/common/string/tools';
|
||||
import { replaceSensitiveText } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
export interface ResponseType<T = any> {
|
||||
code: number;
|
||||
@@ -53,7 +53,7 @@ export const jsonRes = <T = any>(
|
||||
res.status(code).json({
|
||||
code,
|
||||
statusText: '',
|
||||
message: replaceSensitiveLink(message || msg),
|
||||
message: replaceSensitiveText(message || msg),
|
||||
data: data !== undefined ? data : null
|
||||
});
|
||||
};
|
||||
@@ -91,7 +91,7 @@ export const sseErrRes = (res: NextApiResponse, error: any) => {
|
||||
responseWrite({
|
||||
res,
|
||||
event: sseResponseEventEnum.error,
|
||||
data: JSON.stringify({ message: replaceSensitiveLink(msg) })
|
||||
data: JSON.stringify({ message: replaceSensitiveText(msg) })
|
||||
});
|
||||
};
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { FastGPTConfigFileType } from '@fastgpt/global/common/system/types';
|
||||
import { isIPv6 } from 'net';
|
||||
|
||||
export const SERVICE_LOCAL_PORT = `${process.env.PORT || 3000}`;
|
||||
@@ -5,3 +6,16 @@ export const SERVICE_LOCAL_HOST =
|
||||
process.env.HOSTNAME && isIPv6(process.env.HOSTNAME)
|
||||
? `[${process.env.HOSTNAME}]:${SERVICE_LOCAL_PORT}`
|
||||
: `${process.env.HOSTNAME || 'localhost'}:${SERVICE_LOCAL_PORT}`;
|
||||
|
||||
export const initFastGPTConfig = (config?: FastGPTConfigFileType) => {
|
||||
if (!config) return;
|
||||
|
||||
global.feConfigs = config.feConfigs;
|
||||
global.subPlans = config.subPlans;
|
||||
|
||||
global.llmModels = config.llmModels;
|
||||
global.vectorModels = config.vectorModels;
|
||||
global.audioSpeechModels = config.audioSpeechModels;
|
||||
global.whisperModel = config.whisperModel;
|
||||
global.reRankModels = config.reRankModels;
|
||||
};
|
||||
|
@@ -11,7 +11,6 @@ const getVectorObj = () => {
|
||||
export const initVectorStore = getVectorObj().init;
|
||||
export const deleteDatasetDataVector = getVectorObj().delete;
|
||||
export const recallFromVectorStore = getVectorObj().recall;
|
||||
export const checkVectorDataExist = getVectorObj().checkDataExist;
|
||||
export const getVectorDataByTime = getVectorObj().getVectorDataByTime;
|
||||
export const getVectorCountByTeamId = getVectorObj().getVectorCountByTeamId;
|
||||
|
||||
@@ -38,22 +37,22 @@ export const insertDatasetDataVector = async ({
|
||||
};
|
||||
};
|
||||
|
||||
export const updateDatasetDataVector = async ({
|
||||
id,
|
||||
...props
|
||||
}: InsertVectorProps & {
|
||||
id: string;
|
||||
query: string;
|
||||
model: VectorModelItemType;
|
||||
}) => {
|
||||
// insert new vector
|
||||
const { charsLength, insertId } = await insertDatasetDataVector(props);
|
||||
// export const updateDatasetDataVector = async ({
|
||||
// id,
|
||||
// ...props
|
||||
// }: InsertVectorProps & {
|
||||
// id: string;
|
||||
// query: string;
|
||||
// model: VectorModelItemType;
|
||||
// }) => {
|
||||
// // insert new vector
|
||||
// const { charsLength, insertId } = await insertDatasetDataVector(props);
|
||||
|
||||
// delete old vector
|
||||
await deleteDatasetDataVector({
|
||||
teamId: props.teamId,
|
||||
id
|
||||
});
|
||||
// // delete old vector
|
||||
// await deleteDatasetDataVector({
|
||||
// teamId: props.teamId,
|
||||
// id
|
||||
// });
|
||||
|
||||
return { charsLength, insertId };
|
||||
};
|
||||
// return { charsLength, insertId };
|
||||
// };
|
||||
|
@@ -4,8 +4,7 @@ import {
|
||||
deleteDatasetDataVector,
|
||||
embeddingRecall,
|
||||
getVectorDataByTime,
|
||||
getVectorCountByTeamId,
|
||||
checkDataExist
|
||||
getVectorCountByTeamId
|
||||
} from './controller';
|
||||
|
||||
export class PgVector {
|
||||
@@ -14,7 +13,6 @@ export class PgVector {
|
||||
insert = insertDatasetDataVector;
|
||||
delete = deleteDatasetDataVector;
|
||||
recall = embeddingRecall;
|
||||
checkDataExist = checkDataExist;
|
||||
getVectorCountByTeamId = getVectorCountByTeamId;
|
||||
getVectorDataByTime = getVectorDataByTime;
|
||||
}
|
||||
|
@@ -25,6 +25,18 @@ export async function initPg() {
|
||||
await PgClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS vector_index ON ${PgDatasetTableName} USING hnsw (vector vector_ip_ops) WITH (m = 32, ef_construction = 64);`
|
||||
);
|
||||
await PgClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS team_dataset_index ON ${PgDatasetTableName} USING btree(team_id, dataset_id);`
|
||||
);
|
||||
await PgClient.query(
|
||||
` CREATE INDEX CONCURRENTLY IF NOT EXISTS team_collection_index ON ${PgDatasetTableName} USING btree(team_id, collection_id);`
|
||||
);
|
||||
await PgClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS team_id_index ON ${PgDatasetTableName} USING btree(team_id, id);`
|
||||
);
|
||||
await PgClient.query(
|
||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS create_time_index ON ${PgDatasetTableName} USING btree(createtime);`
|
||||
);
|
||||
|
||||
console.log('init pg successful');
|
||||
} catch (error) {
|
||||
@@ -152,11 +164,6 @@ export const embeddingRecall = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const checkDataExist = async (id: string) => {
|
||||
const { rows } = await PgClient.query(`SELECT id FROM ${PgDatasetTableName} WHERE id=${id};`);
|
||||
|
||||
return rows.length > 0;
|
||||
};
|
||||
export const getVectorCountByTeamId = async (teamId: string) => {
|
||||
const total = await PgClient.count(PgDatasetTableName, {
|
||||
where: [['team_id', String(teamId)]]
|
||||
|
@@ -11,6 +11,7 @@ export const getAIApi = (props?: {
|
||||
timeout?: number;
|
||||
}) => {
|
||||
const { userKey, timeout } = props || {};
|
||||
|
||||
return new OpenAI({
|
||||
apiKey: userKey?.key || systemAIChatKey,
|
||||
baseURL: userKey?.baseUrl || baseUrl,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { VectorModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
import { getAIApi } from '../config';
|
||||
import { replaceValidChars } from '../../chat/utils';
|
||||
|
||||
type GetVectorProps = {
|
||||
model: VectorModelItemType;
|
||||
@@ -36,7 +37,7 @@ export async function getVectorsByText({ model, input }: GetVectorProps) {
|
||||
}
|
||||
|
||||
return {
|
||||
charsLength: input.length,
|
||||
charsLength: replaceValidChars(input).length,
|
||||
vectors: await Promise.all(res.data.map((item) => unityDimensional(item.embedding)))
|
||||
};
|
||||
});
|
||||
|
@@ -1,159 +0,0 @@
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { getAIApi } from '../config';
|
||||
import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
|
||||
/*
|
||||
cfr: coreference resolution - 指代消除
|
||||
可以根据上下文,完事当前问题指代内容,利于检索。
|
||||
*/
|
||||
|
||||
const defaultPrompt = `请不要回答任何问题。
|
||||
你的任务是结合历史记录,为当前问题,实现代词替换,确保问题描述的对象清晰明确。例如:
|
||||
历史记录:
|
||||
"""
|
||||
Q: 对话背景。
|
||||
A: 关于 FatGPT 的介绍和使用等问题。
|
||||
"""
|
||||
当前问题: 怎么下载
|
||||
输出: FastGPT 怎么下载?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 报错 "no connection"
|
||||
A: FastGPT 报错"no connection"可能是因为……
|
||||
"""
|
||||
当前问题: 怎么解决
|
||||
输出: FastGPT 报错"no connection"如何解决?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 作者是谁?
|
||||
A: FastGPT 的作者是 labring。
|
||||
"""
|
||||
当前问题: 介绍下他
|
||||
输出: 介绍下 FastGPT 的作者 labring。
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 作者是谁?
|
||||
A: FastGPT 的作者是 labring。
|
||||
"""
|
||||
当前问题: 我想购买商业版。
|
||||
输出: FastGPT 商业版如何购买?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 对话背景。
|
||||
A: 关于 FatGPT 的介绍和使用等问题。
|
||||
"""
|
||||
当前问题: nh
|
||||
输出: nh
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: FastGPT 如何收费?
|
||||
A: FastGPT 收费可以参考……
|
||||
"""
|
||||
当前问题: 你知道 laf 么?
|
||||
输出: 你知道 laf 么?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: FastGPT 的优势
|
||||
A: 1. 开源
|
||||
2. 简便
|
||||
3. 扩展性强
|
||||
"""
|
||||
当前问题: 介绍下第2点。
|
||||
输出: 介绍下 FastGPT 简便的优势。
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 什么是 FastGPT?
|
||||
A: FastGPT 是一个 RAG 平台。
|
||||
Q: 什么是 Sealos?
|
||||
A: Sealos 是一个云操作系统。
|
||||
"""
|
||||
当前问题: 它们有什么关系?
|
||||
输出: FastGPT 和 Sealos 有什么关系?
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
{{histories}}
|
||||
"""
|
||||
当前问题: {{query}}
|
||||
输出: `;
|
||||
|
||||
export const queryCfr = async ({
|
||||
chatBg,
|
||||
query,
|
||||
histories = [],
|
||||
model
|
||||
}: {
|
||||
chatBg?: string;
|
||||
query: string;
|
||||
histories: ChatItemType[];
|
||||
model: string;
|
||||
}) => {
|
||||
if (histories.length === 0 && !chatBg) {
|
||||
return {
|
||||
rawQuery: query,
|
||||
cfrQuery: query,
|
||||
model,
|
||||
inputTokens: 0,
|
||||
outputTokens: 0
|
||||
};
|
||||
}
|
||||
|
||||
const systemFewShot = chatBg
|
||||
? `Q: 对话背景。
|
||||
A: ${chatBg}
|
||||
`
|
||||
: '';
|
||||
const historyFewShot = histories
|
||||
.map((item) => {
|
||||
const role = item.obj === 'Human' ? 'Q' : 'A';
|
||||
return `${role}: ${item.value}`;
|
||||
})
|
||||
.join('\n');
|
||||
const concatFewShot = `${systemFewShot}${historyFewShot}`.trim();
|
||||
|
||||
const ai = getAIApi({
|
||||
timeout: 480000
|
||||
});
|
||||
|
||||
const result = await ai.chat.completions.create({
|
||||
model: model,
|
||||
temperature: 0.01,
|
||||
max_tokens: 150,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: replaceVariable(defaultPrompt, {
|
||||
query: `${query}`,
|
||||
histories: concatFewShot
|
||||
})
|
||||
}
|
||||
],
|
||||
stream: false
|
||||
});
|
||||
|
||||
const answer = result.choices?.[0]?.message?.content || '';
|
||||
if (!answer) {
|
||||
return {
|
||||
rawQuery: query,
|
||||
cfrQuery: query,
|
||||
model,
|
||||
inputTokens: 0,
|
||||
outputTokens: 0
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
rawQuery: query,
|
||||
cfrQuery: answer,
|
||||
model,
|
||||
inputTokens: result.usage?.prompt_tokens || 0,
|
||||
outputTokens: result.usage?.completion_tokens || 0
|
||||
};
|
||||
};
|
@@ -1,5 +1,6 @@
|
||||
import type { ChatMessageItemType } from '@fastgpt/global/core/ai/type.d';
|
||||
import { getAIApi } from '../config';
|
||||
import { countGptMessagesChars } from '../../chat/utils';
|
||||
|
||||
export const Prompt_QuestionGuide = `我不太清楚问你什么问题,请帮我生成 3 个问题,引导我继续提问。问题的长度应小于20个字符,按 JSON 格式返回: ["问题1", "问题2", "问题3"]`;
|
||||
|
||||
@@ -10,6 +11,13 @@ export async function createQuestionGuide({
|
||||
messages: ChatMessageItemType[];
|
||||
model: string;
|
||||
}) {
|
||||
const concatMessages: ChatMessageItemType[] = [
|
||||
...messages,
|
||||
{
|
||||
role: 'user',
|
||||
content: Prompt_QuestionGuide
|
||||
}
|
||||
];
|
||||
const ai = getAIApi({
|
||||
timeout: 480000
|
||||
});
|
||||
@@ -17,28 +25,21 @@ export async function createQuestionGuide({
|
||||
model: model,
|
||||
temperature: 0.1,
|
||||
max_tokens: 200,
|
||||
messages: [
|
||||
...messages,
|
||||
{
|
||||
role: 'user',
|
||||
content: Prompt_QuestionGuide
|
||||
}
|
||||
],
|
||||
messages: concatMessages,
|
||||
stream: false
|
||||
});
|
||||
|
||||
const answer = data.choices?.[0]?.message?.content || '';
|
||||
const inputTokens = data.usage?.prompt_tokens || 0;
|
||||
const outputTokens = data.usage?.completion_tokens || 0;
|
||||
|
||||
const start = answer.indexOf('[');
|
||||
const end = answer.lastIndexOf(']');
|
||||
|
||||
const charsLength = countGptMessagesChars(concatMessages);
|
||||
|
||||
if (start === -1 || end === -1) {
|
||||
return {
|
||||
result: [],
|
||||
inputTokens,
|
||||
outputTokens
|
||||
charsLength: 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,14 +51,12 @@ export async function createQuestionGuide({
|
||||
try {
|
||||
return {
|
||||
result: JSON.parse(jsonStr),
|
||||
inputTokens,
|
||||
outputTokens
|
||||
charsLength
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
result: [],
|
||||
inputTokens,
|
||||
outputTokens
|
||||
charsLength: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,19 @@
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { getAIApi } from '../config';
|
||||
import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { countGptMessagesChars } from '../../chat/utils';
|
||||
|
||||
/*
|
||||
query extension - 问题扩展
|
||||
可以根据上下文,消除指代性问题以及扩展问题,利于检索。
|
||||
*/
|
||||
|
||||
const defaultPrompt = `作为一个向量检索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高向量检索的语义丰富度,提高向量检索的精度。生成的问题要求指向对象清晰明确。例如:
|
||||
const defaultPrompt = `作为一个向量检索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高向量检索的语义丰富度,提高向量检索的精度。生成的问题要求指向对象清晰明确,并与原问题语言相同。例如:
|
||||
历史记录:
|
||||
"""
|
||||
"""
|
||||
原问题: 介绍下剧情。
|
||||
检索词: ["发生了什么故事?","故事梗概是什么?","讲述了什么故事?"]
|
||||
检索词: ["介绍下故事的背景和主要人物。","故事的主题是什么?","剧情是是如何发展的?"]
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
@@ -20,7 +21,7 @@ Q: 对话背景。
|
||||
A: 当前对话是关于 FatGPT 的介绍和使用等。
|
||||
"""
|
||||
原问题: 怎么下载
|
||||
检索词: ["FastGPT 怎么下载?","下载 FastGPT 需要什么条件?","有哪些渠道可以下载 FastGPT?"]
|
||||
检索词: ["FastGPT 如何下载?","下载 FastGPT 需要什么条件?","有哪些渠道可以下载 FastGPT?"]
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
@@ -30,15 +31,15 @@ Q: 报错 "no connection"
|
||||
A: 报错"no connection"可能是因为……
|
||||
"""
|
||||
原问题: 怎么解决
|
||||
检索词: ["FastGPT 报错"no connection"如何解决?", "报错 'no connection' 是什么原因?", "FastGPT提示'no connection',要怎么办?"]
|
||||
检索词: ["FastGPT 报错"no connection"如何解决?", "造成 'no connection' 报错的原因。", "FastGPT提示'no connection',要怎么办?"]
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 作者是谁?
|
||||
A: FastGPT 的作者是 labring。
|
||||
"""
|
||||
原问题: 介绍下他
|
||||
检索词: ["介绍下 FastGPT 的作者 labring。","作者 labring 的背景信息。","labring 为什么要做 FastGPT?"]
|
||||
原问题: Tell me about him
|
||||
检索词: ["Introduce labring, the author of FastGPT." ," Background information on author labring." "," Why does labring do FastGPT?"]
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
@@ -105,8 +106,7 @@ export const queryExtension = async ({
|
||||
rawQuery: string;
|
||||
extensionQueries: string[];
|
||||
model: string;
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
charsLength: number;
|
||||
}> => {
|
||||
const systemFewShot = chatBg
|
||||
? `Q: 对话背景。
|
||||
@@ -125,18 +125,20 @@ A: ${chatBg}
|
||||
timeout: 480000
|
||||
});
|
||||
|
||||
const messages = [
|
||||
{
|
||||
role: 'user',
|
||||
content: replaceVariable(defaultPrompt, {
|
||||
query: `${query}`,
|
||||
histories: concatFewShot
|
||||
})
|
||||
}
|
||||
];
|
||||
const result = await ai.chat.completions.create({
|
||||
model: model,
|
||||
temperature: 0.01,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: replaceVariable(defaultPrompt, {
|
||||
query: `${query}`,
|
||||
histories: concatFewShot
|
||||
})
|
||||
}
|
||||
],
|
||||
// @ts-ignore
|
||||
messages,
|
||||
stream: false
|
||||
});
|
||||
|
||||
@@ -146,8 +148,7 @@ A: ${chatBg}
|
||||
rawQuery: query,
|
||||
extensionQueries: [],
|
||||
model,
|
||||
inputTokens: 0,
|
||||
outputTokens: 0
|
||||
charsLength: 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -160,8 +161,7 @@ A: ${chatBg}
|
||||
rawQuery: query,
|
||||
extensionQueries: queries,
|
||||
model,
|
||||
inputTokens: result.usage?.prompt_tokens || 0,
|
||||
outputTokens: result.usage?.completion_tokens || 0
|
||||
charsLength: countGptMessagesChars(messages)
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
@@ -169,8 +169,7 @@ A: ${chatBg}
|
||||
rawQuery: query,
|
||||
extensionQueries: [],
|
||||
model,
|
||||
inputTokens: 0,
|
||||
outputTokens: 0
|
||||
charsLength: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
|
42
packages/service/core/ai/model.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
export const getLLMModel = (model?: string) => {
|
||||
return global.llmModels.find((item) => item.model === model) ?? global.llmModels[0];
|
||||
};
|
||||
export const getDatasetModel = (model?: string) => {
|
||||
return (
|
||||
global.llmModels?.filter((item) => item.datasetProcess)?.find((item) => item.model === model) ??
|
||||
global.llmModels[0]
|
||||
);
|
||||
};
|
||||
|
||||
export const getVectorModel = (model?: string) => {
|
||||
return global.vectorModels.find((item) => item.model === model) || global.vectorModels[0];
|
||||
};
|
||||
|
||||
export function getAudioSpeechModel(model?: string) {
|
||||
return (
|
||||
global.audioSpeechModels.find((item) => item.model === model) || global.audioSpeechModels[0]
|
||||
);
|
||||
}
|
||||
|
||||
export function getWhisperModel(model?: string) {
|
||||
return global.whisperModel;
|
||||
}
|
||||
|
||||
export function getReRankModel(model?: string) {
|
||||
return global.reRankModels.find((item) => item.model === model);
|
||||
}
|
||||
|
||||
export enum ModelTypeEnum {
|
||||
llm = 'llm',
|
||||
vector = 'vector',
|
||||
audioSpeech = 'audioSpeech',
|
||||
whisper = 'whisper',
|
||||
rerank = 'rerank'
|
||||
}
|
||||
export const getModelMap = {
|
||||
[ModelTypeEnum.llm]: getLLMModel,
|
||||
[ModelTypeEnum.vector]: getVectorModel,
|
||||
[ModelTypeEnum.audioSpeech]: getAudioSpeechModel,
|
||||
[ModelTypeEnum.whisper]: getWhisperModel,
|
||||
[ModelTypeEnum.rerank]: getReRankModel
|
||||
};
|
@@ -61,6 +61,9 @@ const AppSchema = new Schema({
|
||||
type: String,
|
||||
enum: Object.keys(PermissionTypeMap),
|
||||
default: PermissionTypeEnum.private
|
||||
},
|
||||
teamTags: {
|
||||
type: [String]
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -92,6 +92,8 @@ try {
|
||||
ChatItemSchema.index({ appId: 1, chatId: 1, dataId: 1 }, { background: true });
|
||||
// admin charts
|
||||
ChatItemSchema.index({ time: -1, obj: 1 }, { background: true });
|
||||
// timer, clear history
|
||||
ChatItemSchema.index({ teamId: 1, time: -1 }, { background: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@@ -83,6 +83,9 @@ try {
|
||||
ChatSchema.index({ teamId: 1, appId: 1, updateTime: -1 }, { background: true });
|
||||
// get share chat history
|
||||
ChatSchema.index({ shareId: 1, outLinkUid: 1, updateTime: -1, source: 1 }, { background: true });
|
||||
|
||||
// timer, clear history
|
||||
ChatSchema.index({ teamId: 1, updateTime: -1 }, { background: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@@ -2,7 +2,10 @@ import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { ChatRoleEnum, IMG_BLOCK_KEY } from '@fastgpt/global/core/chat/constants';
|
||||
import { countMessagesTokens, countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
||||
import { adaptRole_Chat2Message } from '@fastgpt/global/core/chat/adapt';
|
||||
import type { ChatCompletionContentPart } from '@fastgpt/global/core/ai/type.d';
|
||||
import type {
|
||||
ChatCompletionContentPart,
|
||||
ChatMessageItemType
|
||||
} from '@fastgpt/global/core/ai/type.d';
|
||||
import axios from 'axios';
|
||||
|
||||
/* slice chat context by tokens */
|
||||
@@ -56,6 +59,16 @@ export function ChatContextFilter({
|
||||
return [...systemPrompts, ...chats];
|
||||
}
|
||||
|
||||
export const replaceValidChars = (str: string) => {
|
||||
const reg = /[\s\r\n]+/g;
|
||||
return str.replace(reg, '');
|
||||
};
|
||||
export const countMessagesChars = (messages: ChatItemType[]) => {
|
||||
return messages.reduce((sum, item) => sum + replaceValidChars(item.value).length, 0);
|
||||
};
|
||||
export const countGptMessagesChars = (messages: ChatMessageItemType[]) =>
|
||||
messages.reduce((sum, item) => sum + replaceValidChars(item.content).length, 0);
|
||||
|
||||
/**
|
||||
string to vision model. Follow the markdown code block rule for interception:
|
||||
|
||||
|
@@ -147,8 +147,6 @@ export async function delCollectionAndRelatedSources({
|
||||
collectionId: { $in: collectionIds }
|
||||
});
|
||||
|
||||
await delay(2000);
|
||||
|
||||
// delete dataset.datas
|
||||
await MongoDatasetData.deleteMany({ teamId, collectionId: { $in: collectionIds } }, { session });
|
||||
// delete imgs
|
||||
|
@@ -66,6 +66,11 @@ export async function delDatasetRelevantData({
|
||||
if (!datasets.length) return;
|
||||
|
||||
const teamId = datasets[0].teamId;
|
||||
|
||||
if (!teamId) {
|
||||
return Promise.reject('teamId is required');
|
||||
}
|
||||
|
||||
const datasetIds = datasets.map((item) => String(item._id));
|
||||
|
||||
// Get _id, teamId, fileId, metadata.relatedImgId for all collections
|
||||
|
@@ -7,10 +7,6 @@ import {
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
import { DatasetCollectionName } from '../schema';
|
||||
import { DatasetColCollectionName } from '../collection/schema';
|
||||
import {
|
||||
DatasetDataIndexTypeEnum,
|
||||
DatasetDataIndexTypeMap
|
||||
} from '@fastgpt/global/core/dataset/constants';
|
||||
|
||||
export const DatasetDataCollectionName = 'dataset.datas';
|
||||
|
||||
@@ -54,11 +50,6 @@ const DatasetDataSchema = new Schema({
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: Object.keys(DatasetDataIndexTypeMap),
|
||||
default: DatasetDataIndexTypeEnum.custom
|
||||
},
|
||||
dataId: {
|
||||
type: String,
|
||||
required: true
|
||||
|
@@ -14,22 +14,54 @@ export const datasetSearchQueryExtension = async ({
|
||||
extensionBg?: string;
|
||||
histories?: ChatItemType[];
|
||||
}) => {
|
||||
// concat query
|
||||
let queries = [query];
|
||||
let rewriteQuery =
|
||||
histories.length > 0
|
||||
? `${histories
|
||||
.map((item) => {
|
||||
return `${item.obj}: ${item.value}`;
|
||||
})
|
||||
.join('\n')}
|
||||
Human: ${query}
|
||||
`
|
||||
: query;
|
||||
const filterSamQuery = (queries: string[]) => {
|
||||
const set = new Set<string>();
|
||||
const filterSameQueries = queries.filter((item) => {
|
||||
// 删除所有的标点符号与空格等,只对文本进行比较
|
||||
const str = hashStr(item.replace(/[^\p{L}\p{N}]/gu, ''));
|
||||
if (set.has(str)) return false;
|
||||
set.add(str);
|
||||
return true;
|
||||
});
|
||||
|
||||
return filterSameQueries;
|
||||
};
|
||||
|
||||
let { queries, rewriteQuery, alreadyExtension } = (() => {
|
||||
// concat query
|
||||
let rewriteQuery =
|
||||
histories.length > 0
|
||||
? `${histories
|
||||
.map((item) => {
|
||||
return `${item.obj}: ${item.value}`;
|
||||
})
|
||||
.join('\n')}
|
||||
Human: ${query}
|
||||
`
|
||||
: query;
|
||||
|
||||
/* if query already extension, direct parse */
|
||||
try {
|
||||
const jsonParse = JSON.parse(query);
|
||||
const queries: string[] = Array.isArray(jsonParse) ? filterSamQuery(jsonParse) : [query];
|
||||
const alreadyExtension = Array.isArray(jsonParse);
|
||||
return {
|
||||
queries,
|
||||
rewriteQuery: alreadyExtension ? queries.join('\n') : rewriteQuery,
|
||||
alreadyExtension: alreadyExtension
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
queries: [query],
|
||||
rewriteQuery,
|
||||
alreadyExtension: false
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
// ai extension
|
||||
const aiExtensionResult = await (async () => {
|
||||
if (!extensionModel) return;
|
||||
if (!extensionModel || alreadyExtension) return;
|
||||
const result = await queryExtension({
|
||||
chatBg: extensionBg,
|
||||
query,
|
||||
@@ -39,23 +71,13 @@ export const datasetSearchQueryExtension = async ({
|
||||
if (result.extensionQueries?.length === 0) return;
|
||||
return result;
|
||||
})();
|
||||
|
||||
if (aiExtensionResult) {
|
||||
queries = queries.concat(aiExtensionResult.extensionQueries);
|
||||
queries = filterSamQuery(queries.concat(aiExtensionResult.extensionQueries));
|
||||
rewriteQuery = queries.join('\n');
|
||||
}
|
||||
|
||||
const set = new Set<string>();
|
||||
const filterSameQueries = queries.filter((item) => {
|
||||
// 删除所有的标点符号与空格等,只对文本进行比较
|
||||
const str = hashStr(item.replace(/[^\p{L}\p{N}]/gu, ''));
|
||||
if (set.has(str)) return false;
|
||||
set.add(str);
|
||||
return true;
|
||||
});
|
||||
|
||||
return {
|
||||
concatQueries: filterSameQueries,
|
||||
concatQueries: queries,
|
||||
rewriteQuery,
|
||||
aiExtensionResult
|
||||
};
|
||||
|
@@ -11,7 +11,7 @@ import { simpleText } from '@fastgpt/global/common/string/tools';
|
||||
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
||||
import type { VectorModelItemType, LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
|
||||
export const lockTrainingDataByTeamId = async (teamId: string, retry = 3): Promise<any> => {
|
||||
export const lockTrainingDataByTeamId = async (teamId: string): Promise<any> => {
|
||||
try {
|
||||
await MongoDatasetTraining.updateMany(
|
||||
{
|
||||
@@ -21,13 +21,7 @@ export const lockTrainingDataByTeamId = async (teamId: string, retry = 3): Promi
|
||||
lockTime: new Date('2999/5/5')
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
if (retry > 0) {
|
||||
await delay(1000);
|
||||
return lockTrainingDataByTeamId(teamId, retry - 1);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
export async function pushDataListToTrainingQueue({
|
||||
@@ -51,17 +45,15 @@ export async function pushDataListToTrainingQueue({
|
||||
datasetId: { _id: datasetId, vectorModel, agentModel }
|
||||
} = await getCollectionWithDataset(collectionId);
|
||||
|
||||
const checkModelValid = async ({ collectionId }: { collectionId: string }) => {
|
||||
if (!collectionId) return Promise.reject(`CollectionId is empty`);
|
||||
|
||||
const checkModelValid = async () => {
|
||||
if (trainingMode === TrainingModeEnum.chunk) {
|
||||
const vectorModelData = vectorModelList?.find((item) => item.model === vectorModel);
|
||||
if (!vectorModelData) {
|
||||
return Promise.reject(`Model ${vectorModel} is inValid`);
|
||||
return Promise.reject(`File model ${vectorModel} is inValid`);
|
||||
}
|
||||
|
||||
return {
|
||||
maxToken: vectorModelData.maxToken * 1.5,
|
||||
maxToken: vectorModelData.maxToken * 1.3,
|
||||
model: vectorModelData.model,
|
||||
weight: vectorModelData.weight
|
||||
};
|
||||
@@ -70,7 +62,7 @@ export async function pushDataListToTrainingQueue({
|
||||
if (trainingMode === TrainingModeEnum.qa) {
|
||||
const qaModelData = datasetModelList?.find((item) => item.model === agentModel);
|
||||
if (!qaModelData) {
|
||||
return Promise.reject(`Model ${agentModel} is inValid`);
|
||||
return Promise.reject(`Vector model ${agentModel} is inValid`);
|
||||
}
|
||||
return {
|
||||
maxToken: qaModelData.maxContext * 0.8,
|
||||
@@ -81,9 +73,7 @@ export async function pushDataListToTrainingQueue({
|
||||
return Promise.reject(`Training mode "${trainingMode}" is inValid`);
|
||||
};
|
||||
|
||||
const { model, maxToken, weight } = await checkModelValid({
|
||||
collectionId
|
||||
});
|
||||
const { model, maxToken, weight } = await checkModelValid();
|
||||
|
||||
// format q and a, remove empty char
|
||||
data.forEach((item) => {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import { connectionMongo, type Model } from '../../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import { DatasetTrainingSchemaType } from '@fastgpt/global/core/dataset/type';
|
||||
import { DatasetDataIndexTypeMap, TrainingTypeMap } from '@fastgpt/global/core/dataset/constants';
|
||||
import { TrainingTypeMap } from '@fastgpt/global/core/dataset/constants';
|
||||
import { DatasetColCollectionName } from '../collection/schema';
|
||||
import { DatasetCollectionName } from '../schema';
|
||||
import {
|
||||
@@ -86,11 +86,6 @@ const TrainingDataSchema = new Schema({
|
||||
indexes: {
|
||||
type: [
|
||||
{
|
||||
type: {
|
||||
type: String,
|
||||
enum: Object.keys(DatasetDataIndexTypeMap),
|
||||
required: true
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
required: true
|
||||
|
@@ -15,7 +15,7 @@
|
||||
"nextjs-cors": "^2.1.2",
|
||||
"node-cron": "^3.0.3",
|
||||
"pg": "^8.10.0",
|
||||
"date-fns": "^2.30.0",
|
||||
"date-fns": "2.30.0",
|
||||
"tunnel": "^0.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@@ -19,14 +19,15 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
||||
// auth limit
|
||||
// @ts-ignore
|
||||
if (global.feConfigs?.isPlus) {
|
||||
await POST('/support/openapi/authLimit', { openApi } as AuthOpenApiLimitProps);
|
||||
await POST('/support/openapi/authLimit', {
|
||||
openApi: openApi.toObject()
|
||||
} as AuthOpenApiLimitProps);
|
||||
}
|
||||
|
||||
updateApiKeyUsedTime(openApi._id);
|
||||
|
||||
return {
|
||||
apikey,
|
||||
userId: String(openApi.userId),
|
||||
teamId: String(openApi.teamId),
|
||||
tmbId: String(openApi.tmbId),
|
||||
appId: openApi.appId || ''
|
||||
|
@@ -1,8 +1,6 @@
|
||||
import { connectionMongo, type Model } from '../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import type { OpenApiSchema } from '@fastgpt/global/support/openapi/type';
|
||||
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
@@ -10,10 +8,6 @@ import {
|
||||
|
||||
const OpenApiSchema = new Schema(
|
||||
{
|
||||
userId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'user'
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
@@ -44,22 +38,17 @@ const OpenApiSchema = new Schema(
|
||||
type: String,
|
||||
default: 'Api Key'
|
||||
},
|
||||
usage: {
|
||||
// total usage. value from bill total
|
||||
usagePoints: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
get: (val: number) => formatStorePrice2Read(val)
|
||||
default: 0
|
||||
},
|
||||
limit: {
|
||||
expiredTime: {
|
||||
type: Date
|
||||
},
|
||||
credit: {
|
||||
// value from user settings
|
||||
maxUsagePoints: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
set: (val: number) => val * PRICE_SCALE,
|
||||
get: (val: number) => formatStorePrice2Read(val)
|
||||
default: -1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -8,15 +8,21 @@ export function updateApiKeyUsedTime(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
export function updateApiKeyUsage({ apikey, usage }: { apikey: string; usage: number }) {
|
||||
export function updateApiKeyUsage({
|
||||
apikey,
|
||||
totalPoints
|
||||
}: {
|
||||
apikey: string;
|
||||
totalPoints: number;
|
||||
}) {
|
||||
MongoOpenApi.findOneAndUpdate(
|
||||
{ apiKey: apikey },
|
||||
{
|
||||
$inc: {
|
||||
usage
|
||||
usagePoints: totalPoints
|
||||
}
|
||||
}
|
||||
).catch((err) => {
|
||||
console.log('update apiKey usage error', err);
|
||||
console.log('update apiKey totalPoints error', err);
|
||||
});
|
||||
}
|
||||
|
@@ -35,8 +35,7 @@ const OutLinkSchema = new Schema({
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
total: {
|
||||
// total amount
|
||||
usagePoints: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
@@ -48,6 +47,10 @@ const OutLinkSchema = new Schema({
|
||||
default: false
|
||||
},
|
||||
limit: {
|
||||
maxUsagePoints: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
expiredTime: {
|
||||
type: Date
|
||||
},
|
||||
@@ -55,16 +58,18 @@ const OutLinkSchema = new Schema({
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
credit: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
hookUrl: {
|
||||
type: String
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
OutLinkSchema.index({ shareId: -1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoOutLink: Model<SchemaType> =
|
||||
models['outlinks'] || model('outlinks', OutLinkSchema);
|
||||
|
||||
|
@@ -1,18 +1,19 @@
|
||||
import axios from 'axios';
|
||||
import { MongoOutLink } from './schema';
|
||||
import { FastGPTProUrl } from '../../common/system/constants';
|
||||
import { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type';
|
||||
|
||||
export const updateOutLinkUsage = async ({
|
||||
export const addOutLinkUsage = async ({
|
||||
shareId,
|
||||
total
|
||||
totalPoints
|
||||
}: {
|
||||
shareId: string;
|
||||
total: number;
|
||||
totalPoints: number;
|
||||
}) => {
|
||||
MongoOutLink.findOneAndUpdate(
|
||||
{ shareId },
|
||||
{
|
||||
$inc: { total },
|
||||
$inc: { usagePoints: totalPoints },
|
||||
lastTime: new Date()
|
||||
}
|
||||
).catch((err) => {
|
||||
@@ -23,11 +24,13 @@ export const updateOutLinkUsage = async ({
|
||||
export const pushResult2Remote = async ({
|
||||
outLinkUid,
|
||||
shareId,
|
||||
appName,
|
||||
responseData
|
||||
}: {
|
||||
outLinkUid?: string; // raw id, not parse
|
||||
shareId?: string;
|
||||
responseData?: any[];
|
||||
appName: string;
|
||||
responseData?: ChatHistoryItemResType[];
|
||||
}) => {
|
||||
if (!shareId || !outLinkUid || !FastGPTProUrl) return;
|
||||
try {
|
||||
@@ -42,6 +45,7 @@ export const pushResult2Remote = async ({
|
||||
url: '/shareAuth/finish',
|
||||
data: {
|
||||
token: outLinkUid,
|
||||
appName,
|
||||
responseData
|
||||
}
|
||||
});
|
||||
|
@@ -107,7 +107,7 @@ export async function authDatasetCollection({
|
||||
collection: CollectionWithDatasetType;
|
||||
}
|
||||
> {
|
||||
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||
const { teamId, tmbId } = await parseHeaderCert(props);
|
||||
const { role } = await getTmbInfoByTmbId({ tmbId });
|
||||
|
||||
const { collection, isOwner, canWrite } = await (async () => {
|
||||
@@ -143,7 +143,6 @@ export async function authDatasetCollection({
|
||||
})();
|
||||
|
||||
return {
|
||||
userId,
|
||||
teamId,
|
||||
tmbId,
|
||||
collection,
|
||||
@@ -163,7 +162,7 @@ export async function authDatasetFile({
|
||||
file: DatasetFileSchema;
|
||||
}
|
||||
> {
|
||||
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||
const { teamId, tmbId } = await parseHeaderCert(props);
|
||||
|
||||
const [file, collection] = await Promise.all([
|
||||
getFileById({ bucketName: BucketNameEnum.dataset, fileId }),
|
||||
@@ -190,7 +189,6 @@ export async function authDatasetFile({
|
||||
});
|
||||
|
||||
return {
|
||||
userId,
|
||||
teamId,
|
||||
tmbId,
|
||||
file,
|
||||
@@ -200,4 +198,4 @@ export async function authDatasetFile({
|
||||
} catch (error) {
|
||||
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ export async function authUserNotVisitor(props: AuthModeType): Promise<
|
||||
role: `${TeamMemberRoleEnum}`;
|
||||
}
|
||||
> {
|
||||
const { userId, teamId, tmbId } = await parseHeaderCert(props);
|
||||
const { teamId, tmbId } = await parseHeaderCert(props);
|
||||
const team = await getTmbInfoByTmbId({ tmbId });
|
||||
|
||||
if (team.role === TeamMemberRoleEnum.visitor) {
|
||||
@@ -20,7 +20,6 @@ export async function authUserNotVisitor(props: AuthModeType): Promise<
|
||||
}
|
||||
|
||||
return {
|
||||
userId,
|
||||
teamId,
|
||||
tmbId,
|
||||
team,
|
||||
|
@@ -94,10 +94,10 @@ export async function parseHeaderCert({
|
||||
})();
|
||||
|
||||
// auth apikey
|
||||
const { userId, teamId, tmbId, appId: apiKeyAppId = '' } = await authOpenApiKey({ apikey });
|
||||
const { teamId, tmbId, appId: apiKeyAppId = '' } = await authOpenApiKey({ apikey });
|
||||
|
||||
return {
|
||||
uid: userId,
|
||||
uid: '',
|
||||
teamId,
|
||||
tmbId,
|
||||
apikey,
|
||||
@@ -217,4 +217,4 @@ export const authFileToken = (token?: string) =>
|
||||
fileId: decoded.fileId
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,23 +0,0 @@
|
||||
import { StandSubPlanLevelMapType } from '@fastgpt/global/support/wallet/sub/type';
|
||||
import { getVectorCountByTeamId } from '../../../common/vectorStore/controller';
|
||||
import { getTeamDatasetMaxSize } from '../../wallet/sub/utils';
|
||||
|
||||
export const checkDatasetLimit = async ({
|
||||
teamId,
|
||||
insertLen = 0,
|
||||
standardPlans
|
||||
}: {
|
||||
teamId: string;
|
||||
insertLen?: number;
|
||||
standardPlans?: StandSubPlanLevelMapType;
|
||||
}) => {
|
||||
const [{ maxSize }, usedSize] = await Promise.all([
|
||||
getTeamDatasetMaxSize({ teamId, standardPlans }),
|
||||
getVectorCountByTeamId(teamId)
|
||||
]);
|
||||
|
||||
if (usedSize + insertLen >= maxSize) {
|
||||
return Promise.reject(`数据库容量不足,无法继续添加。可以在账号页面进行扩容。`);
|
||||
}
|
||||
return;
|
||||
};
|
91
packages/service/support/permission/teamLimit.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { getVectorCountByTeamId } from '../../common/vectorStore/controller';
|
||||
import { getTeamPlanStatus, getTeamStandPlan } from '../../support/wallet/sub/utils';
|
||||
import { MongoApp } from '../../core/app/schema';
|
||||
import { MongoPlugin } from '../../core/plugin/schema';
|
||||
import { MongoDataset } from '../../core/dataset/schema';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
||||
|
||||
export const checkDatasetLimit = async ({
|
||||
teamId,
|
||||
insertLen = 0
|
||||
}: {
|
||||
teamId: string;
|
||||
insertLen?: number;
|
||||
}) => {
|
||||
const [{ standardConstants, totalPoints, usedPoints, datasetMaxSize }, usedSize] =
|
||||
await Promise.all([getTeamPlanStatus({ teamId }), getVectorCountByTeamId(teamId)]);
|
||||
|
||||
if (!standardConstants) return;
|
||||
|
||||
if (usedSize + insertLen >= datasetMaxSize) {
|
||||
return Promise.reject(TeamErrEnum.datasetSizeNotEnough);
|
||||
}
|
||||
|
||||
if (usedPoints >= totalPoints) {
|
||||
return Promise.reject(TeamErrEnum.aiPointsNotEnough);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
export const checkTeamAIPoints = async (teamId: string) => {
|
||||
const { standardConstants, totalPoints, usedPoints } = await getTeamPlanStatus({
|
||||
teamId
|
||||
});
|
||||
|
||||
if (!standardConstants) return;
|
||||
|
||||
if (usedPoints >= totalPoints) {
|
||||
return Promise.reject(TeamErrEnum.aiPointsNotEnough);
|
||||
}
|
||||
|
||||
return {
|
||||
totalPoints,
|
||||
usedPoints
|
||||
};
|
||||
};
|
||||
|
||||
export const checkTeamDatasetLimit = async (teamId: string) => {
|
||||
const [{ standardConstants }, datasetCount] = await Promise.all([
|
||||
getTeamStandPlan({ teamId }),
|
||||
MongoDataset.countDocuments({
|
||||
teamId,
|
||||
type: { $ne: DatasetTypeEnum.folder }
|
||||
})
|
||||
]);
|
||||
|
||||
if (standardConstants && datasetCount >= standardConstants.maxDatasetAmount) {
|
||||
return Promise.reject(TeamErrEnum.datasetAmountNotEnough);
|
||||
}
|
||||
};
|
||||
export const checkTeamAppLimit = async (teamId: string) => {
|
||||
const [{ standardConstants }, appCount] = await Promise.all([
|
||||
getTeamStandPlan({ teamId }),
|
||||
MongoApp.count({ teamId })
|
||||
]);
|
||||
|
||||
if (standardConstants && appCount >= standardConstants.maxAppAmount) {
|
||||
return Promise.reject(TeamErrEnum.appAmountNotEnough);
|
||||
}
|
||||
};
|
||||
export const checkTeamPluginLimit = async (teamId: string) => {
|
||||
const [{ standardConstants }, pluginCount] = await Promise.all([
|
||||
getTeamStandPlan({ teamId }),
|
||||
MongoPlugin.count({ teamId })
|
||||
]);
|
||||
|
||||
if (standardConstants && pluginCount >= standardConstants.maxAppAmount) {
|
||||
return Promise.reject(TeamErrEnum.pluginAmountNotEnough);
|
||||
}
|
||||
};
|
||||
|
||||
export const checkTeamReRankPermission = async (teamId: string) => {
|
||||
const { standardConstants } = await getTeamStandPlan({
|
||||
teamId
|
||||
});
|
||||
|
||||
if (standardConstants && !standardConstants?.permissionReRank) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
@@ -2,7 +2,6 @@ import { UserType } from '@fastgpt/global/support/user/type';
|
||||
import { MongoUser } from './schema';
|
||||
import { getTmbInfoByTmbId, getUserDefaultTeam } from './team/controller';
|
||||
import { ERROR_ENUM } from '@fastgpt/global/common/error/errorCode';
|
||||
import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
|
||||
|
||||
export async function authUserExist({ userId, username }: { userId?: string; username?: string }) {
|
||||
if (userId) {
|
||||
@@ -47,22 +46,3 @@ export async function getUserDetail({
|
||||
team: tmb
|
||||
};
|
||||
}
|
||||
|
||||
export async function getUserAndAuthBalance({
|
||||
tmbId,
|
||||
minBalance
|
||||
}: {
|
||||
tmbId: string;
|
||||
minBalance?: number;
|
||||
}) {
|
||||
const user = await getUserDetail({ tmbId });
|
||||
|
||||
if (!user) {
|
||||
return Promise.reject(UserErrEnum.unAuthUser);
|
||||
}
|
||||
if (minBalance !== undefined && user.team.balance < minBalance) {
|
||||
return Promise.reject(UserErrEnum.balanceNotEnough);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { connectionMongo, type Model } from '../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/constants';
|
||||
import type { UserModelSchema } from '@fastgpt/global/support/user/type';
|
||||
import { UserStatusEnum, userStatusMap } from '@fastgpt/global/support/user/constant';
|
||||
|
||||
@@ -63,6 +63,8 @@ const UserSchema = new Schema({
|
||||
});
|
||||
|
||||
try {
|
||||
// login
|
||||
UserSchema.index({ username: 1, password: 1 });
|
||||
UserSchema.index({ createTime: -1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
@@ -36,7 +36,7 @@ export async function getTmbInfoByTmbId({ tmbId }: { tmbId: string }) {
|
||||
return Promise.reject('tmbId or userId is required');
|
||||
}
|
||||
return getTeamMember({
|
||||
_id: new Types.ObjectId(tmbId),
|
||||
_id: new Types.ObjectId(String(tmbId)),
|
||||
status: notLeaveStatus
|
||||
});
|
||||
}
|
||||
|
@@ -27,7 +27,10 @@ const TeamSchema = new Schema({
|
||||
},
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 3
|
||||
default: 1
|
||||
},
|
||||
tagsUrl: {
|
||||
type: String
|
||||
},
|
||||
limit: {
|
||||
lastExportDatasetTime: {
|
||||
|
35
packages/service/support/user/team/teamTagsSchema.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { connectionMongo, type Model } from '../../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import { TeamTagsSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamTagsCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
const TeamTagsSchema = new Schema({
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
key: {
|
||||
type: String
|
||||
},
|
||||
createTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
TeamTagsSchema.index({ teamId: 1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoTeamTags: Model<TeamTagsSchemaType> =
|
||||
models[TeamTagsCollectionName] || model(TeamTagsCollectionName, TeamTagsSchema);
|
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
user sub plan
|
||||
1. type=standard: There will only be 1, and each team will have one
|
||||
2. type=extraDatasetSize/extraPoints: Can buy multiple
|
||||
*/
|
||||
import { connectionMongo, type Model } from '../../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||
@@ -23,25 +28,10 @@ const SubSchema = new Schema({
|
||||
required: true
|
||||
},
|
||||
status: {
|
||||
// active: continue sub; canceled: canceled sub;
|
||||
type: String,
|
||||
enum: Object.keys(subStatusMap),
|
||||
required: true
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
enum: Object.keys(subModeMap)
|
||||
},
|
||||
currentMode: {
|
||||
type: String,
|
||||
enum: Object.keys(subModeMap),
|
||||
required: true
|
||||
},
|
||||
nextMode: {
|
||||
type: String,
|
||||
enum: Object.keys(subModeMap),
|
||||
required: true
|
||||
},
|
||||
startTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
@@ -55,12 +45,16 @@ const SubSchema = new Schema({
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
pointPrice: {
|
||||
// stand level point total price
|
||||
type: Number
|
||||
},
|
||||
|
||||
// sub content
|
||||
// standard sub
|
||||
currentMode: {
|
||||
type: String,
|
||||
enum: Object.keys(subModeMap)
|
||||
},
|
||||
nextMode: {
|
||||
type: String,
|
||||
enum: Object.keys(subModeMap)
|
||||
},
|
||||
currentSubLevel: {
|
||||
type: String,
|
||||
enum: Object.keys(standardSubLevelMap)
|
||||
@@ -69,79 +63,32 @@ const SubSchema = new Schema({
|
||||
type: String,
|
||||
enum: Object.keys(standardSubLevelMap)
|
||||
},
|
||||
|
||||
// stand sub and extra points sub. Plan total points
|
||||
totalPoints: {
|
||||
type: Number
|
||||
},
|
||||
pointPrice: {
|
||||
// stand level point total price
|
||||
type: Number
|
||||
},
|
||||
surplusPoints: {
|
||||
// plan surplus points
|
||||
type: Number
|
||||
},
|
||||
|
||||
// extra dataset size
|
||||
currentExtraDatasetSize: {
|
||||
type: Number
|
||||
},
|
||||
nextExtraDatasetSize: {
|
||||
type: Number
|
||||
},
|
||||
|
||||
currentExtraPoints: {
|
||||
type: Number
|
||||
},
|
||||
nextExtraPoints: {
|
||||
type: Number
|
||||
},
|
||||
|
||||
// standard sub limit
|
||||
// maxTeamMember: {
|
||||
// type: Number
|
||||
// },
|
||||
// maxAppAmount: {
|
||||
// type: Number
|
||||
// },
|
||||
// maxDatasetAmount: {
|
||||
// type: Number
|
||||
// },
|
||||
// chatHistoryStoreDuration: {
|
||||
// // n day
|
||||
// type: Number
|
||||
// },
|
||||
// maxDatasetSize: {
|
||||
// type: Number
|
||||
// },
|
||||
// trainingWeight: {
|
||||
// // 0 1 2 3
|
||||
// type: Number
|
||||
// },
|
||||
// customApiKey: {
|
||||
// type: Boolean
|
||||
// },
|
||||
// customCopyright: {
|
||||
// type: Boolean
|
||||
// },
|
||||
// websiteSyncInterval: {
|
||||
// // hours
|
||||
// type: Number
|
||||
// },
|
||||
// reRankWeight: {
|
||||
// // 0 1 2 3
|
||||
// type: Number
|
||||
// },
|
||||
// totalPoints: {
|
||||
// // record standard sub points
|
||||
// type: Number
|
||||
// },
|
||||
|
||||
surplusPoints: {
|
||||
// standard sub / extra points sub
|
||||
type: Number
|
||||
},
|
||||
|
||||
// abandon
|
||||
renew: Boolean, //决定是否续费
|
||||
datasetStoreAmount: Number
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
SubSchema.index({ teamId: 1 });
|
||||
SubSchema.index({ status: 1 });
|
||||
SubSchema.index({ type: 1 });
|
||||
SubSchema.index({ expiredTime: -1 });
|
||||
// get team plan
|
||||
SubSchema.index({ teamId: 1, type: 1, expiredTime: -1 });
|
||||
|
||||
// timer task. check expired plan; update standard plan;
|
||||
SubSchema.index({ type: 1, currentSubLevel: 1, expiredTime: -1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@@ -1,87 +1,147 @@
|
||||
import { SubTypeEnum } from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import {
|
||||
StandardSubLevelEnum,
|
||||
SubModeEnum,
|
||||
SubStatusEnum,
|
||||
SubTypeEnum
|
||||
} from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import { MongoTeamSub } from './schema';
|
||||
import { addHours } from 'date-fns';
|
||||
import { FeTeamSubType, StandSubPlanLevelMapType } from '@fastgpt/global/support/wallet/sub/type.d';
|
||||
import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type.d';
|
||||
import { getVectorCountByTeamId } from '../../../common/vectorStore/controller';
|
||||
import dayjs from 'dayjs';
|
||||
import { ClientSession } from '../../../common/mongo';
|
||||
import { addMonths } from 'date-fns';
|
||||
|
||||
/* get team dataset max size */
|
||||
export const getTeamDatasetMaxSize = async ({
|
||||
teamId,
|
||||
standardPlans
|
||||
}: {
|
||||
teamId: string;
|
||||
standardPlans?: StandSubPlanLevelMapType;
|
||||
}) => {
|
||||
if (!standardPlans) {
|
||||
return {
|
||||
maxSize: Infinity,
|
||||
sub: null
|
||||
};
|
||||
}
|
||||
export const getStandardPlans = () => {
|
||||
return global?.subPlans?.standard;
|
||||
};
|
||||
export const getStandardPlan = (level: `${StandardSubLevelEnum}`) => {
|
||||
return global.subPlans?.standard?.[level];
|
||||
};
|
||||
|
||||
const plans = await MongoTeamSub.find({
|
||||
teamId,
|
||||
expiredTime: { $gte: addHours(new Date(), -3) }
|
||||
}).lean();
|
||||
|
||||
const standard = plans.find((plan) => plan.type === SubTypeEnum.standard);
|
||||
const extraDatasetSize = plans.find((plan) => plan.type === SubTypeEnum.extraDatasetSize);
|
||||
|
||||
const standardMaxDatasetSize =
|
||||
standard?.currentSubLevel && standardPlans
|
||||
? standardPlans[standard.currentSubLevel]?.maxDatasetSize || Infinity
|
||||
: Infinity;
|
||||
const totalDatasetSize =
|
||||
standardMaxDatasetSize + (extraDatasetSize?.currentExtraDatasetSize || 0);
|
||||
export const getTeamStandPlan = async ({ teamId }: { teamId: string }) => {
|
||||
const standardPlans = global.subPlans?.standard;
|
||||
const standard = await MongoTeamSub.findOne({ teamId, type: SubTypeEnum.standard }).lean();
|
||||
|
||||
return {
|
||||
maxSize: totalDatasetSize,
|
||||
sub: extraDatasetSize
|
||||
[SubTypeEnum.standard]: standard,
|
||||
standardConstants:
|
||||
standard?.currentSubLevel && standardPlans
|
||||
? standardPlans[standard.currentSubLevel]
|
||||
: undefined
|
||||
};
|
||||
};
|
||||
|
||||
export const getTeamSubPlanStatus = async ({
|
||||
export const initTeamStandardPlan2Free = async ({
|
||||
teamId,
|
||||
standardPlans
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
standardPlans?: StandSubPlanLevelMapType;
|
||||
}): Promise<FeTeamSubType> => {
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
const freePoints = global?.subPlans?.standard?.free?.totalPoints || 100;
|
||||
|
||||
const teamStandardSub = await MongoTeamSub.findOne({ teamId, type: SubTypeEnum.standard });
|
||||
|
||||
if (teamStandardSub) {
|
||||
teamStandardSub.status = SubStatusEnum.active;
|
||||
teamStandardSub.currentMode = SubModeEnum.month;
|
||||
teamStandardSub.nextMode = SubModeEnum.month;
|
||||
teamStandardSub.startTime = new Date();
|
||||
teamStandardSub.expiredTime = addMonths(new Date(), 1);
|
||||
|
||||
teamStandardSub.currentSubLevel = StandardSubLevelEnum.free;
|
||||
teamStandardSub.nextSubLevel = StandardSubLevelEnum.free;
|
||||
|
||||
teamStandardSub.price = 0;
|
||||
teamStandardSub.pointPrice = 0;
|
||||
|
||||
teamStandardSub.totalPoints = freePoints;
|
||||
teamStandardSub.surplusPoints =
|
||||
teamStandardSub.surplusPoints && teamStandardSub.surplusPoints < 0
|
||||
? teamStandardSub.surplusPoints + freePoints
|
||||
: freePoints;
|
||||
return teamStandardSub.save({ session });
|
||||
}
|
||||
|
||||
return MongoTeamSub.create(
|
||||
[
|
||||
{
|
||||
teamId,
|
||||
type: SubTypeEnum.standard,
|
||||
status: SubStatusEnum.active,
|
||||
currentMode: SubModeEnum.month,
|
||||
nextMode: SubModeEnum.month,
|
||||
startTime: new Date(),
|
||||
expiredTime: addMonths(new Date(), 1),
|
||||
price: 0,
|
||||
pointPrice: 0,
|
||||
|
||||
currentSubLevel: StandardSubLevelEnum.free,
|
||||
nextSubLevel: StandardSubLevelEnum.free,
|
||||
|
||||
totalPoints: freePoints,
|
||||
surplusPoints: freePoints
|
||||
}
|
||||
],
|
||||
{ session }
|
||||
);
|
||||
};
|
||||
|
||||
export const getTeamPlanStatus = async ({
|
||||
teamId
|
||||
}: {
|
||||
teamId: string;
|
||||
}): Promise<FeTeamPlanStatusType> => {
|
||||
const standardPlans = global.subPlans?.standard;
|
||||
|
||||
const [plans, usedDatasetSize] = await Promise.all([
|
||||
MongoTeamSub.find({ teamId }).lean(),
|
||||
getVectorCountByTeamId(teamId)
|
||||
]);
|
||||
|
||||
const standard = plans.find((plan) => plan.type === SubTypeEnum.standard);
|
||||
const extraDatasetSize = plans.find((plan) => plan.type === SubTypeEnum.extraDatasetSize);
|
||||
const extraPoints = plans.find((plan) => plan.type === SubTypeEnum.extraPoints);
|
||||
const extraDatasetSize = plans.filter((plan) => plan.type === SubTypeEnum.extraDatasetSize);
|
||||
const extraPoints = plans.filter((plan) => plan.type === SubTypeEnum.extraPoints);
|
||||
|
||||
// Free user, first login after expiration. The free subscription plan will be reset
|
||||
if (
|
||||
standard &&
|
||||
standard.expiredTime &&
|
||||
standard.currentSubLevel === StandardSubLevelEnum.free &&
|
||||
dayjs(standard.expiredTime).isBefore(new Date())
|
||||
) {
|
||||
console.log('Init free stand plan', { teamId });
|
||||
await initTeamStandardPlan2Free({ teamId });
|
||||
return getTeamPlanStatus({ teamId });
|
||||
}
|
||||
|
||||
const totalPoints = standardPlans
|
||||
? (standard?.totalPoints || 0) +
|
||||
extraPoints.reduce((acc, cur) => acc + (cur.totalPoints || 0), 0)
|
||||
: Infinity;
|
||||
const surplusPoints =
|
||||
(standard?.surplusPoints || 0) +
|
||||
extraPoints.reduce((acc, cur) => acc + (cur.surplusPoints || 0), 0);
|
||||
|
||||
const standardMaxDatasetSize =
|
||||
standard?.currentSubLevel && standardPlans
|
||||
? standardPlans[standard.currentSubLevel]?.maxDatasetSize || Infinity
|
||||
: Infinity;
|
||||
const totalDatasetSize =
|
||||
standardMaxDatasetSize + (extraDatasetSize?.currentExtraDatasetSize || 0);
|
||||
|
||||
const standardMaxPoints =
|
||||
standard?.currentSubLevel && standardPlans
|
||||
? standardPlans[standard.currentSubLevel]?.totalPoints || Infinity
|
||||
: Infinity;
|
||||
const totalPoints = standardMaxPoints + (extraPoints?.currentExtraPoints || 0);
|
||||
|
||||
const surplusPoints = (standard?.surplusPoints || 0) + (extraPoints?.surplusPoints || 0);
|
||||
standardMaxDatasetSize +
|
||||
extraDatasetSize.reduce((acc, cur) => acc + (cur.currentExtraDatasetSize || 0), 0);
|
||||
|
||||
return {
|
||||
[SubTypeEnum.standard]: standard,
|
||||
[SubTypeEnum.extraDatasetSize]: extraDatasetSize,
|
||||
[SubTypeEnum.extraPoints]: extraPoints,
|
||||
standardConstants:
|
||||
standard?.currentSubLevel && standardPlans
|
||||
? standardPlans[standard.currentSubLevel]
|
||||
: undefined,
|
||||
|
||||
standardMaxDatasetSize,
|
||||
datasetMaxSize: totalDatasetSize,
|
||||
usedDatasetSize,
|
||||
|
||||
standardMaxPoints,
|
||||
totalPoints,
|
||||
usedPoints: totalPoints - surplusPoints
|
||||
usedPoints: totalPoints - surplusPoints,
|
||||
|
||||
datasetMaxSize: totalDatasetSize,
|
||||
usedDatasetSize
|
||||
};
|
||||
};
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { MongoBill } from './schema';
|
||||
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
||||
import { MongoUsage } from './schema';
|
||||
import { ClientSession } from '../../../common/mongo';
|
||||
|
||||
export const createTrainingBill = async ({
|
||||
export const createTrainingUsage = async ({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName,
|
||||
@@ -14,33 +14,33 @@ export const createTrainingBill = async ({
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
appName: string;
|
||||
billSource: `${BillSourceEnum}`;
|
||||
billSource: `${UsageSourceEnum}`;
|
||||
vectorModel: string;
|
||||
agentModel: string;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
const [{ _id }] = await MongoBill.create(
|
||||
const [{ _id }] = await MongoUsage.create(
|
||||
[
|
||||
{
|
||||
teamId,
|
||||
tmbId,
|
||||
appName,
|
||||
source: billSource,
|
||||
totalPoints: 0,
|
||||
list: [
|
||||
{
|
||||
moduleName: 'wallet.moduleName.index',
|
||||
moduleName: 'support.wallet.moduleName.index',
|
||||
model: vectorModel,
|
||||
charsLength: 0,
|
||||
amount: 0
|
||||
},
|
||||
{
|
||||
moduleName: 'wallet.moduleName.qa',
|
||||
moduleName: 'support.wallet.moduleName.qa',
|
||||
model: agentModel,
|
||||
charsLength: 0,
|
||||
amount: 0
|
||||
}
|
||||
],
|
||||
total: 0
|
||||
]
|
||||
}
|
||||
],
|
||||
{ session }
|
@@ -1,13 +1,15 @@
|
||||
import { connectionMongo, type Model } from '../../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import { BillSchema as BillType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import { BillSourceMap } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { UsageSchemaType } from '@fastgpt/global/support/wallet/usage/type';
|
||||
import { UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
const BillSchema = new Schema({
|
||||
export const UsageCollectionName = 'usages';
|
||||
|
||||
const UsageSchema = new Schema({
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
@@ -18,6 +20,11 @@ const BillSchema = new Schema({
|
||||
ref: TeamMemberCollectionName,
|
||||
required: true
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
enum: Object.keys(UsageSourceMap),
|
||||
required: true
|
||||
},
|
||||
appName: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -31,16 +38,16 @@ const BillSchema = new Schema({
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
total: {
|
||||
// 1 * PRICE_SCALE
|
||||
totalPoints: {
|
||||
// total points
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
enum: Object.keys(BillSourceMap),
|
||||
required: true
|
||||
},
|
||||
// total: {
|
||||
// // total points
|
||||
// type: Number,
|
||||
// required: true
|
||||
// },
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
@@ -48,11 +55,15 @@ const BillSchema = new Schema({
|
||||
});
|
||||
|
||||
try {
|
||||
BillSchema.index({ teamId: 1, tmbId: 1, source: 1, time: -1 }, { background: true });
|
||||
BillSchema.index({ time: 1 }, { expireAfterSeconds: 180 * 24 * 60 * 60 });
|
||||
UsageSchema.index({ teamId: 1, tmbId: 1, source: 1, time: -1 }, { background: true });
|
||||
// timer task. clear dead team
|
||||
UsageSchema.index({ teamId: 1, time: -1 }, { background: true });
|
||||
|
||||
UsageSchema.index({ time: 1 }, { expireAfterSeconds: 180 * 24 * 60 * 60 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoBill: Model<BillType> = models['bill'] || model('bill', BillSchema);
|
||||
MongoBill.syncIndexes();
|
||||
export const MongoUsage: Model<UsageSchemaType> =
|
||||
models[UsageCollectionName] || model(UsageCollectionName, UsageSchema);
|
||||
MongoUsage.syncIndexes();
|
19
packages/service/type.d.ts
vendored
@@ -1,3 +1,20 @@
|
||||
import { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types';
|
||||
import {
|
||||
AudioSpeechModelType,
|
||||
ReRankModelItemType,
|
||||
WhisperModelType,
|
||||
VectorModelItemType,
|
||||
LLMModelItemType
|
||||
} from '@fastgpt/global/core/ai/model.d';
|
||||
import { SubPlanType } from '@fastgpt/global/support/wallet/sub/type';
|
||||
|
||||
declare global {
|
||||
var defaultTeamDatasetLimit: number;
|
||||
var feConfigs: FastGPTFeConfigsType;
|
||||
var subPlans: SubPlanType | undefined;
|
||||
|
||||
var llmModels: LLMModelItemType[];
|
||||
var vectorModels: VectorModelItemType[];
|
||||
var audioSpeechModels: AudioSpeechModelType[];
|
||||
var whisperModel: WhisperModelType;
|
||||
var reRankModels: ReRankModelItemType[];
|
||||
}
|
||||
|
@@ -128,10 +128,12 @@ export const iconPaths = {
|
||||
kbTest: () => import('./icons/kbTest.svg'),
|
||||
menu: () => import('./icons/menu.svg'),
|
||||
minus: () => import('./icons/minus.svg'),
|
||||
'modal/confirmPay': () => import('./icons/modal/confirmPay.svg'),
|
||||
'modal/edit': () => import('./icons/modal/edit.svg'),
|
||||
'modal/manualDataset': () => import('./icons/modal/manualDataset.svg'),
|
||||
'modal/selectSource': () => import('./icons/modal/selectSource.svg'),
|
||||
'modal/setting': () => import('./icons/modal/setting.svg'),
|
||||
'modal/teamPlans': () => import('./icons/modal/teamPlans.svg'),
|
||||
more: () => import('./icons/more.svg'),
|
||||
out: () => import('./icons/out.svg'),
|
||||
'phoneTabbar/me': () => import('./icons/phoneTabbar/me.svg'),
|
||||
@@ -142,20 +144,23 @@ export const iconPaths = {
|
||||
save: () => import('./icons/save.svg'),
|
||||
stop: () => import('./icons/stop.svg'),
|
||||
'support/account/loginoutLight': () => import('./icons/support/account/loginoutLight.svg'),
|
||||
'support/account/plans': () => import('./icons/support/account/plans.svg'),
|
||||
'support/account/promotionLight': () => import('./icons/support/account/promotionLight.svg'),
|
||||
'support/bill/billRecordLight': () => import('./icons/support/bill/billRecordLight.svg'),
|
||||
'support/bill/extraDatasetsize': () => import('./icons/support/bill/extraDatasetsize.svg'),
|
||||
'support/bill/extraPoints': () => import('./icons/support/bill/extraPoints.svg'),
|
||||
'support/bill/payRecordLight': () => import('./icons/support/bill/payRecordLight.svg'),
|
||||
'support/bill/priceLight': () => import('./icons/support/bill/priceLight.svg'),
|
||||
'support/bill/shoppingCart': () => import('./icons/support/bill/shoppingCart.svg'),
|
||||
'support/outlink/apikeyFill': () => import('./icons/support/outlink/apikeyFill.svg'),
|
||||
'support/outlink/apikeyLight': () => import('./icons/support/outlink/apikeyLight.svg'),
|
||||
'support/outlink/iframeLight': () => import('./icons/support/outlink/iframeLight.svg'),
|
||||
'support/outlink/share': () => import('./icons/support/outlink/share.svg'),
|
||||
'support/outlink/shareLight': () => import('./icons/support/outlink/shareLight.svg'),
|
||||
'support/pay/extraDatasetsize': () => import('./icons/support/pay/extraDatasetsize.svg'),
|
||||
'support/pay/extraPoints': () => import('./icons/support/pay/extraPoints.svg'),
|
||||
'support/pay/payRecordLight': () => import('./icons/support/pay/payRecordLight.svg'),
|
||||
'support/pay/priceLight': () => import('./icons/support/pay/priceLight.svg'),
|
||||
'support/permission/privateLight': () => import('./icons/support/permission/privateLight.svg'),
|
||||
'support/permission/publicLight': () => import('./icons/support/permission/publicLight.svg'),
|
||||
'support/team/memberLight': () => import('./icons/support/team/memberLight.svg'),
|
||||
'support/usage/usageRecordLight': () => import('./icons/support/usage/usageRecordLight.svg'),
|
||||
'support/user/individuation': () => import('./icons/support/user/individuation.svg'),
|
||||
'support/user/informLight': () => import('./icons/support/user/informLight.svg'),
|
||||
'support/user/userFill': () => import('./icons/support/user/userFill.svg'),
|
||||
'support/user/userLight': () => import('./icons/support/user/userLight.svg'),
|
||||
|
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M15.277 4.64527C13.6911 3.93863 11.9193 3.76357 10.2257 4.1462C8.5322 4.52883 7.00773 5.44865 5.87967 6.76847C4.75162 8.08829 4.08042 9.73741 3.96618 11.4699C3.85195 13.2023 4.30079 14.9253 5.24577 16.3818C6.19076 17.8383 7.58125 18.9503 9.20987 19.552C10.8385 20.1537 12.618 20.2128 14.2829 19.7206C15.9479 19.2283 17.4091 18.211 18.4487 16.8204C19.4883 15.4298 20.0505 13.7404 20.0515 12.0042V11.1721C20.0515 10.6198 20.4992 10.1721 21.0515 10.1721C21.6037 10.1721 22.0515 10.6198 22.0515 11.1721V12.0048C22.0502 14.1723 21.3484 16.2819 20.0506 18.0179C18.7528 19.7539 16.9286 21.0239 14.85 21.6385C12.7715 22.253 10.5499 22.1792 8.51676 21.4281C6.48359 20.6769 4.74769 19.2887 3.56797 17.4704C2.38824 15.652 1.8279 13.5011 1.97052 11.3383C2.11313 9.17546 2.95106 7.1167 4.35933 5.46903C5.7676 3.82136 7.67076 2.67305 9.78496 2.19537C11.8992 1.7177 14.1111 1.93624 16.091 2.81841C16.5955 3.04319 16.8222 3.63437 16.5974 4.13884C16.3727 4.64331 15.7815 4.87005 15.277 4.64527ZM21.7582 4.05106C22.1489 4.44138 22.1492 5.07455 21.7589 5.46527L12.7076 14.5257C12.5201 14.7134 12.2656 14.8189 12.0003 14.8189C11.735 14.819 11.4806 14.7136 11.293 14.526L8.57758 11.8106C8.18705 11.4201 8.18705 10.7869 8.57758 10.3964C8.9681 10.0059 9.60127 10.0059 9.99179 10.3964L11.9997 12.4044L20.344 4.05176C20.7343 3.66104 21.3675 3.66073 21.7582 4.05106Z"
|
||||
fill="#3370FF" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||
<path
|
||||
d="M18.5546 20.9758C19.1277 20.9437 19.5295 20.8689 19.8711 20.6948C20.398 20.4264 20.8263 19.998 21.0948 19.4712C21.4 18.8722 21.4 18.0881 21.4 16.52V7.48C21.4 5.91185 21.4 5.12778 21.0948 4.52883C20.8263 4.00197 20.398 3.57363 19.8711 3.30518C19.5295 3.13113 19.1277 3.05634 18.5546 3.02421C18.5576 3.26564 18.5576 3.53559 18.5576 3.84V4.82796C18.5762 4.8293 18.5945 4.8307 18.6124 4.83217C18.9618 4.86072 19.0476 4.90564 19.0537 4.90886C19.2419 5.00473 19.3951 5.15785 19.491 5.34601C19.4942 5.35215 19.5393 5.43815 19.5678 5.78754C19.5986 6.16415 19.6 6.66622 19.6 7.48V16.52C19.6 17.3338 19.5986 17.8359 19.5678 18.2125C19.5393 18.5619 19.4943 18.6476 19.4911 18.6537C19.3952 18.8419 19.2421 18.9951 19.054 19.091C19.0478 19.0942 18.9618 19.1393 18.6124 19.1678C18.5945 19.1693 18.5762 19.1707 18.5576 19.172V20.16C18.5576 20.4644 18.5576 20.7344 18.5546 20.9758Z"
|
||||
fill="#3370FF" />
|
||||
<path
|
||||
d="M5.44233 20.9756C4.8708 20.9434 4.4698 20.8686 4.1288 20.6948C3.60195 20.4264 3.1736 19.998 2.90516 19.4712C2.59998 18.8722 2.59998 18.0881 2.59998 16.52V7.48C2.59998 5.91185 2.59998 5.12778 2.90516 4.52883C3.1736 4.00197 3.60195 3.57363 4.1288 3.30518C4.4698 3.13143 4.8708 3.0566 5.44233 3.02438V4.82796C5.42376 4.8293 5.4055 4.8307 5.38752 4.83217C5.03813 4.86071 4.95238 4.90564 4.94624 4.90886C4.75808 5.00473 4.60484 5.15785 4.50897 5.34601C4.50575 5.35215 4.46069 5.43815 4.43215 5.78754C4.40138 6.16415 4.39998 6.66622 4.39998 7.48V16.52C4.39998 17.3338 4.40138 17.8358 4.43215 18.2125C4.46069 18.5619 4.50562 18.6476 4.50884 18.6537C4.60471 18.8419 4.75782 18.9951 4.94598 19.091C4.95214 19.0942 5.03815 19.1393 5.38752 19.1678C5.4055 19.1693 5.42376 19.1707 5.44233 19.172V20.9756Z"
|
||||
fill="#3370FF" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M13.7492 4H10.2507C9.54564 4 9.13713 4.00156 8.83726 4.02606C8.70514 4.03685 8.63526 4.04974 8.60619 4.05624C8.5489 4.09032 8.50103 4.13819 8.46694 4.19548C8.46044 4.22455 8.44756 4.29443 8.43676 4.42655C8.41226 4.72642 8.41071 5.13494 8.41071 5.84V18.16C8.41071 18.8651 8.41226 19.2736 8.43676 19.5735C8.44756 19.7056 8.46044 19.7754 8.46694 19.8045C8.50103 19.8618 8.5489 19.9097 8.60619 19.9438C8.63526 19.9503 8.70514 19.9632 8.83726 19.9739C9.13713 19.9984 9.54564 20 10.2507 20H13.7492C14.4543 20 14.8628 19.9984 15.1627 19.9739C15.2948 19.9631 15.3647 19.9503 15.3938 19.9438C15.451 19.9097 15.4989 19.8618 15.533 19.8045C15.5395 19.7754 15.5524 19.7056 15.5632 19.5735C15.5877 19.2736 15.5892 18.8651 15.5892 18.16V5.84C15.5892 5.13494 15.5877 4.72642 15.5632 4.42655C15.5524 4.29443 15.5395 4.22455 15.533 4.19548C15.4989 4.13819 15.451 4.09032 15.3938 4.05624C15.3647 4.04974 15.2948 4.03685 15.1627 4.02606C14.8628 4.00156 14.4543 4 13.7492 4ZM15.4104 4.06043L15.4089 4.05997L15.4104 4.06043ZM15.5288 19.8212L15.5293 19.8197L15.5288 19.8212ZM8.58952 19.9396L8.59104 19.94L8.58952 19.9396ZM6.67229 3.31042C6.41071 3.82381 6.41071 4.49587 6.41071 5.84V18.16C6.41071 19.5041 6.41071 20.1762 6.67229 20.6896C6.90239 21.1412 7.26954 21.5083 7.72113 21.7384C8.23452 22 8.90658 22 10.2507 22H13.7492C15.0934 22 15.7654 22 16.2788 21.7384C16.7304 21.5083 17.0976 21.1412 17.3277 20.6896C17.5892 20.1762 17.5892 19.5041 17.5892 18.16V5.84C17.5892 4.49587 17.5892 3.82381 17.3277 3.31042C17.0976 2.85883 16.7304 2.49168 16.2788 2.26158C15.7654 2 15.0934 2 13.7492 2H10.2507C8.90658 2 8.23452 2 7.72113 2.26158C7.26954 2.49168 6.90239 2.85883 6.67229 3.31042Z"
|
||||
fill="#3370FF" />
|
||||
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.4622 17.4792C15.9398 17.4524 16.2747 17.3901 16.5593 17.245C16.9984 17.0213 17.3553 16.6644 17.579 16.2253C17.8334 15.7262 17.8334 15.0728 17.8334 13.766V6.23268C17.8334 4.92589 17.8334 4.2725 17.579 3.77337C17.3553 3.33433 16.9984 2.97737 16.5593 2.75367C16.2747 2.60862 15.9398 2.5463 15.4622 2.51952C15.4647 2.72072 15.4647 2.94567 15.4647 3.19935V4.02265C15.4802 4.02376 15.4954 4.02493 15.5104 4.02616C15.8016 4.04995 15.873 4.08738 15.8781 4.09007C16.0349 4.16996 16.1626 4.29756 16.2425 4.45436C16.2452 4.45947 16.2828 4.53114 16.3065 4.8223C16.3322 5.13614 16.3334 5.55454 16.3334 6.23268V13.766C16.3334 14.4442 16.3322 14.8626 16.3065 15.1764C16.2828 15.4676 16.2453 15.539 16.2426 15.5441C16.1627 15.7009 16.0351 15.8286 15.8783 15.9085C15.8732 15.9112 15.8015 15.9488 15.5104 15.9725C15.4954 15.9738 15.4802 15.9749 15.4647 15.976V16.7993C15.4647 17.053 15.4647 17.278 15.4622 17.4792Z" fill="#111824"/>
|
||||
<path d="M4.53531 17.479C4.05904 17.4522 3.72487 17.3898 3.44071 17.245C3.00166 17.0213 2.64471 16.6644 2.421 16.2253C2.16669 15.7262 2.16669 15.0728 2.16669 13.766V6.23268C2.16669 4.92589 2.16669 4.2725 2.421 3.77337C2.64471 3.33433 3.00166 2.97737 3.44071 2.75367C3.72487 2.60888 4.05904 2.54652 4.53531 2.51966V4.02265C4.51984 4.02376 4.50462 4.02493 4.48964 4.02616C4.19848 4.04994 4.12702 4.08738 4.12191 4.09007C3.9651 4.16996 3.83741 4.29755 3.75752 4.45436C3.75483 4.45947 3.71728 4.53114 3.69349 4.8223C3.66785 5.13614 3.66669 5.55454 3.66669 6.23268V13.766C3.66669 14.4442 3.66785 14.8626 3.69349 15.1764C3.71728 15.4676 3.75472 15.539 3.75741 15.5441C3.8373 15.7009 3.96489 15.8286 4.12169 15.9085C4.12682 15.9112 4.1985 15.9488 4.48964 15.9725C4.50462 15.9738 4.51984 15.9749 4.53531 15.976V17.479Z" fill="#111824"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.4577 3.33268H8.5423C7.95474 3.33268 7.61431 3.33398 7.36442 3.3544C7.25432 3.36339 7.19609 3.37413 7.17186 3.37955C7.12412 3.40795 7.08423 3.44784 7.05583 3.49558C7.05041 3.51981 7.03967 3.57804 7.03068 3.68814C7.01026 3.93803 7.00896 4.27846 7.00896 4.86602V15.1327C7.00896 15.7202 7.01026 16.0607 7.03068 16.3106C7.03967 16.4207 7.05041 16.4789 7.05583 16.5031C7.08423 16.5509 7.12412 16.5907 7.17187 16.6192C7.19609 16.6246 7.25432 16.6353 7.36442 16.6443C7.61431 16.6647 7.95474 16.666 8.5423 16.666H11.4577C12.0453 16.666 12.3857 16.6647 12.6356 16.6443C12.7457 16.6353 12.8039 16.6246 12.8282 16.6191C12.8759 16.5907 12.9158 16.5509 12.9442 16.5031C12.9496 16.4789 12.9604 16.4207 12.9694 16.3106C12.9898 16.0607 12.9911 15.7202 12.9911 15.1327V4.86602C12.9911 4.27846 12.9898 3.93803 12.9694 3.68814C12.9604 3.57804 12.9496 3.51981 12.9442 3.49558C12.9158 3.44784 12.8759 3.40795 12.8282 3.37955C12.8039 3.37413 12.7457 3.36339 12.6356 3.3544C12.3857 3.33398 12.0453 3.33268 11.4577 3.33268ZM12.8421 3.38304L12.8408 3.38266L12.8421 3.38304ZM12.9407 16.517L12.9411 16.5157L12.9407 16.517ZM7.15797 16.6157L7.15924 16.616L7.15797 16.6157ZM5.56028 2.75803C5.3423 3.18586 5.3423 3.74591 5.3423 4.86602V15.1327C5.3423 16.2528 5.3423 16.8128 5.56028 17.2407C5.75203 17.617 6.05799 17.9229 6.43432 18.1147C6.86214 18.3327 7.42219 18.3327 8.5423 18.3327H11.4577C12.5778 18.3327 13.1379 18.3327 13.5657 18.1147C13.942 17.9229 14.248 17.617 14.4397 17.2407C14.6577 16.8128 14.6577 16.2528 14.6577 15.1327V4.86602C14.6577 3.74591 14.6577 3.18586 14.4397 2.75803C14.248 2.38171 13.942 2.07575 13.5657 1.884C13.1379 1.66602 12.5778 1.66602 11.4577 1.66602H8.5423C7.42219 1.66602 6.86214 1.66602 6.43432 1.884C6.05799 2.07575 5.75203 2.38171 5.56028 2.75803Z" fill="#111824"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M1.00332 1.83758H1.81954L2.53389 13.2672C2.53944 13.3565 2.54623 13.466 2.56003 13.5627C2.5762 13.6759 2.60963 13.8372 2.70433 14.0046C2.8274 14.2221 3.01365 14.397 3.23839 14.5063C3.41135 14.5904 3.5744 14.6137 3.68844 14.6228C3.78573 14.6305 3.89538 14.6304 3.98486 14.6304L14.5957 14.6304C15.0559 14.6304 15.429 14.2573 15.429 13.7971C15.429 13.3368 15.0559 12.9637 14.5957 12.9637H4.18485L4.08913 11.4322H13.9345C14.314 11.4322 14.6453 11.4322 14.9207 11.4108C15.2135 11.3881 15.5068 11.3377 15.7953 11.2025C16.2272 11.0002 16.5901 10.6754 16.8389 10.2685C17.0051 9.99663 17.0875 9.71073 17.1425 9.42221C17.1942 9.1509 17.2308 8.82158 17.2727 8.44437L17.7459 4.18496C17.7576 4.08038 17.7715 3.95605 17.7743 3.84616C17.7775 3.72047 17.7706 3.53205 17.6864 3.32954C17.5794 3.07183 17.388 2.85804 17.1437 2.72315C16.9517 2.61716 16.7652 2.58946 16.6399 2.57879C16.5304 2.56947 16.4053 2.56952 16.3001 2.56956L3.53521 2.56956L3.4705 1.53411C3.46496 1.44478 3.45816 1.3353 3.44436 1.23865C3.4282 1.12539 3.39476 0.964112 3.30006 0.796741C3.17699 0.579249 2.99074 0.404282 2.766 0.29502C2.59305 0.210937 2.42999 0.187632 2.31595 0.178561C2.21863 0.170821 2.10894 0.170867 2.01944 0.170904L1.00332 0.170909C0.543079 0.170909 0.169983 0.544005 0.169983 1.00424C0.169983 1.46448 0.543079 1.83758 1.00332 1.83758ZM13.9048 9.76553H3.98496L3.63938 4.23623H16.0633L15.6195 8.23082C15.5733 8.64611 15.5434 8.91032 15.5053 9.11032C15.4691 9.30015 15.4364 9.36731 15.4169 9.39917C15.3386 9.52728 15.2243 9.62954 15.0884 9.69323C15.0545 9.70907 14.9842 9.73419 14.7915 9.74917C14.5885 9.76495 14.3226 9.76553 13.9048 9.76553ZM5.40085 15.3624C4.71982 15.3624 4.16774 15.9145 4.16774 16.5955C4.16774 17.2765 4.71983 17.8286 5.40085 17.8286C6.08188 17.8286 6.63396 17.2765 6.63396 16.5955C6.63396 15.9145 6.08188 15.3624 5.40085 15.3624ZM12.5968 15.3624C11.9158 15.3624 11.3637 15.9145 11.3637 16.5955C11.3637 17.2765 11.9158 17.8286 12.5968 17.8286C13.2778 17.8286 13.8299 17.2765 13.8299 16.5955C13.8299 15.9145 13.2778 15.3624 12.5968 15.3624Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M8.95334 16.4281C9.05498 16.5828 8.93673 16.8071 8.75405 16.777C7.16443 16.5146 5.94181 15.8533 5.05187 14.9994C3.73702 13.7379 3.01725 11.931 3.01725 9.9769C3.01725 6.18011 6.09515 3.10221 9.89194 3.10221C13.8727 3.10221 16.9827 5.87983 16.9827 9.50285C16.9827 10.4282 16.7524 10.9955 16.4763 11.3538C16.1992 11.7133 15.7615 12.011 15.0821 12.191C14.485 12.3493 13.879 12.3607 13.0988 12.3754C12.9461 12.3782 12.7868 12.3812 12.6195 12.3855C11.7922 12.4065 10.4224 12.4464 9.36346 13.3001C8.72411 13.8156 8.524 14.5121 8.52868 15.0653C8.5328 15.5521 8.68681 15.9446 8.79908 16.1635C8.84683 16.2566 8.89859 16.3447 8.95334 16.4281ZM15.5091 13.8021C17.4217 13.2951 18.6494 11.9261 18.6494 9.50285C18.6494 4.7856 14.6092 1.43555 9.89194 1.43555C5.17468 1.43555 1.35059 5.25964 1.35059 9.9769C1.35059 14.6942 4.8343 19.0091 11.2788 18.5298C12.2308 18.459 12.5569 17.3597 12.122 16.8903C11.89 16.6399 11.5858 16.4575 11.2857 16.2776C10.8812 16.035 10.4842 15.797 10.2821 15.4029C10.214 15.2701 10.0763 14.8663 10.4095 14.5977C11.0553 14.0771 12.0167 14.0611 13.082 14.0434C13.8631 14.0304 14.7 14.0165 15.5091 13.8021ZM6.85887 9.40095C6.85887 10.1411 6.25883 10.7412 5.51863 10.7412C4.77844 10.7412 4.1784 10.1411 4.1784 9.40095C4.1784 8.66076 4.77844 8.06071 5.51863 8.06071C6.25883 8.06071 6.85887 8.66076 6.85887 9.40095ZM8.09584 7.52192C8.83604 7.52192 9.43608 6.92187 9.43608 6.18168C9.43608 5.44149 8.83604 4.84144 8.09584 4.84144C7.35565 4.84144 6.75561 5.44149 6.75561 6.18168C6.75561 6.92187 7.35565 7.52192 8.09584 7.52192ZM13.4525 6.18168C13.4525 6.92187 12.8525 7.52192 12.1123 7.52192C11.3721 7.52192 10.772 6.92187 10.772 6.18168C10.772 5.44149 11.3721 4.84144 12.1123 4.84144C12.8525 4.84144 13.4525 5.44149 13.4525 6.18168ZM14.4814 10.7412C15.2216 10.7412 15.8216 10.1411 15.8216 9.40095C15.8216 8.66076 15.2216 8.06071 14.4814 8.06071C13.7412 8.06071 13.1411 8.66076 13.1411 9.40095C13.1411 10.1411 13.7412 10.7412 14.4814 10.7412Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
127
packages/web/components/common/Input/HttpInput/Editor.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import { useState, useRef, useTransition, useEffect, useMemo } from 'react';
|
||||
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
||||
import { PlainTextPlugin } from '@lexical/react/LexicalPlainTextPlugin';
|
||||
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
|
||||
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
|
||||
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import styles from './index.module.scss';
|
||||
import { EditorState, LexicalEditor } from 'lexical';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { EditorVariablePickerType } from '../../Textarea/PromptEditor/type';
|
||||
import { VariableNode } from '../../Textarea/PromptEditor/plugins/VariablePlugin/node';
|
||||
import { textToEditorState } from '../../Textarea/PromptEditor/utils';
|
||||
import DropDownMenu from '../../Textarea/PromptEditor/modules/DropDownMenu';
|
||||
import { SingleLinePlugin } from '../../Textarea/PromptEditor/plugins/SingleLinePlugin';
|
||||
import OnBlurPlugin from '../../Textarea/PromptEditor/plugins/OnBlurPlugin';
|
||||
import VariablePlugin from '../../Textarea/PromptEditor/plugins/VariablePlugin';
|
||||
import VariablePickerPlugin from '../../Textarea/PromptEditor/plugins/VariablePickerPlugin';
|
||||
import FocusPlugin from '../../Textarea/PromptEditor/plugins/FocusPlugin';
|
||||
|
||||
export default function Editor({
|
||||
h = 40,
|
||||
hasVariablePlugin = true,
|
||||
hasDropDownPlugin = false,
|
||||
variables,
|
||||
onChange,
|
||||
onBlur,
|
||||
value,
|
||||
currentValue,
|
||||
placeholder = '',
|
||||
setDropdownValue,
|
||||
updateTrigger
|
||||
}: {
|
||||
h?: number;
|
||||
hasVariablePlugin?: boolean;
|
||||
hasDropDownPlugin?: boolean;
|
||||
variables: EditorVariablePickerType[];
|
||||
onChange?: (editorState: EditorState) => void;
|
||||
onBlur?: (editor: LexicalEditor) => void;
|
||||
value?: string;
|
||||
currentValue?: string;
|
||||
placeholder?: string;
|
||||
setDropdownValue?: (value: string) => void;
|
||||
updateTrigger?: boolean;
|
||||
}) {
|
||||
const [key, setKey] = useState(getNanoid(6));
|
||||
const [_, startSts] = useTransition();
|
||||
const [focus, setFocus] = useState(false);
|
||||
|
||||
const initialConfig = {
|
||||
namespace: 'HttpInput',
|
||||
nodes: [VariableNode],
|
||||
editorState: textToEditorState(value),
|
||||
onError: (error: Error) => {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (focus) return;
|
||||
setKey(getNanoid(6));
|
||||
}, [value, variables.length]);
|
||||
|
||||
useEffect(() => {
|
||||
setKey(getNanoid(6));
|
||||
}, [updateTrigger]);
|
||||
|
||||
const dropdownVariables = useMemo(
|
||||
() =>
|
||||
variables.filter((item) => {
|
||||
return item.key.includes(currentValue || '') && item.key !== currentValue;
|
||||
}),
|
||||
[currentValue]
|
||||
);
|
||||
|
||||
return (
|
||||
<Box position={'relative'} width={'full'} h={`${h}px`} cursor={'text'}>
|
||||
<LexicalComposer initialConfig={initialConfig} key={key}>
|
||||
<PlainTextPlugin
|
||||
contentEditable={<ContentEditable className={styles.contentEditable} />}
|
||||
placeholder={
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
py={3}
|
||||
px={2}
|
||||
pointerEvents={'none'}
|
||||
overflow={'overlay'}
|
||||
>
|
||||
<Box
|
||||
color={'myGray.500'}
|
||||
fontSize={'xs'}
|
||||
userSelect={'none'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
wordBreak={'break-all'}
|
||||
h={'100%'}
|
||||
>
|
||||
{placeholder}
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
ErrorBoundary={LexicalErrorBoundary}
|
||||
/>
|
||||
<HistoryPlugin />
|
||||
<FocusPlugin focus={focus} setFocus={setFocus} />
|
||||
<OnChangePlugin
|
||||
onChange={(e) => {
|
||||
startSts(() => {
|
||||
onChange?.(e);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{hasVariablePlugin ? <VariablePickerPlugin variables={variables} /> : ''}
|
||||
{hasVariablePlugin ? <VariablePlugin variables={variables} /> : ''}
|
||||
<OnBlurPlugin onBlur={onBlur} />
|
||||
<SingleLinePlugin />
|
||||
</LexicalComposer>
|
||||
{focus && hasDropDownPlugin && (
|
||||
<DropDownMenu variables={dropdownVariables} setDropdownValue={setDropdownValue} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
.contentEditable {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow: auto;
|
||||
padding-left: 8px;
|
||||
position: relative;
|
||||
}
|