Canonicalize brand names; slim the scaffold to rated specs

Manufacturer input maps to one canonical spelling (seed list plus
whatever the database and cache already use), so Philips is never
philips/PHILIPS. Identity fields no longer duplicate into the device
page specs (the site renders them from metrics.json); the weight scan
ignores index.md so a fresh run starts at weight 1.
This commit is contained in:
2026-07-09 15:38:53 +07:00
parent b62eac37c6
commit 9fdb12b533
+38 -12
View File
@@ -98,6 +98,32 @@ def next_lamp_id(data_repo):
return f"L{max(used, default=0) + 1:04d}"
# Canonical spellings for brands; extended at runtime by whatever is already
# in the database and the cache, so the first accepted spelling of a new brand
# becomes its canonical form for every later scan.
BRAND_SEED = [
"Philips", "OSRAM", "LAMPTAN", "TKL", "ST", "IKEA", "Panasonic",
"Toshiba", "GE", "Sylvania", "Xiaomi", "Opple", "EVE",
]
def canonical_brand(name, lamps):
"""Map a manufacturer string to its canonical capitalization."""
name = " ".join(name.split())
if not name:
return name
brands = {b.lower(): b for b in BRAND_SEED}
for entry in load_cache().values():
b = entry.get("manufacturer", "")
if b:
brands.setdefault(b.lower(), b)
for m in lamps.values():
b = m.get("manufacturer", "")
if b:
brands[b.lower()] = b # the database is the strongest source
return brands.get(name.lower(), name)
def load_cache():
try:
return json.loads(CACHE_FILE.read_text())
@@ -185,21 +211,16 @@ def scaffold_device_page(web_repo, lamp_id, meta):
page = pages / f"{lamp_id}.md"
if page.exists():
return
weights = [int(m.group(1)) for f in pages.glob("*.md")
weights = [int(m.group(1)) for f in pages.glob("*.md") if f.name != "index.md"
for m in [re.search(r"^weight:\s*(\d+)", f.read_text(), re.M)] if m]
title = meta["model"] or lamp_id
if meta["variant"]:
title = f"{title} ({meta['variant']})"
# Identity fields (ID, EAN, type, dimmable, variant) live in metrics.json,
# which the detail page renders directly — only human-editable extras like
# the rated values go into the page's specs front matter.
rated = meta.get("rated", {})
specs = [("ID", lamp_id)]
if meta["ean"]:
specs.append(("EAN", meta["ean"]))
if meta.get("type"):
specs.append(("Type", meta["type"].upper() if meta["type"] in ("led", "cfl") else meta["type"].capitalize()))
if meta.get("dimmable") is not None:
specs.append(("Dimmable", "Yes" if meta["dimmable"] else "No"))
if meta["variant"]:
specs.append(("Variant", meta["variant"]))
specs = []
if "Power_W" in rated:
power = f"{rated['Power_W']:g} W"
if "W_equiv" in rated:
@@ -221,7 +242,8 @@ def scaffold_device_page(web_repo, lamp_id, meta):
lines += [
f'description: "Household {type_word} lamp, measured in our integrating sphere."',
f'csv: "/data/comparisons/lamps/{lamp_id}/spd.csv"',
"specs:",
# a bare "specs:" would parse as YAML null and fail the site's schema
*(["specs:"] if specs else []),
*[f' - {{ label: "{k}", value: "{v}" }}' for k, v in specs],
f"weight: {max(weights, default=0) + 1}",
"---",
@@ -269,7 +291,11 @@ def measure_one(ean, args, data_repo):
else:
manufacturer = model = ""
manufacturer = prompt("Manufacturer", manufacturer)
manufacturer = prompt("Manufacturer", canonical_brand(manufacturer, lamps))
canon = canonical_brand(manufacturer, lamps)
if canon != manufacturer:
print(f" Using canonical brand name: {canon}")
manufacturer = canon
model = prompt("Model", model)
lamp_type = prompt("Type (led / halogen / cfl / incandescent / ...)",
previous.get("type", "led")).lower().strip()