Legora / db /parsers /consitution /schedule_parser.py
sai-Rohan's picture
combined results of all parsers and made a single pipeline
dbabef2
Raw
History Blame Contribute Delete
6.44 kB
from __future__ import annotations
import re
from typing import List, Dict
from db.parsers.consitution.legal_models import (
Schedule,
ScheduleParagraph
)
class ScheduleParser:
"""
Constitution Schedule Parser
Supports:
FIRST SCHEDULE
SECOND SCHEDULE
THIRD SCHEDULE
...
TWELFTH SCHEDULE
"""
# =====================================================
# SCHEDULE DETECTOR
# =====================================================
SCHEDULE_RE = re.compile(
r"""
^
(
FIRST
|SECOND
|THIRD
|FOURTH
|FIFTH
|SIXTH
|SEVENTH
|EIGHTH
|NINTH
|TENTH
|ELEVENTH
|TWELFTH
)
\s+
SCHEDULE
\s*$
""",
re.IGNORECASE
| re.MULTILINE
| re.VERBOSE
)
# =====================================================
# PARAGRAPHS
# =====================================================
PARAGRAPH_RE = re.compile(
r"(?m)^\s*(\d+)\.\s"
)
# =====================================================
# CLEAN
# =====================================================
def clean_text(
self,
text: str
) -> str:
text = text.strip()
text = re.sub(
r"\s+",
" ",
text
)
return text
# =====================================================
# EXTRACT TITLE
# =====================================================
def extract_schedule_title(
self,
schedule_text: str
) -> str:
lines = [
line.strip()
for line in schedule_text.split(
"\n"
)
if line.strip()
]
if len(lines) < 2:
return ""
title_lines = []
for line in lines[1:8]:
if re.match(
r"^\d+\.",
line
):
break
title_lines.append(
line
)
return self.clean_text(
" ".join(title_lines)
)
# =====================================================
# PARAGRAPHS
# =====================================================
def parse_paragraphs(
self,
schedule_text: str
) -> List[ScheduleParagraph]:
paragraphs = []
matches = list(
self.PARAGRAPH_RE.finditer(
schedule_text
)
)
if not matches:
return paragraphs
for i, match in enumerate(
matches
):
start = match.start()
end = (
matches[i + 1].start()
if i + 1 < len(matches)
else len(schedule_text)
)
para_no = match.group(1)
para_text = (
schedule_text[start:end]
.strip()
)
paragraphs.append(
ScheduleParagraph(
document="constitution",
paragraph_no=para_no,
text=para_text
)
)
return paragraphs
# =====================================================
# EXTRACT SCHEDULES
# =====================================================
def extract_schedules(
self,
text: str
) -> List[Schedule]:
matches = list(
self.SCHEDULE_RE.finditer(
text
)
)
schedules = []
if not matches:
return schedules
for i, match in enumerate(
matches
):
start = match.start()
end = (
matches[i + 1].start()
if i + 1 < len(matches)
else len(text)
)
schedule_no = (
match.group(1)
.upper()
)
schedule_text = (
text[start:end]
.strip()
)
schedule_title = (
self.extract_schedule_title(
schedule_text
)
)
schedule = Schedule(
document="constitution",
schedule_no=schedule_no,
schedule_title=schedule_title,
text=schedule_text
)
schedule.paragraphs.extend(
self.parse_paragraphs(
schedule_text
)
)
schedules.append(
schedule
)
return schedules
# =====================================================
# VALIDATION
# =====================================================
def validate_schedules(
self,
schedules: List[Schedule]
) -> List[str]:
errors = []
seen = set()
for schedule in schedules:
if schedule.schedule_no in seen:
errors.append(
f"Duplicate Schedule "
f"{schedule.schedule_no}"
)
seen.add(
schedule.schedule_no
)
if not schedule.schedule_title:
errors.append(
f"Missing Title "
f"for Schedule "
f"{schedule.schedule_no}"
)
return errors
# =========================================================
# EXAMPLE
# =========================================================
if __name__ == "__main__":
sample = """
FIRST SCHEDULE
THE STATES
1. Andhra Pradesh
2. Telangana
3. Karnataka
SECOND SCHEDULE
SALARIES
1. President
2. Governors
"""
parser = ScheduleParser()
schedules = (
parser.extract_schedules(
sample
)
)
print(
f"Schedules Found: "
f"{len(schedules)}"
)
for sch in schedules:
print()
print(
sch.schedule_no
)
print(
sch.schedule_title
)
print(
len(
sch.paragraphs
)
)
print(
parser.validate_schedules(
schedules
)
)