64 lines
2.2 KiB
Python
64 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Extract the Stackchain Magazine photo catalog into a normalized table (CSV + JSON).
|
|
|
|
Source: /root/stackchain_catalog.md (the 'vee-supply-2026-09-21' magazine transcription)
|
|
Read the whole file here; the result is evidence, not a claim.
|
|
"""
|
|
import csv
|
|
import json
|
|
import os
|
|
import re
|
|
|
|
SRC = "/root/stackchain_catalog.md"
|
|
OUT_DIR = "/root/.hermes/wizard-outputs/ledger"
|
|
OS = os.path.join(OUT_DIR, "stackchain_catalog.csv")
|
|
JS = os.path.join(OUT_DIR, "stackchain_catalog.json")
|
|
|
|
with open(SRC,encoding="utf-8") as f:
|
|
raw = f.read()
|
|
|
|
# Split into entry blocks on '## N. <filename> — <section>' headers.
|
|
entry_re = re.compile(r"^## (\d+)\. (\S+\.\S+) — (.+)$", re.M)
|
|
parts = entry_re.split(raw)
|
|
# parts: [head, num, fname, title, body, num, fname, title, body, ...]
|
|
entries = []
|
|
for i in range(1, len(parts), 4):
|
|
num = parts[i]
|
|
fname = parts[i+1]
|
|
title = parts[i+2]
|
|
body = parts[i+3]
|
|
# Type
|
|
m = re.search(r"^\s*-\s*\*\*Type:\*\*\s*(.*)$", body, re.M)
|
|
typ = m.group(1).strip() if m else ""
|
|
# Text: capture the first fenced code block (the exact transcription)
|
|
tm = re.search(r"```(.*?)```", body, re.S)
|
|
text_block = tm.group(1) if tm else ""
|
|
text_lines = [ln.strip() for ln in text_block.splitlines() if ln.strip()]
|
|
text_preview = (text_lines[0][:160] + ("…" if len(text_lines[0]) > 160 else "")) if text_lines else ""
|
|
# Identifiers (remainder of the Identifiers line)
|
|
im = re.search(r"^\s*-\s*\*\*Identifiers:\*\*\s*(.*)$", body, re.M)
|
|
ident = im.group(1).strip() if im else ""
|
|
entries.append({
|
|
"id": int(num),
|
|
"filename": fname,
|
|
"section": title.strip(),
|
|
"type": typ,
|
|
"text_preview": text_preview,
|
|
"identifiers": ident,
|
|
})
|
|
|
|
os.makedirs(OUT_DIR, exist_ok=True)
|
|
|
|
with open(OS, "w", newline="", encoding="utf-8") as f:
|
|
w = csv.DictWriter(f, fieldnames=["id","filename","section","type","text_preview","identifiers"])
|
|
w.writeheader()
|
|
for e in entries:
|
|
w.writerow(e)
|
|
|
|
with open(JS, "w", encoding="utf-8") as f:
|
|
json.dump(entries, f, indent=2, ensure_ascii=False)
|
|
|
|
print("entries:", len(entries))
|
|
for e in entries:
|
|
print(f"{e['id']:>2} | {e['filename']:<24} | {e['section']:<28} | {e['type']:<28} | {e['text_preview'][:60]!r}")
|