Spaces:
Sleeping
Sleeping
| """ | |
| Data models for cross-reference extraction. | |
| All dataclasses are pure Python (no Neo4j dependency) so they can be | |
| used/tested independently by any team member without a running DB. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| from enum import Enum | |
| from typing import Optional | |
| # --------------------------------------------------------------------------- | |
| # Enums | |
| # --------------------------------------------------------------------------- | |
| class RefType(str, Enum): | |
| """Top-level classification of a reference.""" | |
| INTERNAL = "INTERNAL" # same document, different Điều/Khoản/Điểm | |
| EXTERNAL = "EXTERNAL" # cross-document reference | |
| MODIFICATION = "MODIFICATION" # sửa đổi / bổ sung / bãi bỏ link | |
| class ModAction(str, Enum): | |
| """The legal action performed by a modifying document.""" | |
| SUA_DOI = "sua_doi" # sửa đổi — replace content | |
| BO_SUNG = "bo_sung" # bổ sung — insert new content | |
| THAY_THE = "thay_the" # thay thế — replace a segment | |
| BAI_BO = "bai_bo" # bãi bỏ — void/remove | |
| HET_HIEU_LUC = "het_hieu_luc" # hết hiệu lực một phần | |
| class DocType(str, Enum): | |
| """Loại văn bản supported by the system.""" | |
| LUAT = "Luật" | |
| BO_LUAT = "Bộ luật" | |
| NGHI_DINH = "Nghị định" | |
| THONG_TU = "Thông tư" | |
| TTLT = "Thông tư liên tịch" | |
| QUYET_DINH = "Quyết định" # out-of-scope but kept for logging | |
| UNKNOWN = "unknown" | |
| # --------------------------------------------------------------------------- | |
| # Reference dataclasses (plain data, no DB coupling) | |
| # --------------------------------------------------------------------------- | |
| class InternalRef: | |
| """ | |
| A reference from one structural element to another within the same document. | |
| Produced by: T2.1 — extract_internal_references() | |
| Written to Neo4j as: [:REFERENCES_INTERNAL] | |
| """ | |
| source_doc_id: str # Document node id | |
| source_article_uid: str # Article.uid of the citing element | |
| source_clause_uid: Optional[str] = None # Clause.uid if reference is inside a clause | |
| source_point_uid: Optional[str] = None # Point.uid if reference is inside a point | |
| # Target within the same document | |
| target_article_index: int = 0 # Điều number (integer) | |
| target_clause_index: Optional[int] = None # Khoản number | |
| target_point_label: Optional[str] = None # Điểm letter, e.g. "a", "b" | |
| # Resolved node UIDs (filled in after lookup; None = unresolved) | |
| target_article_uid: Optional[str] = None | |
| target_clause_uid: Optional[str] = None | |
| target_point_uid: Optional[str] = None | |
| context_text: str = "" # original phrase where the reference was found | |
| confidence: float = 1.0 # 1.0 = exact regex match, <1.0 = fuzzy/ambiguous | |
| start_char: int = 0 # Start position in the original fragment | |
| end_char: int = 0 # End position in the original fragment | |
| is_exception: bool = False # Phase 2: Đánh dấu quan hệ ngoại trừ | |
| class ExternalRef: | |
| """ | |
| A reference from a provision in one document to a provision in another. | |
| Produced by: T2.2 — extract_external_references() | |
| Written to Neo4j as: [:REFERENCES_EXTERNAL] | |
| """ | |
| source_doc_id: str | |
| source_article_uid: str | |
| source_clause_uid: Optional[str] = None | |
| source_point_uid: Optional[str] = None | |
| # Raw parsed fields (before lookup) | |
| raw_so_ky_hieu: str = "" # e.g. "46/2014/NĐ-CP" | |
| normalized_so_ky_hieu: str = "" # e.g. "ND-046-2014" | |
| target_doc_type: DocType = DocType.UNKNOWN | |
| target_article_index: Optional[int] = None | |
| target_clause_index: Optional[int] = None | |
| target_point_label: Optional[str] = None | |
| # Resolved IDs (filled in after lookup) | |
| target_doc_id: Optional[str] = None | |
| target_article_uid: Optional[str] = None | |
| target_clause_uid: Optional[str] = None | |
| target_point_uid: Optional[str] = None | |
| context_text: str = "" | |
| match_method: str = "exact" # "exact" | "fuzzy_levenshtein" | "fuzzy_substring" | |
| confidence: float = 1.0 | |
| start_char: int = 0 | |
| end_char: int = 0 | |
| is_exception: bool = False # Phase 2: Đánh dấu nếu là quan hệ ngoại trừ (trừ trường hợp...) | |
| class ModificationRef: | |
| """ | |
| An article-level modification link produced from a "sửa đổi/bổ sung" document. | |
| Produced by: T2.3 — extract_modification_references() | |
| Written to Neo4j as: [:MODIFIES] | |
| """ | |
| # The modifying document | |
| source_doc_id: str | |
| source_article_uid: str # Article in the modifying doc that contains the action | |
| source_clause_index: Optional[str] = None # Clause number in the source document | |
| # The action | |
| action: ModAction = ModAction.SUA_DOI | |
| # The target (resolved) | |
| raw_target_so_ky_hieu: str = "" | |
| target_doc_id: Optional[str] = None | |
| target_article_index: Optional[int] = None | |
| target_clause_index: Optional[int] = None | |
| target_point_label: Optional[str] = None | |
| target_doc_uid: Optional[str] = None | |
| target_article_uid: Optional[str] = None | |
| target_clause_uid: Optional[str] = None | |
| target_point_uid: Optional[str] = None | |
| new_text: Optional[str] = None # replacement/inserted text (for sửa đổi/bổ sung) | |
| context_text: str = "" | |
| confidence: float = 1.0 | |
| start_char: int = 0 | |
| end_char: int = 0 | |
| # T2.3 improvement: flag to indicate this ref needs target_doc_id/article from context | |
| is_partial_ref: bool = False | |
| # --------------------------------------------------------------------------- | |
| # Aggregate result container | |
| # --------------------------------------------------------------------------- | |
| class ExtractionResult: | |
| """ | |
| Returned by CrossReferenceExtractor for a single document. | |
| All lists contain only successfully *parsed* references | |
| (resolution happens in a separate step). | |
| """ | |
| doc_id: str | |
| internal_refs: list[InternalRef] = field(default_factory=list) | |
| external_refs: list[ExternalRef] = field(default_factory=list) | |
| modification_refs: list[ModificationRef] = field(default_factory=list) | |
| # Counts for monitoring | |
| parse_errors: list[str] = field(default_factory=list) # human-readable error strings | |
| def total(self) -> int: | |
| return len(self.internal_refs) + len(self.external_refs) + len(self.modification_refs) | |