#!/usr/bin/env python3 """modutech_v30.json → modutech_v30_1.json — แพตช์ก่อน launch prototype เท่านั้น แก้แค่สองอย่าง ไม่ใช่ v31 1. เติม specifications.notes ของ 8 รุ่นที่ว่างเปล่าใน v30 ทั้งที่เล่มพิมพ์หมายเหตุไว้ครบ ดึงจาก PDF ตรง ๆ ตัดคำนำหน้า "- " ออกอย่างเดียว ไม่เรียบเรียงใหม่ ทำไมต้องเติม: catalogue_increment_status() อ่าน specifications.notes เท่านั้น ถ้า notes ว่าง gate จะตรวจค่า "เพิ่มทีละ" ของรุ่นนั้นไม่ได้เลย 2. ตั้ง temperature_trust = "unconfirmed" ให้ variant md254-rr--pph-pph ตัวเดียว พร้อมข้อความเตือนใน temperature_unconfirmed_th บอทยังตอบ 93 °C (ค่าที่เข้มกว่า) แต่แนบคำเตือนไปด้วย แทนที่จะตอบเหมือนเป็นค่ายืนยันแล้ว ไม่แตะ: ค่าตัวเลขทุกตัว · width_effective · temperature_effective · answering · จำนวนนับ รัน: python patch_v30_1.py modutech_v30.json [modutech_v30_1.json] """ from __future__ import annotations import copy import hashlib import json import re import sys # ── สิ่งที่ตั้งใจจะแก้ ประกาศไว้ล่วงหน้าเพื่อให้ shadow copy ตรวจได้ ── NOTES_PAGES = { "SM127 C": 75, "HC127 C": 67, "EC254 GT": 133, "MD254 FG-RT": 157, "MD254 GT": 163, "MD254 RR": 165, "XP254 C": 113, "XP254 PR22%": 117, } UNCONFIRMED_VARIANT = "md254-rr--pph-pph" UNCONFIRMED_TH = ( "ค่าสูงสุด 93 °C ยังไม่ยืนยัน — แคตตาล็อกหน้า 165 พิมพ์ +5/+93 °C คู่กับ +40/+230 °F " "ซึ่ง 230 °F เท่ากับ 110 °C ไม่ใช่ 93 °C และ 93 °C เป็นค่าเดียวกับเกรด POM ที่พิมพ์อยู่สามแถวเหนือขึ้นไป " "ในเล่มเดียวกันเกรด PPH ของรุ่น HC508 PR22 ระบุ 110 °C และ HP508 RR (ผิว Raised Rib เหมือนกัน) ระบุ 118 °C " "ระบบเลือกใช้ค่าที่เข้มกว่าคือ 93 °C ไว้ก่อน ถ้างานจริงต้องเกิน 93 °C ต้องยืนยันกับฝ่ายเทคนิคก่อนเสนอ" ) def fingerprint(obj) -> str: return hashlib.sha256( json.dumps(obj, ensure_ascii=False, sort_keys=True, default=str).encode() ).hexdigest() def notes_from_page(doc, page: int) -> list[str]: """บรรทัดใต้หัวข้อ Important Notes ที่ขึ้นต้นด้วย '-' ติดกัน หยุดที่บรรทัดแรกที่ไม่ขึ้นต้นด้วย '-'""" lines = doc[page - 1].get_text().split("\n") try: i = next(k for k, l in enumerate(lines) if l.strip() == "Important Notes") except StopIteration: raise SystemExit(f"หน้า {page}: ไม่พบหัวข้อ Important Notes — หยุด ไม่เดา") out = [] for l in lines[i + 1:]: s = l.strip() if not s: continue if not s.startswith("-"): break out.append(s.lstrip("- ").strip()) if not out: raise SystemExit(f"หน้า {page}: อ่านหมายเหตุไม่ได้สักบรรทัด — หยุด") return out def scrub(doc: dict) -> dict: """ลบเฉพาะฟิลด์ที่ตั้งใจจะแก้ออกจากทั้งสองฝั่ง เพื่อให้ที่เหลือต้องเหมือนกันเป๊ะ""" d = copy.deepcopy(doc) for p in d.get("products", []): if p.get("belt_code") in NOTES_PAGES: p.get("specifications", {}).pop("notes", None) for v in p.get("specifications", {}).get("variants") or []: if v.get("variant_id") == UNCONFIRMED_VARIANT: v.pop("temperature_trust", None) v.pop("temperature_unconfirmed_th", None) return d def main() -> int: if len(sys.argv) < 3: print(__doc__) return 2 src, pdf = sys.argv[1], sys.argv[2] dst = sys.argv[3] if len(sys.argv) > 3 else "modutech_v30_1.json" import pymupdf doc = pymupdf.open(pdf) with open(src, encoding="utf-8") as f: data = json.load(f) shadow = copy.deepcopy(data) # ของดิบไว้เทียบ by_code = {p.get("belt_code"): p for p in data.get("products", [])} print("1) เติม specifications.notes") for code, page in NOTES_PAGES.items(): p = by_code.get(code) if p is None: raise SystemExit(f"ไม่พบรุ่น {code} ในไฟล์ — หยุด") spec = p.setdefault("specifications", {}) if spec.get("page") != page: raise SystemExit(f"{code}: ไฟล์ระบุหน้า {spec.get('page')} แต่สคริปต์ตั้งไว้ {page} — หยุด") if spec.get("notes"): raise SystemExit(f"{code}: notes ไม่ว่าง ({len(spec['notes'])} บรรทัด) — หยุด ไม่ทับของเดิม") notes = notes_from_page(doc, page) spec["notes"] = notes m = re.search(r"(?