Spaces:
Running
Running
| import time | |
| import uuid | |
| import json | |
| import os | |
| _HISTORY_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "session_history.json") | |
| class HistoryEntry: | |
| __slots__ = ("id", "timestamp", "prompt", "model", "rating", "num_variations", | |
| "creativity", "weight_mode", "results", "neg_results", | |
| "categories", "seed", "liked_indices") | |
| def __init__(self, prompt: str, results: list[str], model: str = "anima", | |
| rating: str = "pg", num_variations: int = 5, | |
| creativity: str = "medium", weight_mode: str = "off", | |
| neg_results: list[str] | None = None, | |
| categories: list[str] | None = None, | |
| seed: int | None = None): | |
| self.id = uuid.uuid4().hex[:8] | |
| self.timestamp = time.time() | |
| self.prompt = prompt | |
| self.model = model | |
| self.rating = rating | |
| self.num_variations = num_variations | |
| self.creativity = creativity | |
| self.weight_mode = weight_mode | |
| self.results = list(results) | |
| self.neg_results = list(neg_results) if neg_results else [] | |
| self.categories = list(categories) if categories else [] | |
| self.seed = seed | |
| self.liked_indices: list[int] = [] | |
| def from_dict(cls, d: dict) -> "HistoryEntry": | |
| entry = cls.__new__(cls) | |
| entry.id = d.get("id", uuid.uuid4().hex[:8]) | |
| entry.timestamp = d.get("timestamp", time.time()) | |
| entry.prompt = d.get("prompt", "") | |
| entry.model = d.get("model", "anima") | |
| entry.rating = d.get("rating", "pg") | |
| entry.num_variations = d.get("num_variations", 5) | |
| entry.creativity = d.get("creativity", "medium") | |
| entry.weight_mode = d.get("weight_mode", "off") | |
| entry.results = list(d.get("results", [])) | |
| entry.neg_results = list(d.get("neg_results", [])) | |
| entry.categories = list(d.get("categories", [])) | |
| entry.seed = d.get("seed") | |
| entry.liked_indices = list(d.get("liked_indices", [])) | |
| return entry | |
| def toggle_like(self, index: int) -> bool: | |
| if index in self.liked_indices: | |
| self.liked_indices.remove(index) | |
| return False | |
| self.liked_indices.append(index) | |
| return True | |
| def is_liked(self, index: int) -> bool: | |
| return index in self.liked_indices | |
| def get_liked_results(self) -> list[tuple[int, str]]: | |
| return [(i, self.results[i]) for i in self.liked_indices if i < len(self.results)] | |
| def to_dict(self) -> dict: | |
| return { | |
| "id": self.id, | |
| "timestamp": self.timestamp, | |
| "prompt": self.prompt, | |
| "model": self.model, | |
| "rating": self.rating, | |
| "num_variations": self.num_variations, | |
| "creativity": self.creativity, | |
| "weight_mode": self.weight_mode, | |
| "results": self.results, | |
| "neg_results": self.neg_results, | |
| "categories": self.categories, | |
| "seed": self.seed, | |
| "liked_indices": self.liked_indices, | |
| } | |
| class SessionHistory: | |
| def __init__(self, max_entries: int = 50, file_path: str | None = None): | |
| self._entries: list[HistoryEntry] = [] | |
| self._max_entries = max_entries | |
| self._file_path = file_path or _HISTORY_FILE | |
| self._load() | |
| def persist(self): | |
| self._save() | |
| def toggle_like(self, entry_index: int, result_index: int) -> bool: | |
| if entry_index < 0 or entry_index >= len(self._entries): | |
| return False | |
| liked = self._entries[entry_index].toggle_like(result_index) | |
| self._save() | |
| return liked | |
| def add(self, entry: HistoryEntry) -> str: | |
| self._entries.insert(0, entry) | |
| if len(self._entries) > self._max_entries: | |
| self._entries.pop() | |
| self._save() | |
| return entry.id | |
| def get(self, entry_id: str) -> HistoryEntry | None: | |
| for e in self._entries: | |
| if e.id == entry_id: | |
| return e | |
| return None | |
| def get_all(self) -> list[HistoryEntry]: | |
| return list(self._entries) | |
| def get_favorites(self) -> list[tuple[HistoryEntry, int, str]]: | |
| items = [] | |
| for entry in self._entries: | |
| for idx, text in entry.get_liked_results(): | |
| items.append((entry, idx, text)) | |
| return items | |
| def clear(self): | |
| self._entries.clear() | |
| self._save() | |
| def _save(self): | |
| data = [e.to_dict() for e in self._entries] | |
| tmp_path = self._file_path + ".tmp" | |
| try: | |
| with open(tmp_path, "w", encoding="utf-8") as f: | |
| json.dump(data, f, ensure_ascii=False, indent=2) | |
| if os.path.exists(self._file_path): | |
| os.replace(self._file_path, self._file_path + ".bak") | |
| os.replace(tmp_path, self._file_path) | |
| except (OSError, TypeError): | |
| try: | |
| if os.path.exists(tmp_path): | |
| os.remove(tmp_path) | |
| except OSError: | |
| pass | |
| def _load(self): | |
| # Try primary, then .bak (recovers from an interrupted write), then reset. | |
| for path in (self._file_path, self._file_path + ".bak"): | |
| if not os.path.exists(path): | |
| continue | |
| try: | |
| with open(path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| self._entries = [HistoryEntry.from_dict(d) for d in data[:self._max_entries]] | |
| return | |
| except (json.JSONDecodeError, UnicodeDecodeError, ValueError, OSError): | |
| continue | |
| self._entries = [] | |
| def __len__(self) -> int: | |
| return len(self._entries) | |
| _history = SessionHistory() | |
| def get_history() -> SessionHistory: | |
| return _history | |
| def add_to_history(prompt: str, results: list[str], **kwargs) -> str: | |
| entry = HistoryEntry(prompt, results, **kwargs) | |
| return _history.add(entry) | |