import json from datetime import datetime, timezone from pathlib import Path import aiosqlite from app.core.config import Settings class RoadmapCache: def __init__(self, settings: Settings): self.settings = settings async def init(self) -> None: db_parent = Path(self.settings.sqlite_db_path).expanduser().parent if db_parent != Path("."): db_parent.mkdir(parents=True, exist_ok=True) async with aiosqlite.connect(self.settings.sqlite_db_path) as db: await db.execute( """ CREATE TABLE IF NOT EXISTS roadmap_cache ( normalized_skill TEXT NOT NULL, request_hash TEXT NOT NULL, roadmap_json TEXT NOT NULL, created_at TEXT NOT NULL, model_used TEXT NOT NULL, PRIMARY KEY (normalized_skill, request_hash) ) """ ) await db.commit() async def get(self, normalized_skill: str, request_hash: str) -> dict | None: if not self.settings.enable_cache: return None await self.init() async with aiosqlite.connect(self.settings.sqlite_db_path) as db: cursor = await db.execute( "SELECT roadmap_json FROM roadmap_cache WHERE normalized_skill = ? AND request_hash = ?", (normalized_skill, request_hash), ) row = await cursor.fetchone() if not row: return None data = json.loads(row[0]) data.setdefault("metadata", {})["cached"] = True return data async def set(self, normalized_skill: str, request_hash: str, roadmap: dict, model_used: str) -> None: if not self.settings.enable_cache: return await self.init() to_store = json.loads(json.dumps(roadmap)) to_store.setdefault("metadata", {})["cached"] = False async with aiosqlite.connect(self.settings.sqlite_db_path) as db: await db.execute( """ INSERT OR REPLACE INTO roadmap_cache (normalized_skill, request_hash, roadmap_json, created_at, model_used) VALUES (?, ?, ?, ?, ?) """, ( normalized_skill, request_hash, json.dumps(to_store), datetime.now(timezone.utc).isoformat(), model_used, ), ) await db.commit()