Skip to content
Divyanshi760Public

About

Maintex is an information extraction pipeline for industrial maintenance work orders. Parses PDFs, Excel, and JSON from CMMS systems and extracts structured fields (equipment, failure mode, severity, cause, and more) using spaCy NER and weak supervision, served through a FastAPI backend with a Next.js UI.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Maintex

Python 3.11+ Tests spaCy FastAPI MLflow uv Schema

Information extraction pipeline for industrial maintenance work orders. Ingests PDFs, Excel files, and JSON from CMMS systems; extracts seven structured fields per record; and serves results via a REST API with a Next.js UI.


Extracted Fields

Field Type Example
equipment surface form "hydraulic pump"
canonical_tag resolved identifier HYDRAULIC_PUMP
failure_mode 11-class label LEAK, BROKEN, WORN …
activity surface form "replaced"
component surface form "shaft seal"
severity 4-class label CRITICAL, HIGH, MEDIUM, LOW
cause 5-class label CONTAMINATION, WEAR, ELECTRICAL …

Architecture

flowchart LR
    PDF[PDF] -->|4-tier segmenter| IG
    XLS[Excel / JSON] --> IG

    IG[Ingest\nSHA-256 · content IDs] --> SRC[(sources\ntable)]
    IG --> NM
    IG --> WS

    subgraph Training
        NM[Normalize\nrule → fuzzy → embed] --- TR[(tag_resolutions)]
        WS[Weak Supervision\nSnorkel LFs × 3 fields] -->|weak_labels.jsonl| EX
        EX[Extract\nspaCy NER × 6 fields] --- ML[(MLflow\nruns · metrics)]
        EX --> MDL[(models/\nner_*_v1.2.0)]
    end

    MDL -->|load| API
    SRC --- API

    subgraph Serve
        API[FastAPI :8765\nPOST /upload\nGET /pipeline/*\nGET /analytics/*] -->|async| GEM[Gemini 2.0 Flash\ncause fallback]
        API --- DDB[(DuckDB\nMTBF · bad-actors\nspike detection)]
    end

    API -->|REST| UI[Next.js UI :3000\nupload · results · CSV]
Loading

Evaluation

spaCy NER, schema v1.2.0, gold set 250 records (span-level greedy 1:1 overlap).

Field F1
equipment 0.894
activity 0.871
failure_mode 0.854
component 0.850
cause — (no gold annotations; 0.6% LF coverage — Gemini fallback active)
severity — (no gold annotations; 8.6% LF coverage)

Installation

Requires Python 3.11+ and uv.

uv sync
uv run python -m spacy download en_core_web_md

Optional — PostgreSQL + MLflow tracking (Docker):

docker compose up -d

Optional — Gemini cause extraction:

export GEMINI_API_KEY=<key>          # from aistudio.google.com

Running

Training pipeline (offline, one-time)

# Ingest MaintIE corpus
DATABASE_URL=sqlite:///maintex.db bash scripts/demo_ingest.sh

# Resolve equipment surface forms
DATABASE_URL=sqlite:///maintex.db bash scripts/demo_normalize.sh

# Generate weak labels (Snorkel)
uv run python -c "from maintex.extract.weak_labels import run; run()"

# Train NER models + evaluate
bash scripts/demo_extract.sh

Inference server

# Backend — port 8765
DATABASE_URL=sqlite:///maintex.db uv run uvicorn maintex.serve.app:app --port 8765

# Frontend — port 3000  (in maintex-ui/)
npm run dev

Swagger UI: http://localhost:8765/docs

Analytics

uv run python scripts/analytics.py

Design Principles

Content-addressed IDs — source_id and fact_id are SHA-256 over content. Same input always produces the same ID, regardless of when or where it runs.

source_id = sha256(dataset_name ‖ native_id ‖ raw_text)[:16]
fact_id   = sha256(source_id ‖ field ‖ char_start ‖ char_end ‖ schema_version)[:16]
run_id    = ULID()  ← execution identity only, excluded from all fingerprints

Reproducibility — output_fingerprint is SHA-256 over all content rows (sorted by primary key, timestamps excluded). Two runs over the same corpus must produce identical fingerprints.

Gold set isolation — training runs exclusively on silver_release.json. The 250-record gold set is never seen during training or hyperparameter selection.

Stateless upload — POST /upload runs inference in-memory and returns JSON. No database writes.


Tests

uv run pytest tests/

531 tests covering unit, integration, and idempotency. No external services required.

Test file What it verifies
tests/test_idempotency.py 6 idempotency proofs across all pipeline stages
tests/unit/test_labeling.py LF coverage and label correctness
tests/unit/test_fuzzy.py Entity resolver tiers (rule → fuzzy → embedding)
tests/unit/test_train.py Training pipeline contract

Data Stores

Store Written by Read by
sources table Ingest Normalize, Serve
facts table Extract (inference) Serve
tag_resolutions table Normalize Serve, Analytics
runs table All stages Serve
weak_labels.jsonl Weak supervision Extract, Analytics
models/ner_*_v1.2.0 Extract (training) Extract (inference)

Project Layout

maintex/
├── src/maintex/
│   ├── ingest/          # PDF (4-tier), Excel, JSON loaders
│   ├── normalize/       # Rule → fuzzy → embedding entity resolution
│   ├── extract/         # Weak supervision LFs, NER training, Gemini fallback
│   ├── serve/           # FastAPI app + upload endpoint
│   └── analytics/       # DuckDB MTBF / bad-actor / spike queries
├── conf/
│   ├── equipment_master.yaml   # 246 canonical tags + aliases
│   └── label_schema.yaml       # schema v1.2.0, all class enums
├── data/gold/           # 250-record held-out evaluation set (read-only)
├── models/              # Trained spaCy NER models
├── docs/                # Architecture, evaluation methodology, provenance design
└── tests/               # 531 tests

Key Constants

Constant Value Location
MIN_RECORD_CHARS 15 ingest/load.py
Upload size limit 50 MB serve/upload.py
Schema version 1.2.0 conf/label_schema.yaml
Canonical tags 246 conf/equipment_master.yaml

Further Reading

About

Maintex is an information extraction pipeline for industrial maintenance work orders. Parses PDFs, Excel, and JSON from CMMS systems and extracts structured fields (equipment, failure mode, severity, cause, and more) using spaCy NER and weak supervision, served through a FastAPI backend with a Next.js UI.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages