feat: новая функция
This commit is contained in:
@@ -4,12 +4,16 @@
|
||||
|
||||
const crypto = require('crypto');
|
||||
const logger = require('../utils/logger');
|
||||
const ollamaConfig = require('./ollamaConfig');
|
||||
|
||||
class AICache {
|
||||
constructor() {
|
||||
const timeouts = ollamaConfig.getTimeouts();
|
||||
|
||||
this.cache = new Map();
|
||||
this.maxSize = 1000; // Максимальное количество кэшированных ответов
|
||||
this.ttl = 24 * 60 * 60 * 1000; // 24 часа в миллисекундах
|
||||
this.maxSize = timeouts.cacheMax; // Из централизованных настроек
|
||||
this.ttl = timeouts.cacheLLM; // 24 часа (для LLM)
|
||||
this.ragTtl = timeouts.cacheRAG; // 5 минут (для RAG результатов)
|
||||
}
|
||||
|
||||
// Генерация ключа кэша на основе запроса
|
||||
@@ -22,6 +26,12 @@ class AICache {
|
||||
return crypto.createHash('md5').update(content).digest('hex');
|
||||
}
|
||||
|
||||
// ✨ НОВОЕ: Генерация ключа для RAG результатов
|
||||
generateKeyForRAG(tableId, userQuestion, product = null) {
|
||||
const content = JSON.stringify({ tableId, userQuestion, product });
|
||||
return crypto.createHash('md5').update(content).digest('hex');
|
||||
}
|
||||
|
||||
// Получение ответа из кэша
|
||||
get(key) {
|
||||
const cached = this.cache.get(key);
|
||||
@@ -37,6 +47,24 @@ class AICache {
|
||||
return cached.response;
|
||||
}
|
||||
|
||||
// ✨ НОВОЕ: Получение с учетом типа кэша (RAG или LLM)
|
||||
getWithTTL(key, type = 'llm') {
|
||||
const cached = this.cache.get(key);
|
||||
if (!cached) return null;
|
||||
|
||||
// Выбираем TTL в зависимости от типа
|
||||
const ttl = type === 'rag' ? this.ragTtl : this.ttl;
|
||||
|
||||
// Проверяем TTL
|
||||
if (Date.now() - cached.timestamp > ttl) {
|
||||
this.cache.delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.info(`[AICache] Cache hit (${type}) for key: ${key.substring(0, 8)}...`);
|
||||
return cached.response;
|
||||
}
|
||||
|
||||
// Сохранение ответа в кэш
|
||||
set(key, response) {
|
||||
// Очищаем старые записи если кэш переполнен
|
||||
@@ -53,6 +81,23 @@ class AICache {
|
||||
logger.info(`[AICache] Cached response for key: ${key.substring(0, 8)}...`);
|
||||
}
|
||||
|
||||
// ✨ НОВОЕ: Сохранение с указанием типа (rag или llm)
|
||||
setWithType(key, response, type = 'llm') {
|
||||
// Очищаем старые записи если кэш переполнен
|
||||
if (this.cache.size >= this.maxSize) {
|
||||
const oldestKey = this.cache.keys().next().value;
|
||||
this.cache.delete(oldestKey);
|
||||
}
|
||||
|
||||
this.cache.set(key, {
|
||||
response,
|
||||
timestamp: Date.now(),
|
||||
type: type // Сохраняем тип для статистики
|
||||
});
|
||||
|
||||
logger.info(`[AICache] Cached ${type} response for key: ${key.substring(0, 8)}...`);
|
||||
}
|
||||
|
||||
// Очистка кэша
|
||||
clear() {
|
||||
this.cache.clear();
|
||||
@@ -90,6 +135,31 @@ class AICache {
|
||||
if (this.maxSize === 0) return 0;
|
||||
return this.cache.size / this.maxSize;
|
||||
}
|
||||
|
||||
// ✨ НОВОЕ: Статистика по типу кэша
|
||||
getStatsByType() {
|
||||
const stats = { rag: 0, llm: 0, other: 0 };
|
||||
for (const [key, value] of this.cache.entries()) {
|
||||
const type = value.type || 'other';
|
||||
stats[type] = (stats[type] || 0) + 1;
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
// ✨ НОВОЕ: Инвалидация по префиксу (для очистки RAG кэша при обновлении таблиц)
|
||||
invalidateByPrefix(prefix) {
|
||||
let deletedCount = 0;
|
||||
for (const [key, value] of this.cache.entries()) {
|
||||
if (key.startsWith(prefix)) {
|
||||
this.cache.delete(key);
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
if (deletedCount > 0) {
|
||||
logger.info(`[AICache] Инвалидировано ${deletedCount} записей с префиксом: ${prefix}`);
|
||||
}
|
||||
return deletedCount;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new AICache();
|
||||
Reference in New Issue
Block a user