You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
52 lines
1.9 KiB
52 lines
1.9 KiB
#!/usr/bin/env python3
|
|
"""Phase 4 Step 3: Match generated audio blobs back to generation plan via filename.
|
|
|
|
Usage: python3 scripts/match_blobs.py <chapter_number>
|
|
|
|
Reads generation_plan.json + assets.json, matches blobs by filename (last-write-wins),
|
|
and updates generation_plan.json with blob_path.
|
|
"""
|
|
import json, os, sys
|
|
from pathlib import Path
|
|
|
|
PROJECT_DIR = Path(os.getcwd())
|
|
AUDIOBOOK_ROOT = PROJECT_DIR / ".audiobook"
|
|
BOOK_DIR = next(d for d in sorted(AUDIOBOOK_ROOT.iterdir()) if d.is_dir() and (d / ".audiobook-state.json").exists())
|
|
|
|
CHAPTER_N = int(sys.argv[1]) if len(sys.argv) > 1 else 1
|
|
|
|
assets_path = PROJECT_DIR / ".hilo/assets.json"
|
|
plan_path = BOOK_DIR / f"audio/chapter_{CHAPTER_N}/generation_plan.json"
|
|
|
|
assets = json.loads(assets_path.read_text())
|
|
plan = json.loads(plan_path.read_text())
|
|
|
|
# Build lookup: filename (without extension) -> asset entry
|
|
# Iterate forward so later entries (retries) overwrite earlier ones
|
|
name_to_asset = {}
|
|
for a in assets:
|
|
if a.get("type") == "audio" and a.get("name"):
|
|
name_key = a["name"].rsplit(".", 1)[0] # strip .mp3
|
|
name_to_asset[name_key] = a
|
|
|
|
matched = 0
|
|
for entry in plan:
|
|
if entry.get("blob_path"):
|
|
matched += 1
|
|
continue
|
|
asset = name_to_asset.get(entry["filename"])
|
|
if asset and asset.get("blobRef"):
|
|
entry["blob_path"] = str(PROJECT_DIR / ".hilo/.blobs" / asset["blobRef"])
|
|
matched += 1
|
|
|
|
with open(plan_path, 'w', encoding='utf-8') as f:
|
|
json.dump(plan, f, ensure_ascii=False, indent=2)
|
|
|
|
unmatched = [e for e in plan if not e.get("blob_path")]
|
|
print(f"Matched: {matched}/{len(plan)}")
|
|
if unmatched:
|
|
print(f"WARNING: {len(unmatched)} segments not matched -- run Failure & Retry")
|
|
for e in unmatched[:5]:
|
|
print(f" [{e['index']}] filename={e['filename']}, voice={e['voice_id']}")
|
|
else:
|
|
print("All segments matched successfully! Proceed to Step 3.5.")
|
|
|