Skip to content

Commit 0696d29

Browse files
committed
feat: 实现模型重定向中键自动映射到模型配置并优化JSON编辑器布局
1 parent a3c2b28 commit 0696d29

File tree

2 files changed

+171
-11
lines changed

2 files changed

+171
-11
lines changed

web/src/components/common/ui/JSONEditor.jsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -247,16 +247,9 @@ const JSONEditor = ({
247247
// 添加键值对
248248
const addKeyValue = useCallback(() => {
249249
const newPairs = [...keyValuePairs];
250-
const existingKeys = newPairs.map(p => p.key);
251-
let counter = 1;
252-
let newKey = `field_${counter}`;
253-
while (existingKeys.includes(newKey)) {
254-
counter += 1;
255-
newKey = `field_${counter}`;
256-
}
257250
newPairs.push({
258251
id: generateUniqueId(),
259-
key: newKey,
252+
key: '',
260253
value: ''
261254
});
262255
handleVisualChange(newPairs);
@@ -408,7 +401,7 @@ const JSONEditor = ({
408401

409402
return (
410403
<Row key={pair.id} gutter={8} align="middle">
411-
<Col span={6}>
404+
<Col span={12}>
412405
<div className="relative">
413406
<Input
414407
placeholder={t('键名')}
@@ -435,7 +428,7 @@ const JSONEditor = ({
435428
)}
436429
</div>
437430
</Col>
438-
<Col span={16}>
431+
<Col span={10}>
439432
{renderValueInput(pair.id, pair.value)}
440433
</Col>
441434
<Col span={2}>

web/src/components/table/channels/modals/EditChannelModal.jsx

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,133 @@ const EditChannelModal = (props) => {
214214
handleInputChange('settings', settingsJson);
215215
}
216216

217+
// 用于追踪模型的原始名称映射关系 { displayName: originalName }
218+
const [modelOriginalMapping, setModelOriginalMapping] = useState({});
219+
220+
// 解析模型映射配置的工具函数
221+
const parseModelMapping = (mappingValue) => {
222+
if (!mappingValue || typeof mappingValue !== 'string' || mappingValue.trim() === '') {
223+
return null;
224+
}
225+
226+
try {
227+
const mapping = JSON.parse(mappingValue);
228+
if (typeof mapping !== 'object' || mapping === null) {
229+
return null;
230+
}
231+
return mapping;
232+
} catch (error) {
233+
console.warn('模型重定向 JSON 解析失败:', error);
234+
return null;
235+
}
236+
};
237+
238+
// 获取当前模型列表的工具函数
239+
const getCurrentModels = () => {
240+
return formApiRef.current
241+
? formApiRef.current.getValue('models') || []
242+
: inputs.models || [];
243+
};
244+
245+
// 更新模型列表的统一方法
246+
const updateModelsList = (newModels, newMapping) => {
247+
const uniqueModels = Array.from(new Set(newModels.filter(model => model && model.trim())));
248+
249+
setInputs((inputs) => ({ ...inputs, models: uniqueModels }));
250+
if (formApiRef.current) {
251+
formApiRef.current.setValue('models', uniqueModels);
252+
}
253+
setModelOriginalMapping(newMapping);
254+
};
255+
256+
// 恢复模型到原始名称
257+
const restoreModelsToOriginalNames = () => {
258+
const currentModels = getCurrentModels();
259+
const restoredModels = currentModels.map(model => modelOriginalMapping[model] || model);
260+
261+
// 使用数组比较而不是JSON.stringify提高性能
262+
const hasChanges = currentModels.length !== restoredModels.length ||
263+
currentModels.some((model, index) => model !== restoredModels[index]);
264+
265+
if (hasChanges) {
266+
updateModelsList(restoredModels, {});
267+
}
268+
};
269+
270+
// 应用模型映射的核心逻辑
271+
const applyModelMapping = (mapping, currentModels, currentMapping) => {
272+
let updatedModels = [...currentModels];
273+
let newMapping = { ...currentMapping };
274+
let hasChanges = false;
275+
276+
// 遍历重定向映射
277+
Object.entries(mapping).forEach(([key, mappedValue]) => {
278+
if (typeof key === 'string' && typeof mappedValue === 'string') {
279+
const keyTrimmed = key.trim();
280+
const valueTrimmed = mappedValue.trim();
281+
282+
if (keyTrimmed && valueTrimmed) {
283+
// 查找模型配置中是否存在重定向的"值"(原始模型名)
284+
const valueIndex = updatedModels.findIndex(model => {
285+
return model === valueTrimmed || newMapping[model] === valueTrimmed;
286+
});
287+
288+
if (valueIndex !== -1) {
289+
const currentDisplayName = updatedModels[valueIndex];
290+
if (currentDisplayName !== keyTrimmed) {
291+
// 记录原始映射关系
292+
if (!newMapping[keyTrimmed]) {
293+
newMapping[keyTrimmed] = newMapping[currentDisplayName] || currentDisplayName;
294+
}
295+
// 清理旧的映射关系
296+
if (newMapping[currentDisplayName]) {
297+
delete newMapping[currentDisplayName];
298+
}
299+
// 更新显示名称为重定向的键
300+
updatedModels[valueIndex] = keyTrimmed;
301+
hasChanges = true;
302+
}
303+
}
304+
}
305+
}
306+
});
307+
308+
// 处理不在映射中的模型,恢复为原始名称
309+
const mappingKeys = new Set(Object.keys(mapping).map(key => key.trim()));
310+
updatedModels = updatedModels.map(model => {
311+
if (!mappingKeys.has(model) && newMapping[model]) {
312+
const originalName = newMapping[model];
313+
delete newMapping[model];
314+
hasChanges = true;
315+
return originalName;
316+
}
317+
return model;
318+
});
319+
320+
return { updatedModels, newMapping, hasChanges };
321+
};
322+
323+
// 实时同步模型重定向到模型配置的函数
324+
const syncModelMappingToModels = (mappingValue) => {
325+
const mapping = parseModelMapping(mappingValue);
326+
327+
if (!mapping) {
328+
restoreModelsToOriginalNames();
329+
return;
330+
}
331+
332+
const currentModels = getCurrentModels();
333+
const { updatedModels, newMapping, hasChanges } = applyModelMapping(
334+
mapping,
335+
currentModels,
336+
modelOriginalMapping
337+
);
338+
339+
if (hasChanges) {
340+
updateModelsList(updatedModels, newMapping);
341+
}
342+
};
343+
217344
const handleInputChange = (name, value) => {
218345
if (formApiRef.current) {
219346
formApiRef.current.setValue(name, value);
@@ -233,6 +360,14 @@ const EditChannelModal = (props) => {
233360
});
234361
return;
235362
}
363+
364+
// 处理模型重定向变更时自动同步模型配置(实时同步)
365+
if (name === 'model_mapping') {
366+
setInputs((inputs) => ({ ...inputs, [name]: value }));
367+
syncModelMappingToModels(value);
368+
return;
369+
}
370+
236371
setInputs((inputs) => ({ ...inputs, [name]: value }));
237372
if (name === 'type') {
238373
let localModels = [];
@@ -375,6 +510,22 @@ const EditChannelModal = (props) => {
375510
setAutoBan(true);
376511
}
377512
setBasicModels(getChannelModels(data.type));
513+
514+
// 初始化模型原始映射关系
515+
const mapping = parseModelMapping(data.model_mapping);
516+
if (mapping) {
517+
const initialMapping = {};
518+
// 根据当前的模型映射和模型列表,建立原始映射关系
519+
Object.entries(mapping).forEach(([key, value]) => {
520+
if (data.models.includes(key)) {
521+
initialMapping[key] = value;
522+
}
523+
});
524+
setModelOriginalMapping(initialMapping);
525+
} else {
526+
setModelOriginalMapping({});
527+
}
528+
378529
// 同步更新channelSettings状态显示
379530
setChannelSettings({
380531
force_format: data.force_format,
@@ -592,11 +743,20 @@ const EditChannelModal = (props) => {
592743
if (formApiRef.current) {
593744
formApiRef.current.setValue('key_mode', undefined);
594745
}
746+
// 重置模型原始映射关系
747+
setModelOriginalMapping({});
595748
// 重置本地输入,避免下次打开残留上一次的 JSON 字段值
596749
setInputs(getInitValues());
597750
}
598751
}, [props.visible, channelId]);
599752

753+
// 组件卸载时清理资源
754+
useEffect(() => {
755+
return () => {
756+
setModelOriginalMapping({});
757+
};
758+
}, []);
759+
600760
const handleVertexUploadChange = ({ fileList }) => {
601761
vertexErroredNames.current.clear();
602762
(async () => {
@@ -1607,7 +1767,14 @@ const EditChannelModal = (props) => {
16071767
templateLabel={t('填入模板')}
16081768
editorType="keyValue"
16091769
formApi={formApiRef.current}
1610-
extraText={t('键为请求中的模型名称,值为要替换的模型名称')}
1770+
extraText={
1771+
<div>
1772+
<div className="text-center">{t('键为请求中的模型名称,值为要替换的模型名称')}</div>
1773+
<div className="text-blue-600 text-xs mt-1">
1774+
{t('💡 提示:设置重定向后,系统自动将“模型配置”中对应的"值"替换为"键"')}
1775+
</div>
1776+
</div>
1777+
}
16111778
/>
16121779
</Card>
16131780

0 commit comments

Comments
 (0)