完成请求推送,但组装mes还有问题

This commit is contained in:
2026-05-04 00:33:29 +08:00
parent 7fc9e10c99
commit 2050a30a52
93 changed files with 9499 additions and 2719 deletions

View File

@@ -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);
}
}
}
)
);

View File

@@ -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
}
});
},

View File

@@ -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;

View File

@@ -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 })

View 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;