Enhance document processing in scrapers
- Updated pediatric multiple sclerosis article reference ID. - Improved document_to_markdown.py to handle differential diagnoses, tables, anatomy, and cases more effectively. - Added logging for cached entries of DDX, Tables, Anatomy, and Cases. - Adjusted file pattern matching to process all JSON files by default. - Fixed document ID extraction logic for various data types.
This commit is contained in:
@@ -15,6 +15,7 @@ Output: a .md file next to the JSON (or in --output-dir) with the same base name
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import fnmatch
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
@@ -679,6 +680,135 @@ def process_file(path: str, out_dir: str, overwrite: bool = False) -> tuple[bool
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
# DDX / Tables / Anatomy / Cases: detect and append to frontmatter and body
|
||||
try:
|
||||
# DDX: only consider cached DDX[docid]; if not present, ddx is treated as not existing
|
||||
ddx_entry = None
|
||||
ddx_html = None
|
||||
ddx_list = None
|
||||
if isinstance(DDX, dict) and docid and docid in DDX:
|
||||
ddx_entry = DDX.get(docid)
|
||||
logger.debug(f"Found DDX entry for docid {docid}: {ddx_entry}")
|
||||
# ddx_entry may be HTML or structured list/dict
|
||||
if isinstance(ddx_entry, dict):
|
||||
ddx_html = ddx_entry.get("ddxHtml")
|
||||
ddx_list = ddx_entry.get("ddx") or ddx_entry.get("differentialDiagnoses") or ddx_entry.get("differentials")
|
||||
else:
|
||||
# could be list or simple string
|
||||
ddx_list = ddx_entry
|
||||
else:
|
||||
logger.debug(f"No cached DDX entry for docid {docid}")
|
||||
logger.debug(f"DDX keys available: {list(DDX.keys())}")
|
||||
|
||||
logger.debug(f"DDX entry for docid {docid}: {ddx_entry}")
|
||||
if ddx_html and isinstance(ddx_html, str) and ddx_html.strip():
|
||||
try:
|
||||
ddx_md = html_to_markdown(ddx_html)
|
||||
md = md.rstrip() + "\n\n" + "## Differential diagnosis\n\n" + ddx_md + "\n"
|
||||
front_lines.append(f"ddx: {json.dumps(True)}")
|
||||
except Exception:
|
||||
logger.debug("Failed to convert ddxHtml for %s", out_path)
|
||||
elif ddx_list:
|
||||
# render list representation
|
||||
try:
|
||||
front_lines.append(f"ddx: {json.dumps(True)}")
|
||||
md = md.rstrip() + "\n\n" + "## Differential diagnosis\n\n"
|
||||
if isinstance(ddx_list, list):
|
||||
for item in ddx_list:
|
||||
md += "- " + str(item).strip() + "\n"
|
||||
else:
|
||||
md += str(ddx_list).strip() + "\n"
|
||||
md += "\n"
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Tables: only consider cached TABLES[docid]
|
||||
tables_entry = None
|
||||
tables_html = None
|
||||
tables_list = None
|
||||
if isinstance(TABLES, dict) and docid and docid in TABLES:
|
||||
tables_entry = TABLES.get(docid)
|
||||
if isinstance(tables_entry, dict):
|
||||
tables_html = tables_entry.get("tableHtml")
|
||||
tables_list = tables_entry.get("tables")
|
||||
else:
|
||||
tables_list = tables_entry
|
||||
if tables_html and isinstance(tables_html, str) and tables_html.strip():
|
||||
try:
|
||||
tbl_md = html_to_markdown(tables_html)
|
||||
md = md.rstrip() + "\n\n" + "## Tables\n\n" + tbl_md + "\n"
|
||||
front_lines.append(f"tables: {json.dumps(True)}")
|
||||
except Exception:
|
||||
logger.debug("Failed to convert tableHtml for %s", out_path)
|
||||
elif tables_list:
|
||||
try:
|
||||
front_lines.append(f"tables: {json.dumps(len(tables_list) if isinstance(tables_list, list) else True)}")
|
||||
md = md.rstrip() + "\n\n" + "## Tables\n\n"
|
||||
if isinstance(tables_list, list):
|
||||
for t in tables_list:
|
||||
if isinstance(t, str) and "<" in t:
|
||||
md += html_to_markdown(t) + "\n"
|
||||
else:
|
||||
md += str(t) + "\n\n"
|
||||
else:
|
||||
md += str(tables_list) + "\n"
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Anatomy: only consider cached ANATOMY[docid]
|
||||
anatomy_entry = None
|
||||
anatomy_data = None
|
||||
if isinstance(ANATOMY, dict) and docid and docid in ANATOMY:
|
||||
anatomy_entry = ANATOMY.get(docid)
|
||||
anatomy_data = anatomy_entry
|
||||
if anatomy_data:
|
||||
try:
|
||||
if isinstance(anatomy_data, list):
|
||||
front_lines.append('anatomy:')
|
||||
for a in anatomy_data:
|
||||
front_lines.append(f" - {json.dumps(str(a))}")
|
||||
md = md.rstrip() + "\n\n" + "## Anatomy\n\n"
|
||||
for a in anatomy_data:
|
||||
md += "- " + str(a).strip() + "\n"
|
||||
md += "\n"
|
||||
else:
|
||||
front_lines.append(f"anatomy: {json.dumps(str(anatomy_data))}")
|
||||
md = md.rstrip() + "\n\n" + "## Anatomy\n\n" + str(anatomy_data).strip() + "\n"
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Cases / caseStudies: only consider cached CASES[docid]
|
||||
cases_entry = None
|
||||
cases_data = None
|
||||
if isinstance(CASES, dict) and docid and docid in CASES:
|
||||
cases_entry = CASES.get(docid)
|
||||
cases_data = cases_entry
|
||||
if cases_data:
|
||||
try:
|
||||
front_lines.append(f"cases: {json.dumps(len(cases_data) if isinstance(cases_data, list) else True)}")
|
||||
md = md.rstrip() + "\n\n" + "## Cases\n\n"
|
||||
if isinstance(cases_data, list):
|
||||
for c in cases_data:
|
||||
if isinstance(c, str) and "<" in c:
|
||||
md += html_to_markdown(c) + "\n"
|
||||
else:
|
||||
md += "- " + str(c).strip() + "\n"
|
||||
md += "\n"
|
||||
else:
|
||||
md += str(cases_data).strip() + "\n"
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
# collect breadcrumbs and render as YAML list if present
|
||||
crumbs = []
|
||||
if docid:
|
||||
@@ -990,7 +1120,7 @@ def main(argv: Iterable[str] | None = None) -> int:
|
||||
help="Where to write .md files (defaults to input-dir) ",
|
||||
)
|
||||
p.add_argument(
|
||||
"--pattern", default="*.json", help="Glob pattern to find files in input dir"
|
||||
"--pattern", default="*", help="Glob pattern to limit files processed"
|
||||
)
|
||||
p.add_argument(
|
||||
"--overwrite", action="store_true", help="Overwrite existing .md files"
|
||||
@@ -1014,9 +1144,9 @@ def main(argv: Iterable[str] | None = None) -> int:
|
||||
# remove all .md files in output_dir
|
||||
shutil.rmtree(output_dir, ignore_errors=True)
|
||||
|
||||
files = sorted(glob.glob(os.path.join(input_dir, args.pattern)))
|
||||
files = sorted(glob.glob(os.path.join(input_dir, "*.json")))
|
||||
if not files:
|
||||
print(f"No files found in {input_dir} matching {args.pattern}")
|
||||
print(f"No files found in {input_dir} matching *.json")
|
||||
return 1
|
||||
|
||||
# Start by caching image group metadata
|
||||
@@ -1065,7 +1195,7 @@ def main(argv: Iterable[str] | None = None) -> int:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
ddx_data = json.load(f)
|
||||
|
||||
doc_id = base.split("_ddx_")[1].split("_")[0]
|
||||
doc_id = base.split("_document_")[1].split("_")[0]
|
||||
|
||||
DDX[doc_id] = (
|
||||
ddx_data # logger.debug(f"Document summary {n}: {pformat(doc)}")
|
||||
@@ -1074,7 +1204,7 @@ def main(argv: Iterable[str] | None = None) -> int:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
tables_data = json.load(f)
|
||||
|
||||
doc_id = base.split("_tables_")[1].split("_")[0]
|
||||
doc_id = base.split("_document_")[1].split("_")[0]
|
||||
|
||||
TABLES[doc_id] = (
|
||||
tables_data # logger.debug(f"Document summary {n}: {pformat(doc)}")
|
||||
@@ -1083,7 +1213,7 @@ def main(argv: Iterable[str] | None = None) -> int:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
anatomy_data = json.load(f)
|
||||
|
||||
doc_id = base.split("_anatomy_")[1].split("_")[0]
|
||||
doc_id = base.split("_document_")[1].split("_")[0]
|
||||
|
||||
ANATOMY[doc_id] = (
|
||||
anatomy_data # logger.debug(f"Document summary {n}: {pformat(doc)}")
|
||||
@@ -1092,7 +1222,7 @@ def main(argv: Iterable[str] | None = None) -> int:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
cases_data = json.load(f)
|
||||
|
||||
doc_id = base.split("_cases_")[1].split("_")[0]
|
||||
doc_id = base.split("_document_")[1].split("_")[0]
|
||||
|
||||
CASES[doc_id] = (
|
||||
cases_data # logger.debug(f"Document summary {n}: {pformat(doc)}")
|
||||
@@ -1102,10 +1232,19 @@ def main(argv: Iterable[str] | None = None) -> int:
|
||||
logger.debug(
|
||||
f"Cached {len(DOCUMENT_SUMMARYS)} document summaries from summary files."
|
||||
)
|
||||
logger.debug(f"Cached {len(DDX)} DDX entries from ddx files.")
|
||||
logger.debug(f"Cached {len(TABLES)} Tables entries from tables files.")
|
||||
logger.debug(f"Cached {len(ANATOMY)} Anatomy entries from anatomy files.")
|
||||
logger.debug(f"Cached {len(CASES)} Cases entries from cases files.")
|
||||
|
||||
ok = 0
|
||||
for path in files:
|
||||
base = os.path.basename(path)
|
||||
|
||||
if args.pattern and not fnmatch.fnmatch(base, args.pattern):
|
||||
# if args.verbose:
|
||||
# print(f"SKIP (pattern mismatch): {path}")
|
||||
continue
|
||||
# only process files that match the desired prefix
|
||||
if (
|
||||
not base.startswith("app.statdx.com_document_")
|
||||
|
||||
Reference in New Issue
Block a user