A layout-aware Python parser for extracting legal clauses from a maritime voyage charter party agreement PDF into structured JSON
This project was developed for the Marcura AI Engineer Challenge
The parser processes Part II of the document (pages 6–39) and extracts clauses in order while preserving:
- clause
id - clause
title - clause
text
The implementation uses a deterministic-first parsing pipeline with optional LLM fallback and deterministic post-processing to handle layout inconsistencies in the original document
The source document is a voyage charter party agreement containing two main sections:
- Part I — voyage particulars and operational details
- Part II — numbered legal clauses
This solution parses Part II only, as required by the challenge.
For each clause the parser extracts:
idtitletext
Additional constraints from the task:
- clauses must be returned in the same order as in the document
- strike-through text must not be included
- the code must run locally
- API keys must not be committed
The parser generates two output files in:
data/output/clauses_flat.json
Clauses grouped by document section clauses_grouped.json
A flat ordered list of clauses
Example:
{
"id": "5",
"title": "FREIGHT REMITTANCE",
"text": "Freight, Dead-freight and Demurrage payable in U.S.D. via T.T."
}Both outputs preserve the original ordering of clauses.
The parser uses a deterministic-first extraction strategy.
Pipeline stages include:
- PDF text extraction
- text normalization
- clause identifier detection
- clause grouping
- title extraction
- clause body assembly
- deterministic cleanup
- structured JSON generation
LLM assistance is optional and used only as fallback
For the test of LLM assistance - a key for Antropic API is needed Be sure to take it to the .env.example file before running the pipeline
| group_order | section | description |
|---|---|---|
| 1 | Main Charter Party Clauses | core legal clauses |
| 2 | Additional Clauses | supplemental clauses |
| 3 | Essar Rider Clauses | rider clauses with different formatting |
Create environment:
bash scripts/setup_conda_env.shActivate:
conda activate charter-parser-2Install dependencies:
pip install -r requirements-dev.txtPYTHONPATH=src python -m charter_parser.mainor
bash scripts/run_parser.shpytest
ruff check .
mypy srcThe goal of this project is deterministic and reproducible clause extraction despite layout inconsistencies in the original PDF