diff --git a/frontend-react/src/Store/Slices/LeftTabsSlices/PresetSlice.jsx b/frontend-react/src/Store/Slices/LeftTabsSlices/PresetSlice.jsx index 15ba181..93448a2 100644 --- a/frontend-react/src/Store/Slices/LeftTabsSlices/PresetSlice.jsx +++ b/frontend-react/src/Store/Slices/LeftTabsSlices/PresetSlice.jsx @@ -28,6 +28,9 @@ const usePresetStore = create((set, get) => ({ // 参数设置折叠状态 isParametersExpanded: true, + // 预设组件列表 + promptComponents: [], + // 从后端加载预设列表 fetchPresets: async () => { set({ isLoadingPresets: true }); @@ -49,6 +52,8 @@ const usePresetStore = create((set, get) => ({ } }, + // 设置选中的预设 + // 设置选中的预设 // 设置选中的预设 setSelectedPreset: async (presetId) => { try { @@ -56,30 +61,71 @@ const usePresetStore = create((set, get) => ({ const response = await fetch(`/api/presets/${presetId}`); const presetData = await response.json(); - // 提取参数并更新状态 + // 记录原始数据用于调试 + console.log('从后端获取的预设数据:', presetData); + + // 提取参数并更新状态,确保所有参数都有默认值 const parameters = { - temperature: presetData.temperature || 1.0, - frequency_penalty: presetData.frequency_penalty || 0.0, - presence_penalty: presetData.presence_penalty || 0.0, - top_p: presetData.top_p || 1.0, - top_k: presetData.top_k || 0, - max_context: presetData.openai_max_context || 1000000, - max_tokens: presetData.openai_max_tokens || 30000, - max_context_unlocked: presetData.max_context_unlocked || false, - stream_openai: presetData.stream_openai || true, - seed: presetData.seed || -1, - n: presetData.n || 1 + temperature: presetData.temperature !== undefined ? presetData.temperature : 1.0, + frequency_penalty: presetData.frequency_penalty !== undefined ? presetData.frequency_penalty : 0.0, + presence_penalty: presetData.presence_penalty !== undefined ? presetData.presence_penalty : 0.0, + top_p: presetData.top_p !== undefined ? presetData.top_p : 1.0, + top_k: presetData.top_k !== undefined ? presetData.top_k : 0, + max_context: presetData.openai_max_context !== undefined ? presetData.openai_max_context : + (presetData.max_context !== undefined ? presetData.max_context : 1000000), + max_tokens: presetData.openai_max_tokens !== undefined ? presetData.openai_max_tokens : + (presetData.max_tokens !== undefined ? presetData.max_tokens : 30000), + max_context_unlocked: presetData.max_context_unlocked !== undefined ? presetData.max_context_unlocked : false, + stream_openai: presetData.stream_openai !== undefined ? presetData.stream_openai : true, + seed: presetData.seed !== undefined ? presetData.seed : -1, + n: presetData.n !== undefined ? presetData.n : 1 }; + // 记录映射后的参数用于调试 + console.log('映射后的参数:', parameters); + + // 处理预设组件 + let components = []; + if (presetData.prompts && Array.isArray(presetData.prompts)) { + // 获取当前角色的prompt_order + const currentOrder = presetData.prompt_order && presetData.prompt_order.length > 0 + ? presetData.prompt_order[0].order + : []; + + // 根据prompt_order排序组件 + components = presetData.prompts.map(prompt => { + const orderItem = currentOrder.find(item => item.identifier === prompt.identifier); + return { + ...prompt, + enabled: orderItem ? orderItem.enabled : true, + role: prompt.role !== undefined ? prompt.role : (prompt.system_prompt ? 0 : 1) + }; + }); + + // 如果有prompt_order,按照它排序 + if (currentOrder.length > 0) { + components.sort((a, b) => { + const indexA = currentOrder.findIndex(item => item.identifier === a.identifier); + const indexB = currentOrder.findIndex(item => item.identifier === b.identifier); + return indexA - indexB; + }); + } + } + + // 更新状态,确保参数容器展开 set({ selectedPreset: presetId, - parameters + parameters, + promptComponents: components, + isParametersExpanded: true // 确保参数容器展开 }); } catch (error) { console.error('Failed to load preset:', error); } }, + + // 更新参数 updateParameter: ({ name, value }) => set((state) => ({ parameters: { ...state.parameters, [name]: value } @@ -95,7 +141,8 @@ const usePresetStore = create((set, get) => ({ const newPreset = { id: `preset_${Date.now()}`, name, - parameters: { ...state.parameters } + parameters: { ...state.parameters }, + promptComponents: [...state.promptComponents] }; return { presets: [...state.presets, newPreset], @@ -113,7 +160,56 @@ const usePresetStore = create((set, get) => ({ // 切换参数设置折叠状态 toggleParametersExpanded: () => set((state) => ({ isParametersExpanded: !state.isParametersExpanded - })) + })), + + // 设置预设组件列表 + setPromptComponents: (components) => set({ promptComponents: components }), + + // 更新组件 + updateComponent: (index, updatedComponent) => set((state) => { + const newComponents = [...state.promptComponents]; + newComponents[index] = { ...newComponents[index], ...updatedComponent }; + return { promptComponents: newComponents }; + }), + + // 切换组件启用状态 + toggleComponentEnabled: (index) => set((state) => { + const newComponents = [...state.promptComponents]; + newComponents[index] = { + ...newComponents[index], + enabled: !newComponents[index].enabled + }; + return { promptComponents: newComponents }; + }), + + // 添加新组件 + addComponent: (component) => set((state) => ({ + promptComponents: [...state.promptComponents, component] + })), + + // 删除组件 + removeComponent: (index) => set((state) => { + const newComponents = [...state.promptComponents]; + newComponents.splice(index, 1); + return { promptComponents: newComponents }; + }), + + // 移动组件位置 + moveComponent: (fromIndex, toIndex) => set((state) => { + const newComponents = [...state.promptComponents]; + const [movedComponent] = newComponents.splice(fromIndex, 1); + newComponents.splice(toIndex, 0, movedComponent); + return { promptComponents: newComponents }; + }), + + // 获取当前预设的prompt_order + getPromptOrder: () => { + const { promptComponents } = get(); + return promptComponents.map(component => ({ + identifier: component.identifier, + enabled: component.enabled !== false + })); + } })); export default usePresetStore; diff --git a/frontend-react/src/components/SideBarLeft/tab/Presets.jsx b/frontend-react/src/components/SideBarLeft/tab/Presets.jsx index d44b5b4..a93e9ca 100644 --- a/frontend-react/src/components/SideBarLeft/tab/Presets.jsx +++ b/frontend-react/src/components/SideBarLeft/tab/Presets.jsx @@ -8,23 +8,41 @@ const PresetPanel = () => { parameters, presets, isLoadingPresets, + promptComponents, setSelectedPreset, updateParameter, saveCurrentAsPreset, editPresetName: updatePresetName, isParametersExpanded, toggleParametersExpanded, - fetchPresets + fetchPresets, + setPromptComponents, + toggleComponentEnabled, + updateComponent, + addComponent, + removeComponent, + moveComponent } = usePresetStore(); + const [showSaveDialog, setShowSaveDialog] = useState(false); const [showEditDialog, setShowEditDialog] = useState(false); const [showImportDialog, setShowImportDialog] = useState(false); + const [showComponentEditDialog, setShowComponentEditDialog] = useState(false); const [newPresetName, setNewPresetName] = useState(''); const [editPresetId, setEditPresetId] = useState(''); const [editPresetName, setEditPresetName] = useState(''); const [importPresetData, setImportPresetData] = useState(''); const [tooltip, setTooltip] = useState({ visible: false, content: '', x: 0, y: 0 }); + // 组件编辑状态 + const [editingComponentIndex, setEditingComponentIndex] = useState(-1); + const [editComponentContent, setEditComponentContent] = useState(''); + const [isEditing, setIsEditing] = useState(false); // 添加编辑状态标志 + + // 拖拽状态 + const [draggedItem, setDraggedItem] = useState(null); + const [dragOverItem, setDragOverItem] = useState(null); + // 参数描述映射 const parameterDescriptions = { temperature: "生成温度,控制随机性(0-2)", @@ -99,10 +117,16 @@ const PresetPanel = () => { const importedPreset = JSON.parse(importPresetData); if (importedPreset.name && importedPreset.parameters) { saveCurrentAsPreset({ name: importedPreset.name }); - // 这里需要更新参数 + // 更新参数 Object.keys(importedPreset.parameters).forEach(key => { updateParameter({ name: key, value: importedPreset.parameters[key] }); }); + + // 更新组件列表 + if (importedPreset.promptComponents) { + setPromptComponents(importedPreset.promptComponents); + } + setImportPresetData(''); setShowImportDialog(false); } @@ -116,7 +140,12 @@ const PresetPanel = () => { if (selectedPreset) { const preset = presets.find(p => p.id === selectedPreset); if (preset) { - const dataStr = JSON.stringify(preset, null, 2); + const exportData = { + ...preset, + parameters, + promptComponents + }; + const dataStr = JSON.stringify(exportData, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); @@ -128,6 +157,111 @@ const PresetPanel = () => { } }; + // 添加新组件 + const handleAddNewComponent = () => { + const newComponent = { + identifier: `component_${Date.now()}`, + name: '新组件', + content: '', + role: 0, + system_prompt: false, + marker: false, + enabled: true + }; + addComponent(newComponent); + }; + + // 开始编辑组件 + const handleStartEditComponent = (index) => { + setEditingComponentIndex(index); + setEditComponentContent(promptComponents[index].content); + setIsEditing(true); // 设置为编辑模式 + setShowComponentEditDialog(true); + }; + + // 查看组件内容 + const handleViewComponent = (index) => { + setEditingComponentIndex(index); + setEditComponentContent(promptComponents[index].content); + setIsEditing(false); // 设置为查看模式 + setShowComponentEditDialog(true); + }; + + // 保存组件编辑 + const handleSaveComponentEdit = () => { + if (editingComponentIndex >= 0 && isEditing) { // 只在编辑模式下保存 + updateComponent(editingComponentIndex, { content: editComponentContent }); + } + setEditingComponentIndex(-1); + setEditComponentContent(''); + setShowComponentEditDialog(false); + }; + + // 取消组件编辑 + const handleCancelComponentEdit = () => { + setEditingComponentIndex(-1); + setEditComponentContent(''); + setShowComponentEditDialog(false); + }; + + // 关闭组件查看对话框 + const handleCloseComponentView = () => { + setEditingComponentIndex(-1); + setEditComponentContent(''); + setShowComponentEditDialog(false); + }; + + // 切换组件启用状态 + const handleToggleComponentEnabled = (index) => { + toggleComponentEnabled(index); + }; + + // 删除组件 + const handleDeleteComponent = (index) => { + if (window.confirm('确定要删除这个组件吗?')) { + removeComponent(index); + } + }; + + // 拖拽开始 + const handleDragStart = (e, index) => { + setDraggedItem(index); + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('text/plain', index.toString()); + // 添加拖拽时的样式 + setTimeout(() => { + e.target.classList.add('dragging'); + }, 0); + }; + + // 拖拽结束 + const handleDragEnd = (e) => { + setDraggedItem(null); + setDragOverItem(null); + e.target.classList.remove('dragging'); + }; + + // 拖拽经过 + const handleDragOver = (e, index) => { + e.preventDefault(); + e.dataTransfer.dropEffect = 'move'; + if (draggedItem === null || draggedItem === index) return; + setDragOverItem(index); + }; + + // 放置 + const handleDrop = (e, index) => { + e.preventDefault(); + if (draggedItem === null || draggedItem === index) return; + + // 移动组件 + moveComponent(draggedItem, index); + + // 重置拖拽状态 + setDraggedItem(null); + setDragOverItem(null); + }; + return (