Spaces:
Sleeping
Sleeping
| """Caching. In-process LRU cache for diagnosis results keyed by image hash. | |
| For privacy, we hash the image bytes; the image itself is never persisted | |
| in the cache. Identical scans produce identical hashes, giving us a simple | |
| content-addressed cache. | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import json | |
| import logging | |
| import time | |
| from collections import OrderedDict | |
| from threading import Lock | |
| from typing import Any | |
| logger = logging.getLogger(__name__) | |
| class DiagnosisCache: | |
| """Thread-safe LRU cache for diagnosis results.""" | |
| def __init__(self, max_size: int = 64, ttl_seconds: int = 3600) -> None: | |
| self._max_size = max_size | |
| self._ttl = ttl_seconds | |
| self._store: OrderedDict[str, tuple[float, dict]] = OrderedDict() | |
| self._lock = Lock() | |
| self._hits = 0 | |
| self._misses = 0 | |
| def hash_image(image_bytes: bytes) -> str: | |
| return hashlib.sha256(image_bytes).hexdigest() | |
| def get(self, image_bytes: bytes) -> dict | None: | |
| key = self.hash_image(image_bytes) | |
| now = time.time() | |
| with self._lock: | |
| entry = self._store.get(key) | |
| if entry is None: | |
| self._misses += 1 | |
| return None | |
| ts, value = entry | |
| if now - ts > self._ttl: | |
| del self._store[key] | |
| self._misses += 1 | |
| return None | |
| self._store.move_to_end(key) | |
| self._hits += 1 | |
| logger.info("Cache hit for %s", key[:12]) | |
| return value | |
| def put(self, image_bytes: bytes, value: dict) -> None: | |
| key = self.hash_image(image_bytes) | |
| now = time.time() | |
| with self._lock: | |
| self._store[key] = (now, value) | |
| self._store.move_to_end(key) | |
| while len(self._store) > self._max_size: | |
| self._store.popitem(last=False) | |
| def stats(self) -> dict: | |
| with self._lock: | |
| return { | |
| "size": len(self._store), | |
| "max_size": self._max_size, | |
| "hits": self._hits, | |
| "misses": self._misses, | |
| } | |
| def clear(self) -> None: | |
| with self._lock: | |
| self._store.clear() | |
| self._hits = 0 | |
| self._misses = 0 | |
| _default_cache: DiagnosisCache | None = None | |
| def get_cache() -> DiagnosisCache: | |
| global _default_cache | |
| if _default_cache is None: | |
| _default_cache = DiagnosisCache() | |
| return _default_cache | |
| __all__ = ["DiagnosisCache", "get_cache"] | |