import sys, os, json, re import fitz # PyMuPDF sys.stdout.reconfigure(encoding='utf-8') pdf_path = "resources/knowledge/original/원가계산/건설공사_표준품셈/2026년_건설공사_표준품셈.pdf" doc = fitz.open(pdf_path) # MD file mapping for chapters md_map = { "공통_제1장": "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제1장_적용기준.md", "공통_제3장": "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제3장_토공사.md", "공통_제4장": "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제4장_조경공사.md", "공통_제6장": "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제6장_철근콘크리트공사.md", "토목_제1장": "resources/knowledge/original/원가계산/건설공사_표준품셈/02_토목부문/제1장_도로포장공사.md", "토목_제6장": "resources/knowledge/original/원가계산/건설공사_표준품셈/02_토목부문/제6장_관부설및접합공사.md", "건축_제9장": "resources/knowledge/original/원가계산/건설공사_표준품셈/03_건축부문/제9장_미장공사.md", "유지관리_제1장": "resources/knowledge/original/원가계산/건설공사_표준품셈/05_유지관리부문/제1장_공통.md", "유지관리_제3장": "resources/knowledge/original/원가계산/건설공사_표준품셈/05_유지관리부문/제3장_건축.md", } # Read MD contents into memory md_contents = {} for k, p in md_map.items(): if os.path.exists(p): with open(p, 'r', encoding='utf-8') as f: md_contents[k] = f.read() else: print(f"MD missing: {p}") with open('scratch/located_const_sections.json', 'r', encoding='utf-8') as f: located_items = json.load(f) print(f"Loaded located items: {len(located_items)}") results = [] for item in located_items: k = item['key'] num = item['number'] name = item['name'] pn = item['path_name'] pdf_pages = item.get('pdf_pages', []) # Exclude chapter 8 (already audited by codex) if "공통부문 › 건설기계" in pn: continue print(f"\n==================================================") print(f"Auditing: {k} | {num} {name} | {pn}") print(f"PDF Pages: {pdf_pages}") # Determine MD chapter md_key = None if "공통부문 › 적용기준" in pn: md_key = "공통_제1장" elif "공통부문 › 토공사" in pn: md_key = "공통_제3장" elif "공통부문 › 조경공사" in pn: md_key = "공통_제4장" elif "공통부문 › 철근콘크리트공사" in pn: md_key = "공통_제6장" elif "토목부문 › 도로포장공사" in pn: md_key = "토목_제1장" elif "토목부문 › 관부설" in pn: md_key = "토목_제6장" elif "건축부문 › 미장공사" in pn: md_key = "건축_제9장" elif "유지관리부문 › 공 통" in pn: md_key = "유지관리_제1장" elif "유지관리부문 › 건 축" in pn: md_key = "유지관리_제3장" md_text = md_contents.get(md_key, "") # Extract MD section chunk # Usually in MD, sections start with "### 1-2-2" or "## 1-2-2" or "1-2-2." escaped_num = re.escape(num) sec_pattern = re.compile(rf"(^|\n)(#+\s+{escaped_num}[\.\s].*?)(?=\n#+\s+\d+-\d+-\d+[\.\s]|\Z)", re.DOTALL) m = sec_pattern.search(md_text) if not m: # try without leading hash sec_pattern2 = re.compile(rf"(^|\n)({escaped_num}[\.\s].*?)(?=\n\d+-\d+-\d+[\.\s]|\Z)", re.DOTALL) m = sec_pattern2.search(md_text) md_sec_text = m.group(2) if m else "" if not md_sec_text: print(f"⚠ Warning: Could not isolate section in MD: {num}") else: print(f"MD Section found (len={len(md_sec_text)} chars)") # Extract PDF page text pdf_text = "" # Use the relevant page (typically the 2nd match if first was toc/index, or the page > 50) actual_pages = [p for p in pdf_pages if p > 50] for p in actual_pages: pdf_text += f"\n--- PDF Page {p} ---\n" + doc[p - 1].get_text() # Check 8 branches audit = { "work_item_key": k, "section_number": num, "section_name": name, "path_name": pn, "md_file": md_map.get(md_key), "pdf_pages": actual_pages, "branch1_basis_unit": {"status": "ok", "notes": []}, "branch2_multilevel_header": {"status": "ok", "notes": []}, "branch3_notes_boundary": {"status": "ok", "notes": []}, "branch4_page_break_row_merge": {"status": "ok", "notes": []}, "branch5_cell_values": {"status": "ok", "notes": []}, "branch6_missing_sections": {"status": "ok", "notes": []}, "branch7_notes_formula_boundary": {"status": "ok", "notes": []}, "branch8_hidden_materials_ref": {"status": "ok", "notes": []} } # 1. Check if section exists in MD if not md_sec_text: audit["branch6_missing_sections"]["status"] = "missing_in_md" audit["branch6_missing_sections"]["notes"].append(f"Section {num} not found in MD {md_key}") else: # Check notes [주] pdf_notes = re.findall(r"\[주\]|\[\s*주\s*\]|[①-⑩]", pdf_text) md_notes = re.findall(r"\[주\]|\[\s*주\s*\]|[①-⑩]", md_sec_text) if len(pdf_notes) > 0 and len(md_notes) == 0: audit["branch3_notes_boundary"]["status"] = "suspicious_notes_missing" audit["branch3_notes_boundary"]["notes"].append(f"PDF has {len(pdf_notes)} note markers, MD has 0") # Check units in PDF vs MD units_in_pdf = re.findall(r"\((?:단위\s*:\s*)?([^\)]+당|[^\)]+)\)", pdf_text) # Check table presence if "|" in pdf_text and "|" not in md_sec_text: audit["branch4_page_break_row_merge"]["status"] = "table_flattened_to_text" audit["branch4_page_break_row_merge"]["notes"].append("Table in PDF not rendered as markdown table") results.append(audit) with open('scratch/audit_const_linked_results.json', 'w', encoding='utf-8') as f: json.dump(results, f, ensure_ascii=False, indent=2) print(f"\nAudit completed for {len(results)} linked non-machine sections.")