RICS / backend /core /section_bridge.py
StormShadow308's picture
Add demo documentation and Docker setup for v2 report generation system
aad7814
Raw
History Blame Contribute Delete
2.48 kB
"""Bridge report-template section IDs to standard-paragraph section IDs.
When the PDF report template and Word standard-paragraphs file share the same
canonical RICS L3 codes (D1, D2, …), aliases are identity mappings. Title overlap
is used only when Word paragraph buckets use legacy alternate codes.
"""
from __future__ import annotations
import re
from pathlib import Path
from backend.core.template_discoverer import (
DiscoveredChunk,
discover_standard_paragraph_chunks,
discover_standard_paragraph_titles,
)
from backend.models.schema import SectionDefinition
_STOP_WORDS = frozenset({
"about", "with", "from", "this", "that", "level", "section", "inside",
"outside", "other", "property", "report", "survey", "your", "the", "and",
})
def _title_tokens(title: str) -> set[str]:
return {
w for w in re.findall(r"[a-z]{4,}", (title or "").lower())
if w not in _STOP_WORDS
}
def _score_titles(report_title: str, paragraph_title: str) -> int:
a, b = _title_tokens(report_title), _title_tokens(paragraph_title)
if not a or not b:
return 0
return len(a & b)
def build_section_alias_map(
report_sections: list[SectionDefinition],
paragraph_titles: dict[str, str],
) -> dict[str, str]:
"""Map each report-template section id to a standard-paragraph section id.
Strategy (in order):
1. Exact id match when the Word file has the same code.
2. Best title-token overlap (minimum 2 shared significant words).
3. Fallback: report id maps to itself (retrieval uses title+notes only).
"""
aliases: dict[str, str] = {}
for sec in report_sections:
if sec.id in paragraph_titles:
aliases[sec.id] = sec.id
continue
best_id: str | None = None
best_score = 0
for pid, ptitle in paragraph_titles.items():
score = _score_titles(sec.title, ptitle)
if score > best_score:
best_score = score
best_id = pid
if best_id and best_score >= 2:
aliases[sec.id] = best_id
else:
aliases[sec.id] = sec.id
return aliases
def paragraph_titles_from_word(path: Path) -> dict[str, str]:
"""Return ``{section_id: title}`` from the standard-paragraphs Word file."""
return discover_standard_paragraph_titles(path)
def paragraph_chunks_from_word(path: Path) -> list[DiscoveredChunk]:
return discover_standard_paragraph_chunks(path)