refactor: remove fps from annotation — path + label only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -101,12 +101,10 @@ def build_annotation_json_path(folder: str) -> str:
|
||||
return os.path.join(folder, "dataset.json")
|
||||
|
||||
|
||||
def upsert_clip_annotation(
|
||||
folder: str, clip_path: str, label: str, fps: float | None
|
||||
) -> None:
|
||||
def upsert_clip_annotation(folder: str, clip_path: str, label: str) -> None:
|
||||
"""Insert or update one entry in <folder>/dataset.json.
|
||||
|
||||
Each entry stores a path relative to *folder*, the sound label, and fps.
|
||||
Each entry stores a path relative to *folder* and the sound label.
|
||||
Matches on ``path``; if an entry for the same clip already exists it is
|
||||
replaced (overwrite-export case). Nothing is written when *label* is
|
||||
empty.
|
||||
@@ -124,8 +122,6 @@ def upsert_clip_annotation(
|
||||
entries = []
|
||||
rel_path = os.path.relpath(clip_path, folder)
|
||||
entry: dict = {"path": rel_path, "label": label}
|
||||
if fps is not None:
|
||||
entry["fps"] = fps
|
||||
for i, e in enumerate(entries):
|
||||
if e.get("path") == rel_path:
|
||||
entries[i] = entry
|
||||
@@ -1591,7 +1587,7 @@ class MainWindow(QMainWindow):
|
||||
category=category,
|
||||
)
|
||||
folder = self._txt_folder.text()
|
||||
upsert_clip_annotation(folder, path, label, self._fps)
|
||||
upsert_clip_annotation(folder, path, label)
|
||||
# For MP4 exports path is a file; for WebP sequence it is a directory.
|
||||
# build_mask_output_dir handles both correctly via Path.stem.
|
||||
self._last_export_path = path
|
||||
|
||||
+7
-16
@@ -240,18 +240,17 @@ def test_annotation_json_path():
|
||||
def test_upsert_creates_file():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
clip = os.path.join(d, "clip_001.mp4")
|
||||
upsert_clip_annotation(d, clip, "dog barking", 25.0)
|
||||
upsert_clip_annotation(d, clip, "dog barking")
|
||||
with open(os.path.join(d, "dataset.json")) as f:
|
||||
entries = json.load(f)
|
||||
assert len(entries) == 1
|
||||
assert entries[0]["label"] == "dog barking"
|
||||
assert entries[0]["fps"] == 25.0
|
||||
assert entries[0]["path"] == "clip_001.mp4"
|
||||
|
||||
def test_upsert_appends_new_clips():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
upsert_clip_annotation(d, os.path.join(d, "clip_001.mp4"), "dog barking", 25.0)
|
||||
upsert_clip_annotation(d, os.path.join(d, "clip_002.mp4"), "cat meowing", 30.0)
|
||||
upsert_clip_annotation(d, os.path.join(d, "clip_001.mp4"), "dog barking")
|
||||
upsert_clip_annotation(d, os.path.join(d, "clip_002.mp4"), "cat meowing")
|
||||
with open(os.path.join(d, "dataset.json")) as f:
|
||||
entries = json.load(f)
|
||||
assert len(entries) == 2
|
||||
@@ -259,8 +258,8 @@ def test_upsert_appends_new_clips():
|
||||
def test_upsert_replaces_existing():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
clip = os.path.join(d, "clip_001.mp4")
|
||||
upsert_clip_annotation(d, clip, "dog barking", 25.0)
|
||||
upsert_clip_annotation(d, clip, "cat meowing", 25.0)
|
||||
upsert_clip_annotation(d, clip, "dog barking")
|
||||
upsert_clip_annotation(d, clip, "cat meowing")
|
||||
with open(os.path.join(d, "dataset.json")) as f:
|
||||
entries = json.load(f)
|
||||
assert len(entries) == 1
|
||||
@@ -268,21 +267,13 @@ def test_upsert_replaces_existing():
|
||||
|
||||
def test_upsert_empty_label_skips():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
upsert_clip_annotation(d, os.path.join(d, "clip_001.mp4"), "", 25.0)
|
||||
upsert_clip_annotation(d, os.path.join(d, "clip_001.mp4"), "")
|
||||
assert not os.path.exists(os.path.join(d, "dataset.json"))
|
||||
|
||||
def test_upsert_no_fps():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
clip = os.path.join(d, "clip_001.mp4")
|
||||
upsert_clip_annotation(d, clip, "dog barking", None)
|
||||
with open(os.path.join(d, "dataset.json")) as f:
|
||||
entries = json.load(f)
|
||||
assert "fps" not in entries[0]
|
||||
|
||||
def test_upsert_missing_folder_creates_it():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
nested = os.path.join(d, "subdir", "deep")
|
||||
upsert_clip_annotation(nested, os.path.join(nested, "clip_001.mp4"), "dog barking", 25.0)
|
||||
upsert_clip_annotation(nested, os.path.join(nested, "clip_001.mp4"), "dog barking")
|
||||
assert os.path.exists(os.path.join(nested, "dataset.json"))
|
||||
|
||||
def test_db_stores_label_and_category():
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
"""One-shot migration: generate dataset.json files from ~/.8cut.db history.
|
||||
|
||||
For each export folder that has records in the database, writes (or merges
|
||||
into) a dataset.json with path (relative to the folder), label, and fps when
|
||||
a <clip>.fps.txt sidecar exists alongside the WAV file.
|
||||
into) a dataset.json with path (relative to the folder) and label per clip.
|
||||
|
||||
Usage:
|
||||
python tools/migrate_dataset_json.py [--dry-run]
|
||||
@@ -29,30 +28,11 @@ def load_db_records(db_path: Path) -> list[dict]:
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
def read_fps_sidecar(output_path: str) -> float | None:
|
||||
"""Read fps from <output_path>.fps.txt if it exists."""
|
||||
sidecar = output_path + ".fps.txt"
|
||||
if os.path.exists(sidecar):
|
||||
try:
|
||||
return float(Path(sidecar).read_text().strip())
|
||||
except ValueError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def build_entries_for_folder(
|
||||
folder: str, records: list[dict]
|
||||
) -> list[dict]:
|
||||
entries = []
|
||||
for rec in records:
|
||||
output_path = rec["output_path"]
|
||||
rel = os.path.relpath(output_path, folder)
|
||||
entry: dict = {"path": rel, "label": rec["label"]}
|
||||
fps = read_fps_sidecar(output_path)
|
||||
if fps is not None:
|
||||
entry["fps"] = fps
|
||||
entries.append(entry)
|
||||
return entries
|
||||
def build_entries_for_folder(folder: str, records: list[dict]) -> list[dict]:
|
||||
return [
|
||||
{"path": os.path.relpath(rec["output_path"], folder), "label": rec["label"]}
|
||||
for rec in records
|
||||
]
|
||||
|
||||
|
||||
def merge_into_json(json_path: str, new_entries: list[dict], dry_run: bool) -> int:
|
||||
|
||||
Reference in New Issue
Block a user