完成请求推送,但组装mes还有问题
This commit is contained in:
@@ -27,6 +27,7 @@ const useApiConfigStore = create(
|
||||
set({ loading: true, error: null });
|
||||
try {
|
||||
const response = await fetch('/api/api-config/profiles');
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch profiles');
|
||||
}
|
||||
@@ -47,7 +48,11 @@ const useApiConfigStore = create(
|
||||
throw new Error('Failed to fetch profile');
|
||||
}
|
||||
const data = await response.json();
|
||||
set({ currentProfile: data, loading: false });
|
||||
set({
|
||||
currentProfile: data,
|
||||
currentProfileId: profileId, // ✅ 保存当前配置 ID
|
||||
loading: false
|
||||
});
|
||||
return data;
|
||||
} catch (err) {
|
||||
set({ error: err.message, loading: false });
|
||||
@@ -193,8 +198,27 @@ const useApiConfigStore = create(
|
||||
{
|
||||
name: 'ApiConfigStore',
|
||||
partialize: (state) => ({
|
||||
activeMap: state.activeMap
|
||||
})
|
||||
activeMap: state.activeMap,
|
||||
// ✅ 持久化当前选中的配置文件 ID
|
||||
currentProfileId: state.currentProfile?.id || null
|
||||
}),
|
||||
// ✅ 恢复时自动加载对应的配置详情
|
||||
onRehydrateStorage: () => (state, error) => {
|
||||
if (error) {
|
||||
console.error('[ApiConfigStore] 恢复状态失败:', error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state?.currentProfileId) {
|
||||
console.log(`[ApiConfigStore] 🔄 恢复上次选中的配置: ${state.currentProfileId}`);
|
||||
// 异步加载配置详情
|
||||
setTimeout(() => {
|
||||
useApiConfigStore.getState().fetchProfile(state.currentProfileId).catch(err => {
|
||||
console.error('[ApiConfigStore] 加载配置详情失败:', err);
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
@@ -7,8 +7,9 @@ import { create } from 'zustand';
|
||||
const useCharacterCardUIStore = create((set) => ({
|
||||
// ==================== 状态 ====================
|
||||
|
||||
// 筛选标签
|
||||
filterTag: '',
|
||||
// 筛选标签数组 - 支持多标签交集筛选
|
||||
// 格式: ['include:tag1', 'exclude:tag2', 'include:tag3']
|
||||
filterTags: [],
|
||||
|
||||
// 是否处于编辑模式
|
||||
isEditing: false,
|
||||
@@ -25,11 +26,27 @@ const useCharacterCardUIStore = create((set) => ({
|
||||
// ==================== Actions ====================
|
||||
|
||||
/**
|
||||
* 设置筛选标签
|
||||
* 设置筛选标签(三次切换:无筛选 -> 包含 -> 排除 -> 无筛选)
|
||||
* @param {string} tag - 标签名
|
||||
*/
|
||||
setFilterTag: (tag) => {
|
||||
set({ filterTag: tag, currentPage: 1 }); // 重置页码
|
||||
set((state) => {
|
||||
const currentFilter = state.filterTag;
|
||||
|
||||
// 如果点击的是同一个标签,循环切换状态
|
||||
if (currentFilter && (currentFilter === tag || currentFilter === `include:${tag}` || currentFilter === `exclude:${tag}`)) {
|
||||
if (currentFilter === tag || currentFilter === `include:${tag}`) {
|
||||
// 从包含切换到排除
|
||||
return { filterTag: `exclude:${tag}`, currentPage: 1 };
|
||||
} else {
|
||||
// 从排除切换到无筛选
|
||||
return { filterTag: '', currentPage: 1 };
|
||||
}
|
||||
} else {
|
||||
// 点击新标签,设置为包含模式
|
||||
return { filterTag: `include:${tag}`, currentPage: 1 };
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -54,7 +71,8 @@ const useCharacterCardUIStore = create((set) => ({
|
||||
first_mes: character.first_mes || '',
|
||||
mes_example: character.mes_example || '',
|
||||
categories: character.categories || [],
|
||||
tags: character.tags || []
|
||||
tags: character.tags || [],
|
||||
worldInfoId: character.worldInfoId || null
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware'; // ✅ 添加持久化支持
|
||||
|
||||
const usePresetStore = create((set, get) => ({
|
||||
const usePresetStore = create(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
// 预设选择
|
||||
selectedPreset: '',
|
||||
|
||||
@@ -405,6 +408,47 @@ const usePresetStore = create((set, get) => ({
|
||||
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;
|
||||
|
||||
@@ -11,7 +11,8 @@ const useSideBarLeftStore = create(
|
||||
{ id: 'character', label: '角色', title: '管理AI角色卡' },
|
||||
{ id: 'api', label: 'API', title: '配置LLM和生图、向量化API连接' },
|
||||
{ id: 'presets', label: '预设', title: '管理对话预设和系统提示词' },
|
||||
{ id: 'worldbook', label: '世界', title: '管理世界观设定和背景知识' }
|
||||
{ id: 'worldbook', label: '世界', title: '管理世界观设定和背景知识' },
|
||||
{ id: 'tokenUsage', label: 'Token', title: '查看 Token 使用统计' }
|
||||
],
|
||||
|
||||
setActiveTab: (tab) => set({ activeTab: tab })
|
||||
|
||||
122
frontend/src/Store/SideBarLeft/TokenUsageSlice.jsx
Normal file
122
frontend/src/Store/SideBarLeft/TokenUsageSlice.jsx
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Token 使用统计 Store
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
|
||||
const useTokenUsageStore = create((set, get) => ({
|
||||
// 状态
|
||||
months: [],
|
||||
currentMonth: null,
|
||||
stats: null,
|
||||
roles: [],
|
||||
chats: [],
|
||||
selectedRole: null,
|
||||
selectedChat: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
// Actions
|
||||
fetchMonths: async () => {
|
||||
try {
|
||||
set({ loading: true, error: null });
|
||||
const response = await fetch('/api/token-usage/months');
|
||||
if (!response.ok) throw new Error('Failed to fetch months');
|
||||
|
||||
const months = await response.json();
|
||||
set({ months, loading: false });
|
||||
|
||||
// 默认选择最新的月份
|
||||
if (months.length > 0) {
|
||||
const latest = months[months.length - 1];
|
||||
await get().fetchStats(latest.year, latest.month);
|
||||
}
|
||||
} catch (error) {
|
||||
set({ error: error.message, loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
fetchStats: async (year, month, role = null, chat = null) => {
|
||||
try {
|
||||
set({ loading: true, error: null, currentMonth: { year, month } });
|
||||
|
||||
let url = `/api/token-usage/stats/${year}/${month}`;
|
||||
const params = new URLSearchParams();
|
||||
if (role) params.append('role_name', role);
|
||||
if (chat) params.append('chat_name', chat);
|
||||
|
||||
if (params.toString()) {
|
||||
url += `?${params.toString()}`;
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error('Failed to fetch stats');
|
||||
|
||||
const stats = await response.json();
|
||||
set({ stats, loading: false });
|
||||
} catch (error) {
|
||||
set({ error: error.message, loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
fetchRoles: async (year, month) => {
|
||||
try {
|
||||
const response = await fetch(`/api/token-usage/roles/${year}/${month}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch roles');
|
||||
|
||||
const data = await response.json();
|
||||
set({ roles: data.roles });
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch roles:', error);
|
||||
}
|
||||
},
|
||||
|
||||
fetchChats: async (year, month, role = null) => {
|
||||
try {
|
||||
let url = `/api/token-usage/chats/${year}/${month}`;
|
||||
if (role) {
|
||||
url += `?role_name=${encodeURIComponent(role)}`;
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error('Failed to fetch chats');
|
||||
|
||||
const data = await response.json();
|
||||
set({ chats: data.chats });
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch chats:', error);
|
||||
}
|
||||
},
|
||||
|
||||
setSelectedRole: (role) => {
|
||||
set({ selectedRole: role });
|
||||
const { currentMonth } = get();
|
||||
if (currentMonth) {
|
||||
get().fetchStats(currentMonth.year, currentMonth.month, role, get().selectedChat);
|
||||
}
|
||||
},
|
||||
|
||||
setSelectedChat: (chat) => {
|
||||
set({ selectedChat: chat });
|
||||
const { currentMonth } = get();
|
||||
if (currentMonth) {
|
||||
get().fetchStats(currentMonth.year, currentMonth.month, get().selectedRole, chat);
|
||||
}
|
||||
},
|
||||
|
||||
setCurrentMonth: (year, month) => {
|
||||
set({ currentMonth: { year, month } });
|
||||
get().fetchStats(year, month, get().selectedRole, get().selectedChat);
|
||||
get().fetchRoles(year, month);
|
||||
get().fetchChats(year, month, get().selectedRole);
|
||||
},
|
||||
|
||||
resetFilters: () => {
|
||||
set({ selectedRole: null, selectedChat: null });
|
||||
const { currentMonth } = get();
|
||||
if (currentMonth) {
|
||||
get().fetchStats(currentMonth.year, currentMonth.month);
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
export default useTokenUsageStore;
|
||||
Reference in New Issue
Block a user