81 lines
2.9 KiB
Python
81 lines
2.9 KiB
Python
"""
|
|
Manage per-document output folders and their sidecar files.
|
|
|
|
Parallels meetus/output_manager.py but for the document contract:
|
|
|
|
docs-output/<YYYYMMDD-NNN-stem>/
|
|
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
|