apply_enrich_output.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/usr/bin/env python3
  2. """
  3. Merge web-UI LLM output (NDJSON) back into categories.json.
  4. The LLM outputs one JSON object per line:
  5. {"id": 51, "description": "...", "examples": ["...", "..."]}
  6. This script applies only the missing fields — already-populated fields are untouched.
  7. Usage:
  8. python -m bom_assistant.suppliers.lcsc.apply_enrich_output < enrich_output.ndjson
  9. # or
  10. python -m bom_assistant.suppliers.lcsc.apply_enrich_output enrich_output.ndjson
  11. """
  12. from __future__ import annotations
  13. import json
  14. import sys
  15. from pathlib import Path
  16. _CATS_PATH = Path(__file__).parent / "categories.json"
  17. def main() -> None:
  18. if len(sys.argv) > 1:
  19. lines = Path(sys.argv[1]).read_text(encoding="utf-8").splitlines()
  20. else:
  21. lines = sys.stdin.read().splitlines()
  22. cats = json.loads(_CATS_PATH.read_text(encoding="utf-8"))
  23. # build id → (cat_idx, sub_idx) index
  24. idx: dict[int, tuple[int, int]] = {}
  25. for ci, cat in enumerate(cats):
  26. for si, sub in enumerate(cat["subcategories"]):
  27. idx[sub["id"]] = (ci, si)
  28. applied = 0
  29. skipped = 0
  30. for line in lines:
  31. line = line.strip()
  32. if not line:
  33. continue
  34. try:
  35. entry = json.loads(line)
  36. except json.JSONDecodeError:
  37. print(f"warn: bad JSON line: {line[:80]!r}", file=sys.stderr)
  38. skipped += 1
  39. continue
  40. sub_id = entry.get("id")
  41. if sub_id not in idx:
  42. print(f"warn: unknown id {sub_id}", file=sys.stderr)
  43. skipped += 1
  44. continue
  45. ci, si = idx[sub_id]
  46. sub = cats[ci]["subcategories"][si]
  47. changed = False
  48. if entry.get("description") and not sub.get("description"):
  49. sub["description"] = entry["description"]
  50. changed = True
  51. if entry.get("examples") and not sub.get("examples"):
  52. sub["examples"] = entry["examples"]
  53. changed = True
  54. if changed:
  55. applied += 1
  56. _CATS_PATH.write_text(
  57. json.dumps(cats, indent=2, ensure_ascii=False), encoding="utf-8"
  58. )
  59. total = sum(len(c["subcategories"]) for c in cats)
  60. with_desc = sum(1 for c in cats for s in c["subcategories"] if s.get("description"))
  61. with_ex = sum(1 for c in cats for s in c["subcategories"] if s.get("examples"))
  62. print(f"Applied {applied} updates ({skipped} skipped). Saved categories.json.")
  63. print(f"Coverage: {with_desc}/{total} descriptions, {with_ex}/{total} examples")
  64. if __name__ == "__main__":
  65. main()