dataprocessing-ai 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gbemi Lesi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: dataprocessing-ai
3
+ Version: 0.1.1
4
+ Summary: AI-native data processing library — REST API, MCP server, and Python package
5
+ Author: oluwagbemilesi
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Techlon/dataprocessing-ai
8
+ Project-URL: Repository, https://github.com/Techlon/dataprocessing-ai
9
+ Project-URL: Issues, https://github.com/Techlon/dataprocessing-ai/issues
10
+ Keywords: data,processing,AI,REST,MCP,pandas
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: pandas>=2.2.0
18
+ Requires-Dist: numpy>=1.26.0
19
+ Provides-Extra: api
20
+ Requires-Dist: fastapi>=0.110.0; extra == "api"
21
+ Requires-Dist: uvicorn>=0.27.0; extra == "api"
22
+ Requires-Dist: pydantic>=2.6.0; extra == "api"
23
+ Requires-Dist: python-multipart>=0.0.9; extra == "api"
24
+ Provides-Extra: mcp
25
+ Requires-Dist: mcp>=0.9.0; extra == "mcp"
26
+ Provides-Extra: formats
27
+ Requires-Dist: openpyxl>=3.1.0; extra == "formats"
28
+ Requires-Dist: pyarrow>=15.0.0; extra == "formats"
29
+ Provides-Extra: all
30
+ Requires-Dist: dataprocessing-ai[api,formats,mcp]; extra == "all"
31
+ Provides-Extra: dev
32
+ Requires-Dist: dataprocessing-ai[all]; extra == "dev"
33
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
34
+ Requires-Dist: httpx>=0.27.0; extra == "dev"
35
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # DataProcessing AI
39
+
40
+ An AI-native Python library for data processing and transformation.
41
+ Built to be called by any AI agent via REST API, MCP server, or direct Python import.
42
+
43
+ ## What it does
44
+
45
+ - **Ingest** - read CSV, JSON, Excel, Parquet files into a standard format
46
+ - **Clean** - remove nulls, duplicates, outliers, standardise column names
47
+ - **Transform** - filter, sort, group, pivot, merge, reshape datasets
48
+ - **Analyse** - generate statistics, correlations, distributions, outlier reports
49
+ - **Visualise** - produce Vega-Lite chart specs (histogram, bar, scatter, line, correlation heatmap)
50
+
51
+ ## Three ways to use it
52
+
53
+ ### 1. REST API (any AI, any language)
54
+
55
+ Install with the API extra, then start the server:
56
+ ```bash
57
+ pip install "dataprocessing-ai[api]"
58
+ uvicorn dataprocessing.api:app --host 0.0.0.0 --port 8000
59
+ ```
60
+
61
+ Call it:
62
+ ```bash
63
+ curl -X POST http://localhost:8000/ingest -F "file=@data.csv"
64
+ curl -X POST http://localhost:8000/clean -H "Content-Type: application/json" -d '{"data": [...]}'
65
+ curl -X POST http://localhost:8000/transform -H "Content-Type: application/json" -d '{"data": [...], "operation": "filter_rows", "params": {"column": "age", "operator": "gt", "value": 25}}'
66
+ curl -X POST http://localhost:8000/analyse -H "Content-Type: application/json" -d '{"data": [...]}'
67
+ curl -X POST http://localhost:8000/visualise -H "Content-Type: application/json" -d '{"data": [...], "chart": "histogram", "params": {"column": "age", "bins": 10}}'
68
+ ```
69
+
70
+ ### 2. MCP Server (Claude native tools)
71
+
72
+ Install with the MCP extra:
73
+ ```bash
74
+ pip install "dataprocessing-ai[mcp]"
75
+ ```
76
+
77
+ Then add to your `claude_desktop_config.json`:
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "dataprocessing": {
82
+ "command": "dataprocessing-mcp"
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ No paths, no `PYTHONPATH` — the installed package provides the
89
+ `dataprocessing-mcp` command directly.
90
+
91
+ ### 3. Python package (direct import)
92
+
93
+ ```python
94
+ from dataprocessing.ingest import read_file
95
+ from dataprocessing.clean import clean_all
96
+ from dataprocessing.transform import filter_rows
97
+ from dataprocessing.analyse import full_report
98
+ from dataprocessing.visualise import histogram, correlation_heatmap
99
+
100
+ df = read_file("data.csv")
101
+ df = clean_all(df)
102
+ report = full_report(df)
103
+
104
+ # Chart functions return Vega-Lite spec dicts (JSON-serialisable)
105
+ hist_spec = histogram(df, column="age", bins=10)
106
+ heatmap_spec = correlation_heatmap(df)
107
+ ```
108
+
109
+ ## Installation
110
+
111
+ ```bash
112
+ pip install dataprocessing-ai
113
+ ```
114
+
115
+ That gives you the core library (`ingest`, `clean`, `transform`, `analyse`,
116
+ `visualise`) with a minimal dependency footprint.
117
+
118
+ Optional extras add the interfaces and file formats you need:
119
+
120
+ ```bash
121
+ pip install "dataprocessing-ai[mcp]" # MCP server (for Claude and other agents)
122
+ pip install "dataprocessing-ai[api]" # REST API server
123
+ pip install "dataprocessing-ai[formats]" # Excel (.xlsx) and Parquet support
124
+ pip install "dataprocessing-ai[all]" # everything
125
+ ```
126
+
127
+ ### Installing from source
128
+
129
+ ```bash
130
+ git clone https://github.com/Techlon/dataprocessing-ai.git
131
+ cd dataprocessing-ai
132
+ python3 -m venv .venv
133
+ source .venv/bin/activate
134
+ pip install -e ".[dev]"
135
+ ```
136
+
137
+ ## API Endpoints
138
+
139
+ | Method | Endpoint | Description |
140
+ |--------|----------|-------------|
141
+ | GET | /health | API status |
142
+ | POST | /ingest | Upload and read a data file |
143
+ | POST | /clean | Clean a dataset |
144
+ | POST | /transform | Transform a dataset |
145
+ | POST | /analyse | Analyse a dataset |
146
+ | POST | /visualise | Produce a Vega-Lite chart spec from a dataset |
147
+
148
+ ## Charts
149
+
150
+ The `/visualise` endpoint (and the `visualise_data` MCP tool) accept a `chart`
151
+ name and a `params` object. Each returns a [Vega-Lite](https://vega.github.io/vega-lite/)
152
+ spec dict that any Vega-Lite renderer can display.
153
+
154
+ | Chart | Params | Notes |
155
+ |-------|--------|-------|
156
+ | `histogram` | `column` (numeric), `bins` (int, default 10) | Distribution of a numeric column |
157
+ | `bar_chart` | `column` (any) | Counts per category |
158
+ | `scatter` | `x` (numeric), `y` (numeric) | Relationship between two numeric columns |
159
+ | `line_chart` | `x` (any), `y` (numeric) | `x` may be a date or category; `y` must be numeric |
160
+ | `correlation_heatmap` | `columns` (list, optional) | Correlations across numeric columns; defaults to all numeric columns |
161
+
162
+ A bad chart name, a missing column, or a non-numeric column where a numeric one
163
+ is required returns HTTP 400 (or raises `ValueError` when called directly).
164
+
165
+ ### Example response
166
+
167
+ A call with `{"chart": "histogram", "params": {"column": "age", "bins": 3}}`
168
+ returns a Vega-Lite spec like:
169
+
170
+ ```json
171
+ {
172
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
173
+ "description": "Histogram of age",
174
+ "data": {
175
+ "values": [
176
+ {"bin_start": 23.0, "bin_end": 29.33, "count": 4},
177
+ {"bin_start": 29.33, "bin_end": 35.67, "count": 3},
178
+ {"bin_start": 35.67, "bin_end": 42.0, "count": 1}
179
+ ]
180
+ },
181
+ "mark": "bar",
182
+ "encoding": {
183
+ "x": {"field": "bin_start", "type": "quantitative"},
184
+ "x2": {"field": "bin_end", "type": "quantitative"},
185
+ "y": {"field": "count", "type": "quantitative"}
186
+ }
187
+ }
188
+ ```
189
+
190
+ Paste the returned spec into the [Vega-Lite editor](https://vega.github.io/editor/)
191
+ or render it with any Vega-Lite-compatible frontend.
192
+
193
+ ## MCP Tools
194
+
195
+ The MCP server exposes each capability as a Claude-native tool:
196
+
197
+ | Tool | Arguments | Description |
198
+ |------|-----------|-------------|
199
+ | `ingest_file` | `file_path` | Read a data file (CSV, JSON, Excel, Parquet) from disk |
200
+ | `clean_data` | `data`, `drop_null_threshold`, `remove_dupes`, `standardise_cols` | Remove nulls, duplicates, and standardise column names |
201
+ | `transform_data` | `data`, `operation`, `params` | Apply a named transform (filter, select, rename, sort, group, add column) |
202
+ | `analyse_data` | `data` | Full statistical report (summary, correlations, missing, outliers) |
203
+ | `visualise_data` | `data`, `chart`, `params` | Produce a Vega-Lite chart spec (see [Charts](#charts) for names and params) |
204
+
205
+ The `visualise_data` tool uses the same chart names and params as the `/visualise`
206
+ endpoint and returns a Vega-Lite spec dict.
207
+
208
+ ## Supported formats
209
+ CSV, JSON, Excel (.xlsx), Parquet
210
+
211
+ ## License
212
+ MIT
@@ -0,0 +1,175 @@
1
+ # DataProcessing AI
2
+
3
+ An AI-native Python library for data processing and transformation.
4
+ Built to be called by any AI agent via REST API, MCP server, or direct Python import.
5
+
6
+ ## What it does
7
+
8
+ - **Ingest** - read CSV, JSON, Excel, Parquet files into a standard format
9
+ - **Clean** - remove nulls, duplicates, outliers, standardise column names
10
+ - **Transform** - filter, sort, group, pivot, merge, reshape datasets
11
+ - **Analyse** - generate statistics, correlations, distributions, outlier reports
12
+ - **Visualise** - produce Vega-Lite chart specs (histogram, bar, scatter, line, correlation heatmap)
13
+
14
+ ## Three ways to use it
15
+
16
+ ### 1. REST API (any AI, any language)
17
+
18
+ Install with the API extra, then start the server:
19
+ ```bash
20
+ pip install "dataprocessing-ai[api]"
21
+ uvicorn dataprocessing.api:app --host 0.0.0.0 --port 8000
22
+ ```
23
+
24
+ Call it:
25
+ ```bash
26
+ curl -X POST http://localhost:8000/ingest -F "file=@data.csv"
27
+ curl -X POST http://localhost:8000/clean -H "Content-Type: application/json" -d '{"data": [...]}'
28
+ curl -X POST http://localhost:8000/transform -H "Content-Type: application/json" -d '{"data": [...], "operation": "filter_rows", "params": {"column": "age", "operator": "gt", "value": 25}}'
29
+ curl -X POST http://localhost:8000/analyse -H "Content-Type: application/json" -d '{"data": [...]}'
30
+ curl -X POST http://localhost:8000/visualise -H "Content-Type: application/json" -d '{"data": [...], "chart": "histogram", "params": {"column": "age", "bins": 10}}'
31
+ ```
32
+
33
+ ### 2. MCP Server (Claude native tools)
34
+
35
+ Install with the MCP extra:
36
+ ```bash
37
+ pip install "dataprocessing-ai[mcp]"
38
+ ```
39
+
40
+ Then add to your `claude_desktop_config.json`:
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "dataprocessing": {
45
+ "command": "dataprocessing-mcp"
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ No paths, no `PYTHONPATH` — the installed package provides the
52
+ `dataprocessing-mcp` command directly.
53
+
54
+ ### 3. Python package (direct import)
55
+
56
+ ```python
57
+ from dataprocessing.ingest import read_file
58
+ from dataprocessing.clean import clean_all
59
+ from dataprocessing.transform import filter_rows
60
+ from dataprocessing.analyse import full_report
61
+ from dataprocessing.visualise import histogram, correlation_heatmap
62
+
63
+ df = read_file("data.csv")
64
+ df = clean_all(df)
65
+ report = full_report(df)
66
+
67
+ # Chart functions return Vega-Lite spec dicts (JSON-serialisable)
68
+ hist_spec = histogram(df, column="age", bins=10)
69
+ heatmap_spec = correlation_heatmap(df)
70
+ ```
71
+
72
+ ## Installation
73
+
74
+ ```bash
75
+ pip install dataprocessing-ai
76
+ ```
77
+
78
+ That gives you the core library (`ingest`, `clean`, `transform`, `analyse`,
79
+ `visualise`) with a minimal dependency footprint.
80
+
81
+ Optional extras add the interfaces and file formats you need:
82
+
83
+ ```bash
84
+ pip install "dataprocessing-ai[mcp]" # MCP server (for Claude and other agents)
85
+ pip install "dataprocessing-ai[api]" # REST API server
86
+ pip install "dataprocessing-ai[formats]" # Excel (.xlsx) and Parquet support
87
+ pip install "dataprocessing-ai[all]" # everything
88
+ ```
89
+
90
+ ### Installing from source
91
+
92
+ ```bash
93
+ git clone https://github.com/Techlon/dataprocessing-ai.git
94
+ cd dataprocessing-ai
95
+ python3 -m venv .venv
96
+ source .venv/bin/activate
97
+ pip install -e ".[dev]"
98
+ ```
99
+
100
+ ## API Endpoints
101
+
102
+ | Method | Endpoint | Description |
103
+ |--------|----------|-------------|
104
+ | GET | /health | API status |
105
+ | POST | /ingest | Upload and read a data file |
106
+ | POST | /clean | Clean a dataset |
107
+ | POST | /transform | Transform a dataset |
108
+ | POST | /analyse | Analyse a dataset |
109
+ | POST | /visualise | Produce a Vega-Lite chart spec from a dataset |
110
+
111
+ ## Charts
112
+
113
+ The `/visualise` endpoint (and the `visualise_data` MCP tool) accept a `chart`
114
+ name and a `params` object. Each returns a [Vega-Lite](https://vega.github.io/vega-lite/)
115
+ spec dict that any Vega-Lite renderer can display.
116
+
117
+ | Chart | Params | Notes |
118
+ |-------|--------|-------|
119
+ | `histogram` | `column` (numeric), `bins` (int, default 10) | Distribution of a numeric column |
120
+ | `bar_chart` | `column` (any) | Counts per category |
121
+ | `scatter` | `x` (numeric), `y` (numeric) | Relationship between two numeric columns |
122
+ | `line_chart` | `x` (any), `y` (numeric) | `x` may be a date or category; `y` must be numeric |
123
+ | `correlation_heatmap` | `columns` (list, optional) | Correlations across numeric columns; defaults to all numeric columns |
124
+
125
+ A bad chart name, a missing column, or a non-numeric column where a numeric one
126
+ is required returns HTTP 400 (or raises `ValueError` when called directly).
127
+
128
+ ### Example response
129
+
130
+ A call with `{"chart": "histogram", "params": {"column": "age", "bins": 3}}`
131
+ returns a Vega-Lite spec like:
132
+
133
+ ```json
134
+ {
135
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
136
+ "description": "Histogram of age",
137
+ "data": {
138
+ "values": [
139
+ {"bin_start": 23.0, "bin_end": 29.33, "count": 4},
140
+ {"bin_start": 29.33, "bin_end": 35.67, "count": 3},
141
+ {"bin_start": 35.67, "bin_end": 42.0, "count": 1}
142
+ ]
143
+ },
144
+ "mark": "bar",
145
+ "encoding": {
146
+ "x": {"field": "bin_start", "type": "quantitative"},
147
+ "x2": {"field": "bin_end", "type": "quantitative"},
148
+ "y": {"field": "count", "type": "quantitative"}
149
+ }
150
+ }
151
+ ```
152
+
153
+ Paste the returned spec into the [Vega-Lite editor](https://vega.github.io/editor/)
154
+ or render it with any Vega-Lite-compatible frontend.
155
+
156
+ ## MCP Tools
157
+
158
+ The MCP server exposes each capability as a Claude-native tool:
159
+
160
+ | Tool | Arguments | Description |
161
+ |------|-----------|-------------|
162
+ | `ingest_file` | `file_path` | Read a data file (CSV, JSON, Excel, Parquet) from disk |
163
+ | `clean_data` | `data`, `drop_null_threshold`, `remove_dupes`, `standardise_cols` | Remove nulls, duplicates, and standardise column names |
164
+ | `transform_data` | `data`, `operation`, `params` | Apply a named transform (filter, select, rename, sort, group, add column) |
165
+ | `analyse_data` | `data` | Full statistical report (summary, correlations, missing, outliers) |
166
+ | `visualise_data` | `data`, `chart`, `params` | Produce a Vega-Lite chart spec (see [Charts](#charts) for names and params) |
167
+
168
+ The `visualise_data` tool uses the same chart names and params as the `/visualise`
169
+ endpoint and returns a Vega-Lite spec dict.
170
+
171
+ ## Supported formats
172
+ CSV, JSON, Excel (.xlsx), Parquet
173
+
174
+ ## License
175
+ MIT
File without changes
@@ -0,0 +1,56 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+ from typing import List, Dict, Any
4
+
5
+ def summary_stats(df, columns=None):
6
+ if columns is None:
7
+ columns = df.select_dtypes(include=[np.number]).columns
8
+ stats = {}
9
+ for column in columns:
10
+ col_data = df[column]
11
+ stats[column] = {
12
+ 'count': len(col_data), 'mean': col_data.mean(), 'median': col_data.median(),
13
+ 'std': col_data.std(), 'min': col_data.min(), 'max': col_data.max(),
14
+ 'quartiles': {'25%': np.percentile(col_data, 25), '75%': np.percentile(col_data, 75)}
15
+ }
16
+ return stats
17
+
18
+ def correlation_matrix(df, columns=None):
19
+ if columns is None:
20
+ columns = df.select_dtypes(include=[np.number]).columns
21
+ return df[columns].corr().to_dict()
22
+
23
+ def value_counts(df, column):
24
+ if not pd.api.types.is_numeric_dtype(df[column]):
25
+ raise ValueError("Column must be numeric")
26
+ return df[column].value_counts().to_dict()
27
+
28
+ def missing_report(df):
29
+ total = len(df)
30
+ report = {}
31
+ for column in df.columns:
32
+ null_count = df[column].isnull().sum()
33
+ percentage = (null_count / total) * 100 if total > 0 else 0
34
+ report[column] = {'missing_count': int(null_count), 'percentage': float(percentage)}
35
+ return report
36
+
37
+ def distribution(df, column, bins=10):
38
+ if not pd.api.types.is_numeric_dtype(df[column]):
39
+ raise ValueError("Column must be numeric")
40
+ hist, bin_edges = np.histogram(df[column], bins=bins)
41
+ return {'bin_edges': list(bin_edges), 'counts': list(hist)}
42
+
43
+ def detect_outliers(df, columns=None):
44
+ if columns is None:
45
+ columns = df.select_dtypes(include=[np.number]).columns
46
+ outliers = {}
47
+ for column in columns:
48
+ q1 = np.percentile(df[column], 25); q3 = np.percentile(df[column], 75)
49
+ iqr = q3 - q1
50
+ lo = q1 - 1.5 * iqr; hi = q3 + 1.5 * iqr
51
+ outliers[column] = list(df[(df[column] < lo) | (df[column] > hi)].index)
52
+ return outliers
53
+
54
+ def full_report(df):
55
+ return {'summary_stats': summary_stats(df), 'correlation_matrix': correlation_matrix(df),
56
+ 'missing_values': missing_report(df), 'outliers': detect_outliers(df)}
@@ -0,0 +1,162 @@
1
+ """
2
+ DataProcessing REST API
3
+ Exposes ingest, clean, transform and analyse modules over HTTP.
4
+ Any AI agent can call these endpoints.
5
+ """
6
+ from fastapi import FastAPI, UploadFile, File, HTTPException
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from pydantic import BaseModel
9
+ from typing import Optional, List, Dict, Any
10
+ import pandas as pd
11
+ import io
12
+ import json
13
+
14
+ from dataprocessing.clean import drop_nulls, remove_duplicates, standardise_columns
15
+ from dataprocessing.transform import (
16
+ filter_rows, select_columns, rename_columns,
17
+ sort_rows, group_and_aggregate, pivot, add_column
18
+ )
19
+ from dataprocessing.analyse import full_report
20
+
21
+ from dataprocessing.visualise import (
22
+ histogram, bar_chart, scatter, line_chart, correlation_heatmap
23
+ )
24
+
25
+ app = FastAPI(title="DataProcessing API", version="0.1.0")
26
+
27
+ app.add_middleware(
28
+ CORSMiddleware,
29
+ allow_origins=["*"],
30
+ allow_methods=["*"],
31
+ allow_headers=["*"],
32
+ )
33
+
34
+ def df_to_json(df):
35
+ return json.loads(df.where(df.notna(), other=None).to_json(orient="records"))
36
+
37
+ def to_native(obj):
38
+ """Recursively convert numpy scalars/arrays to JSON-serialisable Python types.
39
+
40
+ full_report() returns dicts containing numpy int64/float64 values and numpy
41
+ arrays, which FastAPI's encoder cannot serialise. This normalises them.
42
+ """
43
+ import numpy as np
44
+ if isinstance(obj, dict):
45
+ return {to_native(k): to_native(v) for k, v in obj.items()}
46
+ if isinstance(obj, (list, tuple)):
47
+ return [to_native(v) for v in obj]
48
+ if isinstance(obj, np.generic):
49
+ return obj.item()
50
+ if isinstance(obj, np.ndarray):
51
+ return [to_native(v) for v in obj.tolist()]
52
+ if isinstance(obj, float) and (obj != obj): # NaN -> null
53
+ return None
54
+ return obj
55
+
56
+ class CleanRequest(BaseModel):
57
+ data: List[Dict[str, Any]]
58
+ drop_null_threshold: float = 0.5
59
+ remove_outliers: bool = False
60
+
61
+ class TransformRequest(BaseModel):
62
+ data: List[Dict[str, Any]]
63
+ operation: str
64
+ params: Dict[str, Any] = {}
65
+
66
+ class AnalyseRequest(BaseModel):
67
+ data: List[Dict[str, Any]]
68
+
69
+ @app.get("/health")
70
+ def health():
71
+ return {"status": "ok", "version": "0.1.0"}
72
+
73
+ @app.post("/ingest")
74
+ async def ingest(file: UploadFile = File(...)):
75
+ try:
76
+ contents = await file.read()
77
+ ext = file.filename.rsplit(".", 1)[-1].lower()
78
+ if ext == "csv":
79
+ df = pd.read_csv(io.BytesIO(contents))
80
+ elif ext == "json":
81
+ df = pd.read_json(io.BytesIO(contents))
82
+ elif ext == "xlsx":
83
+ df = pd.read_excel(io.BytesIO(contents))
84
+ elif ext == "parquet":
85
+ df = pd.read_parquet(io.BytesIO(contents))
86
+ else:
87
+ raise HTTPException(status_code=400, detail=f"Unsupported file type: {ext}")
88
+ return {"data": df_to_json(df), "rows": len(df), "columns": list(df.columns)}
89
+ except HTTPException:
90
+ raise
91
+ except Exception as e:
92
+ raise HTTPException(status_code=500, detail=str(e))
93
+
94
+ @app.post("/clean")
95
+ def clean(req: CleanRequest):
96
+ try:
97
+ df = pd.DataFrame(req.data)
98
+ df = drop_nulls(df, threshold=req.drop_null_threshold)
99
+ df = remove_duplicates(df)
100
+ df = standardise_columns(df)
101
+ return {"data": df_to_json(df), "rows": len(df), "columns": list(df.columns)}
102
+ except Exception as e:
103
+ raise HTTPException(status_code=500, detail=str(e))
104
+
105
+ @app.post("/transform")
106
+ def transform(req: TransformRequest):
107
+ try:
108
+ df = pd.DataFrame(req.data)
109
+ ops = {
110
+ "filter_rows": filter_rows,
111
+ "select_columns": select_columns,
112
+ "rename_columns": rename_columns,
113
+ "sort_rows": sort_rows,
114
+ "group_and_aggregate": group_and_aggregate,
115
+ "pivot": pivot,
116
+ "add_column": add_column,
117
+ }
118
+ if req.operation not in ops:
119
+ raise HTTPException(status_code=400, detail=f"Unknown operation: {req.operation}. Valid: {list(ops.keys())}")
120
+ result = ops[req.operation](df, **req.params)
121
+ return {"data": df_to_json(result), "rows": len(result), "columns": list(result.columns)}
122
+ except HTTPException:
123
+ raise
124
+ except Exception as e:
125
+ raise HTTPException(status_code=500, detail=str(e))
126
+
127
+ @app.post("/analyse")
128
+ def analyse(req: AnalyseRequest):
129
+ try:
130
+ df = pd.DataFrame(req.data)
131
+ return to_native(full_report(df))
132
+ except Exception as e:
133
+ raise HTTPException(status_code=500, detail=str(e))
134
+
135
+ class VisualiseRequest(BaseModel):
136
+ data: List[Dict[str, Any]]
137
+ chart: str
138
+ params: Dict[str, Any] = {}
139
+
140
+ @app.post("/visualise")
141
+ def visualise(req: VisualiseRequest):
142
+ try:
143
+ df = pd.DataFrame(req.data)
144
+ charts = {
145
+ "histogram": histogram,
146
+ "bar_chart": bar_chart,
147
+ "scatter": scatter,
148
+ "line_chart": line_chart,
149
+ "correlation_heatmap": correlation_heatmap,
150
+ }
151
+ if req.chart not in charts:
152
+ raise HTTPException(
153
+ status_code=400,
154
+ detail=f"Unknown chart: {req.chart}. Valid: {list(charts.keys())}",
155
+ )
156
+ result = charts[req.chart](df, **req.params)
157
+ return to_native(result)
158
+ except HTTPException:
159
+ raise
160
+ except Exception as e:
161
+ # bad/missing/non-numeric column raises ValueError -> client error
162
+ raise HTTPException(status_code=400, detail=str(e))
@@ -0,0 +1,60 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+ from typing import Optional
4
+
5
+ def drop_nulls(df, threshold=0.5):
6
+ cols_to_drop = df.columns[df.isnull().mean() > threshold]
7
+ df.drop(columns=cols_to_drop, inplace=True)
8
+ df.dropna(inplace=True)
9
+ return df
10
+
11
+ def fix_types(df):
12
+ for col in df.columns:
13
+ # Check bool BEFORE numeric: pandas treats bool as a numeric dtype, so
14
+ # the numeric branch would otherwise swallow boolean columns.
15
+ if pd.api.types.is_bool_dtype(df[col]):
16
+ df[col] = df[col].astype(bool)
17
+ elif pd.api.types.is_numeric_dtype(df[col]):
18
+ try:
19
+ df[col] = pd.to_numeric(df[col], errors='coerce')
20
+ except Exception as e:
21
+ print(f"Error converting column {col} to numeric: {e}")
22
+ elif pd.api.types.is_datetime64_any_dtype(df[col]):
23
+ continue
24
+ else:
25
+ try:
26
+ df[col] = pd.to_datetime(df[col], errors='coerce')
27
+ except Exception as e:
28
+ print(f"Error converting column {col} to datetime: {e}")
29
+ return df
30
+
31
+ def remove_duplicates(df, subset=None):
32
+ if subset is not None:
33
+ df.drop_duplicates(subset=subset, inplace=True)
34
+ else:
35
+ df.drop_duplicates(inplace=True)
36
+ return df
37
+
38
+ def remove_outliers(df, columns=None, method='iqr'):
39
+ if method == 'iqr':
40
+ if columns is None:
41
+ numeric_df = df.select_dtypes(include=[np.number])
42
+ else:
43
+ numeric_df = df[columns]
44
+ Q1 = numeric_df.quantile(0.25); Q3 = numeric_df.quantile(0.75)
45
+ IQR = Q3 - Q1
46
+ lower = Q1 - 1.5 * IQR; upper = Q3 + 1.5 * IQR
47
+ df = df[~((numeric_df < lower) | (numeric_df > upper)).any(axis=1)]
48
+ return df
49
+
50
+ def standardise_columns(df):
51
+ df.columns = [col.lower().replace(" ", "_") for col in df.columns]
52
+ return df
53
+
54
+ def clean_all(df):
55
+ df = drop_nulls(df)
56
+ df = fix_types(df)
57
+ df = remove_duplicates(df)
58
+ df = remove_outliers(df)
59
+ df = standardise_columns(df)
60
+ return df