quantumbit commited on
Commit
c1bb97a
·
verified ·
1 Parent(s): bcd24f8

Delete cache.py

Browse files
Files changed (1) hide show
  1. cache.py +0 -131
cache.py DELETED
@@ -1,131 +0,0 @@
1
- """
2
- Two-layer cache:
3
- 1. Exact-match hash cache (Redis/in-memory fallback)
4
- 2. Semantic near-duplicate cache using cosine similarity on query embeddings
5
-
6
- Semantic caching prevents re-querying the LLM for paraphrased versions of the
7
- same question - a major cost & latency win in production
8
- """
9
-
10
- import hashlib
11
- import json
12
- import logging
13
- import time
14
- from typing import Optional
15
-
16
- from google_crc32c import value
17
- import numpy as np
18
-
19
- from .config import get_settings
20
- from .embeddings import cosine_similarity
21
-
22
- logger = logging.getLogger(__name__)
23
- settings = get_settings()
24
-
25
- # In memory fallback (used when Redis is unavailable)
26
-
27
- class InMemoryCache:
28
- def __init__(self,ttl: int = 3600, max_size: int = 1000):
29
- self._store: dict[str,tuple[str, float]] = {} # Key -> (value, expiry)
30
- self.ttl = ttl
31
- self.max_size = max_size
32
-
33
- def get(self,key: str) -> Optional[str]:
34
- entry = self._store.get(key)
35
- if entry is None:
36
- return None
37
- value, expiry = entry
38
- if time.time() > expiry:
39
- del self._store[key]
40
- return None
41
- return value
42
-
43
- def set(self,key: str, value: str) -> None:
44
- if len(self._store) >= self.max_size:
45
- oldest = next(iter(self._store))
46
- del self._store[oldest]
47
- self._store[key] = (value, time.time() + self.ttl)
48
-
49
- def ping(self) -> bool:
50
- return True
51
-
52
- def _build_redis_client():
53
- try:
54
- import redis
55
- client = redis.from_url(settings.redis_url, decode_responses=True)
56
- client.ping()
57
- logger.info("Redis cache connected")
58
- return client
59
- except Exception as e:
60
- logger.warning(f"Redis unavalaible ({e}) - using in-memory cache.")
61
- return InMemoryCache(ttl=settings.cache_ttl_seconds)
62
-
63
- _cache_client = _build_redis_client()
64
-
65
- # Exact match cache
66
- def _cache_key(query: str, collection: str, mode: str) -> str:
67
- payload = f"{query}::{collection}::{mode}"
68
- return "rag:exact:" + hashlib.sha256(payload.encode()).hexdigest()[:32]
69
-
70
- def get_exact(query: str, collection: str, mode: str) -> Optional[dict]:
71
- key = _cache_key(query, collection, mode)
72
- raw = _cache_client.get(key)
73
- if raw:
74
- logger.debug(f"Exact cache hit: {key[:16]}...")
75
- return json.loads(raw)
76
- return None
77
-
78
- def set_exact(query: str, collection: str, mode: str, value: str) -> None:
79
- key = _cache_key(query,collection,mode)
80
- serialized = json.dumps(value)
81
- if hasattr(_cache_client,"setex"):
82
- _cache_client.setex(key,settings.cache_ttl_seconds,serialized)
83
- else:
84
- _cache_client.set(key,serialized)
85
-
86
- # Semantic Cache
87
- # stores (embedding, serialized_response) pairs keyed by short hash
88
- _semantic_index: list[tuple[list[float],str,dict]] = [] # (vec,key,response)
89
-
90
- def get_semantic(query_vec: list[float]) -> Optional[dict]:
91
- """Return the cache response if cosine similarity > threshold"""
92
- best_score = 0.0
93
- best_response = None
94
- for vec, _,response in _semantic_index:
95
- score = cosine_similarity(query_vec,vec)
96
- if score > best_score:
97
- best_score = score
98
- best_response = response
99
- if best_score >= settings.semantic_cache_threshold:
100
- logger.info(f"Semantic Cache hit (score={best_score:.3f})")
101
- return best_response
102
- return None
103
-
104
- def set_semantic(query_vec: list[float], query: str, response: dict) -> None:
105
- h = hashlib.md5(query.encode()).hexdigest()[:8]
106
- _semantic_index.append((query_vec, h, response))
107
- if len(_semantic_index) > 5000: # cap memory
108
- _semantic_index.pop(0)
109
-
110
- def cache_connected() -> bool:
111
- try:
112
- return bool(_cache_client.ping())
113
- except Exception:
114
- return False
115
-
116
- def get_cache_stats() -> dict:
117
- stats = {}
118
- if isinstance(_cache_client, InMemoryCache):
119
- stats["system"] = "in-memory (python dictionary)"
120
- stats["exact_matches_cached"] = len(_cache_client._store)
121
- else:
122
- stats["system"] = "redis"
123
- try:
124
- stats["exact_matches_cached"] = _cache_client.dbsize()
125
- except:
126
- stats["exact_matches_cached"] = "unknown"
127
-
128
- stats["semantic_matches_cached"] = len(_semantic_index)
129
- return stats
130
-
131
- print("[cache] Module ready")