mirror of
https://github.com/NekoMonci12/RakunNakun-AI.git
synced 2025-12-19 14:59:15 +00:00
Redis Is now optional
This commit is contained in:
@@ -6,68 +6,141 @@ class CacheManagerRedis {
|
||||
* Example: { url: 'redis://localhost:6379' }
|
||||
*/
|
||||
constructor(options) {
|
||||
this.client = createClient(options);
|
||||
this.client.on('error', (err) => console.error('Redis Client Error', err));
|
||||
this.client.connect();
|
||||
this.options = options;
|
||||
this.client = createClient(this.options);
|
||||
this.connected = false;
|
||||
this.connecting = false;
|
||||
|
||||
this.redisErrorCount = 0;
|
||||
this.redisErrorLimit = 3;
|
||||
|
||||
this.client.on('error', (err) => {
|
||||
this.connected = false;
|
||||
|
||||
if (this.redisErrorCount < this.redisErrorLimit) {
|
||||
console.error('[RedisCache] Redis Client Error:', err.message);
|
||||
this.redisErrorCount++;
|
||||
|
||||
if (this.redisErrorCount === this.redisErrorLimit) {
|
||||
console.warn('[RedisCache] Reached max Redis error log limit. Further errors will be silenced.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this._initialConnect();
|
||||
}
|
||||
|
||||
async _initialConnect() {
|
||||
try {
|
||||
this.connecting = true;
|
||||
await this.client.connect();
|
||||
this.connected = true;
|
||||
this.redisErrorCount = 0;
|
||||
console.log('[RedisCache] Connected to Redis.');
|
||||
} catch (err) {
|
||||
console.error('[RedisCache] Initial Redis connection failed:', err.message);
|
||||
this.connected = false;
|
||||
} finally {
|
||||
this.connecting = false;
|
||||
}
|
||||
}
|
||||
|
||||
async _reconnectIfNeeded() {
|
||||
if (!this.connected && !this.connecting) {
|
||||
console.warn('[RedisCache] Attempting to reconnect to Redis...');
|
||||
try {
|
||||
this.connecting = true;
|
||||
this.client = createClient(this.options);
|
||||
|
||||
// Reset listener and error limiter
|
||||
this.redisErrorCount = 0;
|
||||
this.client.on('error', (err) => {
|
||||
this.connected = false;
|
||||
|
||||
if (this.redisErrorCount < this.redisErrorLimit) {
|
||||
console.error('[RedisCache] Redis Client Error:', err.message);
|
||||
this.redisErrorCount++;
|
||||
|
||||
if (this.redisErrorCount === this.redisErrorLimit) {
|
||||
console.warn('[RedisCache] Reached max Redis error log limit. Further errors will be silenced.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await this.client.connect();
|
||||
this.connected = true;
|
||||
console.log('[RedisCache] Reconnected to Redis.');
|
||||
} catch (err) {
|
||||
console.error('[RedisCache] Reconnection failed:', err.message);
|
||||
} finally {
|
||||
this.connecting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize input for consistent comparison
|
||||
normalize(input) {
|
||||
return input.trim().toLowerCase();
|
||||
}
|
||||
|
||||
// Compute the Levenshtein distance between two strings
|
||||
levenshtein(a, b) {
|
||||
const matrix = [];
|
||||
for (let i = 0; i <= b.length; i++) {
|
||||
matrix[i] = [i];
|
||||
}
|
||||
for (let j = 0; j <= a.length; j++) {
|
||||
matrix[0][j] = j;
|
||||
}
|
||||
for (let i = 0; i <= b.length; i++) matrix[i] = [i];
|
||||
for (let j = 0; j <= a.length; j++) matrix[0][j] = j;
|
||||
|
||||
for (let i = 1; i <= b.length; i++) {
|
||||
for (let j = 1; j <= a.length; j++) {
|
||||
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
||||
matrix[i][j] = matrix[i - 1][j - 1];
|
||||
} else {
|
||||
matrix[i][j] = Math.min(
|
||||
matrix[i][j] = b.charAt(i - 1) === a.charAt(j - 1)
|
||||
? matrix[i - 1][j - 1]
|
||||
: Math.min(
|
||||
matrix[i - 1][j - 1] + 1,
|
||||
matrix[i][j - 1] + 1,
|
||||
matrix[i - 1][j] + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matrix[b.length][a.length];
|
||||
}
|
||||
|
||||
// Calculate similarity between two strings (1 means identical, 0 means completely different)
|
||||
similarity(a, b) {
|
||||
const distance = this.levenshtein(a, b);
|
||||
const maxLen = Math.max(a.length, b.length);
|
||||
if (maxLen === 0) return 1;
|
||||
return 1 - distance / maxLen;
|
||||
return maxLen === 0 ? 1 : 1 - distance / maxLen;
|
||||
}
|
||||
|
||||
// Check the cache for a result that is at least 80% similar to the new input.
|
||||
async getCachedResult(input) {
|
||||
await this._reconnectIfNeeded();
|
||||
if (!this.connected) return null;
|
||||
|
||||
try {
|
||||
const normalizedInput = this.normalize(input);
|
||||
const keys = await this.client.keys('cache:*');
|
||||
|
||||
for (const key of keys) {
|
||||
const storedNormalizedInput = key.slice(6); // remove "cache:" prefix
|
||||
const storedNormalizedInput = key.slice(6);
|
||||
const sim = this.similarity(normalizedInput, storedNormalizedInput);
|
||||
if (sim >= 0.8) {
|
||||
const cachedOutput = await this.client.get(key);
|
||||
return cachedOutput;
|
||||
return await this.client.get(key);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[RedisCache] Error in getCachedResult:', err.message);
|
||||
this.connected = false;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Store the result in cache with key as normalized input
|
||||
async setCache(input, output) {
|
||||
await this._reconnectIfNeeded();
|
||||
if (!this.connected) return;
|
||||
|
||||
try {
|
||||
const normalizedInput = this.normalize(input);
|
||||
await this.client.set(`cache:${normalizedInput}`, output, { EX: 3600 });
|
||||
} catch (err) {
|
||||
console.error('[RedisCache] Error in setCache:', err.message);
|
||||
this.connected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user