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}"
|
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():
|
def load_cache():
|
||||||
try:
|
try:
|
||||||
return json.loads(CACHE_FILE.read_text())
|
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"
|
page = pages / f"{lamp_id}.md"
|
||||||
if page.exists():
|
if page.exists():
|
||||||
return
|
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]
|
for m in [re.search(r"^weight:\s*(\d+)", f.read_text(), re.M)] if m]
|
||||||
title = meta["model"] or lamp_id
|
title = meta["model"] or lamp_id
|
||||||
if meta["variant"]:
|
if meta["variant"]:
|
||||||
title = f"{title} ({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", {})
|
rated = meta.get("rated", {})
|
||||||
specs = [("ID", lamp_id)]
|
specs = []
|
||||||
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"]))
|
|
||||||
if "Power_W" in rated:
|
if "Power_W" in rated:
|
||||||
power = f"{rated['Power_W']:g} W"
|
power = f"{rated['Power_W']:g} W"
|
||||||
if "W_equiv" in rated:
|
if "W_equiv" in rated:
|
||||||
@@ -221,7 +242,8 @@ def scaffold_device_page(web_repo, lamp_id, meta):
|
|||||||
lines += [
|
lines += [
|
||||||
f'description: "Household {type_word} lamp, measured in our integrating sphere."',
|
f'description: "Household {type_word} lamp, measured in our integrating sphere."',
|
||||||
f'csv: "/data/comparisons/lamps/{lamp_id}/spd.csv"',
|
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' - {{ label: "{k}", value: "{v}" }}' for k, v in specs],
|
||||||
f"weight: {max(weights, default=0) + 1}",
|
f"weight: {max(weights, default=0) + 1}",
|
||||||
"---",
|
"---",
|
||||||
@@ -269,7 +291,11 @@ def measure_one(ean, args, data_repo):
|
|||||||
else:
|
else:
|
||||||
manufacturer = model = ""
|
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)
|
model = prompt("Model", model)
|
||||||
lamp_type = prompt("Type (led / halogen / cfl / incandescent / ...)",
|
lamp_type = prompt("Type (led / halogen / cfl / incandescent / ...)",
|
||||||
previous.get("type", "led")).lower().strip()
|
previous.get("type", "led")).lower().strip()
|
||||||
|
|||||||
Reference in New Issue
Block a user