Skip to content

Commit fafaa28

Browse files
committed
fix: schema parse,default config
1 parent b8f81e9 commit fafaa28

7 files changed

Lines changed: 97 additions & 60 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const stripUrlTrailingSlash = (value?: string) => value?.replace(/\/+$/, '') || '';
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import z from 'zod';
2+
import { stripUrlTrailingSlash } from '../string/url';
3+
4+
const truthyBoolStrs = ['true', '1', 'yes', 'y', 'on'];
5+
export const BoolSchema = z.preprocess((val) => {
6+
if (typeof val === 'boolean') return val;
7+
8+
if (typeof val === 'string') {
9+
return truthyBoolStrs.includes(val.trim().toLowerCase());
10+
}
11+
12+
if (typeof val === 'number') {
13+
if (val === 1) return true;
14+
if (val === 0) return false;
15+
}
16+
17+
return val;
18+
}, z.boolean());
19+
20+
export const NumSchema = z.coerce.number<number>();
21+
export const IntSchema = NumSchema.int().nonnegative();
22+
export const UrlSchema = z.string().url().transform(stripUrlTrailingSlash);

packages/global/core/workflow/type/io.ts

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { WorkflowIOValueTypeEnum, NodeInputKeyEnum, NodeOutputKeyEnum } from '..
33
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../node/constant';
44
import { SecretValueTypeSchema } from '../../../common/secret/type';
55
import z from 'zod';
6+
import { BoolSchema, IntSchema, NumSchema } from '../../../common/zod';
67

78
/* Dataset node */
89
export const SelectedDatasetSchema = z.object({
@@ -19,8 +20,9 @@ export type SelectedDatasetType = z.infer<typeof SelectedDatasetSchema>;
1920
export const CustomFieldConfigTypeSchema = z.object({
2021
// reference
2122
selectValueTypeList: z.array(z.enum(WorkflowIOValueTypeEnum)).optional(), // 可以选哪个数据类型, 只有1个的话,则默认选择
22-
showDefaultValue: z.boolean().optional(),
23-
showDescription: z.boolean().optional()
23+
showDefaultValue: BoolSchema.optional(),
24+
showDescription: BoolSchema.optional(),
25+
hideBottomDivider: BoolSchema.optional()
2426
});
2527
export type CustomFieldConfigType = z.infer<typeof CustomFieldConfigTypeSchema>;
2628

@@ -29,31 +31,40 @@ export const InputComponentPropsTypeSchema = z.object({
2931
label: z.string(),
3032

3133
valueType: z.enum(WorkflowIOValueTypeEnum).optional(),
32-
required: z.boolean().optional(),
34+
required: BoolSchema.optional(),
3335
defaultValue: z.any().optional(),
3436

3537
// 不同组件的配置嘻嘻
3638
referencePlaceholder: z.string().optional(),
37-
isRichText: z.boolean().optional(), // Prompt editor
39+
isRichText: BoolSchema.optional(), // Prompt editor
3840
placeholder: z.string().optional(), // input,textarea
39-
maxLength: z.number().optional(), // input,textarea
40-
minLength: z.number().optional(), // password
41-
list: z.array(z.object({ label: z.string(), value: z.string() })).optional(), // select
42-
markList: z.array(z.object({ label: z.string(), value: z.number() })).optional(), // slider
43-
step: z.number().optional(), // slider
44-
max: z.number().optional(), // slider, number input
45-
min: z.number().optional(), // slider, number input
46-
precision: z.number().optional(), // number input
47-
48-
canSelectFile: z.boolean().optional(), // file select
49-
canSelectImg: z.boolean().optional(), // file select
50-
canSelectVideo: z.boolean().optional(), // file select
51-
canSelectAudio: z.boolean().optional(), // file select
52-
canSelectCustomFileExtension: z.boolean().optional(), // file select
41+
maxLength: IntSchema.optional(), // input,textarea
42+
minLength: IntSchema.optional(), // password
43+
list: z
44+
.array(
45+
z.object({
46+
label: z.string(),
47+
value: z.string(),
48+
icon: z.string().optional(),
49+
description: z.string().optional()
50+
})
51+
)
52+
.optional(), // select
53+
markList: z.array(z.object({ label: z.string(), value: NumSchema })).optional(), // slider
54+
step: NumSchema.optional(), // slider
55+
max: NumSchema.optional(), // slider, number input
56+
min: NumSchema.optional(), // slider, number input
57+
precision: NumSchema.optional(), // number input
58+
59+
canSelectFile: BoolSchema.optional(), // file select
60+
canSelectImg: BoolSchema.optional(), // file select
61+
canSelectVideo: BoolSchema.optional(), // file select
62+
canSelectAudio: BoolSchema.optional(), // file select
63+
canSelectCustomFileExtension: BoolSchema.optional(), // file select
5364
customFileExtensionList: z.array(z.string()).optional(), // file select
54-
canLocalUpload: z.boolean().optional(), // file select
55-
canUrlUpload: z.boolean().optional(), // file select
56-
maxFiles: z.number().optional(), // file select
65+
canLocalUpload: BoolSchema.optional(), // file select
66+
canUrlUpload: BoolSchema.optional(), // file select
67+
maxFiles: IntSchema.optional(), // file select
5768

5869
// Time
5970
timeGranularity: z.enum(['day', 'hour', 'minute', 'second']).optional(), // time point select, time range select
@@ -76,7 +87,7 @@ export const InputConfigTypeSchema = z.object({
7687
key: z.string(),
7788
label: z.string(),
7889
description: z.string().optional(),
79-
required: z.boolean().optional(),
90+
required: BoolSchema.optional(),
8091
inputType: z.enum(['input', 'numberInput', 'secret', 'switch', 'select']),
8192
value: SecretValueTypeSchema.optional(),
8293

@@ -87,7 +98,7 @@ export type InputConfigType = z.infer<typeof InputConfigTypeSchema>;
8798

8899
// Workflow node input
89100
export const FlowNodeInputItemTypeSchema = InputComponentPropsTypeSchema.extend({
90-
selectedTypeIndex: z.number().optional(),
101+
selectedTypeIndex: IntSchema.optional(),
91102
renderTypeList: z.array(z.enum(FlowNodeInputTypeEnum)), // Node Type. Decide on a render style
92103
valueDesc: z.string().optional(), // data desc
93104
value: z.any().optional(),
@@ -101,11 +112,11 @@ export const FlowNodeInputItemTypeSchema = InputComponentPropsTypeSchema.extend(
101112
inputList: z.array(InputConfigTypeSchema).optional(), // when key === 'system_input_config', this field is used
102113

103114
// render components params
104-
canEdit: z.boolean().optional(), // dynamic inputs
105-
isPro: z.boolean().optional(), // Pro version field
106-
isToolOutput: z.boolean().optional(),
115+
canEdit: BoolSchema.optional(), // dynamic inputs
116+
isPro: BoolSchema.optional(), // Pro version field
117+
isToolOutput: BoolSchema.optional(),
107118

108-
deprecated: z.boolean().optional() // node deprecated
119+
deprecated: BoolSchema.optional() // node deprecated
109120
});
110121
export type FlowNodeInputItemType = z.infer<typeof FlowNodeInputItemTypeSchema>;
111122

@@ -121,18 +132,18 @@ export const FlowNodeOutputItemTypeSchema = z.object({
121132
label: z.string().optional(),
122133
description: z.string().optional(),
123134
defaultValue: z.any().optional(),
124-
required: z.boolean().optional(),
135+
required: BoolSchema.optional(),
125136

126-
invalid: z.boolean().optional(),
137+
invalid: BoolSchema.optional(),
127138
invalidCondition: z
128139
.function({
129140
input: z.tuple([
130141
z.object({
131-
inputs: z.array(FlowNodeInputItemTypeSchema),
142+
inputs: z.custom<FlowNodeInputItemType[]>(),
132143
llmModelMap: z.record(z.string(), LLMModelItemSchema)
133144
})
134145
]),
135-
output: z.boolean()
146+
output: BoolSchema
136147
})
137148
.optional()
138149
.meta({
@@ -143,7 +154,7 @@ export const FlowNodeOutputItemTypeSchema = z.object({
143154
}),
144155

145156
customFieldConfig: CustomFieldConfigTypeSchema.optional(),
146-
deprecated: z.boolean().optional()
157+
deprecated: BoolSchema.optional()
147158
});
148159
export type FlowNodeOutputItemType = z.infer<typeof FlowNodeOutputItemTypeSchema>;
149160

packages/service/core/ai/config/utils.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ export const loadSystemModels = async (init = false, language = 'en') => {
3535
return Promise.reject(error);
3636
}
3737

38-
let _systemModelList: SystemModelItemType[] = [];
39-
let _systemActiveModelList: SystemModelItemType[] = [];
40-
let _llmModelMap = new Map<string, LLMModelItemType>();
41-
let _embeddingModelMap = new Map<string, EmbeddingModelItemType>();
42-
let _ttsModelMap = new Map<string, TTSModelType>();
43-
let _sttModelMap = new Map<string, STTModelType>();
44-
let _reRankModelMap = new Map<string, RerankModelItemType>();
45-
let _systemDefaultModel: SystemDefaultModelType = {};
38+
const _systemModelList: SystemModelItemType[] = [];
39+
const _systemActiveModelList: SystemModelItemType[] = [];
40+
const _llmModelMap = new Map<string, LLMModelItemType>();
41+
const _embeddingModelMap = new Map<string, EmbeddingModelItemType>();
42+
const _ttsModelMap = new Map<string, TTSModelType>();
43+
const _sttModelMap = new Map<string, STTModelType>();
44+
const _reRankModelMap = new Map<string, RerankModelItemType>();
45+
const _systemDefaultModel: SystemDefaultModelType = {};
4646

4747
if (!global.systemModelList) {
4848
global.systemModelList = [];
@@ -144,8 +144,14 @@ export const loadSystemModels = async (init = false, language = 'en') => {
144144
...(model.type === ModelTypeEnum.llm && dbModel?.metadata?.type === ModelTypeEnum.llm
145145
? {
146146
maxResponse: dbModel?.metadata?.maxResponse ?? model.maxTokens ?? 8000,
147-
defaultConfig: mergeObject(model.defaultConfig, dbModel?.metadata?.defaultConfig),
148-
fieldMap: mergeObject(model.fieldMap, dbModel?.metadata?.fieldMap),
147+
defaultConfig:
148+
typeof dbModel?.metadata?.defaultConfig === 'object'
149+
? dbModel?.metadata?.defaultConfig
150+
: model.defaultConfig,
151+
fieldMap:
152+
typeof dbModel?.metadata?.fieldMap === 'object'
153+
? dbModel?.metadata?.fieldMap
154+
: model.fieldMap,
149155
/** @deprecated */
150156
maxTokens: undefined
151157
}

projects/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fastgpt/app",
3-
"version": "4.14.19",
3+
"version": "4.14.20",
44
"private": false,
55
"browserslist": [
66
"Chrome >= 80",

projects/app/src/pages/api/core/ai/model/update.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,16 @@ import { findModelFromAlldata } from '@fastgpt/service/core/ai/model';
66
import { updatedReloadSystemModel } from '@fastgpt/service/core/ai/config/utils';
77
import { ModelTypeEnum } from '@fastgpt/global/core/ai/constants';
88

9-
export type updateQuery = {};
10-
119
export type updateBody = {
1210
model: string;
1311
metadata?: Record<string, any>;
1412
};
1513

16-
export type updateResponse = {};
17-
18-
async function handler(
19-
req: ApiRequestProps<updateBody, updateQuery>,
20-
res: ApiResponseType<any>
21-
): Promise<updateResponse> {
14+
async function handler(req: ApiRequestProps<updateBody>, res: ApiResponseType<any>) {
2215
await authSystemAdmin({ req });
2316

24-
let { model, metadata } = req.body;
17+
const metadata = req.body.metadata;
18+
let { model } = req.body;
2519
if (!model) return Promise.reject(new Error('model is required'));
2620
model = model.trim();
2721

@@ -60,6 +54,11 @@ async function handler(
6054
}
6155
});
6256

57+
// 强制更新 defaultConfig 数据类型
58+
if ('defaultConfig' in metadataConcat && typeof metadataConcat.defaultConfig !== 'object') {
59+
metadataConcat.defaultConfig = {};
60+
}
61+
6362
await MongoSystemModel.updateOne(
6463
{ model },
6564
{

projects/app/src/pages/api/core/ai/model/updateWithJson.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,11 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
66
import { MongoSystemModel } from '@fastgpt/service/core/ai/config/schema';
77
import { updatedReloadSystemModel } from '@fastgpt/service/core/ai/config/utils';
88

9-
export type updateWithJsonQuery = {};
10-
119
export type updateWithJsonBody = {
1210
config: string;
1311
};
1412

15-
export type updateWithJsonResponse = {};
16-
17-
async function handler(
18-
req: ApiRequestProps<updateWithJsonBody, updateWithJsonQuery>,
19-
res: ApiResponseType<any>
20-
): Promise<updateWithJsonResponse> {
13+
async function handler(req: ApiRequestProps<updateWithJsonBody>, res: ApiResponseType<any>) {
2114
await authSystemAdmin({ req });
2215

2316
const { config } = req.body;
@@ -41,6 +34,11 @@ async function handler(
4134
if (!item.metadata.name) {
4235
item.metadata.name = item.model;
4336
}
37+
if ('defaultConfig' in item.metadata && typeof item.metadata.defaultConfig !== 'object') {
38+
{
39+
item.metadata.defaultConfig = {};
40+
}
41+
}
4442
}
4543

4644
await mongoSessionRun(async (session) => {

0 commit comments

Comments
 (0)