vct / app /store.py
vg15o2's picture
Deploy Vconnect API
2c88096
Raw
History Blame Contribute Delete
5.11 kB
"""
store.py — tiny JSON-backed persistence with a swappable interface.
Why JSON for now: the user asked to "store what's needed when there's a need."
This keeps zero external dependencies. NOTE: a Hugging Face Space's disk is
EPHEMERAL — it resets on rebuild/restart — so this is fine for development and
demos, but for durable data we'll swap this layer for a real DB (Supabase,
Postgres, an HF Dataset, etc.) without touching the rest of the app.
Shape:
{
"domains": [
{"id", "name", "description", "system_prompt",
"projects": [
{"id", "name", "description",
"milestones": [ {milestone row dicts} ]}
]}
],
"hr": {"documents": [{"id", "name", "text", "chunks": [str, ...]}]}
}
"""
import json
import os
import threading
import uuid
DATA_DIR = os.environ.get("DATA_DIR", os.path.join(os.path.dirname(__file__), "..", "data"))
DATA_FILE = os.path.join(DATA_DIR, "store.json")
_lock = threading.Lock()
_state = None
def _new_id() -> str:
return uuid.uuid4().hex[:12]
def _empty_state() -> dict:
return {"domains": [], "hr": {"documents": []}}
def _load() -> dict:
global _state
if _state is not None:
return _state
try:
with open(DATA_FILE, "r", encoding="utf-8") as f:
_state = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
_state = _empty_state()
# forward-compat: ensure keys exist
_state.setdefault("domains", [])
_state.setdefault("hr", {"documents": []})
return _state
def _save() -> None:
os.makedirs(DATA_DIR, exist_ok=True)
tmp = DATA_FILE + ".tmp"
with open(tmp, "w", encoding="utf-8") as f:
json.dump(_state, f, ensure_ascii=False, indent=2)
os.replace(tmp, DATA_FILE)
# ---- domains -----------------------------------------------------------------
def list_domains() -> list:
return _load()["domains"]
def get_domain(domain_id: str):
return next((d for d in _load()["domains"] if d["id"] == domain_id), None)
def add_domain(name: str, description: str = "", system_prompt: str = "") -> dict:
with _lock:
d = {
"id": _new_id(),
"name": name.strip(),
"description": description.strip(),
"system_prompt": system_prompt.strip(),
"projects": [],
}
_load()["domains"].append(d)
_save()
return d
def delete_domain(domain_id: str) -> bool:
with _lock:
st = _load()
before = len(st["domains"])
st["domains"] = [d for d in st["domains"] if d["id"] != domain_id]
changed = len(st["domains"]) != before
if changed:
_save()
return changed
# ---- projects ----------------------------------------------------------------
def get_project(domain_id: str, project_id: str):
d = get_domain(domain_id)
if not d:
return None
return next((p for p in d["projects"] if p["id"] == project_id), None)
def add_project(domain_id: str, name: str, description: str = "") -> dict:
with _lock:
d = get_domain(domain_id)
if not d:
raise KeyError("domain not found")
p = {
"id": _new_id(),
"name": name.strip(),
"description": description.strip(),
"sheet_url": "",
"last_synced": None,
"milestones": [],
}
d["projects"].append(p)
_save()
return p
def delete_project(domain_id: str, project_id: str) -> bool:
with _lock:
d = get_domain(domain_id)
if not d:
return False
before = len(d["projects"])
d["projects"] = [p for p in d["projects"] if p["id"] != project_id]
changed = len(d["projects"]) != before
if changed:
_save()
return changed
def set_project_milestones(domain_id: str, project_id: str, milestones: list) -> dict:
with _lock:
p = get_project(domain_id, project_id)
if not p:
raise KeyError("project not found")
p["milestones"] = milestones
_save()
return p
def update_project(domain_id: str, project_id: str, **fields) -> dict:
with _lock:
p = get_project(domain_id, project_id)
if not p:
raise KeyError("project not found")
p.update(fields)
_save()
return p
# ---- HR documents ------------------------------------------------------------
def list_hr_documents() -> list:
return _load()["hr"]["documents"]
def add_hr_document(name: str, text: str, chunks: list) -> dict:
with _lock:
doc = {"id": _new_id(), "name": name, "text": text, "chunks": chunks}
_load()["hr"]["documents"].append(doc)
_save()
return doc
def delete_hr_document(doc_id: str) -> bool:
with _lock:
docs = _load()["hr"]["documents"]
before = len(docs)
_load()["hr"]["documents"] = [d for d in docs if d["id"] != doc_id]
changed = len(_load()["hr"]["documents"]) != before
if changed:
_save()
return changed