|
b2df90e…
|
leo
|
1 |
"""Standardized output directory structure and manifest I/O for PlanOpticon.""" |
|
b2df90e…
|
leo
|
2 |
|
|
b2df90e…
|
leo
|
3 |
import logging |
|
b2df90e…
|
leo
|
4 |
from pathlib import Path |
|
b2df90e…
|
leo
|
5 |
from typing import Dict |
|
b2df90e…
|
leo
|
6 |
|
|
b2df90e…
|
leo
|
7 |
from video_processor.models import BatchManifest, VideoManifest |
|
b2df90e…
|
leo
|
8 |
|
|
b2df90e…
|
leo
|
9 |
logger = logging.getLogger(__name__) |
|
b2df90e…
|
leo
|
10 |
|
|
b2df90e…
|
leo
|
11 |
|
|
b2df90e…
|
leo
|
12 |
def create_video_output_dirs(output_dir: str | Path, video_name: str) -> Dict[str, Path]: |
|
b2df90e…
|
leo
|
13 |
""" |
|
b2df90e…
|
leo
|
14 |
Create standardized single-video output directory structure. |
|
b2df90e…
|
leo
|
15 |
|
|
b2df90e…
|
leo
|
16 |
Layout: |
|
b2df90e…
|
leo
|
17 |
output_dir/ |
|
b2df90e…
|
leo
|
18 |
manifest.json |
|
b2df90e…
|
leo
|
19 |
transcript/ |
|
b2df90e…
|
leo
|
20 |
transcript.json, .txt, .srt |
|
b2df90e…
|
leo
|
21 |
frames/ |
|
b2df90e…
|
leo
|
22 |
frame_0000.jpg ... |
|
b2df90e…
|
leo
|
23 |
diagrams/ |
|
b2df90e…
|
leo
|
24 |
diagram_0.json, .jpg, .mermaid, .svg, .png |
|
b2df90e…
|
leo
|
25 |
captures/ |
|
b2df90e…
|
leo
|
26 |
capture_0.jpg, capture_0.json |
|
b2df90e…
|
leo
|
27 |
results/ |
|
b2df90e…
|
leo
|
28 |
analysis.md, .html, .pdf |
|
0981a08…
|
noreply
|
29 |
knowledge_graph.db (primary, SQLite) |
|
0981a08…
|
noreply
|
30 |
knowledge_graph.json (export copy) |
|
b2df90e…
|
leo
|
31 |
key_points.json |
|
b2df90e…
|
leo
|
32 |
action_items.json |
|
b2df90e…
|
leo
|
33 |
cache/ |
|
b2df90e…
|
leo
|
34 |
|
|
b2df90e…
|
leo
|
35 |
Returns dict mapping directory names to Path objects. |
|
b2df90e…
|
leo
|
36 |
""" |
|
b2df90e…
|
leo
|
37 |
base = Path(output_dir) |
|
b2df90e…
|
leo
|
38 |
dirs = { |
|
b2df90e…
|
leo
|
39 |
"root": base, |
|
b2df90e…
|
leo
|
40 |
"transcript": base / "transcript", |
|
b2df90e…
|
leo
|
41 |
"frames": base / "frames", |
|
b2df90e…
|
leo
|
42 |
"diagrams": base / "diagrams", |
|
b2df90e…
|
leo
|
43 |
"captures": base / "captures", |
|
b2df90e…
|
leo
|
44 |
"results": base / "results", |
|
b2df90e…
|
leo
|
45 |
"cache": base / "cache", |
|
b2df90e…
|
leo
|
46 |
} |
|
b2df90e…
|
leo
|
47 |
for d in dirs.values(): |
|
b2df90e…
|
leo
|
48 |
d.mkdir(parents=True, exist_ok=True) |
|
b2df90e…
|
leo
|
49 |
logger.info(f"Created output structure for '{video_name}' at {base}") |
|
b2df90e…
|
leo
|
50 |
return dirs |
|
b2df90e…
|
leo
|
51 |
|
|
b2df90e…
|
leo
|
52 |
|
|
b2df90e…
|
leo
|
53 |
def create_batch_output_dirs(output_dir: str | Path, batch_name: str) -> Dict[str, Path]: |
|
b2df90e…
|
leo
|
54 |
""" |
|
b2df90e…
|
leo
|
55 |
Create standardized batch output directory structure. |
|
b2df90e…
|
leo
|
56 |
|
|
b2df90e…
|
leo
|
57 |
Layout: |
|
b2df90e…
|
leo
|
58 |
output_dir/ |
|
b2df90e…
|
leo
|
59 |
manifest.json |
|
b2df90e…
|
leo
|
60 |
batch_summary.md |
|
0981a08…
|
noreply
|
61 |
knowledge_graph.db (primary, SQLite) |
|
0981a08…
|
noreply
|
62 |
knowledge_graph.json (export copy) (when falkordblite installed) |
|
b2df90e…
|
leo
|
63 |
videos/ |
|
b2df90e…
|
leo
|
64 |
video_1/manifest.json |
|
b2df90e…
|
leo
|
65 |
video_2/manifest.json |
|
b2df90e…
|
leo
|
66 |
... |
|
b2df90e…
|
leo
|
67 |
|
|
b2df90e…
|
leo
|
68 |
Returns dict mapping directory names to Path objects. |
|
b2df90e…
|
leo
|
69 |
""" |
|
b2df90e…
|
leo
|
70 |
base = Path(output_dir) |
|
b2df90e…
|
leo
|
71 |
dirs = { |
|
b2df90e…
|
leo
|
72 |
"root": base, |
|
b2df90e…
|
leo
|
73 |
"videos": base / "videos", |
|
b2df90e…
|
leo
|
74 |
} |
|
b2df90e…
|
leo
|
75 |
for d in dirs.values(): |
|
b2df90e…
|
leo
|
76 |
d.mkdir(parents=True, exist_ok=True) |
|
b2df90e…
|
leo
|
77 |
logger.info(f"Created batch output structure for '{batch_name}' at {base}") |
|
b2df90e…
|
leo
|
78 |
return dirs |
|
b2df90e…
|
leo
|
79 |
|
|
b2df90e…
|
leo
|
80 |
|
|
b2df90e…
|
leo
|
81 |
# --- Manifest I/O --- |
|
b2df90e…
|
leo
|
82 |
|
|
b2df90e…
|
leo
|
83 |
|
|
b2df90e…
|
leo
|
84 |
def write_video_manifest(manifest: VideoManifest, output_dir: str | Path) -> Path: |
|
b2df90e…
|
leo
|
85 |
"""Write a VideoManifest to output_dir/manifest.json.""" |
|
b2df90e…
|
leo
|
86 |
path = Path(output_dir) / "manifest.json" |
|
b2df90e…
|
leo
|
87 |
path.parent.mkdir(parents=True, exist_ok=True) |
|
b2df90e…
|
leo
|
88 |
path.write_text(manifest.model_dump_json(indent=2)) |
|
b2df90e…
|
leo
|
89 |
logger.info(f"Wrote video manifest to {path}") |
|
b2df90e…
|
leo
|
90 |
return path |
|
b2df90e…
|
leo
|
91 |
|
|
b2df90e…
|
leo
|
92 |
|
|
b2df90e…
|
leo
|
93 |
def read_video_manifest(output_dir: str | Path) -> VideoManifest: |
|
b2df90e…
|
leo
|
94 |
"""Read a VideoManifest from output_dir/manifest.json.""" |
|
b2df90e…
|
leo
|
95 |
path = Path(output_dir) / "manifest.json" |
|
b2df90e…
|
leo
|
96 |
return VideoManifest.model_validate_json(path.read_text()) |
|
b2df90e…
|
leo
|
97 |
|
|
b2df90e…
|
leo
|
98 |
|
|
b2df90e…
|
leo
|
99 |
def write_batch_manifest(manifest: BatchManifest, output_dir: str | Path) -> Path: |
|
b2df90e…
|
leo
|
100 |
"""Write a BatchManifest to output_dir/manifest.json.""" |
|
b2df90e…
|
leo
|
101 |
path = Path(output_dir) / "manifest.json" |
|
b2df90e…
|
leo
|
102 |
path.parent.mkdir(parents=True, exist_ok=True) |
|
b2df90e…
|
leo
|
103 |
path.write_text(manifest.model_dump_json(indent=2)) |
|
b2df90e…
|
leo
|
104 |
logger.info(f"Wrote batch manifest to {path}") |
|
b2df90e…
|
leo
|
105 |
return path |
|
b2df90e…
|
leo
|
106 |
|
|
b2df90e…
|
leo
|
107 |
|
|
b2df90e…
|
leo
|
108 |
def read_batch_manifest(output_dir: str | Path) -> BatchManifest: |
|
b2df90e…
|
leo
|
109 |
"""Read a BatchManifest from output_dir/manifest.json.""" |
|
b2df90e…
|
leo
|
110 |
path = Path(output_dir) / "manifest.json" |
|
b2df90e…
|
leo
|
111 |
return BatchManifest.model_validate_json(path.read_text()) |