entscore / core /cache.py
Joshua
Initial commit: EntScore SEO page optimization tool
608ab71
Raw History Blame Contribute Delete
4.19 kB
"""
3-tier cache: API responses, scrape results, model cache
"""
import json
from typing import Optional, Dict
from datetime import datetime, timedelta
from db.database import get_connection
from core.logger import setup_logger
logger = setup_logger(__name__)
class Cache:
def __init__(
self,
serp_ttl_hours: int = 24,
scrape_ttl_days: int = 7,
keyword_metrics_ttl_days: int = 7,
):
self.serp_ttl_hours = serp_ttl_hours
self.scrape_ttl_days = scrape_ttl_days
self.keyword_metrics_ttl_days = keyword_metrics_ttl_days
def get_api_cache(self, cache_key: str) -> Optional[Dict]:
"""Get cached API response if not expired."""
conn = get_connection()
try:
cursor = conn.execute(
"SELECT response_data FROM api_cache WHERE cache_key = ? AND expires_at > datetime('now')",
(cache_key,),
)
row = cursor.fetchone()
if row:
logger.info(f"Cache hit: {cache_key}")
return json.loads(row["response_data"])
return None
finally:
conn.close()
def set_api_cache(self, cache_key: str, data: Dict, ttl_hours: Optional[int] = None):
"""Cache an API response."""
ttl = ttl_hours or self.serp_ttl_hours
expires_at = (datetime.utcnow() + timedelta(hours=ttl)).isoformat()
conn = get_connection()
try:
conn.execute(
"""INSERT OR REPLACE INTO api_cache (cache_key, response_data, expires_at)
VALUES (?, ?, ?)""",
(cache_key, json.dumps(data), expires_at),
)
conn.commit()
logger.info(f"Cached: {cache_key} (TTL: {ttl}h)")
finally:
conn.close()
def get_scrape_cache(self, url: str) -> Optional[Dict]:
"""Get cached scrape result if not expired."""
conn = get_connection()
try:
cursor = conn.execute(
"SELECT html, clean_text, metadata FROM scrape_cache WHERE url = ? AND expires_at > datetime('now')",
(url,),
)
row = cursor.fetchone()
if row:
logger.info(f"Scrape cache hit: {url}")
metadata = {}
if row["metadata"]:
try:
metadata = json.loads(row["metadata"])
except (json.JSONDecodeError, TypeError):
pass
return {
"html": row["html"],
"clean_text": row["clean_text"],
"metadata": metadata,
}
return None
finally:
conn.close()
def set_scrape_cache(self, url: str, html: str, clean_text: str, metadata: Optional[Dict] = None):
"""Cache a scrape result."""
expires_at = (
datetime.utcnow() + timedelta(days=self.scrape_ttl_days)
).isoformat()
conn = get_connection()
try:
conn.execute(
"""INSERT OR REPLACE INTO scrape_cache (url, html, clean_text, metadata, expires_at)
VALUES (?, ?, ?, ?, ?)""",
(
url,
html,
clean_text,
json.dumps(metadata) if metadata else None,
expires_at,
),
)
conn.commit()
logger.info(f"Scrape cached: {url}")
finally:
conn.close()
def clear_expired(self):
"""Remove expired cache entries."""
conn = get_connection()
try:
from db.database import clear_expired_cache
clear_expired_cache(conn)
logger.info("Expired cache entries cleared")
finally:
conn.close()
def clear_all(self):
"""Clear all cache entries."""
conn = get_connection()
try:
from db.database import clear_all_cache
clear_all_cache(conn)
logger.info("All cache cleared")
finally:
conn.close()