divar-rent-analyzer / data_manager.py
Manus Bot
Fix Gradio version conflict for Hugging Face Spaces deployment
435b526
Raw
History Blame Contribute Delete
6.15 kB
"""
Data Manager Module
Handles in-memory storage, persistence, and data operations.
"""
import json
import logging
from typing import List, Dict, Any, Set
from datetime import datetime
from pathlib import Path
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
DATA_DIR = Path("data")
LISTINGS_FILE = DATA_DIR / "listings.json"
FAVORITES_FILE = DATA_DIR / "favorites.json"
class DataManager:
"""Manages in-memory and persistent storage of listings."""
def __init__(self):
self.listings: Dict[str, Dict[str, Any]] = {}
self.favorites: Set[str] = set()
self.seen_ids: Set[str] = set()
self._ensure_data_dir()
self._load_data()
def _ensure_data_dir(self):
"""Ensure data directory exists."""
DATA_DIR.mkdir(exist_ok=True)
def _load_data(self):
"""Load persisted data from files."""
try:
if LISTINGS_FILE.exists():
with open(LISTINGS_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
self.listings = data.get("listings", {})
self.seen_ids = set(self.listings.keys())
logger.info(f"Loaded {len(self.listings)} listings from disk")
except Exception as e:
logger.error(f"Error loading listings: {e}")
try:
if FAVORITES_FILE.exists():
with open(FAVORITES_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
self.favorites = set(data.get("favorites", []))
logger.info(f"Loaded {len(self.favorites)} favorites from disk")
except Exception as e:
logger.error(f"Error loading favorites: {e}")
def _save_listings(self):
"""Persist listings to disk."""
try:
with open(LISTINGS_FILE, "w", encoding="utf-8") as f:
json.dump({"listings": self.listings}, f, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"Error saving listings: {e}")
def _save_favorites(self):
"""Persist favorites to disk."""
try:
with open(FAVORITES_FILE, "w", encoding="utf-8") as f:
json.dump({"favorites": list(self.favorites)}, f, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"Error saving favorites: {e}")
def add_listings(self, listings: List[Dict[str, Any]]) -> int:
"""
Add new listings to storage.
Args:
listings: List of listing dictionaries
Returns:
Number of new listings added
"""
new_count = 0
for listing in listings:
divar_id = listing.get("divar_id")
if divar_id and divar_id not in self.seen_ids:
self.listings[divar_id] = listing
self.seen_ids.add(divar_id)
new_count += 1
if new_count > 0:
self._save_listings()
logger.info(f"Added {new_count} new listings")
return new_count
def get_all_listings(self) -> List[Dict[str, Any]]:
"""Get all listings."""
return list(self.listings.values())
def get_listings_by_neighborhood(self, neighborhood: str) -> List[Dict[str, Any]]:
"""Get listings for a specific neighborhood."""
return [l for l in self.listings.values() if l.get("neighborhood") == neighborhood]
def get_budget_fit_listings(self) -> List[Dict[str, Any]]:
"""Get listings that fit the budget."""
return [l for l in self.listings.values() if l.get("budget_fit") == "fits_budget"]
def get_listing(self, divar_id: str) -> Dict[str, Any]:
"""Get a specific listing by ID."""
return self.listings.get(divar_id, {})
def add_favorite(self, divar_id: str) -> bool:
"""Add a listing to favorites (max 3)."""
if len(self.favorites) >= 3 and divar_id not in self.favorites:
logger.warning("Favorites limit (3) reached")
return False
self.favorites.add(divar_id)
self._save_favorites()
logger.info(f"Added {divar_id} to favorites")
return True
def remove_favorite(self, divar_id: str) -> bool:
"""Remove a listing from favorites."""
if divar_id in self.favorites:
self.favorites.remove(divar_id)
self._save_favorites()
logger.info(f"Removed {divar_id} from favorites")
return True
return False
def get_favorites(self) -> List[Dict[str, Any]]:
"""Get all favorite listings."""
return [self.listings[fid] for fid in self.favorites if fid in self.listings]
def is_favorite(self, divar_id: str) -> bool:
"""Check if a listing is in favorites."""
return divar_id in self.favorites
def clear_all(self):
"""Clear all data (for testing)."""
self.listings.clear()
self.favorites.clear()
self.seen_ids.clear()
self._save_listings()
self._save_favorites()
logger.info("Cleared all data")
def get_statistics(self) -> Dict[str, Any]:
"""Get statistics about stored listings."""
listings = self.get_all_listings()
budget_fit = len(self.get_budget_fit_listings())
return {
"total_listings": len(listings),
"budget_fit_count": budget_fit,
"favorites_count": len(self.favorites),
"neighborhoods": list(set(l.get("neighborhood", "") for l in listings)),
"last_updated": datetime.now().isoformat()
}
# Global instance
_data_manager = None
def get_data_manager() -> DataManager:
"""Factory function to get or create data manager instance."""
global _data_manager
if _data_manager is None:
_data_manager = DataManager()
return _data_manager
if __name__ == "__main__":
manager = get_data_manager()
print(f"Statistics: {manager.get_statistics()}")