Spaces:
Runtime error
Runtime error
import sqlite3 | |
import numpy as np | |
from typing import Optional, List | |
from pathlib import Path | |
import time | |
class EmbeddingCache: | |
def __init__(self, db_path: str = "embeddings_cache.db"): | |
""" | |
Ініціалізація кешу ембедінгів | |
Args: | |
db_path: шлях до файлу SQLite бази даних | |
""" | |
self.db_path = db_path | |
self._init_db() | |
self.hits = 0 | |
self.misses = 0 | |
def _init_db(self): | |
"""Ініціалізація структури бази даних""" | |
with sqlite3.connect(self.db_path) as conn: | |
conn.execute(""" | |
CREATE TABLE IF NOT EXISTS embeddings ( | |
text_hash TEXT PRIMARY KEY, | |
text TEXT NOT NULL, | |
model TEXT NOT NULL, | |
embedding BLOB NOT NULL, | |
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | |
) | |
""") | |
# Індекс для швидкого пошуку за хешем | |
conn.execute(""" | |
CREATE INDEX IF NOT EXISTS idx_text_hash | |
ON embeddings(text_hash) | |
""") | |
def _get_hash(self, text: str, model: str) -> str: | |
"""Створення унікального хешу для тексту та моделі""" | |
return str(hash(f"{text}:{model}")) | |
def get(self, text: str, model: str) -> Optional[np.ndarray]: | |
""" | |
Отримання ембедінгу з кешу | |
Args: | |
text: текст для пошуку | |
model: назва моделі ембедінгів | |
Returns: | |
np.ndarray якщо знайдено, None якщо не знайдено | |
""" | |
text_hash = self._get_hash(text, model) | |
with sqlite3.connect(self.db_path) as conn: | |
result = conn.execute( | |
"SELECT embedding FROM embeddings WHERE text_hash = ?", | |
(text_hash,) | |
).fetchone() | |
if result: | |
self.hits += 1 | |
return np.frombuffer(result[0], dtype=np.float32) | |
self.misses += 1 | |
return None | |
def put(self, text: str, model: str, embedding: np.ndarray) -> None: | |
""" | |
Збереження ембедінгу в кеш | |
Args: | |
text: вхідний текст | |
model: назва моделі | |
embedding: ембедінг для збереження | |
""" | |
text_hash = self._get_hash(text, model) | |
with sqlite3.connect(self.db_path) as conn: | |
conn.execute( | |
""" | |
INSERT OR REPLACE INTO embeddings | |
(text_hash, text, model, embedding) | |
VALUES (?, ?, ?, ?) | |
""", | |
( | |
text_hash, | |
text, | |
model, | |
np.array(embedding, dtype=np.float32).tobytes() | |
) | |
) | |
def clear_old(self, days: int = 30) -> int: | |
""" | |
Очищення старих записів з кешу | |
Args: | |
days: кількість днів, старіші записи будуть видалені | |
Returns: | |
Кількість видалених записів | |
""" | |
with sqlite3.connect(self.db_path) as conn: | |
cursor = conn.execute( | |
""" | |
DELETE FROM embeddings | |
WHERE created_at < datetime('now', ?) | |
""", | |
(f"-{days} days",) | |
) | |
return cursor.rowcount | |
def get_stats(self) -> dict: | |
"""Отримання статистики використання кешу""" | |
with sqlite3.connect(self.db_path) as conn: | |
total = conn.execute( | |
"SELECT COUNT(*) FROM embeddings" | |
).fetchone()[0] | |
size = Path(self.db_path).stat().st_size / (1024 * 1024) # Size in MB | |
if self.hits + self.misses > 0: | |
hit_rate = self.hits / (self.hits + self.misses) * 100 | |
else: | |
hit_rate = 0 | |
return { | |
"total_entries": total, | |
"cache_size_mb": round(size, 2), | |
"hits": self.hits, | |
"misses": self.misses, | |
"hit_rate_percent": round(hit_rate, 2) | |
} |