import { create } from 'zustand'; import { persist } from 'zustand/middleware'; // ✅ 添加持久化支持 const usePresetStore = create( persist( (set, get) => ({ // 预设选择 selectedPreset: '', // 核心参数 parameters: { temperature: 1.0, frequency_penalty: 0.0, presence_penalty: 0.0, top_p: 1.0, top_k: 0, max_context: 1000000, max_tokens: 30000, max_context_unlocked: false, stream_openai: true, seed: -1, n: 1 }, // 可用的预设列表 - 初始为空,将从后端加载 presets: [], // 是否正在加载预设列表 isLoadingPresets: false, // 参数设置折叠状态 isParametersExpanded: true, // 分页状态 currentPage: 1, pageSize: 8, // 预设组件列表 promptComponents: [ { identifier: "dialogueExamples", name: "Chat Examples", system_prompt: true, marker: true, enabled: true, role: 0 }, { identifier: "chatHistory", name: "Chat History", system_prompt: true, marker: true, enabled: true, role: 0 }, { identifier: "worldInfoAfter", name: "World Info (after)", system_prompt: true, marker: true, enabled: true, role: 0 }, { identifier: "worldInfoBefore", name: "World Info (before)", system_prompt: true, marker: true, enabled: true, role: 0 }, { identifier: "charDescription", name: "Char Description", system_prompt: true, marker: true, enabled: true, role: 0 }, { identifier: "charPersonality", name: "Char Personality", system_prompt: true, marker: true, enabled: true, role: 0 }, { identifier: "scenario", name: "Scenario", system_prompt: true, marker: true, enabled: true, role: 0 }, { identifier: "personaDescription", name: "Persona Description", system_prompt: true, marker: true, enabled: true, role: 0 } ], // 从后端加载预设列表 fetchPresets: async () => { set({ isLoadingPresets: true }); try { const response = await fetch('/api/presets'); const data = await response.json(); // 转换为预设对象数组 const presetList = data.presets.map(preset => ({ id: preset.name, name: preset.name, description: preset.description, component_count: preset.component_count, temperature: preset.temperature })); set({ presets: presetList, isLoadingPresets: false }); } catch (error) { console.error('Failed to fetch presets:', error); set({ isLoadingPresets: false }); } }, // 设置选中的预设 setSelectedPreset: async (presetId) => { try { // 从后端获取预设的完整内容 const response = await fetch(`/api/presets/${presetId}`); const presetData = await response.json(); // 记录原始数据用于调试 console.log('从后端获取的预设数据:', presetData); // 提取参数并更新状态,支持内部结构和SillyTavern结构 const parameters = { temperature: presetData.temperature !== undefined ? presetData.temperature : 1.0, frequency_penalty: presetData.frequency_penalty !== undefined ? presetData.frequency_penalty : (presetData.frequencyPenalty !== undefined ? presetData.frequencyPenalty : 0.0), presence_penalty: presetData.presence_penalty !== undefined ? presetData.presence_penalty : (presetData.presencePenalty !== undefined ? presetData.presencePenalty : 0.0), top_p: presetData.top_p !== undefined ? presetData.top_p : (presetData.topP !== undefined ? presetData.topP : 1.0), top_k: presetData.top_k !== undefined ? presetData.top_k : (presetData.topK !== undefined ? presetData.topK : 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 : (presetData.maxLength !== undefined ? presetData.maxLength : 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); // 处理预设组件 - 支持内部结构和SillyTavern结构 let components = []; // 优先使用内部结构的 entries if (presetData.entries && Array.isArray(presetData.entries)) { components = presetData.entries.map(entry => ({ identifier: entry.identifier, name: entry.name, content: entry.content || '', enabled: entry.enabled !== false, role: entry.role === 'system' ? 0 : entry.role === 'user' ? 1 : 2, system_prompt: entry.role === 'system', marker: entry.isSystemNode || false })); // 按 order 排序 components.sort((a, b) => { const orderA = presetData.entries.find(e => e.identifier === a.identifier)?.order || 0; const orderB = presetData.entries.find(e => e.identifier === b.identifier)?.order || 0; return orderA - orderB; }); } // 兼容SillyTavern结构的 prompts else if (presetData.prompts && Array.isArray(presetData.prompts)) { // 获取当前角色的prompt_order,添加更严格的检查 const currentOrder = (presetData.prompt_order && Array.isArray(presetData.prompt_order) && presetData.prompt_order.length > 0 && presetData.prompt_order[0] && presetData.prompt_order[0].order && Array.isArray(presetData.prompt_order[0].order)) ? presetData.prompt_order[0].order : []; // 根据prompt_order排序组件 components = presetData.prompts.map(prompt => { const orderItem = currentOrder.find(item => 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 && item.identifier === a.identifier); const indexB = currentOrder.findIndex(item => item && item.identifier === b.identifier); return indexA - indexB; }); } } // 更新状态,确保参数容器展开 set({ selectedPreset: presetId, parameters, promptComponents: components, isParametersExpanded: true // 确保参数容器展开 }); } catch (error) { console.error('Failed to load preset:', error); } }, // 更新参数 updateParameter: ({ name, value }) => set((state) => ({ parameters: { ...state.parameters, [name]: value } })), // 添加预设 addPreset: (preset) => set((state) => ({ presets: [...state.presets, preset] })), // 保存当前设置为预设 saveCurrentAsPreset: async ({ name }) => { const state = get(); try { // 构建预设数据 - 使用内部专有结构 const presetData = { // GenerationPreset 部分 - 采样参数 id: `preset_${Date.now()}`, name: name, temperature: state.parameters.temperature, topP: state.parameters.top_p, topK: state.parameters.top_k, frequencyPenalty: state.parameters.frequency_penalty, presencePenalty: state.parameters.presence_penalty, maxLength: state.parameters.max_tokens, isDefault: false, // PromptPresetView 部分 - prompt组件列表 characterId: 'global', // 全局预设,不绑定特定角色 entries: state.promptComponents.map((component, index) => ({ identifier: component.identifier, name: component.name, enabled: component.enabled !== false, content: component.content || '', order: index, role: component.role === 0 ? 'system' : component.role === 1 ? 'user' : 'ai', tokenCount: component.content ? component.content.length : 0, isSystemNode: component.marker || false })) }; // 发送到后端 const response = await fetch('/api/presets', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(presetData) }); if (!response.ok) { throw new Error('Failed to save preset'); } const result = await response.json(); // 添加到本地预设列表 const newPreset = { id: presetData.id, name, description: '', component_count: state.promptComponents.length, temperature: state.parameters.temperature }; set((state) => ({ presets: [...state.presets, newPreset], selectedPreset: presetData.id })); return result; } catch (error) { console.error('Failed to save preset:', error); throw error; } }, // 编辑预设名称 editPresetName: async (presetId, newName) => { try { const response = await fetch(`/api/presets/${presetId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newName }) }); if (!response.ok) { throw new Error('Failed to update preset name'); } // 更新本地状态 set((state) => ({ presets: state.presets.map(preset => preset.id === presetId ? { ...preset, name: newName } : preset ) })); return await response.json(); } catch (error) { console.error('Failed to update preset name:', error); throw error; } }, // 切换参数设置折叠状态 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 })); }, // 设置当前页 setCurrentPage: (page) => set({ currentPage: page }), // 设置每页数量 setPageSize: (size) => set({ pageSize: size, currentPage: 1 }), // 获取当前页的预设列表 getCurrentPagePresets: () => { const { presets, currentPage, pageSize } = get(); const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; return presets.slice(startIndex, endIndex); }, // 获取总页数 getTotalPages: () => { const { presets, pageSize } = get(); return Math.ceil(presets.length / pageSize); } }), // ✅ 闭合 (set, get) => ({...}) { name: 'PresetStore', // localStorage 中的键名 partialize: (state) => ({ // ✅ 持久化选中的预设名称 selectedPreset: state.selectedPreset, // ✅ 持久化参数设置 parameters: state.parameters, // ✅ 持久化提示词组件配置 promptComponents: state.promptComponents, // ✅ 持久化折叠状态 isParametersExpanded: state.isParametersExpanded }), // ✅ 恢复时的回调 onRehydrateStorage: () => { return (state, error) => { if (error) { console.error('[PresetStore] 恢复状态失败:', error); return; } if (state?.selectedPreset) { console.log(`[PresetStore] 🔄 恢复上次选中的预设: ${state.selectedPreset}`); // 异步加载预设详情 setTimeout(() => { usePresetStore.getState().fetchPresets().then(() => { // 加载完列表后,重新选择之前选中的预设以加载其详细配置 if (state.selectedPreset) { usePresetStore.getState().setSelectedPreset(state.selectedPreset).catch(err => { console.error('[PresetStore] 加载预设详情失败:', err); }); } }).catch(err => { console.error('[PresetStore] 加载预设列表失败:', err); }); }, 0); } }; } } ) // ✅ 闭合 persist( ); export default usePresetStore;