import json
from pathlib import Path
from datetime import datetime, timezone
from typing import Any, Optional
from core.utils.config import output_files_dir, settings
def new_run_id(prefix: str = "run") -> str:
ts = datetime.now(timezone.utc).astimezone().strftime("%Y%m%d_%H%M%S")
return f"{ts}_{prefix}"
def ensure_dir(path: str | Path) -> str:
p = Path(path)
p.mkdir(parents=True, exist_ok=True)
return str(p)
def run_dir(run_id: str) -> str:
"""Return the cache directory for a given run_id, creating it if necessary.
Uses the configured ``output_files_dir`` (settings.OUTPUT_DIR or the
default ``<app_base_dir>/output``) as the root.
"""
return ensure_dir(Path(output_files_dir) / run_id)
def get_run_id(config: dict | None) -> str:
if not config:
return ""
cfg = config.get("configurable") if isinstance(config, dict) else None
if isinstance(cfg, dict):
rid = cfg.get("run_id")
return rid or ""
return ""
def _cache_enabled() -> bool:
return settings.USE_CACHE
def run_dir_from_config(config: dict | None, base_dir: str = "") -> str:
"""Resolve the cache directory for the run_id carried in ``config``.
``base_dir`` is accepted for backward compatibility with callers that
imported the previous signature but no longer affects resolution — the
output root is governed by ``settings.OUTPUT_DIR`` / ``output_files_dir``.
"""
if not _cache_enabled():
return ""
rid = get_run_id(config)
if not rid:
return ""
return run_dir(rid)
def save_json(path: str | Path, data: Any) -> None:
p = Path(path)
ensure_dir(p.parent)
with open(p, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def load_json(path: str | Path) -> Optional[Any]:
p = Path(path)
if not p.exists():
return None
with open(p, "r", encoding="utf-8") as f:
return json.load(f)
def save_text(path: str | Path, text: str) -> None:
p = Path(path)
ensure_dir(p.parent)
with open(p, "w", encoding="utf-8") as f:
f.write(text)
def load_text(path: str | Path) -> Optional[str]:
p = Path(path)
if not p.exists():
return None
return p.read_text(encoding="utf-8")