equiaudit 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- equiaudit-0.1.1/PKG-INFO +161 -0
- equiaudit-0.1.1/README.md +127 -0
- equiaudit-0.1.1/pyproject.toml +56 -0
- equiaudit-0.1.1/setup.cfg +4 -0
- equiaudit-0.1.1/src/equiaudit/__init__.py +3 -0
- equiaudit-0.1.1/src/equiaudit/cli/__init__.py +7 -0
- equiaudit-0.1.1/src/equiaudit/cli/__main__.py +204 -0
- equiaudit-0.1.1/src/equiaudit/cli/evaluator.py +455 -0
- equiaudit-0.1.1/src/equiaudit/data/GermanCredit.csv +1001 -0
- equiaudit-0.1.1/src/equiaudit/data/UCI_Credit_Card.csv +30001 -0
- equiaudit-0.1.1/src/equiaudit/data/adult-all.csv +48843 -0
- equiaudit-0.1.1/src/equiaudit/data/adult-all_discretized.csv +48843 -0
- equiaudit-0.1.1/src/equiaudit/data/bank-additional.csv +41189 -0
- equiaudit-0.1.1/src/equiaudit/data/german.csv +1001 -0
- equiaudit-0.1.1/src/equiaudit/data/german_discretized.csv +1001 -0
- equiaudit-0.1.1/src/equiaudit/gui/__init__.py +113 -0
- equiaudit-0.1.1/src/equiaudit/gui/app.py +30 -0
- equiaudit-0.1.1/src/equiaudit/gui/config.py +89 -0
- equiaudit-0.1.1/src/equiaudit/gui/screens/main_page.py +32 -0
- equiaudit-0.1.1/src/equiaudit/gui/screens/new_evaluation.py +983 -0
- equiaudit-0.1.1/src/equiaudit/gui/screens/view_results.py +704 -0
- equiaudit-0.1.1/src/equiaudit/gui/state.py +36 -0
- equiaudit-0.1.1/src/equiaudit/gui/styles.py +183 -0
- equiaudit-0.1.1/src/equiaudit/gui/utils.py +130 -0
- equiaudit-0.1.1/src/equiaudit/gui/widgets/fairness.py +748 -0
- equiaudit-0.1.1/src/equiaudit/gui/widgets/results.py +342 -0
- equiaudit-0.1.1/src/equiaudit/gui/widgets/stage_display.py +650 -0
- equiaudit-0.1.1/src/equiaudit/main.py +161 -0
- equiaudit-0.1.1/src/equiaudit/models/__init__.py +32 -0
- equiaudit-0.1.1/src/equiaudit/models/agent_manager.py +256 -0
- equiaudit-0.1.1/src/equiaudit/models/agents/__init__.py +11 -0
- equiaudit-0.1.1/src/equiaudit/models/agents/base_agent.py +242 -0
- equiaudit-0.1.1/src/equiaudit/models/agents/conversational_agent.py +21 -0
- equiaudit-0.1.1/src/equiaudit/models/agents/data_analyst_agent.py +84 -0
- equiaudit-0.1.1/src/equiaudit/models/agents/function_caller_agent.py +86 -0
- equiaudit-0.1.1/src/equiaudit/models/agents/humanizer_agent.py +58 -0
- equiaudit-0.1.1/src/equiaudit/models/agents/summary_agent.py +69 -0
- equiaudit-0.1.1/src/equiaudit/models/clients/__init__.py +13 -0
- equiaudit-0.1.1/src/equiaudit/models/clients/base_client.py +89 -0
- equiaudit-0.1.1/src/equiaudit/models/clients/client_factory.py +88 -0
- equiaudit-0.1.1/src/equiaudit/models/clients/gemini_client.py +113 -0
- equiaudit-0.1.1/src/equiaudit/models/clients/ollama_client.py +68 -0
- equiaudit-0.1.1/src/equiaudit/models/clients/openrouter_client.py +135 -0
- equiaudit-0.1.1/src/equiaudit/models/config.yml +147 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/__init__.py +9 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/config.py +88 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/pipeline.py +642 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/pipeline_config.yml +81 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stage.py +102 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/__init__.py +25 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/base.py +86 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/dataset_loading.py +21 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/discretization.py +384 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/fairness.py +176 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/imbalance.py +122 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/mitigation.py +332 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/objective.py +34 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/pair_selection.py +116 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/quality.py +28 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/recommendations.py +45 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/stages/sensitive.py +134 -0
- equiaudit-0.1.1/src/equiaudit/pipeline/utils.py +878 -0
- equiaudit-0.1.1/src/equiaudit/reporting/__init__.py +0 -0
- equiaudit-0.1.1/src/equiaudit/reporting/pdf_generator.py +645 -0
- equiaudit-0.1.1/src/equiaudit/tools/__init__.py +0 -0
- equiaudit-0.1.1/src/equiaudit/tools/bias_mitigation_tools.py +653 -0
- equiaudit-0.1.1/src/equiaudit/tools/discretization_tools.py +259 -0
- equiaudit-0.1.1/src/equiaudit/tools/fairness_tools.py +1037 -0
- equiaudit-0.1.1/src/equiaudit/tools/tool.py +6 -0
- equiaudit-0.1.1/src/equiaudit/tools/tool_manager.py +65 -0
- equiaudit-0.1.1/src/equiaudit.egg-info/PKG-INFO +161 -0
- equiaudit-0.1.1/src/equiaudit.egg-info/SOURCES.txt +74 -0
- equiaudit-0.1.1/src/equiaudit.egg-info/dependency_links.txt +1 -0
- equiaudit-0.1.1/src/equiaudit.egg-info/entry_points.txt +2 -0
- equiaudit-0.1.1/src/equiaudit.egg-info/requires.txt +16 -0
- equiaudit-0.1.1/src/equiaudit.egg-info/top_level.txt +1 -0
equiaudit-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: equiaudit
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: An Agentic AI Framework for Fairness Auditing
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/pchmelo/EquiAudit
|
|
7
|
+
Project-URL: Repository, https://github.com/pchmelo/EquiAudit
|
|
8
|
+
Project-URL: Issues, https://github.com/pchmelo/EquiAudit/issues
|
|
9
|
+
Keywords: fairness,bias,auditing,agentic-ai,machine-learning,tabular-data
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: aif360==0.6.1
|
|
20
|
+
Requires-Dist: imbalanced-learn==0.14.1
|
|
21
|
+
Requires-Dist: matplotlib>=3.10
|
|
22
|
+
Requires-Dist: numpy>=2.2
|
|
23
|
+
Requires-Dist: pandas>=2.2
|
|
24
|
+
Requires-Dist: python-dotenv>=1.2
|
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
|
26
|
+
Requires-Dist: reportlab>=4.2
|
|
27
|
+
Requires-Dist: requests>=2.32
|
|
28
|
+
Requires-Dist: scikit-learn>=1.8
|
|
29
|
+
Requires-Dist: scipy>=1.14
|
|
30
|
+
Requires-Dist: seaborn>=0.13
|
|
31
|
+
Requires-Dist: google-genai>=1.0
|
|
32
|
+
Provides-Extra: gui
|
|
33
|
+
Requires-Dist: streamlit>=1.52; extra == "gui"
|
|
34
|
+
|
|
35
|
+
# EquiAudit — Dataset Quality & Fairness Evaluation System
|
|
36
|
+
|
|
37
|
+
An AI-agent pipeline for evaluating datasets on data quality and fairness concerns, with an interactive Streamlit GUI, a headless CLI, and a Python API.
|
|
38
|
+
|
|
39
|
+
<div align="center">
|
|
40
|
+
<img src="https://raw.githubusercontent.com/pchmelo/EquiAudit/master/docs/img/simple_diagram.png" alt="System overview" width="320"/>
|
|
41
|
+
|
|
42
|
+
*A dataset is fed into EquiAudit, which coordinates AI agents under optional user supervision to produce an audit report and a bias-mitigated dataset.*
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
## How It Works
|
|
46
|
+
|
|
47
|
+
<div align="center">
|
|
48
|
+
<img src="https://raw.githubusercontent.com/pchmelo/EquiAudit/master/docs/img/data_preparation_fairness_analysis.png" alt="Agent-tool-data interaction" width="600"/>
|
|
49
|
+
|
|
50
|
+
*AI agents interact bidirectionally with the analyst, invoke tools to query and compute statistics on the dataset, and synthesise findings into an audit report.*
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div align="center">
|
|
54
|
+
<img src="https://raw.githubusercontent.com/pchmelo/EquiAudit/master/docs/img/mitigation.png" alt="Bias mitigation workflow" width="600"/>
|
|
55
|
+
|
|
56
|
+
*Each selected mitigation technique produces a transformed dataset variant; tools recompute fairness statistics on every variant; the AI agent compares them against the original statistics and produces a comparative mitigation report.*
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
## Demo
|
|
60
|
+
|
|
61
|
+
A video demonstration of the full GUI workflow is available on YouTube:
|
|
62
|
+
[https://youtu.be/_USTmBhzDkI](https://youtu.be/_USTmBhzDkI)
|
|
63
|
+
|
|
64
|
+
## Documentation
|
|
65
|
+
|
|
66
|
+
| Guide | Description |
|
|
67
|
+
|-------|-------------|
|
|
68
|
+
| [USAGE.md](docs/USAGE.md) | Installation, configuration reference, all execution modes (GUI / CLI / Python API), and worked examples |
|
|
69
|
+
| [EXTENDING.md](docs/EXTENDING.md) | How to add new Tools, Agent types, LLM backends, and Pipeline stages |
|
|
70
|
+
|
|
71
|
+
## Installation
|
|
72
|
+
|
|
73
|
+
**From PyPI (recommended):**
|
|
74
|
+
```bash
|
|
75
|
+
pip install equiaudit # core pipeline
|
|
76
|
+
pip install "equiaudit[gui]" # optional: Streamlit GUI
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**From source:**
|
|
80
|
+
```bash
|
|
81
|
+
git clone https://github.com/pchmelo/EquiAudit.git
|
|
82
|
+
cd EquiAudit
|
|
83
|
+
pip install -r requirements.txt # core pipeline
|
|
84
|
+
pip install -r requirements-gui.txt # optional: Streamlit GUI
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Configuration
|
|
88
|
+
|
|
89
|
+
Copy `examples/config.yml` and set your API keys as environment variables or in a `.env` file at the project root:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
GOOGLE_API_KEY=your-google-gemini-api-key-here
|
|
93
|
+
OPENROUTER_API_KEY=your-openrouter-api-key-here
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
At least one cloud API key is required unless running a local model via Ollama (`ollama serve`).
|
|
97
|
+
|
|
98
|
+
See [USAGE.md — Configuration File](docs/USAGE.md#configuration-file) for the full annotated config reference.
|
|
99
|
+
|
|
100
|
+
## Running the Application
|
|
101
|
+
|
|
102
|
+
The recommended entry point is `examples/example_usage.py`. Set `mode: gui` or `mode: quick` in `examples/config.yml`, then run:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
python examples/example_usage.py
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The script dispatches to the GUI or the headless evaluator based on the config:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# examples/example_usage.py
|
|
112
|
+
import os, yaml
|
|
113
|
+
from dotenv import load_dotenv
|
|
114
|
+
load_dotenv()
|
|
115
|
+
|
|
116
|
+
CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.yml")
|
|
117
|
+
DATASET_PATH = os.path.join(os.path.dirname(__file__), "adult-all.csv")
|
|
118
|
+
|
|
119
|
+
with open(CONFIG_PATH, encoding="utf-8") as f:
|
|
120
|
+
_mode = (yaml.safe_load(f) or {}).get("mode", "quick")
|
|
121
|
+
|
|
122
|
+
if _mode == "gui":
|
|
123
|
+
from equiaudit.gui import launch
|
|
124
|
+
launch(config_path=CONFIG_PATH, dataset_path=DATASET_PATH)
|
|
125
|
+
else:
|
|
126
|
+
from equiaudit.cli import FairnessEvaluator
|
|
127
|
+
evaluator = FairnessEvaluator(config_path=CONFIG_PATH)
|
|
128
|
+
result = evaluator.evaluate(
|
|
129
|
+
data=DATASET_PATH,
|
|
130
|
+
# target="Income", # overrides target_column in config
|
|
131
|
+
# sensitive_columns=["Sex", "Race", "Age"], # overrides sensitive_attribute_analysis
|
|
132
|
+
# sensitive_pairs=[["Sex", "Race"], ["Age", "Education"]], # overrides pair_evaluation
|
|
133
|
+
# mitigation_techniques=["reweighting", "smote"], # overrides mitigation_techniques
|
|
134
|
+
)
|
|
135
|
+
if result.success:
|
|
136
|
+
print(f"Report: {result.report_dir}")
|
|
137
|
+
else:
|
|
138
|
+
print(f"Error: {result.error}")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
See [USAGE.md — Execution Modes](docs/USAGE.md#execution-modes) for the full CLI flag reference and Python API usage.
|
|
142
|
+
|
|
143
|
+
## Datasets
|
|
144
|
+
Example datasets are provided in `src/equiaudit/data/` for testing. The default example is `adult-all.csv` (UCI Adult Census Income, target column `Income`).
|
|
145
|
+
|
|
146
|
+
## Reports
|
|
147
|
+
Generated reports are saved under `reports/<dataset>_<timestamp>/` and include a Markdown narrative, a PDF, per-group fairness metrics, and raw JSON stage data. A sample report is available in `reports/`.
|
|
148
|
+
|
|
149
|
+
## GUI Screenshots
|
|
150
|
+
|
|
151
|
+

|
|
152
|
+
*Framework configuration (dataset selection, model backend, target column, and pipeline options).*
|
|
153
|
+
|
|
154
|
+

|
|
155
|
+
*Sensitive attribute identification (agent-generated candidate list pending analyst confirmation).*
|
|
156
|
+
|
|
157
|
+

|
|
158
|
+
*Proxy model fairness results (per-group metric bar charts from the outcome disparity stage).*
|
|
159
|
+
|
|
160
|
+

|
|
161
|
+
*Previous results browser (inspect and compare past audit runs).*
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# EquiAudit — Dataset Quality & Fairness Evaluation System
|
|
2
|
+
|
|
3
|
+
An AI-agent pipeline for evaluating datasets on data quality and fairness concerns, with an interactive Streamlit GUI, a headless CLI, and a Python API.
|
|
4
|
+
|
|
5
|
+
<div align="center">
|
|
6
|
+
<img src="https://raw.githubusercontent.com/pchmelo/EquiAudit/master/docs/img/simple_diagram.png" alt="System overview" width="320"/>
|
|
7
|
+
|
|
8
|
+
*A dataset is fed into EquiAudit, which coordinates AI agents under optional user supervision to produce an audit report and a bias-mitigated dataset.*
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
## How It Works
|
|
12
|
+
|
|
13
|
+
<div align="center">
|
|
14
|
+
<img src="https://raw.githubusercontent.com/pchmelo/EquiAudit/master/docs/img/data_preparation_fairness_analysis.png" alt="Agent-tool-data interaction" width="600"/>
|
|
15
|
+
|
|
16
|
+
*AI agents interact bidirectionally with the analyst, invoke tools to query and compute statistics on the dataset, and synthesise findings into an audit report.*
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div align="center">
|
|
20
|
+
<img src="https://raw.githubusercontent.com/pchmelo/EquiAudit/master/docs/img/mitigation.png" alt="Bias mitigation workflow" width="600"/>
|
|
21
|
+
|
|
22
|
+
*Each selected mitigation technique produces a transformed dataset variant; tools recompute fairness statistics on every variant; the AI agent compares them against the original statistics and produces a comparative mitigation report.*
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
## Demo
|
|
26
|
+
|
|
27
|
+
A video demonstration of the full GUI workflow is available on YouTube:
|
|
28
|
+
[https://youtu.be/_USTmBhzDkI](https://youtu.be/_USTmBhzDkI)
|
|
29
|
+
|
|
30
|
+
## Documentation
|
|
31
|
+
|
|
32
|
+
| Guide | Description |
|
|
33
|
+
|-------|-------------|
|
|
34
|
+
| [USAGE.md](docs/USAGE.md) | Installation, configuration reference, all execution modes (GUI / CLI / Python API), and worked examples |
|
|
35
|
+
| [EXTENDING.md](docs/EXTENDING.md) | How to add new Tools, Agent types, LLM backends, and Pipeline stages |
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
**From PyPI (recommended):**
|
|
40
|
+
```bash
|
|
41
|
+
pip install equiaudit # core pipeline
|
|
42
|
+
pip install "equiaudit[gui]" # optional: Streamlit GUI
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**From source:**
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/pchmelo/EquiAudit.git
|
|
48
|
+
cd EquiAudit
|
|
49
|
+
pip install -r requirements.txt # core pipeline
|
|
50
|
+
pip install -r requirements-gui.txt # optional: Streamlit GUI
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
Copy `examples/config.yml` and set your API keys as environment variables or in a `.env` file at the project root:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
GOOGLE_API_KEY=your-google-gemini-api-key-here
|
|
59
|
+
OPENROUTER_API_KEY=your-openrouter-api-key-here
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
At least one cloud API key is required unless running a local model via Ollama (`ollama serve`).
|
|
63
|
+
|
|
64
|
+
See [USAGE.md — Configuration File](docs/USAGE.md#configuration-file) for the full annotated config reference.
|
|
65
|
+
|
|
66
|
+
## Running the Application
|
|
67
|
+
|
|
68
|
+
The recommended entry point is `examples/example_usage.py`. Set `mode: gui` or `mode: quick` in `examples/config.yml`, then run:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
python examples/example_usage.py
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The script dispatches to the GUI or the headless evaluator based on the config:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
# examples/example_usage.py
|
|
78
|
+
import os, yaml
|
|
79
|
+
from dotenv import load_dotenv
|
|
80
|
+
load_dotenv()
|
|
81
|
+
|
|
82
|
+
CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.yml")
|
|
83
|
+
DATASET_PATH = os.path.join(os.path.dirname(__file__), "adult-all.csv")
|
|
84
|
+
|
|
85
|
+
with open(CONFIG_PATH, encoding="utf-8") as f:
|
|
86
|
+
_mode = (yaml.safe_load(f) or {}).get("mode", "quick")
|
|
87
|
+
|
|
88
|
+
if _mode == "gui":
|
|
89
|
+
from equiaudit.gui import launch
|
|
90
|
+
launch(config_path=CONFIG_PATH, dataset_path=DATASET_PATH)
|
|
91
|
+
else:
|
|
92
|
+
from equiaudit.cli import FairnessEvaluator
|
|
93
|
+
evaluator = FairnessEvaluator(config_path=CONFIG_PATH)
|
|
94
|
+
result = evaluator.evaluate(
|
|
95
|
+
data=DATASET_PATH,
|
|
96
|
+
# target="Income", # overrides target_column in config
|
|
97
|
+
# sensitive_columns=["Sex", "Race", "Age"], # overrides sensitive_attribute_analysis
|
|
98
|
+
# sensitive_pairs=[["Sex", "Race"], ["Age", "Education"]], # overrides pair_evaluation
|
|
99
|
+
# mitigation_techniques=["reweighting", "smote"], # overrides mitigation_techniques
|
|
100
|
+
)
|
|
101
|
+
if result.success:
|
|
102
|
+
print(f"Report: {result.report_dir}")
|
|
103
|
+
else:
|
|
104
|
+
print(f"Error: {result.error}")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
See [USAGE.md — Execution Modes](docs/USAGE.md#execution-modes) for the full CLI flag reference and Python API usage.
|
|
108
|
+
|
|
109
|
+
## Datasets
|
|
110
|
+
Example datasets are provided in `src/equiaudit/data/` for testing. The default example is `adult-all.csv` (UCI Adult Census Income, target column `Income`).
|
|
111
|
+
|
|
112
|
+
## Reports
|
|
113
|
+
Generated reports are saved under `reports/<dataset>_<timestamp>/` and include a Markdown narrative, a PDF, per-group fairness metrics, and raw JSON stage data. A sample report is available in `reports/`.
|
|
114
|
+
|
|
115
|
+
## GUI Screenshots
|
|
116
|
+
|
|
117
|
+

|
|
118
|
+
*Framework configuration (dataset selection, model backend, target column, and pipeline options).*
|
|
119
|
+
|
|
120
|
+

|
|
121
|
+
*Sensitive attribute identification (agent-generated candidate list pending analyst confirmation).*
|
|
122
|
+
|
|
123
|
+

|
|
124
|
+
*Proxy model fairness results (per-group metric bar charts from the outcome disparity stage).*
|
|
125
|
+
|
|
126
|
+

|
|
127
|
+
*Previous results browser (inspect and compare past audit runs).*
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "equiaudit"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "An Agentic AI Framework for Fairness Auditing"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
keywords = ["fairness", "bias", "auditing", "agentic-ai", "machine-learning", "tabular-data"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
dependencies = [
|
|
24
|
+
"aif360==0.6.1",
|
|
25
|
+
"imbalanced-learn==0.14.1",
|
|
26
|
+
"matplotlib>=3.10",
|
|
27
|
+
"numpy>=2.2",
|
|
28
|
+
"pandas>=2.2",
|
|
29
|
+
"python-dotenv>=1.2",
|
|
30
|
+
"pyyaml>=6.0",
|
|
31
|
+
"reportlab>=4.2",
|
|
32
|
+
"requests>=2.32",
|
|
33
|
+
"scikit-learn>=1.8",
|
|
34
|
+
"scipy>=1.14",
|
|
35
|
+
"seaborn>=0.13",
|
|
36
|
+
"google-genai>=1.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
gui = ["streamlit>=1.52"]
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
equiaudit = "equiaudit.cli.__main__:main"
|
|
44
|
+
|
|
45
|
+
[project.urls]
|
|
46
|
+
Homepage = "https://github.com/pchmelo/EquiAudit"
|
|
47
|
+
Repository = "https://github.com/pchmelo/EquiAudit"
|
|
48
|
+
Issues = "https://github.com/pchmelo/EquiAudit/issues"
|
|
49
|
+
|
|
50
|
+
[tool.setuptools.packages.find]
|
|
51
|
+
where = ["src"]
|
|
52
|
+
|
|
53
|
+
[tool.setuptools.package-data]
|
|
54
|
+
"equiaudit.models" = ["config.yml"]
|
|
55
|
+
"equiaudit.pipeline" = ["pipeline_config.yml"]
|
|
56
|
+
"equiaudit.data" = ["*.csv"]
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main(args: argparse.Namespace = None) -> int:
|
|
10
|
+
"""Main entry point for CLI."""
|
|
11
|
+
|
|
12
|
+
if args is None:
|
|
13
|
+
args = parse_args()
|
|
14
|
+
|
|
15
|
+
# Handle environment variable loading from .env file
|
|
16
|
+
if args.env_file:
|
|
17
|
+
load_env_file(args.env_file)
|
|
18
|
+
|
|
19
|
+
# Import after env loading to ensure API keys are available
|
|
20
|
+
from equiaudit.cli.evaluator import FairnessEvaluator
|
|
21
|
+
|
|
22
|
+
# Create evaluator
|
|
23
|
+
evaluator = FairnessEvaluator(
|
|
24
|
+
config_path=args.config,
|
|
25
|
+
output_dir=args.output,
|
|
26
|
+
model=args.model,
|
|
27
|
+
verbose=not args.quiet,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Verify mode
|
|
31
|
+
if args.verify:
|
|
32
|
+
result = evaluator.verify()
|
|
33
|
+
return 0 if result.success else 1
|
|
34
|
+
|
|
35
|
+
# Evaluate mode - requires data
|
|
36
|
+
if not args.data:
|
|
37
|
+
print("Error: --data is required for evaluation mode")
|
|
38
|
+
print("Use --verify to check configuration only")
|
|
39
|
+
return 1
|
|
40
|
+
|
|
41
|
+
# Run evaluation
|
|
42
|
+
result = evaluator.evaluate(
|
|
43
|
+
data=args.data,
|
|
44
|
+
target=args.target,
|
|
45
|
+
objective=args.objective,
|
|
46
|
+
sensitive_columns=args.sensitive.split(",") if args.sensitive else None,
|
|
47
|
+
generate_pdf=not args.no_pdf,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if result.success:
|
|
51
|
+
print("\n" + "=" * 60)
|
|
52
|
+
print("EVALUATION COMPLETE")
|
|
53
|
+
print("=" * 60)
|
|
54
|
+
print(f"Dataset: {result.dataset}")
|
|
55
|
+
print(f"Target: {result.target_column or 'auto-detected'}")
|
|
56
|
+
print(f"Report Dir: {result.report_dir}")
|
|
57
|
+
if result.pdf_path:
|
|
58
|
+
print(f"PDF Report: {result.pdf_path}")
|
|
59
|
+
if result.markdown_path:
|
|
60
|
+
print(f"MD Report: {result.markdown_path}")
|
|
61
|
+
print(f"Stages: {', '.join(result.stages_completed)}")
|
|
62
|
+
if result.warnings:
|
|
63
|
+
print(f"\nWarnings ({len(result.warnings)}):")
|
|
64
|
+
for w in result.warnings:
|
|
65
|
+
print(f" - {w}")
|
|
66
|
+
return 0
|
|
67
|
+
else:
|
|
68
|
+
print("\n" + "=" * 60)
|
|
69
|
+
print("EVALUATION FAILED")
|
|
70
|
+
print("=" * 60)
|
|
71
|
+
print(f"Error: {result.error}")
|
|
72
|
+
return 1
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def parse_args() -> argparse.Namespace:
|
|
76
|
+
"""Parse command-line arguments."""
|
|
77
|
+
|
|
78
|
+
parser = argparse.ArgumentParser(
|
|
79
|
+
prog="fairness-eval",
|
|
80
|
+
description="Evaluate datasets for fairness and bias issues.",
|
|
81
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
82
|
+
epilog="""
|
|
83
|
+
Examples:
|
|
84
|
+
# Basic evaluation
|
|
85
|
+
equiaudit --data adult-all.csv --target Income
|
|
86
|
+
|
|
87
|
+
# Verify configuration
|
|
88
|
+
equiaudit --verify
|
|
89
|
+
|
|
90
|
+
# Custom config and output
|
|
91
|
+
equiaudit --config my_config.yml --data data.csv --output ./reports
|
|
92
|
+
|
|
93
|
+
# Specify model and sensitive columns
|
|
94
|
+
equiaudit --data data.csv --model gemini-flash --sensitive "age,sex,race"
|
|
95
|
+
|
|
96
|
+
Environment Variables:
|
|
97
|
+
OPENROUTER_API_KEY API key for OpenRouter models
|
|
98
|
+
GOOGLE_API_KEY API key for Gemini models
|
|
99
|
+
""",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Data input
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"--data", "-d",
|
|
105
|
+
type=str,
|
|
106
|
+
help="Path to CSV dataset file",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
parser.add_argument(
|
|
110
|
+
"--target", "-t",
|
|
111
|
+
type=str,
|
|
112
|
+
default=None,
|
|
113
|
+
help="Target column name for classification (auto-detected if not specified)",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
parser.add_argument(
|
|
117
|
+
"--objective", "-o",
|
|
118
|
+
type=str,
|
|
119
|
+
default=None,
|
|
120
|
+
help="Custom evaluation objective/prompt",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
parser.add_argument(
|
|
124
|
+
"--sensitive", "-s",
|
|
125
|
+
type=str,
|
|
126
|
+
default=None,
|
|
127
|
+
help="Comma-separated list of sensitive columns (auto-detected if not specified)",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Configuration
|
|
131
|
+
parser.add_argument(
|
|
132
|
+
"--config", "-c",
|
|
133
|
+
type=str,
|
|
134
|
+
default=None,
|
|
135
|
+
help="Path to YAML configuration file (uses bundled default if omitted)",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
parser.add_argument(
|
|
139
|
+
"--model", "-m",
|
|
140
|
+
type=str,
|
|
141
|
+
default=None,
|
|
142
|
+
help="Override default model from config",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
parser.add_argument(
|
|
146
|
+
"--env-file", "-e",
|
|
147
|
+
type=str,
|
|
148
|
+
default=None,
|
|
149
|
+
help="Path to .env file for loading API keys",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Output
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
"--output", "-O",
|
|
155
|
+
type=str,
|
|
156
|
+
default=None,
|
|
157
|
+
help="Output directory for reports (default: reports/)",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
parser.add_argument(
|
|
161
|
+
"--no-pdf",
|
|
162
|
+
action="store_true",
|
|
163
|
+
help="Skip PDF generation",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Modes
|
|
167
|
+
parser.add_argument(
|
|
168
|
+
"--verify", "-V",
|
|
169
|
+
action="store_true",
|
|
170
|
+
help="Verify configuration only (don't run evaluation)",
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
parser.add_argument(
|
|
174
|
+
"--quiet", "-q",
|
|
175
|
+
action="store_true",
|
|
176
|
+
help="Suppress progress messages",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return parser.parse_args()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def load_env_file(env_path: str) -> None:
|
|
183
|
+
"""Load environment variables from a .env file."""
|
|
184
|
+
env_path = Path(env_path)
|
|
185
|
+
if not env_path.exists():
|
|
186
|
+
print(f"Warning: .env file not found: {env_path}")
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
print(f"Loading environment from: {env_path}")
|
|
190
|
+
|
|
191
|
+
with open(env_path, "r") as f:
|
|
192
|
+
for line in f:
|
|
193
|
+
line = line.strip()
|
|
194
|
+
if not line or line.startswith("#"):
|
|
195
|
+
continue
|
|
196
|
+
if "=" in line:
|
|
197
|
+
key, value = line.split("=", 1)
|
|
198
|
+
key = key.strip()
|
|
199
|
+
value = value.strip().strip('"').strip("'")
|
|
200
|
+
os.environ[key] = value
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
sys.exit(main())
|