| --- |
| title: LDV Pilot |
| emoji: ⚖️ |
| colorFrom: blue |
| colorTo: indigo |
| sdk: docker |
| app_port: 7860 |
| --- |
| |
| # Contract Risk Analyzer (CRA) — LDV Pilot |
|
|
| > **Automated contract risk assessment** for legal professionals. Upload a PDF, DOCX, or TXT contract and receive a structured risk score, clause-gap analysis, red-flag detection, and a downloadable PDF report — all offline-capable and multilingual. |
|
|
| --- |
|
|
| ## Features |
|
|
| - **3-layer analysis pipeline** — rule-based clause detection (L1) → NLI document classifier (L2) → deterministic risk scorer with versioned policy (L3) |
| - **56 contract type profiles** — employment, lease, NDA, service, loan, construction, government procurement, and more; covers Indonesian, French, and Dutch contracts |
| - **Red-flag detection** — leonine clauses, abusive penalties, unilateral modification, rights waivers |
| - **Explain Mode** — per-finding annotations with legal citations and replacement clause suggestions |
| - **Multilingual** — detects and processes contracts in Indonesian, French, Dutch, English; offline translation via lightml-translator |
| - **OCR fallback** — scanned PDFs handled via Tesseract (EN / FR / ID / NL) |
| - **Job durability** — queued → processing → completed / retryable; crashed jobs auto-recover after 30 min; max 3 retries enforced |
| - **Professional review workflow** — draft citations suppressed in customer mode; reviewer audit trail |
| - **Multi-tenant auth** — org isolation, MFA (TOTP), per-user download controls, API token access |
| - **Encrypted at rest** — document text and results encrypted with `LDV_ENCRYPTION_KEY` |
| - **Offline deployment** — no outbound network required; all models ship locally |
|
|
| --- |
|
|
| ## Repository Structure |
|
|
| ``` |
| . |
| ├── ldv-backend/ # Flask API + ML pipeline |
| │ ├── app.py # Routes, auth, upload, result, admin |
| │ ├── worker.py # Background thread-pool job executor |
| │ ├── database.py # SQLite schema, migrations, audit log |
| │ ├── auth.py # Session + API token auth, MFA |
| │ ├── crypto.py # Fernet encryption at rest |
| │ ├── pdf_report.py # PDF report generator (ReportLab) |
| │ ├── translator.py # In-process offline translation |
| │ ├── translator_client.py# External microservice translation (disabled by default) |
| │ ├── detector/ |
| │ │ ├── detector_rules.py # L1 rule-based clause & red-flag detection |
| │ │ ├── detector_distilbert.py # L2 NLI document classifier |
| │ │ ├── detector_scorer.py # L3 risk scorer (versioned policy) |
| │ │ ├── detector_explain.py # Explain Mode annotations |
| │ │ ├── clause_db.py # Clause keyword definitions |
| │ │ ├── citation_db.py # Legal citation database |
| │ │ ├── risk_clause_db.py # Red-flag keyword database |
| │ │ ├── profile_registry.py # File-driven contract profile loader |
| │ │ ├── profiles/ |
| │ │ │ └── registry_v1.json # 56 contract type profiles (single source of truth) |
| │ │ └── policies/ |
| │ │ └── default_v1.json # Default scoring policy (weights & thresholds) |
| │ ├── tests/ # Unit, API, and integration tests (51 tests) |
| │ └── manage.py # CLI — seed, migrate, backup, purge |
| │ |
| ├── ldv-frontend/ # Single-page app (Alpine.js + Vanilla CSS) |
| │ ├── index.html # Upload, result, retry, explain mode |
| │ ├── admin.html # User / org management |
| │ ├── result.html # Result permalink page |
| │ └── account.html # MFA setup, API token |
| │ |
| ├── datasets/ # Rule and citation CSV databases |
| │ ├── dangerous_clauses_MASTER.csv |
| │ ├── legal_citations.csv |
| │ ├── leonine_clauses.csv |
| │ └── abusive_clauses.csv |
| │ |
| ├── deploy/ # Production deployment helpers |
| │ ├── nginx.conf # Nginx reverse proxy + TLS config |
| │ ├── setup.sh # Fresh-machine install script |
| │ ├── ldv-backup.cron # Automated backup cron job |
| │ └── gen-cert.sh # Self-signed cert generator |
| │ |
| ├── docs/ # Engineering docs and reports |
| ├── docker-compose.yml # Full stack: app + lightml-translator + nginx |
| └── Dockerfile # Multi-stage production image |
| ``` |
|
|
| --- |
|
|
| ## Quick Start |
|
|
| ### Docker (recommended) |
|
|
| ```bash |
| # 1. Clone and configure |
| git clone https://github.com/vadhh/cra.git && cd cra |
| |
| # 2. Set required secrets |
| cp .env.example .env # then edit LDV_SECRET_KEY and LDV_ENCRYPTION_KEY |
| |
| # 3. Run |
| docker compose up -d |
| ``` |
|
|
| App is available at `http://localhost:7860`. Default admin: `admin@example.com` / `password` — **change immediately**. |
|
|
| ### Local Development |
|
|
| ```bash |
| cd ldv-backend |
| pip install -r requirements.txt |
| python app.py |
| ``` |
|
|
| --- |
|
|
| ## Environment Variables |
|
|
| | Variable | Required | Default | Description | |
| |----------|----------|---------|-------------| |
| | `LDV_SECRET_KEY` | ✅ | (random, non-persistent) | Flask session secret | |
| | `LDV_ENCRYPTION_KEY` | ✅ | (none — plaintext mode) | Fernet key for at-rest encryption | |
| | `LDV_DB_PATH` | | `./sydeco.db` | SQLite database path | |
| | `LDV_ADMIN_EMAIL` | | `admin@example.com` | Auto-seeded admin email | |
| | `LDV_ADMIN_PASSWORD` | | `password` | Auto-seeded admin password | |
| | `EXTERNAL_TRANSLATION_DISABLED` | | `1` | Set to `0` to enable external microservice translation | |
| | `LIGHTML_TRANSLATOR_URL` | | (none) | URL of the lightml-translator service | |
| | `LDV_FORCE_MFA_TESTING` | | (none) | Set `1` to bypass MFA in test environments | |
|
|
| > ⚠️ **Always set `LDV_SECRET_KEY` and `LDV_ENCRYPTION_KEY` before any real deployment.** |
|
|
| --- |
|
|
| ## Analysis Pipeline |
|
|
| ``` |
| Upload (PDF / DOCX / TXT) |
| │ |
| ├── OCR fallback (Tesseract) if scanned PDF |
| ├── Language detection (langdetect) |
| └── Translation to EN if needed |
| │ |
| ▼ |
| Layer 1 — Rule-Based Detection (detector_rules.py) |
| ├── Governing law & venue detection |
| ├── Clause presence check (43 clause types) |
| └── Red-flag detection (leonine, abusive, penalty, waiver) |
| │ |
| ▼ |
| Layer 2 — NLI Document Classifier (detector_distilbert.py) |
| ├── Zero-shot NLI classification (DistilBERT-based) |
| ├── Keyword pre-filter (4 languages) |
| └── Document type → profile lookup (56 types, registry_v1.json) |
| │ |
| ▼ |
| Layer 3 — Risk Scorer (detector_scorer.py) |
| ├── Versioned scoring policy (policies/default_v1.json) |
| ├── Score breakdown persisted per analysis |
| └── Risk score 0–100 + label (LOW / MEDIUM / HIGH / CRITICAL) |
| │ |
| ▼ |
| Result stored in SQLite (encrypted) |
| ├── profile_id, profile_version, detection_source, detection_confidence |
| ├── score_breakdown (JSON), policy_version |
| └── Served via REST API + PDF report |
| ``` |
|
|
| --- |
|
|
| ## Contract Type Support |
|
|
| The profile registry (`detector/profiles/registry_v1.json`) covers **56 contract types**. |
| See [`docs/p7_catalogue_reconciliation.md`](docs/p7_catalogue_reconciliation.md) for the full breakdown: |
|
|
| | Status | Count | Description | |
| |--------|-------|-------------| |
| | ✅ Fully auto-detected | 11 | NLI hypothesis + keyword patterns + profile + scorer | |
| | 🟡 Manual override works | 45 | Profile and scoring correct; auto-detection unreliable | |
|
|
| --- |
|
|
| ## Running Tests |
|
|
| ```bash |
| cd ldv-backend |
| python -m pytest tests/ -q # 51 tests |
| python tests/validate_profiles.py # clause reference validator |
| python tests/test_retry.py # job recovery (B2/B3/B4) |
| ``` |
|
|
| --- |
|
|
| ## Tech Stack |
|
|
| | Layer | Technology | |
| |-------|-----------| |
| | API | Flask 3.1, Gunicorn, Flask-Limiter | |
| | Auth | Session + TOTP MFA (pyotp), API tokens | |
| | ML | PyTorch 2.11, HuggingFace Transformers 5.4 | |
| | OCR | Tesseract + PyMuPDF | |
| | DB | SQLite (via `database.py`) | |
| | Encryption | Fernet (cryptography 48) | |
| | PDF | ReportLab | |
| | Frontend | Alpine.js, Vanilla CSS | |
| | Deployment | Docker, Nginx, Docker Compose | |
| | Translation | In-process (offline) + lightml-translator (optional) | |
|
|
| --- |
|
|
| ## License |
|
|
| Private — PT Sydeco / LDV Pilot. Not for public distribution. |
|
|