Spaces:
Running
Running
Syed Arfan
Add Docker Compose setup with PostgreSQL, Redis, and Nginx; implement caching and database models
66da1e3
| """ | |
| 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 |