Spaces:
Running on Zero
Running on Zero
File size: 6,477 Bytes
b701455 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | """LightDiffusion Settings persistence and history store.
This module provides a small JSON-backed settings store used for:
- persisting the last used seed (previously include/last_seed.txt)
- maintaining a short history of saved generation settings (for UI)
- storing server-wide generation preferences that should survive restarts
Design notes:
- Store file defaults to './include/settings_store.json'. Override via
environment variable LD_SETTINGS_STORE_PATH for tests or custom locations.
- migrate_from_last_seed_txt() will import the legacy include/last_seed.txt
if present and then remove the legacy file.
- Reads/writes are atomic (write to temp file then replace).
This is intentionally lightweight (no DB dependency) and robust to failure.
"""
from __future__ import annotations
import json
import os
import time
import tempfile
import uuid
from typing import Any, Dict, List, Optional
def _default_preferences() -> Dict[str, bool]:
return {
"torch_compile": False,
"vae_autotune": False,
}
def _default_store() -> Dict[str, Any]:
return {
"last_seed": None,
"history": [],
"preferences": _default_preferences(),
}
def _get_store_path() -> str:
env = os.environ.get("LD_SETTINGS_STORE_PATH")
if env:
return env
return os.path.join(os.getcwd(), "include", "settings_store.json")
def _read_store() -> Dict[str, Any]:
path = _get_store_path()
try:
if not os.path.exists(path):
return _default_store()
with open(path, "r", encoding="utf-8") as f:
raw = json.load(f)
if not isinstance(raw, dict):
return _default_store()
data = _default_store()
data.update(raw)
history = raw.get("history")
data["history"] = history if isinstance(history, list) else []
seed = raw.get("last_seed")
data["last_seed"] = int(seed) if seed is not None else None
raw_preferences = raw.get("preferences")
if not isinstance(raw_preferences, dict):
raw_preferences = {}
data["preferences"] = {
"torch_compile": bool(raw_preferences.get("torch_compile", False)),
"vae_autotune": bool(raw_preferences.get("vae_autotune", False)),
}
return data
except Exception:
# Corrupt/invalid file -> return sane default (do not raise)
return _default_store()
def _write_store(data: Dict[str, Any]) -> None:
path = _get_store_path()
ddir = os.path.dirname(path)
os.makedirs(ddir, exist_ok=True)
# atomic write
fd, tmp = tempfile.mkstemp(prefix="settings_store_", dir=ddir)
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
os.replace(tmp, path)
finally:
try:
if os.path.exists(tmp):
os.remove(tmp)
except Exception:
pass
# Public API ---------------------------------------------------------------
def get_last_seed() -> Optional[int]:
"""Return the persisted last-seed or None if not set."""
data = _read_store()
seed = data.get("last_seed")
return int(seed) if seed is not None else None
def get_preferences() -> Dict[str, bool]:
"""Return persisted server-wide generation preferences."""
data = _read_store()
prefs = data.get("preferences") or {}
defaults = _default_preferences()
return {
"torch_compile": bool(prefs.get("torch_compile", defaults["torch_compile"])),
"vae_autotune": bool(prefs.get("vae_autotune", defaults["vae_autotune"])),
}
def set_preferences(preferences: Dict[str, Any]) -> Dict[str, bool]:
"""Persist server-wide generation preferences and return the stored values."""
try:
stored = {
"torch_compile": bool(preferences.get("torch_compile", False)),
"vae_autotune": bool(preferences.get("vae_autotune", False)),
}
d = _read_store()
d["preferences"] = stored
_write_store(d)
return stored
except Exception:
return get_preferences()
def set_last_seed(seed: int) -> None:
"""Persist the provided seed (int).
Also ensures the store file exists and retains existing history.
"""
try:
d = _read_store()
d["last_seed"] = int(seed)
_write_store(d)
except Exception:
# Best-effort only; never raise for caller convenience
pass
def get_history() -> List[Dict[str, Any]]:
"""Return the settings history (most-recent-first)."""
data = _read_store()
hist = data.get("history") or []
# Ensure sensible return type
return list(reversed(hist)) if hist else []
def append_snapshot(snapshot: Dict[str, Any], max_len: int = 64) -> Dict[str, Any]:
"""Append a snapshot to the history and return the stored entry.
The incoming `snapshot` should be a dict (typically containing a
`settings` key). We enrich it with `id` and `ts` fields.
"""
try:
d = _read_store()
hist = d.get("history") or []
entry = {
"id": uuid.uuid4().hex[:12],
"ts": int(time.time()),
**snapshot,
}
# Store newest at the end for compact append logic
hist.append(entry)
# Trim oldest if exceeding max_len
if len(hist) > max_len:
hist = hist[-max_len:]
d["history"] = hist
_write_store(d)
return entry
except Exception:
return {"id": uuid.uuid4().hex[:12], "ts": int(time.time()), **snapshot}
def migrate_from_last_seed_txt() -> Optional[int]:
"""Migrate legacy `include/last_seed.txt` into the JSON store.
Migration target directory is derived from the store path so tests can
override the store location with LD_SETTINGS_STORE_PATH and provide a
corresponding legacy file next to it.
"""
store_path = _get_store_path()
basedir = os.path.dirname(store_path)
legacy = os.path.join(basedir, "last_seed.txt")
if not os.path.exists(legacy):
return None
try:
with open(legacy, "r", encoding="utf-8") as f:
raw = f.read().strip()
if not raw:
return None
seed = int(raw)
set_last_seed(seed)
try:
os.remove(legacy)
except Exception:
pass
return seed
except Exception:
return None
|