mirror of
https://github.com/labring/FastGPT.git
synced 2026-05-17 01:02:24 +08:00
fix: schema parse,default config
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export const stripUrlTrailingSlash = (value?: string) => value?.replace(/\/+$/, '') || '';
|
||||
@@ -0,0 +1,22 @@
|
||||
import z from 'zod';
|
||||
import { stripUrlTrailingSlash } from '../string/url';
|
||||
|
||||
const truthyBoolStrs = ['true', '1', 'yes', 'y', 'on'];
|
||||
export const BoolSchema = z.preprocess((val) => {
|
||||
if (typeof val === 'boolean') return val;
|
||||
|
||||
if (typeof val === 'string') {
|
||||
return truthyBoolStrs.includes(val.trim().toLowerCase());
|
||||
}
|
||||
|
||||
if (typeof val === 'number') {
|
||||
if (val === 1) return true;
|
||||
if (val === 0) return false;
|
||||
}
|
||||
|
||||
return val;
|
||||
}, z.boolean());
|
||||
|
||||
export const NumSchema = z.coerce.number<number>();
|
||||
export const IntSchema = NumSchema.int().nonnegative();
|
||||
export const UrlSchema = z.string().url().transform(stripUrlTrailingSlash);
|
||||
@@ -3,6 +3,7 @@ import { WorkflowIOValueTypeEnum, NodeInputKeyEnum, NodeOutputKeyEnum } from '..
|
||||
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../node/constant';
|
||||
import { SecretValueTypeSchema } from '../../../common/secret/type';
|
||||
import z from 'zod';
|
||||
import { BoolSchema, IntSchema, NumSchema } from '../../../common/zod';
|
||||
|
||||
/* Dataset node */
|
||||
export const SelectedDatasetSchema = z.object({
|
||||
@@ -19,8 +20,9 @@ export type SelectedDatasetType = z.infer<typeof SelectedDatasetSchema>;
|
||||
export const CustomFieldConfigTypeSchema = z.object({
|
||||
// reference
|
||||
selectValueTypeList: z.array(z.enum(WorkflowIOValueTypeEnum)).optional(), // 可以选哪个数据类型, 只有1个的话,则默认选择
|
||||
showDefaultValue: z.boolean().optional(),
|
||||
showDescription: z.boolean().optional()
|
||||
showDefaultValue: BoolSchema.optional(),
|
||||
showDescription: BoolSchema.optional(),
|
||||
hideBottomDivider: BoolSchema.optional()
|
||||
});
|
||||
export type CustomFieldConfigType = z.infer<typeof CustomFieldConfigTypeSchema>;
|
||||
|
||||
@@ -29,31 +31,40 @@ export const InputComponentPropsTypeSchema = z.object({
|
||||
label: z.string(),
|
||||
|
||||
valueType: z.enum(WorkflowIOValueTypeEnum).optional(),
|
||||
required: z.boolean().optional(),
|
||||
required: BoolSchema.optional(),
|
||||
defaultValue: z.any().optional(),
|
||||
|
||||
// 不同组件的配置嘻嘻
|
||||
referencePlaceholder: z.string().optional(),
|
||||
isRichText: z.boolean().optional(), // Prompt editor
|
||||
isRichText: BoolSchema.optional(), // Prompt editor
|
||||
placeholder: z.string().optional(), // input,textarea
|
||||
maxLength: z.number().optional(), // input,textarea
|
||||
minLength: z.number().optional(), // password
|
||||
list: z.array(z.object({ label: z.string(), value: z.string() })).optional(), // select
|
||||
markList: z.array(z.object({ label: z.string(), value: z.number() })).optional(), // slider
|
||||
step: z.number().optional(), // slider
|
||||
max: z.number().optional(), // slider, number input
|
||||
min: z.number().optional(), // slider, number input
|
||||
precision: z.number().optional(), // number input
|
||||
maxLength: IntSchema.optional(), // input,textarea
|
||||
minLength: IntSchema.optional(), // password
|
||||
list: z
|
||||
.array(
|
||||
z.object({
|
||||
label: z.string(),
|
||||
value: z.string(),
|
||||
icon: z.string().optional(),
|
||||
description: z.string().optional()
|
||||
})
|
||||
)
|
||||
.optional(), // select
|
||||
markList: z.array(z.object({ label: z.string(), value: NumSchema })).optional(), // slider
|
||||
step: NumSchema.optional(), // slider
|
||||
max: NumSchema.optional(), // slider, number input
|
||||
min: NumSchema.optional(), // slider, number input
|
||||
precision: NumSchema.optional(), // number input
|
||||
|
||||
canSelectFile: z.boolean().optional(), // file select
|
||||
canSelectImg: z.boolean().optional(), // file select
|
||||
canSelectVideo: z.boolean().optional(), // file select
|
||||
canSelectAudio: z.boolean().optional(), // file select
|
||||
canSelectCustomFileExtension: z.boolean().optional(), // file select
|
||||
canSelectFile: BoolSchema.optional(), // file select
|
||||
canSelectImg: BoolSchema.optional(), // file select
|
||||
canSelectVideo: BoolSchema.optional(), // file select
|
||||
canSelectAudio: BoolSchema.optional(), // file select
|
||||
canSelectCustomFileExtension: BoolSchema.optional(), // file select
|
||||
customFileExtensionList: z.array(z.string()).optional(), // file select
|
||||
canLocalUpload: z.boolean().optional(), // file select
|
||||
canUrlUpload: z.boolean().optional(), // file select
|
||||
maxFiles: z.number().optional(), // file select
|
||||
canLocalUpload: BoolSchema.optional(), // file select
|
||||
canUrlUpload: BoolSchema.optional(), // file select
|
||||
maxFiles: IntSchema.optional(), // file select
|
||||
|
||||
// Time
|
||||
timeGranularity: z.enum(['day', 'hour', 'minute', 'second']).optional(), // time point select, time range select
|
||||
@@ -76,7 +87,7 @@ export const InputConfigTypeSchema = z.object({
|
||||
key: z.string(),
|
||||
label: z.string(),
|
||||
description: z.string().optional(),
|
||||
required: z.boolean().optional(),
|
||||
required: BoolSchema.optional(),
|
||||
inputType: z.enum(['input', 'numberInput', 'secret', 'switch', 'select']),
|
||||
value: SecretValueTypeSchema.optional(),
|
||||
|
||||
@@ -87,7 +98,7 @@ export type InputConfigType = z.infer<typeof InputConfigTypeSchema>;
|
||||
|
||||
// Workflow node input
|
||||
export const FlowNodeInputItemTypeSchema = InputComponentPropsTypeSchema.extend({
|
||||
selectedTypeIndex: z.number().optional(),
|
||||
selectedTypeIndex: IntSchema.optional(),
|
||||
renderTypeList: z.array(z.enum(FlowNodeInputTypeEnum)), // Node Type. Decide on a render style
|
||||
valueDesc: z.string().optional(), // data desc
|
||||
value: z.any().optional(),
|
||||
@@ -101,11 +112,11 @@ export const FlowNodeInputItemTypeSchema = InputComponentPropsTypeSchema.extend(
|
||||
inputList: z.array(InputConfigTypeSchema).optional(), // when key === 'system_input_config', this field is used
|
||||
|
||||
// render components params
|
||||
canEdit: z.boolean().optional(), // dynamic inputs
|
||||
isPro: z.boolean().optional(), // Pro version field
|
||||
isToolOutput: z.boolean().optional(),
|
||||
canEdit: BoolSchema.optional(), // dynamic inputs
|
||||
isPro: BoolSchema.optional(), // Pro version field
|
||||
isToolOutput: BoolSchema.optional(),
|
||||
|
||||
deprecated: z.boolean().optional() // node deprecated
|
||||
deprecated: BoolSchema.optional() // node deprecated
|
||||
});
|
||||
export type FlowNodeInputItemType = z.infer<typeof FlowNodeInputItemTypeSchema>;
|
||||
|
||||
@@ -121,18 +132,18 @@ export const FlowNodeOutputItemTypeSchema = z.object({
|
||||
label: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
defaultValue: z.any().optional(),
|
||||
required: z.boolean().optional(),
|
||||
required: BoolSchema.optional(),
|
||||
|
||||
invalid: z.boolean().optional(),
|
||||
invalid: BoolSchema.optional(),
|
||||
invalidCondition: z
|
||||
.function({
|
||||
input: z.tuple([
|
||||
z.object({
|
||||
inputs: z.array(FlowNodeInputItemTypeSchema),
|
||||
inputs: z.custom<FlowNodeInputItemType[]>(),
|
||||
llmModelMap: z.record(z.string(), LLMModelItemSchema)
|
||||
})
|
||||
]),
|
||||
output: z.boolean()
|
||||
output: BoolSchema
|
||||
})
|
||||
.optional()
|
||||
.meta({
|
||||
@@ -143,7 +154,7 @@ export const FlowNodeOutputItemTypeSchema = z.object({
|
||||
}),
|
||||
|
||||
customFieldConfig: CustomFieldConfigTypeSchema.optional(),
|
||||
deprecated: z.boolean().optional()
|
||||
deprecated: BoolSchema.optional()
|
||||
});
|
||||
export type FlowNodeOutputItemType = z.infer<typeof FlowNodeOutputItemTypeSchema>;
|
||||
|
||||
|
||||
@@ -35,14 +35,14 @@ export const loadSystemModels = async (init = false, language = 'en') => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
let _systemModelList: SystemModelItemType[] = [];
|
||||
let _systemActiveModelList: SystemModelItemType[] = [];
|
||||
let _llmModelMap = new Map<string, LLMModelItemType>();
|
||||
let _embeddingModelMap = new Map<string, EmbeddingModelItemType>();
|
||||
let _ttsModelMap = new Map<string, TTSModelType>();
|
||||
let _sttModelMap = new Map<string, STTModelType>();
|
||||
let _reRankModelMap = new Map<string, RerankModelItemType>();
|
||||
let _systemDefaultModel: SystemDefaultModelType = {};
|
||||
const _systemModelList: SystemModelItemType[] = [];
|
||||
const _systemActiveModelList: SystemModelItemType[] = [];
|
||||
const _llmModelMap = new Map<string, LLMModelItemType>();
|
||||
const _embeddingModelMap = new Map<string, EmbeddingModelItemType>();
|
||||
const _ttsModelMap = new Map<string, TTSModelType>();
|
||||
const _sttModelMap = new Map<string, STTModelType>();
|
||||
const _reRankModelMap = new Map<string, RerankModelItemType>();
|
||||
const _systemDefaultModel: SystemDefaultModelType = {};
|
||||
|
||||
if (!global.systemModelList) {
|
||||
global.systemModelList = [];
|
||||
@@ -144,8 +144,14 @@ export const loadSystemModels = async (init = false, language = 'en') => {
|
||||
...(model.type === ModelTypeEnum.llm && dbModel?.metadata?.type === ModelTypeEnum.llm
|
||||
? {
|
||||
maxResponse: dbModel?.metadata?.maxResponse ?? model.maxTokens ?? 8000,
|
||||
defaultConfig: mergeObject(model.defaultConfig, dbModel?.metadata?.defaultConfig),
|
||||
fieldMap: mergeObject(model.fieldMap, dbModel?.metadata?.fieldMap),
|
||||
defaultConfig:
|
||||
typeof dbModel?.metadata?.defaultConfig === 'object'
|
||||
? dbModel?.metadata?.defaultConfig
|
||||
: model.defaultConfig,
|
||||
fieldMap:
|
||||
typeof dbModel?.metadata?.fieldMap === 'object'
|
||||
? dbModel?.metadata?.fieldMap
|
||||
: model.fieldMap,
|
||||
/** @deprecated */
|
||||
maxTokens: undefined
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fastgpt/app",
|
||||
"version": "4.14.19",
|
||||
"version": "4.14.20",
|
||||
"private": false,
|
||||
"browserslist": [
|
||||
"Chrome >= 80",
|
||||
|
||||
@@ -6,22 +6,16 @@ import { findModelFromAlldata } from '@fastgpt/service/core/ai/model';
|
||||
import { updatedReloadSystemModel } from '@fastgpt/service/core/ai/config/utils';
|
||||
import { ModelTypeEnum } from '@fastgpt/global/core/ai/constants';
|
||||
|
||||
export type updateQuery = {};
|
||||
|
||||
export type updateBody = {
|
||||
model: string;
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
|
||||
export type updateResponse = {};
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<updateBody, updateQuery>,
|
||||
res: ApiResponseType<any>
|
||||
): Promise<updateResponse> {
|
||||
async function handler(req: ApiRequestProps<updateBody>, res: ApiResponseType<any>) {
|
||||
await authSystemAdmin({ req });
|
||||
|
||||
let { model, metadata } = req.body;
|
||||
const metadata = req.body.metadata;
|
||||
let { model } = req.body;
|
||||
if (!model) return Promise.reject(new Error('model is required'));
|
||||
model = model.trim();
|
||||
|
||||
@@ -60,6 +54,11 @@ async function handler(
|
||||
}
|
||||
});
|
||||
|
||||
// 强制更新 defaultConfig 数据类型
|
||||
if ('defaultConfig' in metadataConcat && typeof metadataConcat.defaultConfig !== 'object') {
|
||||
metadataConcat.defaultConfig = {};
|
||||
}
|
||||
|
||||
await MongoSystemModel.updateOne(
|
||||
{ model },
|
||||
{
|
||||
|
||||
@@ -6,18 +6,11 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { MongoSystemModel } from '@fastgpt/service/core/ai/config/schema';
|
||||
import { updatedReloadSystemModel } from '@fastgpt/service/core/ai/config/utils';
|
||||
|
||||
export type updateWithJsonQuery = {};
|
||||
|
||||
export type updateWithJsonBody = {
|
||||
config: string;
|
||||
};
|
||||
|
||||
export type updateWithJsonResponse = {};
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<updateWithJsonBody, updateWithJsonQuery>,
|
||||
res: ApiResponseType<any>
|
||||
): Promise<updateWithJsonResponse> {
|
||||
async function handler(req: ApiRequestProps<updateWithJsonBody>, res: ApiResponseType<any>) {
|
||||
await authSystemAdmin({ req });
|
||||
|
||||
const { config } = req.body;
|
||||
@@ -41,6 +34,11 @@ async function handler(
|
||||
if (!item.metadata.name) {
|
||||
item.metadata.name = item.model;
|
||||
}
|
||||
if ('defaultConfig' in item.metadata && typeof item.metadata.defaultConfig !== 'object') {
|
||||
{
|
||||
item.metadata.defaultConfig = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await mongoSessionRun(async (session) => {
|
||||
|
||||
Reference in New Issue
Block a user