feat: add patent content minimization for LLM consumption

Implemented minimize_patent_for_llm() function that reduces patent
content by keeping only essential sections (abstract, claims, summary)
and explicitly excludes the verbose detailed description section.

This reduces token usage while preserving core innovation details
needed for company performance estimation.

Added comprehensive test coverage (5 new tests) for:
- Essential section inclusion
- Description section exclusion
- Missing section handling
- Empty section handling
- Section separator formatting

All 13 tests passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-02-19 18:54:07 -05:00
parent 6533cef56f
commit 26a23c02ae
2 changed files with 121 additions and 5 deletions
+47 -5
View File
@@ -45,18 +45,28 @@ class SERP:
return patent
def parse_patent_pdf(pdf_path: str) -> Dict:
"""Extract structured sections from patent PDF"""
"""Extract structured sections from patent PDF.
Extracts all major sections from a patent PDF including abstract,
claims, summary, and detailed description.
Args:
pdf_path: Path to the patent PDF file
Returns:
Dictionary containing all extracted sections
"""
with pdfplumber.open(pdf_path) as pdf:
# Extract all text
full_text = ""
for page in pdf.pages:
full_text += page.extract_text() + "\n"
# Define section patterns (common in patents)
sections = {
'abstract': SERP.extract_section(
full_text,
full_text,
start_patterns=[r'ABSTRACT', r'Abstract of the Disclosure'],
end_patterns=[r'BACKGROUND', r'FIELD OF', r'BRIEF DESCRIPTION']
),
@@ -76,9 +86,41 @@ class SERP:
end_patterns=[r'What is claimed', r'CLAIMS?:', r'I claim:']
)
}
return sections
def minimize_patent_for_llm(sections: Dict) -> str:
"""Minimize patent content for LLM consumption.
Removes bloated sections (detailed description) and keeps only
essential information: abstract, claims, and summary. This reduces
token usage while preserving the core innovation details.
Args:
sections: Dictionary of parsed patent sections from parse_patent_pdf()
Returns:
Concatenated string of essential patent sections ready for LLM analysis
"""
essential_parts = []
# Abstract: Concise overview of the invention
if sections.get('abstract'):
essential_parts.append("ABSTRACT:\n" + sections['abstract'])
# Claims: The actual legal claims defining the invention (most important)
if sections.get('claims'):
essential_parts.append("CLAIMS:\n" + sections['claims'])
# Summary: High-level description of the invention
if sections.get('summary'):
essential_parts.append("SUMMARY:\n" + sections['summary'])
# Explicitly exclude 'description' - it's too verbose and contains
# implementation details not needed for high-level analysis
return "\n\n".join(essential_parts)
def extract_section(text: str, start_patterns: list, end_patterns: list) -> str:
"""Extract text between start and end patterns"""