Spaces:
Sleeping
Sleeping
| """ | |
| core/session_memory.py — session snapshot persistence with optional HF Dataset sync. | |
| """ | |
| from __future__ import annotations | |
| import io | |
| import json | |
| import os | |
| import re | |
| import shutil | |
| import tempfile | |
| from pathlib import Path | |
| from typing import Any, Dict, Optional | |
| try: | |
| from huggingface_hub import HfApi, hf_hub_download | |
| except Exception: # pragma: no cover | |
| HfApi = None # type: ignore | |
| hf_hub_download = None # type: ignore | |
| class SessionMemoryManager: | |
| def __init__( | |
| self, | |
| workspace: str, | |
| dataset_repo: Optional[str] = None, | |
| token: Optional[str] = None, | |
| ) -> None: | |
| self.root = Path(workspace).resolve() / "sessions" | |
| self.root.mkdir(parents=True, exist_ok=True) | |
| self.dataset_repo = dataset_repo or os.environ.get("DEVAI_SESSION_DATASET") or os.environ.get("HF_SESSION_DATASET_REPO") | |
| self.token = token or os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_TOKEN") | |
| self.api = HfApi(token=self.token) if (self.dataset_repo and self.token and HfApi is not None) else None | |
| def sanitize_session_id(session_id: str) -> str: | |
| cleaned = re.sub(r"[^A-Za-z0-9._-]+", "-", str(session_id or "anon")).strip("-._") | |
| return cleaned[:120] or "anon" | |
| def _session_dir(self, session_id: str) -> Path: | |
| d = self.root / self.sanitize_session_id(session_id) | |
| d.mkdir(parents=True, exist_ok=True) | |
| return d | |
| def _attachments_dir(self, session_id: str) -> Path: | |
| d = self._session_dir(session_id) / "attachments" | |
| d.mkdir(parents=True, exist_ok=True) | |
| return d | |
| def _snapshot_path(self, session_id: str) -> Path: | |
| return self._session_dir(session_id) / "latest.json" | |
| def _copy_attachment(self, src_path: Optional[str], dst_name: str, session_id: str) -> Optional[str]: | |
| if not src_path or not os.path.exists(src_path): | |
| return None | |
| dst = self._attachments_dir(session_id) / dst_name | |
| shutil.copyfile(src_path, dst) | |
| return str(dst) | |
| def _push_to_dataset(self, session_id: str, snapshot: Dict[str, Any]) -> None: | |
| if not self.api or not self.dataset_repo: | |
| return | |
| payload = json.dumps(snapshot, ensure_ascii=False, indent=2, default=str).encode("utf-8") | |
| self.api.upload_file( | |
| path_or_fileobj=io.BytesIO(payload), | |
| path_in_repo=f"sessions/{self.sanitize_session_id(session_id)}/latest.json", | |
| repo_id=self.dataset_repo, | |
| repo_type="dataset", | |
| ) | |
| def _pull_from_dataset(self, session_id: str) -> Optional[Dict[str, Any]]: | |
| if not (self.dataset_repo and self.token and hf_hub_download is not None): | |
| return None | |
| try: | |
| local = hf_hub_download( | |
| repo_id=self.dataset_repo, | |
| repo_type="dataset", | |
| filename=f"sessions/{self.sanitize_session_id(session_id)}/latest.json", | |
| token=self.token, | |
| local_dir=tempfile.mkdtemp(prefix="devai_session_restore_"), | |
| ) | |
| return json.loads(Path(local).read_text(encoding="utf-8")) | |
| except Exception: | |
| return None | |
| def save_ui_state(self, session_id: str, snapshot: Dict[str, Any]) -> Dict[str, Any]: | |
| sid = self.sanitize_session_id(session_id) | |
| payload = dict(snapshot or {}) | |
| payload["session_id"] = sid | |
| payload["zip_input_path"] = self._copy_attachment(payload.get("zip_input_path"), "last_input.zip", sid) | |
| payload["zip_output_path"] = self._copy_attachment(payload.get("zip_output_path"), "last_output.zip", sid) | |
| path = self._snapshot_path(sid) | |
| path.write_text(json.dumps(payload, ensure_ascii=False, indent=2, default=str), encoding="utf-8") | |
| try: | |
| self._push_to_dataset(sid, payload) | |
| except Exception: | |
| pass | |
| return payload | |
| def restore_ui_state(self, session_id: str) -> Optional[Dict[str, Any]]: | |
| sid = self.sanitize_session_id(session_id) | |
| path = self._snapshot_path(sid) | |
| if path.exists(): | |
| try: | |
| return json.loads(path.read_text(encoding="utf-8")) | |
| except Exception: | |
| pass | |
| pulled = self._pull_from_dataset(sid) | |
| if pulled: | |
| try: | |
| path.write_text(json.dumps(pulled, ensure_ascii=False, indent=2, default=str), encoding="utf-8") | |
| except Exception: | |
| pass | |
| return pulled | |
| __all__ = ["SessionMemoryManager"] | |