优化模型配置和节回显
This commit is contained in:
@@ -141,6 +141,15 @@ These rules capture long-term repository preferences confirmed by the user and s
|
|||||||
- When code changes appear not to take effect, check in this order: compile/HMR status, render conditions, API data, then style overrides.
|
- When code changes appear not to take effect, check in this order: compile/HMR status, render conditions, API data, then style overrides.
|
||||||
- Turn repeated low-level mistakes into explicit workflow checks and follow those checks in future edits.
|
- Turn repeated low-level mistakes into explicit workflow checks and follow those checks in future edits.
|
||||||
|
|
||||||
|
### Environment and Tool Selection Rules
|
||||||
|
|
||||||
|
- Before running environment-dependent commands, first follow the known runtime context already provided by the IDE, such as OS and default shell.
|
||||||
|
- On Windows projects with PowerShell as the active shell, prefer PowerShell-native commands and scripts by default.
|
||||||
|
- Do not assume Python, bash, sed, awk, or other non-default tooling is installed locally unless the user or repository explicitly indicates that they are available.
|
||||||
|
- For reading and editing repository files, prefer dedicated file tools first; use shell-based text replacement only when file tools are not suitable for the change.
|
||||||
|
- When a replacement fails once, do not keep retrying the same method blindly. Re-read the exact target content and switch to a smaller or more reliable edit strategy that matches the current environment.
|
||||||
|
- Avoid trial-and-error probing for basic tooling when the available environment is already known from context.
|
||||||
|
|
||||||
### Componentization and Structure Rules
|
### Componentization and Structure Rules
|
||||||
|
|
||||||
- If a view block has an independent responsibility, prefer extracting it into a component instead of keeping it inside a large page file.
|
- If a view block has an independent responsibility, prefer extracting it into a component instead of keeping it inside a large page file.
|
||||||
|
|||||||
@@ -118,15 +118,22 @@ interface ModelItem {
|
|||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
isPrivate?: number;
|
isPrivate?: number;
|
||||||
isChatModel?: number;
|
isChatModel?: number;
|
||||||
headMsg?: string;
|
headMsg?: string | Record<string, string>;
|
||||||
operatorName?: string;
|
operatorName?: string;
|
||||||
responseBody?: Record<string, unknown>;
|
responseBody?: Record<string, unknown>;
|
||||||
|
responseTokenField?: string;
|
||||||
tokenConfig?: Record<string, unknown> | string;
|
tokenConfig?: Record<string, unknown> | string;
|
||||||
extendMapping?: Record<string, unknown> | string;
|
extendMapping?: Record<string, unknown> | string;
|
||||||
queryConfig?: Record<string, unknown>;
|
queryConfig?: Record<string, unknown>;
|
||||||
|
streamConfig?: Record<string, unknown>;
|
||||||
form?: ModelFormEntry[] | Record<string, unknown>;
|
form?: ModelFormEntry[] | Record<string, unknown>;
|
||||||
requestMapping?: Record<string, unknown>;
|
requestMapping?: Record<string, unknown>;
|
||||||
|
requiredFields?: string[];
|
||||||
|
firstFrame?: string;
|
||||||
|
lastFrame?: string;
|
||||||
responseMapping?: Record<string, unknown>;
|
responseMapping?: Record<string, unknown>;
|
||||||
|
callMode?: number;
|
||||||
|
isAsync?: number;
|
||||||
maxConcurrency?: number;
|
maxConcurrency?: number;
|
||||||
queueLimit?: number;
|
queueLimit?: number;
|
||||||
timeoutSeconds?: number;
|
timeoutSeconds?: number;
|
||||||
@@ -271,74 +278,71 @@ const fieldsToUnknownObject = (fields: Array<{ key: string; value: string }>) =>
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
const flattenNestedObject = (obj: Record<string, unknown>, prefix = ''): Array<{ key: string; value: string }> => {
|
const parseFormEntries = (raw: unknown): ModelFormEntry[] => {
|
||||||
const rows: Array<{ key: string; value: string }> = [];
|
if (Array.isArray(raw)) {
|
||||||
Object.entries(obj || {}).forEach(([k, v]) => {
|
return (raw as ModelFormEntry[])
|
||||||
const fk = prefix ? `${prefix}.${k}` : k;
|
.filter((item) => item && item.key !== undefined)
|
||||||
if (v && typeof v === 'object' && !Array.isArray(v)) {
|
.map((item) => ({
|
||||||
rows.push(...flattenNestedObject(v as Record<string, unknown>, fk));
|
key: String(item.key ?? '').trim(),
|
||||||
return;
|
value: String(item.value ?? ''),
|
||||||
}
|
}))
|
||||||
rows.push({ key: fk, value: String(v ?? '') });
|
.filter((item) => item.key !== '');
|
||||||
});
|
|
||||||
return rows;
|
|
||||||
};
|
|
||||||
|
|
||||||
const nestFieldsToObject = (fields: Array<{ key: string; value: string }>) => {
|
|
||||||
const root: Record<string, unknown> = {};
|
|
||||||
fields.forEach((f) => {
|
|
||||||
const path = String(f.key || '').trim();
|
|
||||||
if (!path) return;
|
|
||||||
const parts = path
|
|
||||||
.split('.')
|
|
||||||
.map((p) => p.trim())
|
|
||||||
.filter(Boolean);
|
|
||||||
if (!parts.length) return;
|
|
||||||
let cur: Record<string, unknown> = root;
|
|
||||||
parts.forEach((part, idx) => {
|
|
||||||
if (idx === parts.length - 1) {
|
|
||||||
cur[part] = String(f.value ?? '');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!cur[part] || typeof cur[part] !== 'object' || Array.isArray(cur[part])) {
|
|
||||||
cur[part] = {};
|
|
||||||
}
|
|
||||||
cur = cur[part] as Record<string, unknown>;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return root;
|
|
||||||
};
|
|
||||||
|
|
||||||
const buildQueryConfigFromRaw = (rawQc: Record<string, unknown> | null): Record<string, unknown> => {
|
|
||||||
if (!rawQc) return { responseType: 'sync', callbackUrl: '' };
|
|
||||||
const rt = String(rawQc.responseType || 'sync');
|
|
||||||
if (rt === 'callback') return { responseType: 'callback', callbackUrl: String(rawQc.callbackUrl || '') };
|
|
||||||
if (rt === 'pull') {
|
|
||||||
const hFields = Object.entries((rawQc.headers as Record<string, unknown>) || {}).map(([k, v]) => ({ key: k, value: String(v ?? '') }));
|
|
||||||
const bFields = flattenNestedObject((rawQc.body as Record<string, unknown>) || {});
|
|
||||||
return {
|
|
||||||
responseType: 'pull',
|
|
||||||
callbackUrl: '',
|
|
||||||
method: String(rawQc.method || 'GET'),
|
|
||||||
url: String(rawQc.url || ''),
|
|
||||||
headers: fieldsToUnknownObject(hFields),
|
|
||||||
body: nestFieldsToObject(bFields),
|
|
||||||
response: ((rawQc.response as unknown[]) || [])
|
|
||||||
.map((item) => {
|
|
||||||
if (typeof item === 'string') {
|
|
||||||
return { value: item, isTokenField: false, isMainBody: false };
|
|
||||||
}
|
|
||||||
const row = item as Record<string, unknown>;
|
|
||||||
return {
|
|
||||||
value: String(row.value ?? ''),
|
|
||||||
isTokenField: Boolean(row.isTokenField),
|
|
||||||
isMainBody: Boolean(row.isMainBody),
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.filter((row) => row.value !== ''),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return { responseType: 'sync', callbackUrl: '' };
|
|
||||||
|
if (raw && typeof raw === 'object') {
|
||||||
|
return Object.entries(raw as Record<string, unknown>).map(([key, value]) => {
|
||||||
|
let nextValue = value;
|
||||||
|
if (nextValue && typeof nextValue === 'object' && !Array.isArray(nextValue) && 'value' in nextValue) {
|
||||||
|
nextValue = (nextValue as { value: unknown }).value;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
key: String(key).trim(),
|
||||||
|
value: String(nextValue ?? ''),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeQueryConfig = (raw: unknown): Record<string, unknown> => {
|
||||||
|
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
||||||
|
return raw as Record<string, unknown>;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseHeadMsgRecord = (raw: ModelItem['headMsg']) => {
|
||||||
|
const headMsgRecord: Record<string, string> = {};
|
||||||
|
if (typeof raw === 'string') {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
||||||
|
Object.entries(parsed).forEach(([k, v]) => {
|
||||||
|
headMsgRecord[k] = String(v);
|
||||||
|
});
|
||||||
|
return headMsgRecord;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
const pairs = raw.split(',');
|
||||||
|
pairs.forEach((pair) => {
|
||||||
|
const idx = pair.indexOf(':');
|
||||||
|
if (idx === -1) return;
|
||||||
|
const key = pair.slice(0, idx).trim();
|
||||||
|
const value = pair.slice(idx + 1).trim();
|
||||||
|
if (key) {
|
||||||
|
headMsgRecord[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return headMsgRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
||||||
|
Object.entries(raw).forEach(([k, v]) => {
|
||||||
|
headMsgRecord[k] = String(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return headMsgRecord;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchModelList = async () => {
|
const fetchModelList = async () => {
|
||||||
@@ -396,43 +400,7 @@ const handleCreatePrivateModel = async () => {
|
|||||||
creatingModel.value = true;
|
creatingModel.value = true;
|
||||||
|
|
||||||
const builtInModel = builtInModelToClone.value;
|
const builtInModel = builtInModelToClone.value;
|
||||||
const formList: ModelFormEntry[] = Array.isArray(builtInModel.form)
|
const formList = parseFormEntries(builtInModel.form);
|
||||||
? (builtInModel.form as ModelFormEntry[])
|
|
||||||
: Object.entries((builtInModel.form as Record<string, unknown>) || {}).map(([key, value]) => ({
|
|
||||||
key: String(key),
|
|
||||||
value: String(value ?? ''),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Parse headMsg to Record<string, string> - it might be stored as string or already as object
|
|
||||||
let headMsgRecord: Record<string, string> = {};
|
|
||||||
if (builtInModel.headMsg && typeof builtInModel.headMsg === 'string') {
|
|
||||||
// Try to parse as JSON first (new format stored as string)
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(builtInModel.headMsg);
|
|
||||||
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
||||||
Object.entries(parsed).forEach(([k, v]) => {
|
|
||||||
headMsgRecord[k] = String(v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// If JSON parse fails, parse as old format "key1:value1,key2:value2"
|
|
||||||
const pairs = builtInModel.headMsg.split(',');
|
|
||||||
pairs.forEach((pair) => {
|
|
||||||
const idx = pair.indexOf(':');
|
|
||||||
if (idx === -1) return;
|
|
||||||
const key = pair.slice(0, idx).trim();
|
|
||||||
const value = pair.slice(idx + 1).trim();
|
|
||||||
if (key) {
|
|
||||||
headMsgRecord[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (builtInModel.headMsg && typeof builtInModel.headMsg === 'object' && !Array.isArray(builtInModel.headMsg)) {
|
|
||||||
// Already an object
|
|
||||||
Object.entries(builtInModel.headMsg).forEach(([k, v]) => {
|
|
||||||
headMsgRecord[k] = String(v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const createParams: CreateModelParams = {
|
const createParams: CreateModelParams = {
|
||||||
modelName: apiKeyForm.modelName,
|
modelName: apiKeyForm.modelName,
|
||||||
@@ -440,7 +408,7 @@ const handleCreatePrivateModel = async () => {
|
|||||||
operatorName: builtInModel.operatorName || '',
|
operatorName: builtInModel.operatorName || '',
|
||||||
baseUrl: builtInModel.baseUrl,
|
baseUrl: builtInModel.baseUrl,
|
||||||
httpMethod: builtInModel.httpMethod || 'POST',
|
httpMethod: builtInModel.httpMethod || 'POST',
|
||||||
headMsg: headMsgRecord,
|
headMsg: parseHeadMsgRecord(builtInModel.headMsg),
|
||||||
isPrivate: builtInModel.isPrivate ?? 1,
|
isPrivate: builtInModel.isPrivate ?? 1,
|
||||||
enabled: builtInModel.enabled ?? 1,
|
enabled: builtInModel.enabled ?? 1,
|
||||||
isChatModel: builtInModel.isChatModel || 0,
|
isChatModel: builtInModel.isChatModel || 0,
|
||||||
@@ -466,14 +434,13 @@ const handleCreatePrivateModel = async () => {
|
|||||||
tokenConfig: fieldsToUnknownObject(
|
tokenConfig: fieldsToUnknownObject(
|
||||||
Object.entries(parseJsonObjectField(builtInModel.tokenConfig)).map(([k, v]) => ({ key: k, value: String(v ?? '') }))
|
Object.entries(parseJsonObjectField(builtInModel.tokenConfig)).map(([k, v]) => ({ key: k, value: String(v ?? '') }))
|
||||||
),
|
),
|
||||||
queryConfig: buildQueryConfigFromRaw(
|
queryConfig: normalizeQueryConfig(builtInModel.queryConfig),
|
||||||
builtInModel.queryConfig && typeof builtInModel.queryConfig === 'object' && !Array.isArray(builtInModel.queryConfig)
|
responseTokenField: String(builtInModel.responseTokenField || ''),
|
||||||
? (builtInModel.queryConfig as Record<string, unknown>)
|
|
||||||
: null
|
|
||||||
),
|
|
||||||
streamConfig:
|
streamConfig:
|
||||||
builtInModel.streamConfig && typeof builtInModel.streamConfig === 'object' && !Array.isArray(builtInModel.streamConfig)
|
Number(builtInModel.callMode ?? builtInModel.isAsync ?? 0) === 2
|
||||||
? (builtInModel.streamConfig as Record<string, unknown>)
|
? builtInModel.streamConfig && typeof builtInModel.streamConfig === 'object' && !Array.isArray(builtInModel.streamConfig)
|
||||||
|
? (builtInModel.streamConfig as Record<string, unknown>)
|
||||||
|
: {}
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1116,6 +1116,11 @@ const availableParentParams = computed(() => {
|
|||||||
|
|
||||||
const allParentIds = findAllParentNodes(selectedElement.value.id);
|
const allParentIds = findAllParentNodes(selectedElement.value.id);
|
||||||
const params: Array<{ label: string; value: string }> = [];
|
const params: Array<{ label: string; value: string }> = [];
|
||||||
|
const pushParentParam = (label: string, value: string) => {
|
||||||
|
if (!label || !value) return;
|
||||||
|
if (params.some((item) => item.value === value)) return;
|
||||||
|
params.push({ label, value });
|
||||||
|
};
|
||||||
|
|
||||||
// 遍历所有上级节点
|
// 遍历所有上级节点
|
||||||
allParentIds.forEach((parentId) => {
|
allParentIds.forEach((parentId) => {
|
||||||
@@ -1133,15 +1138,14 @@ const availableParentParams = computed(() => {
|
|||||||
// 如果是判断节点,跳过不添加其字段
|
// 如果是判断节点,跳过不添加其字段
|
||||||
if (isJudge) return;
|
if (isJudge) return;
|
||||||
|
|
||||||
|
pushParentParam(`${parentNodeName}.输出结果`, `\${${parentId}.nodeOutputResult}`);
|
||||||
|
|
||||||
const modelOutputFields = Array.isArray(parentProps.modelOutputFields) ? parentProps.modelOutputFields : [];
|
const modelOutputFields = Array.isArray(parentProps.modelOutputFields) ? parentProps.modelOutputFields : [];
|
||||||
if (modelOutputFields.length > 0) {
|
if (modelOutputFields.length > 0) {
|
||||||
modelOutputFields.forEach((field: any) => {
|
modelOutputFields.forEach((field: any) => {
|
||||||
const fieldName = String(field || '').trim();
|
const fieldName = String(field || '').trim();
|
||||||
if (!fieldName) return;
|
if (!fieldName) return;
|
||||||
params.push({
|
pushParentParam(`${parentNodeName}.${fieldName}`, `\${${parentId}.${fieldName}}`);
|
||||||
label: `${parentNodeName}.${fieldName}`,
|
|
||||||
value: `\${${parentId}.${fieldName}}`,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1163,10 +1167,7 @@ const availableParentParams = computed(() => {
|
|||||||
if (responseValue && typeof responseValue === 'object' && !Array.isArray(responseValue)) {
|
if (responseValue && typeof responseValue === 'object' && !Array.isArray(responseValue)) {
|
||||||
Object.keys(responseValue).forEach((key) => {
|
Object.keys(responseValue).forEach((key) => {
|
||||||
if (!key || key.startsWith('_temp_')) return;
|
if (!key || key.startsWith('_temp_')) return;
|
||||||
params.push({
|
pushParentParam(`${parentNodeName}.${key}`, `\${${parentId}.${key}}`);
|
||||||
label: `${parentNodeName}.${key}`,
|
|
||||||
value: `\${${parentId}.${key}}`,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1174,10 +1175,7 @@ const availableParentParams = computed(() => {
|
|||||||
|
|
||||||
parentProps.formConfig.forEach((field: any) => {
|
parentProps.formConfig.forEach((field: any) => {
|
||||||
if (field.label) {
|
if (field.label) {
|
||||||
params.push({
|
pushParentParam(`${parentNodeName}.${field.label}`, `\${${parentId}.${field.label}}`);
|
||||||
label: `${parentNodeName}.${field.label}`,
|
|
||||||
value: `\${${parentId}.${field.label}}`,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user