Files
2026-01-10 17:38:47 +08:00

1225 lines
43 KiB
JavaScript

/**
* 一级注释:本地缓存服务模块
* 统一管理历史记录和标签的本地缓存
*/
import { logger } from '../utils/logger.js';
import { PromptFormatter } from "../utils/promptFormatter.js";
// ---缓存配置---
const CACHE_CONFIG = {
// 统一前缀
GLOBAL_PREFIX: "PromptAssistant_",
// 历史缓存配置
HISTORY_CACHE_KEY: "PromptAssistant_history_cache_all",
MAX_HISTORY_PER_NODE: 20, // 每个节点最多保存的历史条数
MAX_HISTORY_GLOBAL: 100, // 全局最多保存的历史条数
MAX_CONTENT_LENGTH: 5000, // 单条历史最大长度限制
// 标签缓存配置
TAG_CACHE_KEY: "PromptAssistant_tag_cache_all",
MAX_TAGS_PER_INPUT: 100, // 每个输入框最多保存的标签数量
MAX_TAGS_GLOBAL: 500, // 全局最多保存的标签数量
// 翻译缓存配置
TRANSLATE_CACHE_KEY: "PromptAssistant_translate_cache",
MAX_TRANSLATE_CACHE: 200, // 最多保存的翻译缓存条数
};
/**
* 通用缓存服务
* 提供基础的缓存操作方法
*/
class CacheService {
/**
* 从localStorage获取数据
*/
static get(key) {
try {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
} catch (error) {
logger.error(`缓存服务 | 读取失败 | 键:${key} | 错误:${error.message}`);
return null;
}
}
/**
* 将数据存储到localStorage
*/
static set(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
logger.error(`缓存服务 | 写入失败 | 键:${key} | 错误:${error.message}`);
return false;
}
}
/**
* 从localStorage删除数据
*/
static remove(key) {
try {
localStorage.removeItem(key);
} catch (error) {
logger.error(`缓存服务 | 删除失败 | 键:${key} | 错误:${error.message}`);
}
}
/**
* 清除指定前缀的所有缓存
*/
static clearByPrefix(prefix) {
try {
const keysToRemove = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key && key.startsWith(prefix)) {
keysToRemove.push(key);
}
}
keysToRemove.forEach(key => this.remove(key));
// logger.debug(`缓存服务 | 清除前缀缓存 | 前缀:${prefix} | 数量:${keysToRemove.length}`);
} catch (error) {
logger.error(`缓存服务 | 清除前缀缓存失败 | 前缀:${prefix} | 错误:${error.message}`);
}
}
}
/**
* 历史缓存服务
* 管理历史记录的缓存操作
*/
class HistoryCacheService {
// 添加撤销/重做状态记录
static undoStates = new Map(); // 格式: { "nodeId_inputId": { currentIndex: number, records: array } }
/**
* 获取所有历史记录
*/
static getAllHistory() {
const key = CACHE_CONFIG.HISTORY_CACHE_KEY;
return CacheService.get(key) || [];
}
/**
* 保存所有历史记录
*/
static saveAllHistory(history) {
const key = CACHE_CONFIG.HISTORY_CACHE_KEY;
CacheService.set(key, history);
}
/**
* 获取历史记录列表
*/
static getHistoryList({ nodeId = null, limit = 50, workflowId = null } = {}) {
try {
const allHistory = this.getAllHistory();
let filteredHistory = allHistory;
if (workflowId) {
filteredHistory = allHistory.filter(item => item.workflow_id === workflowId);
}
// 确保每条历史记录都有必要的字段
const validHistory = filteredHistory.filter(item => {
const isValid = item && item.node_id && item.input_id &&
item.content && item.timestamp && item.operation_type;
if (!isValid) {
logger.debug(`历史缓存 | 跳过无效记录 | 节点:${item?.node_id}`);
}
return isValid;
});
if (!nodeId) {
return validHistory
.sort((a, b) => b.timestamp - a.timestamp)
.slice(0, limit);
}
const currentNodeHistory = [];
const otherNodesHistory = [];
validHistory.forEach(item => {
if (item.node_id === nodeId) {
currentNodeHistory.push(item);
} else {
otherNodesHistory.push(item);
}
});
currentNodeHistory.sort((a, b) => b.timestamp - a.timestamp);
otherNodesHistory.sort((a, b) => b.timestamp - a.timestamp);
return [...currentNodeHistory, ...otherNodesHistory].slice(0, limit);
} catch (error) {
logger.error(`历史缓存 | 获取历史失败 | 错误:${error.message}`);
return [];
}
}
/**
* 获取指定节点和输入框的历史记录
*/
static getInputHistory(nodeId, inputId, oldToNew = false) {
try {
const allHistory = this.getAllHistory();
const workflowId = app.graph?._workflow_id;
const filtered = allHistory.filter(item =>
item.node_id === nodeId &&
item.input_id === inputId &&
(!workflowId || item.workflow_id === workflowId) // 如果有workflowId,则匹配
);
// 根据参数决定排序方向
return filtered.sort((a, b) =>
oldToNew ? a.timestamp - b.timestamp : b.timestamp - a.timestamp
);
} catch (error) {
logger.error(`历史缓存 | 获取输入框历史失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return [];
}
}
/**
* 检查是否为重复的翻译记录
*/
static isRepeatedTranslation(nodeId, inputId, content, operationType) {
try {
if (operationType !== 'translate') {
return false;
}
// 获取该节点和输入框的历史记录
const history = this.getInputHistory(nodeId, inputId, false);
if (!history || history.length === 0) {
return false;
}
// 获取最近的一条记录
const lastRecord = history[0];
if (!lastRecord || lastRecord.operation_type !== 'translate') {
return false;
}
// 检查内容是否匹配
const currentContent = content.trim();
const lastContent = lastRecord.content.trim();
// 查询翻译缓存
const cacheResult = TranslateCacheService.queryTranslateCache(currentContent);
if (!cacheResult) {
return false;
}
// 检查是否为原文-译文或译文-原文的切换
if (cacheResult.type === 'source' && cacheResult.translatedText === lastContent) {
return true;
}
if (cacheResult.type === 'translated' && cacheResult.sourceText === lastContent) {
return true;
}
return false;
} catch (error) {
logger.error(`历史缓存 | 检查重复翻译失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return false;
}
}
/**
* 添加历史记录
*/
static addHistory(historyItem) {
try {
// 验证必要字段
if (!historyItem.node_id || !historyItem.input_id || historyItem.content === undefined) {
logger.error("历史缓存 | 添加历史失败 | 缺少必要字段");
return false;
}
// 如果内容为空或只包含空白字符,跳过记录
if (!historyItem.content || historyItem.content.trim() === '') {
logger.debug(`历史缓存 | 跳过添加 | 节点:${historyItem.node_id} | 原因:空内容`);
return false;
}
// 内容长度限制
let content = historyItem.content;
if (content.length > CACHE_CONFIG.MAX_CONTENT_LENGTH) {
content = content.substring(0, CACHE_CONFIG.MAX_CONTENT_LENGTH) + "...";
}
// 检查是否为重复的翻译记录
if (this.isRepeatedTranslation(historyItem.node_id, historyItem.input_id, content, historyItem.operation_type)) {
logger.debug(`历史缓存 | 跳过添加 | 节点:${historyItem.node_id} | 原因:重复的翻译记录`);
return false;
}
const allHistory = this.getAllHistory();
// 获取当前节点和输入框的历史记录
const nodeHistory = allHistory.filter(item =>
item.node_id === historyItem.node_id &&
item.input_id === historyItem.input_id
);
// 检查是否与最近的一条历史记录内容相同
if (nodeHistory.length > 0) {
// 按时间戳降序排序,获取最新的记录
const latestHistory = nodeHistory.sort((a, b) => b.timestamp - a.timestamp)[0];
if (latestHistory.content === content) {
logger.debug(`历史缓存 | 跳过添加 | 节点:${historyItem.node_id} | 原因:与上一条记录相同`);
return false;
}
}
// 创建新的历史记录
const newItem = {
workflow_id: app.graph?._workflow_id || 'unknown',
node_id: historyItem.node_id,
input_id: historyItem.input_id,
content: content,
operation_type: historyItem.operation_type || null,
timestamp: Date.now() + 1, // 确保时间戳唯一
request_id: historyItem.request_id || null
};
// 添加到历史记录末尾
allHistory.push(newItem);
// 限制每个节点的历史记录数量
const currentNodeHistory = allHistory.filter(item => item.node_id === historyItem.node_id);
if (currentNodeHistory.length > CACHE_CONFIG.MAX_HISTORY_PER_NODE) {
// 按时间戳排序
currentNodeHistory.sort((a, b) => b.timestamp - a.timestamp);
// 获取要保留的记录的时间戳
const cutoffTimestamp = currentNodeHistory[CACHE_CONFIG.MAX_HISTORY_PER_NODE - 1].timestamp;
// 移除旧记录
const filteredHistory = allHistory.filter(item =>
item.node_id !== historyItem.node_id ||
item.timestamp >= cutoffTimestamp
);
allHistory.length = 0;
allHistory.push(...filteredHistory);
}
// 限制全局历史记录数量
if (allHistory.length > CACHE_CONFIG.MAX_HISTORY_GLOBAL) {
// 按时间戳排序
allHistory.sort((a, b) => b.timestamp - a.timestamp);
allHistory.length = CACHE_CONFIG.MAX_HISTORY_GLOBAL;
}
this.saveAllHistory(allHistory);
// logger.debug(`历史缓存 | 添加历史 | 节点:${historyItem.node_id} | 内容长度:${content.length}`);
return true;
} catch (error) {
logger.error(`历史缓存 | 添加历史失败 | 错误:${error.message}`);
return false;
}
}
/**
* 初始化撤销状态
*/
static initUndoState(nodeId, inputId, currentContent) {
try {
const key = `${nodeId}_${inputId}`;
// 获取该输入框的历史记录(从旧到新)
const inputHistory = this.getInputHistory(nodeId, inputId, true);
// 创建撤销状态,指向最新的记录
const undoState = {
currentIndex: inputHistory.length - 1, // 指向最后一条记录
currentContent: currentContent, // 保存当前内容
lastHistoryTimestamp: inputHistory.length > 0 ? inputHistory[inputHistory.length - 1].timestamp : 0
};
// 更新撤销状态
this.undoStates.set(key, undoState);
// logger.debug(`历史缓存 | 初始化撤销状态 | 节点:${nodeId} | 输入框:${inputId} | 历史数:${inputHistory.length} | 当前位置:${undoState.currentIndex}`);
} catch (error) {
logger.error(`历史缓存 | 初始化撤销状态失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
}
}
/**
* 执行撤销操作
*/
static undo(nodeId, inputId) {
try {
const key = `${nodeId}_${inputId}`;
const state = this.undoStates.get(key);
if (!state) {
return null;
}
// 获取历史记录(从旧到新)
const history = this.getInputHistory(nodeId, inputId, true);
// 如果没有历史记录,返回null
if (history.length === 0) {
return null;
}
// 如果已经是第一条记录,无法继续撤销
if (state.currentIndex <= 0) {
return null;
}
// 更新当前位置
state.currentIndex--;
// 从历史记录中获取内容
const content = history[state.currentIndex]?.content || '';
// 更新状态
this.undoStates.set(key, state);
// logger.debug(`历史缓存 | 撤销操作 | 节点:${nodeId} | 输入框:${inputId} | 位置:${state.currentIndex}/${history.length - 1} | 内容:${content}`);
return content;
} catch (error) {
logger.error(`历史缓存 | 撤销操作失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return null;
}
}
/**
* 执行重做操作
*/
static redo(nodeId, inputId) {
try {
const key = `${nodeId}_${inputId}`;
const state = this.undoStates.get(key);
if (!state) {
return null;
}
// 获取历史记录(从旧到新)
const history = this.getInputHistory(nodeId, inputId, true);
// 如果没有历史记录,返回null
if (history.length === 0) {
return null;
}
// 如果已经是最后一条记录,无法重做
if (state.currentIndex >= history.length - 1) {
return null;
}
// 更新当前位置
state.currentIndex++;
// 从历史记录中获取内容
const content = history[state.currentIndex]?.content || '';
// 更新状态
this.undoStates.set(key, state);
logger.debug(`历史缓存 | 重做操作 | 节点:${nodeId} | 输入框:${inputId} | 位置:${state.currentIndex}/${history.length - 1} | 内容:${content}`);
return content;
} catch (error) {
logger.error(`历史缓存 | 重做操作失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return null;
}
}
/**
* 检查是否可以撤销
*/
static canUndo(nodeId, inputId) {
try {
const key = `${nodeId}_${inputId}`;
const state = this.undoStates.get(key);
return state && state.currentIndex > 0;
} catch (error) {
logger.error(`历史缓存 | 检查撤销状态失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return false;
}
}
/**
* 检查是否可以重做
*/
static canRedo(nodeId, inputId) {
try {
const key = `${nodeId}_${inputId}`;
const state = this.undoStates.get(key);
if (!state) return false;
const history = this.getInputHistory(nodeId, inputId, true);
return state.currentIndex < history.length - 1;
} catch (error) {
logger.error(`历史缓存 | 检查重做状态失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return false;
}
}
/**
* 清除所有历史记录
*/
static clearAllHistory() {
try {
// 清除所有历史记录
this.saveAllHistory([]);
// 清除所有撤销状态
this.undoStates.clear();
// logger.debug("历史缓存 | 清除所有历史");
} catch (error) {
logger.error(`历史缓存 | 清除所有历史失败 | 错误:${error.message}`);
}
}
/**
* 清除指定节点的历史记录
*/
static clearNodeHistory(nodeId) {
try {
// 获取所有历史记录
const allHistory = this.getAllHistory();
// 过滤出不属于该节点的记录
const filteredHistory = allHistory.filter(item => item.node_id !== nodeId);
// 保存过滤后的历史记录
this.saveAllHistory(filteredHistory);
// 清除该节点的撤销状态
for (const [key] of this.undoStates) {
if (key.startsWith(nodeId + "_")) {
this.undoStates.delete(key);
}
}
// logger.debug(`历史缓存 | 清除节点历史 | 节点:${nodeId}`);
} catch (error) {
logger.error(`历史缓存 | 清除节点历史失败 | 节点:${nodeId} | 错误:${error.message}`);
}
}
/**
* 清除指定工作流的所有历史记录
*/
static clearWorkflowHistory(workflowId) {
if (!workflowId) return;
try {
const allHistory = this.getAllHistory();
const filteredHistory = allHistory.filter(item => item.workflow_id !== workflowId);
this.saveAllHistory(filteredHistory);
// logger.debug(`历史缓存 | 清除工作流历史 | 工作流ID:${workflowId}`);
} catch (error) {
logger.error(`历史缓存 | 清除工作流历史失败 | 工作流ID:${workflowId} | 错误:${error.message}`);
}
}
/**
* 添加历史记录并更新撤销状态
*/
static addHistoryAndUpdateUndoState(nodeId, inputId, content, operationType = 'input') {
// 首先尝试添加历史记录
const success = this.addHistory({
node_id: nodeId,
input_id: inputId,
content: content,
operation_type: operationType,
timestamp: Date.now()
});
if (success) {
// 更新撤销状态
const key = `${nodeId}_${inputId}`;
const state = this.undoStates.get(key) || {
currentIndex: 0,
currentContent: content,
lastHistoryTimestamp: 0
};
// 获取最新的历史记录
const history = this.getInputHistory(nodeId, inputId, true);
// 更新状态
state.currentIndex = history.length - 1;
state.currentContent = content;
state.lastHistoryTimestamp = Date.now();
// 保存状态
this.undoStates.set(key, state);
// logger.debug(`历史缓存 | 更新撤销状态 | 节点:${nodeId} | 输入框:${inputId} | 位置:${state.currentIndex}`);
}
return success;
}
/**
* 获取历史记录统计信息
*/
static getHistoryStats() {
try {
const allHistory = this.getAllHistory();
const stats = {
total: allHistory.length,
byNode: {}
};
// 按节点统计
allHistory.forEach(item => {
if (!stats.byNode[item.node_id]) {
stats.byNode[item.node_id] = 0;
}
stats.byNode[item.node_id]++;
});
// logger.debug(`历史缓存 | 获取统计 | 总数:${stats.total} | 节点数:${Object.keys(stats.byNode).length}`);
return stats;
} catch (error) {
logger.error(`历史缓存 | 获取统计失败 | 错误:${error.message}`);
return { total: 0, byNode: {} };
}
}
/**
* 修改历史记录项的操作类型
*/
static updateHistoryItemType(nodeId, inputId, timestamp, newType) {
try {
// 获取所有历史记录
const allHistory = this.getAllHistory();
// 查找匹配的历史记录
const itemIndex = allHistory.findIndex(item =>
item.node_id === nodeId &&
item.input_id === inputId &&
item.timestamp === timestamp
);
// 如果找到匹配的记录,修改其操作类型
if (itemIndex !== -1) {
allHistory[itemIndex].operation_type = newType;
// 保存修改后的历史记录
this.saveAllHistory(allHistory);
// logger.debug(`历史缓存 | 修改操作类型 | 节点:${nodeId} | 输入框:${inputId} | 类型:${newType}`);
return true;
} else {
// logger.debug(`历史缓存 | 修改操作类型失败 | 未找到匹配记录 | 节点:${nodeId} | 输入框:${inputId}`);
return false;
}
} catch (error) {
logger.error(`历史缓存 | 修改操作类型失败 | 错误:${error.message}`);
return false;
}
}
/**
* 更新历史记录项
*/
static updateHistoryItem(nodeId, inputId, timestamp, updates) {
try {
// 获取所有历史记录
const allHistory = this.getAllHistory();
// 查找匹配的历史记录
const itemIndex = allHistory.findIndex(item =>
item.node_id === nodeId &&
item.input_id === inputId &&
item.timestamp === timestamp
);
// 如果找到匹配的记录,更新指定字段
if (itemIndex !== -1) {
// 更新所有提供的字段
Object.assign(allHistory[itemIndex], updates);
// 保存修改后的历史记录
this.saveAllHistory(allHistory);
logger.debug(`历史缓存 | 更新记录 | 节点:${nodeId} | 输入框:${inputId} | 字段:${Object.keys(updates).join(',')}`);
return true;
} else {
logger.debug(`历史缓存 | 更新失败 | 未找到匹配记录 | 节点:${nodeId} | 输入框:${inputId}`);
return false;
}
} catch (error) {
logger.error(`历史缓存 | 更新记录失败 | 错误:${error.message}`);
return false;
}
}
/**
* 根据请求ID获取相关联的历史记录
*/
static getHistoryByRequestId(requestId) {
try {
if (!requestId) return [];
const allHistory = this.getAllHistory();
return allHistory.filter(item =>
item.request_id === requestId
).sort((a, b) => b.timestamp - a.timestamp);
} catch (error) {
logger.error(`历史缓存 | 获取请求关联历史失败 | 请求ID:${requestId} | 错误:${error.message}`);
return [];
}
}
}
/**
* 标签缓存服务
* 管理标签的缓存操作
*/
class TagCacheService {
/**
* 获取或创建标签格式
*/
static getOrCreateFormats(rawTag) {
return PromptFormatter.formatTag(rawTag);
}
/**
* 获取所有标签缓存
*/
static getAllTagCache() {
try {
const data = CacheService.get(CACHE_CONFIG.TAG_CACHE_KEY);
return data || {};
} catch (error) {
logger.error(`标签缓存 | 获取所有缓存失败 | 错误:${error.message}`);
return {};
}
}
/**
* 保存所有标签缓存
*/
static saveAllTagCache(cache) {
try {
CacheService.set(CACHE_CONFIG.TAG_CACHE_KEY, cache);
} catch (error) {
logger.error(`标签缓存 | 保存所有缓存失败 | 错误:${error.message}`);
}
}
/**
* 获取标签缓存
*/
static getTagCache(nodeId, inputId) {
try {
const allCache = this.getAllTagCache();
const workflowId = app.graph?._workflow_id || 'unknown';
const key = `${workflowId}_${nodeId}_${inputId}`;
const data = allCache[key] || {};
return new Map(Object.entries(data));
} catch (error) {
logger.error(`标签缓存 | 获取缓存失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return new Map();
}
}
/**
* 添加标签到缓存
*/
static addTag(nodeId, inputId, rawTag, formats) {
try {
const allCache = this.getAllTagCache();
const workflowId = app.graph?._workflow_id || 'unknown';
const key = `${workflowId}_${nodeId}_${inputId}`;
const cache = this.getTagCache(nodeId, inputId);
// 确保formats包含所有必要的格式
const format1 = formats.format1 || ` ${rawTag}`;
const format2 = formats.format2 || ` ${rawTag},`;
const format3 = formats.format3 || `, ${rawTag}`;
const format4 = formats.format4 || `, ${rawTag},`;
const insertedFormat = formats.insertedFormat || null;
// 如果标签已存在,直接更新
if (cache.has(rawTag)) {
cache.set(rawTag, {
format1,
format2,
format3,
format4,
insertedFormat
});
allCache[key] = Object.fromEntries(cache);
this.saveAllTagCache(allCache);
logger.debug(`标签缓存 | 更新标签 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag}`);
return true;
}
// 检查当前输入框的标签数量限制
if (cache.size >= CACHE_CONFIG.MAX_TAGS_PER_INPUT) {
// 获取所有标签及其最后使用时间
const tagEntries = Array.from(cache.entries()).map(([tag, formats]) => ({
tag,
formats,
lastUsed: formats.lastUsed || 0
}));
// 按最后使用时间排序
tagEntries.sort((a, b) => a.lastUsed - b.lastUsed);
// 删除最旧的标签
const oldestTag = tagEntries[0].tag;
cache.delete(oldestTag);
logger.debug(`标签缓存 | 自动淘汰 | 节点:${nodeId} | 输入框:${inputId} | 淘汰标签:${oldestTag}`);
}
// 检查全局标签数量限制
let totalTags = 0;
const allTags = [];
for (const [cacheKey, inputTags] of Object.entries(allCache)) {
const [wfId, nId, iId] = cacheKey.split('_');
for (const [tag, tagFormats] of Object.entries(inputTags)) {
allTags.push({
workflowId: wfId,
nodeId: nId,
inputId: iId,
tag,
lastUsed: tagFormats.lastUsed || 0
});
}
totalTags += Object.keys(inputTags).length;
}
if (totalTags >= CACHE_CONFIG.MAX_TAGS_GLOBAL) {
// 按最后使用时间排序
allTags.sort((a, b) => a.lastUsed - b.lastUsed);
// 删除最旧的标签
const oldest = allTags[0];
const oldKey = `${oldest.workflowId}_${oldest.nodeId}_${oldest.inputId}`;
const oldCache = new Map(Object.entries(allCache[oldKey] || {}));
oldCache.delete(oldest.tag);
if (oldCache.size > 0) {
allCache[oldKey] = Object.fromEntries(oldCache);
} else {
delete allCache[oldKey];
}
logger.debug(`标签缓存 | 自动淘汰 | 全局限制 | 淘汰标签:${oldest.tag} | 位置:${oldKey}`);
}
// 添加新标签
cache.set(rawTag, {
format1,
format2,
format3,
format4,
insertedFormat,
lastUsed: Date.now() // 添加最后使用时间
});
// 更新全局缓存
allCache[key] = Object.fromEntries(cache);
this.saveAllTagCache(allCache);
logger.debug(`标签缓存 | 添加标签 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag}`);
return true;
} catch (error) {
logger.error(`标签缓存 | 添加标签失败 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 错误:${error.message}`);
return false;
}
}
/**
* 从缓存中移除标签
*/
static removeTag(nodeId, inputId, rawTag) {
try {
const allCache = this.getAllTagCache();
const workflowId = app.graph?._workflow_id || 'unknown';
const key = `${workflowId}_${nodeId}_${inputId}`;
const cache = this.getTagCache(nodeId, inputId);
const result = cache.delete(rawTag);
if (result) {
// 更新全局缓存
if (cache.size > 0) {
allCache[key] = Object.fromEntries(cache);
} else {
delete allCache[key];
}
this.saveAllTagCache(allCache);
logger.debug(`标签缓存 | 移除标签 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag}`);
}
return result;
} catch (error) {
logger.error(`标签缓存 | 移除标签失败 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 错误:${error.message}`);
return false;
}
}
/**
* 检查标签是否在输入框中
*/
static isTagInInput(nodeId, inputId, rawTag, inputValue) {
try {
const formats = this.getTagFormats(nodeId, inputId, rawTag);
if (!formats) {
return false;
}
// 按优先级顺序检查各种格式
const checkOrder = ['insertedFormat', 'format4', 'format3', 'format2', 'format1'];
for (const formatKey of checkOrder) {
const format = formats[formatKey];
if (format && inputValue.includes(format)) {
// logger.debug(`标签检查 | 结果:已存在 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 匹配格式:${formatKey}`);
return true;
}
}
return false;
} catch (error) {
logger.error(`标签检查 | 结果:异常 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 错误:${error.message}`);
return false;
}
}
/**
* 获取标签的所有格式
*/
static getTagFormats(nodeId, inputId, rawTag) {
try {
const cache = this.getTagCache(nodeId, inputId);
return cache.get(rawTag) || null;
} catch (error) {
logger.error(`标签缓存 | 获取标签格式失败 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 错误:${error.message}`);
return null;
}
}
/**
* 获取标签的插入格式
*/
static getInsertedFormat(nodeId, inputId, rawTag) {
try {
const formats = this.getTagFormats(nodeId, inputId, rawTag);
return formats ? formats.insertedFormat : null;
} catch (error) {
logger.error(`标签缓存 | 获取插入格式失败 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 错误:${error.message}`);
return null;
}
}
/**
* 获取所有原始标签
*/
static getAllRawTags(nodeId, inputId) {
try {
const cache = this.getTagCache(nodeId, inputId);
return Array.from(cache.keys());
} catch (error) {
logger.error(`标签缓存 | 获取所有标签失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
return [];
}
}
/**
* 清除标签缓存
*/
static clearCache(nodeId, inputId) {
try {
const allCache = this.getAllTagCache();
const workflowId = app.graph?._workflow_id || 'unknown';
const key = `${workflowId}_${nodeId}_${inputId}`;
// 删除指定节点的缓存
if (allCache[key]) {
delete allCache[key];
this.saveAllTagCache(allCache);
}
// logger.debug(`标签缓存 | 清除缓存 | 节点:${nodeId} | 输入框:${inputId}`);
} catch (error) {
logger.error(`标签缓存 | 清除缓存失败 | 节点:${nodeId} | 输入框:${inputId} | 错误:${error.message}`);
}
}
/**
* 获取标签统计信息
*/
static getTagStats() {
try {
const allCache = this.getAllTagCache();
let total = 0;
const byNode = {};
// 遍历所有缓存计算统计信息
for (const [key, tags] of Object.entries(allCache)) {
const [workflowId, nodeId, inputId] = key.split('_');
const count = Object.keys(tags).length;
total += count;
if (!byNode[nodeId]) {
byNode[nodeId] = {};
}
byNode[nodeId][inputId] = count;
}
const stats = { total, byNode };
// logger.debug(`标签缓存 | 获取统计 | 总数:${total} | 节点数:${Object.keys(byNode).length}`);
return stats;
} catch (error) {
logger.error(`标签缓存 | 获取统计失败 | 错误:${error.message}`);
return { total: 0, byNode: {} };
}
}
/**
* 更新标签的插入格式
*/
static updateInsertedFormat(nodeId, inputId, rawTag, insertedFormat) {
try {
const allCache = this.getAllTagCache();
const workflowId = app.graph?._workflow_id || 'unknown';
const key = `${workflowId}_${nodeId}_${inputId}`;
const cache = this.getTagCache(nodeId, inputId);
const formats = cache.get(rawTag);
if (!formats) {
logger.debug(`标签缓存 | 更新插入格式失败 | 原因:标签不存在 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag}`);
return false;
}
// 更新插入格式
formats.insertedFormat = insertedFormat;
cache.set(rawTag, formats);
// 更新全局缓存
allCache[key] = Object.fromEntries(cache);
this.saveAllTagCache(allCache);
logger.debug(`标签缓存 | 更新插入格式 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 新格式:${insertedFormat}`);
return true;
} catch (error) {
logger.error(`标签缓存 | 更新插入格式失败 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 错误:${error.message}`);
return false;
}
}
/**
* 更新标签的最后使用时间
*/
static updateTagLastUsed(nodeId, inputId, rawTag) {
try {
const allCache = this.getAllTagCache();
const workflowId = app.graph?._workflow_id || 'unknown';
const key = `${workflowId}_${nodeId}_${inputId}`;
const cache = this.getTagCache(nodeId, inputId);
if (cache.has(rawTag)) {
const tagData = cache.get(rawTag);
tagData.lastUsed = Date.now();
cache.set(rawTag, tagData);
allCache[key] = Object.fromEntries(cache);
this.saveAllTagCache(allCache);
logger.debug(`标签缓存 | 更新使用时间 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag}`);
}
} catch (error) {
logger.error(`标签缓存 | 更新使用时间失败 | 节点:${nodeId} | 输入框:${inputId} | 标签:${rawTag} | 错误:${error.message}`);
}
}
/**
* 清除指定工作流的所有标签
*/
static clearWorkflowTags(workflowId) {
if (!workflowId) return;
try {
const allCache = this.getAllTagCache();
const newCache = {};
for (const key in allCache) {
// key format is `${workflowId}_${nodeId}_${inputId}`
if (!key.startsWith(workflowId + '_')) {
newCache[key] = allCache[key];
}
}
this.saveAllTagCache(newCache);
logger.debug(`标签缓存 | 清除工作流标签 | 工作流ID:${workflowId}`);
} catch (error) {
logger.error(`标签缓存 | 清除工作流标签失败 | 工作流ID:${workflowId} | 错误:${error.message}`);
}
}
/**
* 清除所有标签缓存
*/
static clearAllTagCache() {
try {
CacheService.remove(CACHE_CONFIG.TAG_CACHE_KEY);
logger.debug("标签缓存 | 清除所有缓存");
} catch (error) {
logger.error(`标签缓存 | 清除缓存失败 | 错误:${error.message}`);
}
}
}
/**
* 翻译缓存服务
* 管理翻译结果的缓存操作
*/
class TranslateCacheService {
/**
* 获取所有翻译缓存
*/
static getAllTranslateCache() {
try {
const data = CacheService.get(CACHE_CONFIG.TRANSLATE_CACHE_KEY);
if (data) {
return new Map(Object.entries(data));
}
return new Map();
} catch (error) {
logger.error(`翻译缓存 | 获取缓存失败 | 错误:${error.message}`);
return new Map();
}
}
/**
* 保存所有翻译缓存
*/
static saveAllTranslateCache(cache) {
try {
// 将Map转换为普通对象
const data = Object.fromEntries(cache);
CacheService.set(CACHE_CONFIG.TRANSLATE_CACHE_KEY, data);
} catch (error) {
logger.error(`翻译缓存 | 保存缓存失败 | 错误:${error.message}`);
}
}
/**
* 添加翻译缓存
*/
static addTranslateCache(sourceText, translatedText) {
try {
// 验证参数
if (!sourceText || !translatedText) {
logger.error("翻译缓存 | 添加缓存失败 | 缺少必要参数");
return false;
}
// 获取现有缓存
const cache = this.getAllTranslateCache();
// 添加或更新缓存
cache.set(sourceText, translatedText);
// 如果缓存过大,删除最旧的条目
if (cache.size > CACHE_CONFIG.MAX_TRANSLATE_CACHE) {
// 将Map转换为数组以便操作
const entries = Array.from(cache.entries());
// 删除最早的条目,保留最新的MAX_TRANSLATE_CACHE条
const newEntries = entries.slice(-CACHE_CONFIG.MAX_TRANSLATE_CACHE);
// 重建缓存
cache.clear();
newEntries.forEach(([key, value]) => cache.set(key, value));
}
// 保存缓存
this.saveAllTranslateCache(cache);
logger.debug(`翻译缓存 | 添加缓存 | 原文长度:${sourceText.length} | 译文长度:${translatedText.length}`);
return true;
} catch (error) {
logger.error(`翻译缓存 | 添加缓存失败 | 错误:${error.message}`);
return false;
}
}
/**
* 查询翻译缓存
*/
static queryTranslateCache(text) {
try {
if (!text) return null;
const cache = this.getAllTranslateCache();
// 检查是否为原文(key)
if (cache.has(text)) {
const translatedText = cache.get(text);
// logger.debug(`翻译缓存 | 查询结果:命中原文 | 原文长度:${text.length} | 译文长度:${translatedText.length}`);
return {
type: 'source',
text: text,
translatedText: translatedText
};
}
// 检查是否为译文(value)
for (const [source, translated] of cache.entries()) {
if (translated === text) {
logger.debug(`翻译缓存 | 查询结果:命中译文 | 原文长度:${source.length} | 译文长度:${text.length}`);
return {
type: 'translated',
text: text,
sourceText: source
};
}
}
// 未命中缓存
logger.debug(`翻译缓存 | 查询结果:未命中 | 文本长度:${text.length}`);
return null;
} catch (error) {
logger.error(`翻译缓存 | 查询缓存失败 | 错误:${error.message}`);
return null;
}
}
/**
* 清除所有翻译缓存
*/
static clearAllTranslateCache() {
try {
CacheService.remove(CACHE_CONFIG.TRANSLATE_CACHE_KEY);
logger.debug("翻译缓存 | 清除所有缓存");
} catch (error) {
logger.error(`翻译缓存 | 清除缓存失败 | 错误:${error.message}`);
}
}
/**
* 获取翻译缓存统计信息
*/
static getTranslateCacheStats() {
try {
const cache = this.getAllTranslateCache();
const stats = {
total: cache.size,
sourceTextLengths: 0,
translatedTextLengths: 0
};
// 计算原文和译文的总长度
for (const [source, translated] of cache.entries()) {
stats.sourceTextLengths += source.length;
stats.translatedTextLengths += translated.length;
}
logger.debug(`翻译缓存 | 获取统计 | 总数:${stats.total} | 原文总长度:${stats.sourceTextLengths} | 译文总长度:${stats.translatedTextLengths}`);
return stats;
} catch (error) {
logger.error(`翻译缓存 | 获取统计失败 | 错误:${error.message}`);
return { total: 0, sourceTextLengths: 0, translatedTextLengths: 0 };
}
}
}
export { CacheService, HistoryCacheService, TagCacheService, TranslateCacheService, CACHE_CONFIG };