← Back to projects

Project 02

AutoInsight: End-to-End AutoML App

Type Full-stack ML Application
Stack Streamlit · XGBoost · LightGBM · SHAP · Optuna · Groq
License GPL-3.0
Streamlit XGBoost LightGBM CatBoost SHAP Optuna Groq API Plotly pytest pandas · NumPy
↗ View on GitHub ⚡ Try on Hugging Face

What it is

AutoInsight is a browser-based AutoML system built for people who need to understand their data but don't want to spend three days wrangling a Jupyter notebook to do it. You upload a CSV, pick a target column, and the system handles the rest: profiling the data, preprocessing it, training a leaderboard of models, computing SHAP feature importances, and generating a plain-language explanation of what the model found, all with no code required.

The project started as a personal exploration of what a lightweight, transparent, and privacy-aware AutoML tool could look like for tabular data. Most existing AutoML tools are either too heavy, too opaque, or both. The goal here was to build something that's fast to run, easy to understand, and honest about what it's doing.

7 classifiers + 7 regressors trained in parallel · Stratified k-fold CV throughout

Bayesian hyperparameter tuning via Optuna (40 trials, TPE sampler) · Streamed LLM responses via Groq API

Raw user data never sent to an external API, LLM only receives aggregated metrics

The pipeline

When a file is uploaded, AutoInsight runs a profiling step before anything else. It identifies column types (numerical, categorical, datetime), computes missing value ratios, flags near-constant features where a single value appears in more than 95% of rows, detects high-correlation pairs using a Pearson threshold of 0.85, and checks class balance, flagging if a dominant class appears in more than 80% of rows. These findings are shown in the UI and passed to the LLM as context.

Preprocessing handles missing values (median imputation for skewed numerical columns, mean otherwise, mode for categoricals), datetime decomposition into year/month/day/hour/day-of-week features, IQR-based outlier capping fitted on the training set only, categorical encoding (one-hot for low-cardinality columns with ≤10 unique values, label encoding for higher-cardinality ones), StandardScaler normalisation, and SelectKBest feature selection retaining the top 30 features by mutual information score. All thresholds are configurable via config.yaml or environment variables.

Once preprocessing is done, seven models train in parallel with cross-validation. Classification tasks run Logistic Regression, Random Forest, Extra Trees, Gradient Boosting, XGBoost, LightGBM, and CatBoost; regression tasks use the same ensemble minus Logistic Regression, plus Linear Regression. If a model crashes during training, the pipeline continues with the remaining ones , it only fails if every single model fails.

Hyperparameter tuning

Tuning is optional and user-triggered from the UI. When enabled, it runs Optuna's TPE sampler for 40 trials on the top-ranked models from the leaderboard. Each model has a defined search space covering tree depth, number of estimators, learning rate, regularisation strength, and leaf count. SHAP analysis always prefers the tuned version of a model when both exist.

The LLM integration

This was the most deliberate design decision in the whole project. The LLM layer uses the Groq API with models like llama-3.3-70b-versatile at temperature 0.2, conservative enough to keep outputs consistent without being completely rigid.

The key constraint: the LLM only ever receives aggregated metrics. Leaderboard scores, SHAP values, feature importances, dataset profile statistics. It never sees raw rows. This was deliberate for two reasons. First, it reduces the chance of hallucinations, because the model can't fabricate dataset-specific claims beyond what it's explicitly told. Second, and more importantly, it means potentially sensitive user data never leaves the browser. The privacy guarantee is structural, not policy-based.

The system prompt constrains the LLM to respond only in valid JSON and to avoid comparing results against external benchmarks unless those benchmarks are explicitly provided. Prompts live as plain text files in the prompts/ directory and are loaded at runtime, so editing system behaviour doesn't require touching any Python code.

For the Q&A tab, responses stream word-by-word via the Groq streaming API, which makes the interaction feel genuinely responsive rather than giving you a spinner followed by a wall of text.

Evaluation metrics

Classification tasks report AUC (one-vs-rest for multiclass), weighted F1, accuracy, and a confusion matrix. Regression reports RMSE, MAE, and R². All results go into a ranked leaderboard ordered by the primary metric for the detected task type.

What I'd change

The biggest limitation is that the pipeline only supports tabular CSV data, images, text corpora, and proper time-series with sequential dependencies aren't handled. Datetime columns get decomposed into component features, which captures some temporal signal but loses any sequential structure.

There's a stacking ensemble in the codebase that isn't exposed through the main UI. It works, but adding another layer of complexity to the UI without a good way to explain why stacking helped felt like the wrong trade-off for a tool aimed at non-technical users.

If I were starting over, I'd think harder about how to communicate model uncertainty, not just which model ranked first, but how confident we should be in that ranking given the dataset size. A 3-point AUC difference on 500 rows means something very different than the same gap on 50,000.

Full source code and documentation on GitHub →