EcoSavvy AI
Completed
Hackathon · AI

EcoSavvy AI

2023

HackOwasp entry around e-waste handling. An Express/MySQL app serves the login, register, dashboard and statistics pages and exposes auth, dashboard and data routes, while a detached python/ folder holds scikit-learn models pickled into the repo: a LinearRegression over weight, battery, screen, RAM and storage for device composition, an SVR for siting collection points, and a random forest ranking state-level volume. All three are trained on data the team generated rather than collected — one generator assigns composition as a uniform random number — and nothing in the Node app loads a pickle or shells out to Python, so no endpoint runs a model.

Built with
Node.jsNode.js
ExpressExpress
MySQLMySQL
PythonPython
scikit-learnscikit-learn
JavaScriptJavaScript
Project Details
RESOURCES

STATUS
Completed
YEAR

2023

TYPE

Hackathon · AI

TAGS
Hackathon
Sustainability
Machine Learning

E-waste recycling has two questions worth predicting: what is actually inside a device once it arrives, and where you should put the facility that receives it. EcoSavvy was a HackOwasp entry that took both, with an Express dashboard on the front and a folder of scikit-learn models behind it.

The honest framing is that neither question had a dataset behind it. Recovering composition from a device's specifications needs teardown data that nobody publishes, and siting a collection facility needs regional volume figures that in India live in Central Pollution Control Board reports rather than in a CSV. Over a weekend, with a demo to give, the team wrote generators instead. That decision is the most interesting thing in the repo, and it determines what every number on the dashboard is worth.

What the Express side is

index.js is 36 lines and mounts three routers. Pages are raw HTML served with sendFile - there is no view engine and no templating anywhere, so the shared header is injected client-side by a jQuery snippet that does $("#header").load("../html/header.html") on every dashboard page. Four static mounts cover /css, /html, /js and /media.

  • GET /, /login, /register and /testing off the root.
  • POST /auth/register inserts into users and maps MySQL's ER_DUP_ENTRY to a 409.
  • POST /auth/login selects by username and compares the password in JavaScript.
  • Seven pages under /dashboard - statistics at the root, then logistics, waste status, inventory capacity, current inventory, components available and shred composition.
  • GET /get/logistics and GET /get/inventory, each a SELECT * returned as JSON.

That is the whole surface. Three of the route files open their own MySQL connection to the ecosavvyai database as root with an empty password, and there is no session layer at all - a successful login is a redirect and nothing more, so /dashboard and /get answer to anyone who asks. Passwords go into the table as plaintext. The only schema in the repo is a CREATE TABLE inventory plus 32 inserts sitting in a file called hello.txt; the users and logistics tables exist only as implications of the queries that read them.

Where the models live, and what calls them

Nothing does. The python/ directory holds four subfolders and nine scripts, and not one of them is invoked from the Node app - there is no endpoint anywhere that runs a model, loads a pickle or shells out to Python. The two halves of the project were built to be demonstrated next to each other rather than wired together, which is a fair weekend tradeoff but worth saying out loud, because it means every figure the dashboard displays comes from a MySQL table rather than from a prediction.

The data problem, stated plainly

Two of the four model folders are named "(Based on random data)", and that is accurate. gen_data.py synthesises 5,000 candidate sites and defines capacity as a fixed linear combination of the inputs; gendata.py generates 1,000 devices and assigns composition as a uniform random number. The regressors therefore recover a formula the generator wrote, or nothing at all. What the pipeline demonstrates is the shape - feature encoding, scaling, train/test split, serialised model, served prediction - with real e-waste data as the substitution that was never made.

It is worth seeing the two failure modes side by side, because they fail in opposite directions. In the siting case the target is written as 0.5*latitude + 0.3*longitude + 1.5*population/1000 + 0.7*gdp/1000 + 2*distance, with no noise term at all, and then train_data.py fits an SVR(kernel='rbf', C=100, gamma=0.1) to recover it. Any score that reports is a measure of how well an RBF kernel approximates a straight line, and since the population term is three orders of magnitude larger than the others, the model is mostly learning 1.5 * population/1000. In the composition case the target is random.uniform(0, 100) appended to each row, statistically independent of weight, battery, screen size, RAM and storage, so LinearRegression has nothing to find and the printed R-squared should sit at roughly zero. The state-level ranking is the same story again: training_data.py draws E-Waste (MT) as an independent uniform over 30 rows, and new.py then prints the top ten states by predicted tonnage, which is a ranking of memorised noise.

What it does

  • Auth pages over MySQL - register with duplicate-username handling that returns a proper 409, login, and a redirect into the dashboard.
  • Seven dashboard views routed off /dashboard: logistics, waste status, inventory capacity, current inventory, components available, shred composition, and statistics.
  • A read API at /get/logistics and /get/inventory serving the underlying tables as JSON, which the two data-backed pages fetch and render into HTML tables client-side.
  • Composition regression. trainer.py one-hot encodes device type through a ColumnTransformer, scales the numeric features, fits a LinearRegression over weight, battery capacity, screen size, RAM and storage, and reports MSE and R-squared on a held-out fifth.
  • An interactive checker that prompts for those six fields at the terminal and prints the predicted recoverable composition for one device.
  • Site capacity prediction. train_data.py fits an SVR(kernel='rbf', C=100, gamma=0.1, epsilon=0.1) over latitude, longitude, population, GDP and distance to nearest city, and serialises the fitted model to e-waste-model.pkl.
  • State-level volume ranking with a RandomForestRegressor over population, urban share, GDP, literacy rate and internet penetration, printing the top ten states by predicted tonnage in metric tons.
  • A component lookup over appliance_dataset.csv that returns which parts of an appliance are still worth recovering given its age. It is a pandas filter over six rows, with no model involved despite the folder name.
  • A rule-based disposal recommendation on the waste-status page - shred, disassemble or refurbish - decided by an if/else over the damage percentage and the age, in the browser.
  • Trained artifacts checked into the repo - ewaste_model.pkl, e-waste-model.pkl, rf_model.pkl and logistic_regression_model.joblib.

The parts that would not survive a second day

Reading it back, the interesting failures are in the seams rather than in the models. Neither trainer saves its StandardScaler or its ColumnTransformer, only the estimator, so none of the four pickles can be loaded and used correctly afterwards. predict_data.py demonstrates exactly that: it fits a fresh scaler on the single row it is trying to predict, which standardises every feature to zero, so it returns the same number whatever coordinates you hand it. checker.py reads e-Twaste_data.csv, a filename that does not exist, and refits the whole pipeline from scratch rather than loading the model that was just trained. Two of the four checked-in artifacts are orphans whose recorded feature names - population density, urbanisation rate, e-waste generation rate - match no CSV and no script in the tree, so they came from a notebook that was never committed.

The front end has its own version of the same gap. Both data-backed pages fetch from /get, write the response into localStorage, and then read localStorage synchronously on the next line, before the fetch has resolved. The table you see is always the previous page load's copy, and on a first-ever visit the parse returns null and the render throws. Two of the seven dashboard pages are six-line stubs with a header loader and nothing else, and the statistics page is a CSS mock chart with 2018 dollar figures still in it.

Built over a hackathon weekend with two teammates. The Express app and the model plumbing both run; the numbers they produce are the part that would need real inventory data behind them.

Project Details
RESOURCES

STATUS
Completed
YEAR

2023

TYPE

Hackathon · AI

TAGS
Hackathon
Sustainability
Machine Learning