""" Manage per-document output folders and their sidecar files. Parallels meetus/output_manager.py but for the document contract: docs-output// content.md textified document — the product meta.json structured metadata thumb.jpg optional single preview image assets/ optional embedded images / per-page text (later) manifest.json run config + outputs inventory + source pointer """ from pathlib import Path from datetime import datetime import json import logging from typing import Dict, Any, Optional from .naming import resolve_run_dir logger = logging.getLogger(__name__) class DocOutputManager: """Create and populate a run folder for one source document.""" def __init__(self, source_path: Path, base_output_dir: str = "docs-output", use_cache: bool = True): self.source_path = Path(source_path) self.base_output_dir = Path(base_output_dir) self.use_cache = use_cache self.output_dir = resolve_run_dir(self.base_output_dir, self.source_path.stem, use_cache) logger.info("Output directory: %s", self.output_dir) def get_path(self, filename: str) -> Path: return self.output_dir / filename def write_content(self, markdown: str) -> Path: path = self.output_dir / "content.md" path.write_text(markdown, encoding="utf-8") return path def write_meta(self, meta: Dict[str, Any]) -> Path: path = self.output_dir / "meta.json" with open(path, "w", encoding="utf-8") as f: json.dump(meta, f, indent=2, ensure_ascii=False) return path def write_thumb(self, jpeg_bytes: bytes) -> Path: path = self.output_dir / "thumb.jpg" path.write_bytes(jpeg_bytes) return path def assets_dir(self) -> Path: d = self.output_dir / "assets" d.mkdir(exist_ok=True) return d def save_manifest(self, config: Dict[str, Any], outputs: Dict[str, Any], source_sha256: str) -> Path: manifest_path = self.output_dir / "manifest.json" manifest = { "source": { "name": self.source_path.name, "path": str(self.source_path.absolute()), "sha256": source_sha256, }, "processed_at": datetime.now().isoformat(), "configuration": config, "outputs": outputs, } with open(manifest_path, "w", encoding="utf-8") as f: json.dump(manifest, f, indent=2, ensure_ascii=False) logger.info("Saved manifest: %s", manifest_path) return manifest_path def load_manifest(self) -> Optional[Dict[str, Any]]: manifest_path = self.output_dir / "manifest.json" if manifest_path.exists(): with open(manifest_path, "r", encoding="utf-8") as f: return json.load(f) return None