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:
+38
-12
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user