sentiment-api / src /cache.py
Syed Arfan
Add Docker Compose setup with PostgreSQL, Redis, and Nginx; implement caching and database models
66da1e3
raw
history blame
3.96 kB
"""
Redis cache layer for sentiment analysis API
Caches ML inference results to avoid redundant model calls
Uses Redis for sub-millisecond lookup times
"""
import redis
import hashlib
import json
import os
from typing import Optional, Dict, Any
# Get Redis URL from environment variable
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379")
# Create Redis client
# decode_responses=True converts bytes to strings automatically
redis_client = redis.from_url(REDIS_URL, decode_responses=True)
# Cache TTL (Time To Live) - how long to keep cached results
CACHE_TTL_SECONDS = 3600 # 1 hour
def generate_cache_key(text: str) -> str:
"""
Generate a unique cache key for the input text
Uses SHA-256 hash to create consistent keys
Same text always generates same key
Args:
text: Input text to analyze
Returns:
Cache key string (e.g., "sentiment:abc123...")
"""
# Create hash of the text (consistent for same input)
text_hash = hashlib.sha256(text.encode()).hexdigest()[:16]
return f"sentiment:{text_hash}"
def get_cached_result(text: str) -> Optional[Dict[str, Any]]:
"""
Retrieve cached sentiment analysis result
Args:
text: Input text to look up
Returns:
Cached result dict if found, None if cache miss
"""
try:
cache_key = generate_cache_key(text)
cached_data = redis_client.get(cache_key)
if cached_data:
# Parse JSON string back to dict
return json.loads(cached_data)
return None
except Exception as e:
# If Redis fails, log but don't crash
print(f"Cache retrieval error: {e}")
return None
def cache_result(text: str, result: Dict[str, Any]) -> bool:
"""
Store sentiment analysis result in cache
Args:
text: Input text that was analyzed
result: Analysis result to cache
Returns:
True if cached successfully, False otherwise
"""
try:
cache_key = generate_cache_key(text)
# Convert dict to JSON string
result_json = json.dumps(result)
# Store in Redis with TTL
redis_client.setex(
cache_key,
CACHE_TTL_SECONDS,
result_json
)
return True
except Exception as e:
print(f"Cache storage error: {e}")
return False
def get_cache_stats() -> Dict[str, Any]:
"""
Get Redis cache statistics
Returns:
Dict with cache info (memory usage, keys, hits, etc.)
"""
try:
info = redis_client.info("stats")
memory = redis_client.info("memory")
# Count sentiment-related keys
sentiment_keys = len(redis_client.keys("sentiment:*"))
return {
"status": "connected",
"total_keys": redis_client.dbsize(),
"sentiment_keys": sentiment_keys,
"memory_used_mb": round(memory["used_memory"] / 1024 / 1024, 2),
"hits": info.get("keyspace_hits", 0),
"misses": info.get("keyspace_misses", 0),
"hit_rate": round(
info.get("keyspace_hits", 0) /
max(info.get("keyspace_hits", 0) + info.get("keyspace_misses", 0), 1) * 100,
2
)
}
except Exception as e:
return {
"status": "error",
"error": str(e)
}
def clear_cache() -> bool:
"""
Clear all sentiment cache entries
WARNING: This removes all cached results
Returns:
True if cleared successfully
"""
try:
# Get all sentiment keys
keys = redis_client.keys("sentiment:*")
if keys:
redis_client.delete(*keys)
return True
except Exception as e:
print(f"Cache clear error: {e}")
return False