|
@@ -23,6 +23,8 @@ Author: auto-generated via Claude Code (2026-07-28)
|
|
|
"""
|
|
"""
|
|
|
from __future__ import annotations
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
+import hashlib
|
|
|
|
|
+
|
|
|
import json
|
|
import json
|
|
|
import os
|
|
import os
|
|
|
import re
|
|
import re
|
|
@@ -81,13 +83,10 @@ find_docx_files = docx_ingest.find_docx_files
|
|
|
# ---------------------------------------------------------------------------
|
|
# ---------------------------------------------------------------------------
|
|
|
IMG_TAG_RE = re.compile(r'<img\s+src="([^"]+)"[^>]*/?>', re.IGNORECASE)
|
|
IMG_TAG_RE = re.compile(r'<img\s+src="([^"]+)"[^>]*/?>', re.IGNORECASE)
|
|
|
|
|
|
|
|
-# Characters that need sanitising for filesystem-safe drug names
|
|
|
|
|
-_RE_UNSAFE = re.compile(r'[\s()() /\\:?*"<>|]+')
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
-def _safe_drug_name(name: str) -> str:
|
|
|
|
|
- """Return a filesystem-safe version of *name* (used as image filename prefix)."""
|
|
|
|
|
- return _RE_UNSAFE.sub("_", name).strip("_")
|
|
|
|
|
|
|
+def _hash_prefix(name: str) -> str:
|
|
|
|
|
+ """Return 8-char MD5 hex for *name* (used as image filename prefix / fallback match)."""
|
|
|
|
|
+ return hashlib.md5(name.encode()).hexdigest()[:8]
|
|
|
|
|
|
|
|
|
|
|
|
|
def _collect_images_from_sections(
|
|
def _collect_images_from_sections(
|
|
@@ -107,20 +106,20 @@ def _collect_images_from_sections(
|
|
|
|
|
|
|
|
|
|
|
|
|
def _find_orphan_images(
|
|
def _find_orphan_images(
|
|
|
- safe_name: str,
|
|
|
|
|
|
|
+ name_hash: str,
|
|
|
images_dir: str,
|
|
images_dir: str,
|
|
|
already_found: set[str],
|
|
already_found: set[str],
|
|
|
) -> list[dict[str, str]]:
|
|
) -> list[dict[str, str]]:
|
|
|
- """Filesystem 兜底:找 <img> 标签中没有覆盖到的图片。
|
|
|
|
|
|
|
+ """Filesystem 兜底:找 <img> 标签中没有覆盖到的图片。
|
|
|
|
|
|
|
|
Some images sit in the same paragraph as text (line 214 of docx_ingest.py
|
|
Some images sit in the same paragraph as text (line 214 of docx_ingest.py
|
|
|
has the ``if not p_text`` guard), so the inline parser does not emit an
|
|
has the ``if not p_text`` guard), so the inline parser does not emit an
|
|
|
- ``<img>`` tag for them. We catch those here by matching file names.
|
|
|
|
|
|
|
+ ``<img>`` tag for them. We catch those here by matching file names.
|
|
|
"""
|
|
"""
|
|
|
if not os.path.isdir(images_dir):
|
|
if not os.path.isdir(images_dir):
|
|
|
return []
|
|
return []
|
|
|
|
|
|
|
|
- prefix = safe_name + "_"
|
|
|
|
|
|
|
+ prefix = name_hash + "_"
|
|
|
orphans: list[dict[str, str]] = []
|
|
orphans: list[dict[str, str]] = []
|
|
|
try:
|
|
try:
|
|
|
for fname in os.listdir(images_dir):
|
|
for fname in os.listdir(images_dir):
|
|
@@ -216,8 +215,8 @@ def main() -> None:
|
|
|
found_filenames = {r["filename"] for r in section_images}
|
|
found_filenames = {r["filename"] for r in section_images}
|
|
|
|
|
|
|
|
# 4b – filesystem fallback for images that the inline parser missed
|
|
# 4b – filesystem fallback for images that the inline parser missed
|
|
|
- safe = _safe_drug_name(entry["name"])
|
|
|
|
|
- orphans = _find_orphan_images(safe, IMAGES_DIR, found_filenames)
|
|
|
|
|
|
|
+ name_hash = _hash_prefix(entry["name"])
|
|
|
|
|
+ orphans = _find_orphan_images(name_hash, IMAGES_DIR, found_filenames)
|
|
|
section_images.extend(orphans)
|
|
section_images.extend(orphans)
|
|
|
|
|
|
|
|
if not section_images:
|
|
if not section_images:
|