Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI | |
| from pydantic import BaseModel | |
| import numpy as np | |
| import pandas as pd | |
| import joblib | |
| from supabase import create_client | |
| import os | |
| from dotenv import load_dotenv | |
| from datetime import datetime | |
| # ---------------- LOAD ENV ---------------- | |
| load_dotenv() | |
| SUPABASE_URL = os.getenv("SUPABASE_URL") | |
| SUPABASE_KEY = os.getenv("SUPABASE_KEY") | |
| supabase = create_client(SUPABASE_URL, SUPABASE_KEY) | |
| # ---------------- LOAD MODEL ---------------- | |
| model = joblib.load("xgb_model.pkl") | |
| scaler = joblib.load("xgb_scaler.pkl") | |
| le = joblib.load("label_encoder.pkl") | |
| # ---------------- FASTAPI ---------------- | |
| app = FastAPI(title="Energy Monitor API") | |
| # ---------------- INPUT SCHEMA ---------------- | |
| class Features(BaseModel): | |
| mean: float | |
| max: float | |
| min: float | |
| std: float | |
| range: float | |
| peak_count: int | |
| slope: float | |
| power: float | |
| relay: bool | |
| # ---------------- FEATURE ENGINEERING ---------------- | |
| def transform_features(data: Features): | |
| mean = data.mean | |
| mx = data.max | |
| mn = data.min | |
| std = data.std | |
| rng = data.range | |
| peak = data.peak_count | |
| slope = data.slope | |
| energy = data.power * (40 * 0.04) / 3600 | |
| ratio = mx / (mn + 1) | |
| cv = std / (mean + 1) | |
| peak_ratio = peak / 40 | |
| delta_mean = std * 0.8 | |
| power_density = mean / (rng + 1) | |
| return [ | |
| mean, mx, mn, std, rng, | |
| peak, slope, | |
| energy, ratio, | |
| cv, peak_ratio, | |
| delta_mean, power_density | |
| ] | |
| # ---------------- ROOT ---------------- | |
| def root(): | |
| return {"message": "Energy API running ๐"} | |
| # ---------------- HEALTH ---------------- | |
| def health(): | |
| return {"status": "ok"} | |
| # ---------------- PREDICT ---------------- | |
| def predict(data: Features): | |
| if not data.relay: | |
| # No power โ skip prediction | |
| appliance = "Overloaded" | |
| confidence = 1.0 | |
| energy = 0.0 # no energy usage | |
| # store in DB | |
| supabase.table("energy_logs").insert({ | |
| "timestamp": datetime.utcnow().isoformat(), | |
| "appliance": appliance, | |
| "confidence": confidence, | |
| "mean": data.mean, | |
| "max": data.max, | |
| "min": data.min, | |
| "std": data.std, | |
| "range": data.range, | |
| "peak_count": data.peak_count, | |
| "slope": data.slope, | |
| "energy": energy, | |
| "power": 0.0, | |
| "relay": data.relay | |
| }).execute() | |
| return { | |
| "appliance": appliance, | |
| "confidence": confidence, | |
| "relay": data.relay | |
| } | |
| features = transform_features(data) | |
| columns = [ | |
| "mean","max","min","std","range", | |
| "peak_count","slope", | |
| "energy","ratio", | |
| "cv","peak_ratio", | |
| "delta_mean","power_density" | |
| ] | |
| df = pd.DataFrame([features], columns=columns) | |
| X = scaler.transform(df) | |
| probs = model.predict_proba(X)[0] | |
| pred_index = np.argmax(probs) | |
| appliance = le.inverse_transform([pred_index])[0] | |
| confidence = float(np.max(probs)) | |
| # ๐ฅ Optional threshold (lower to reduce Unknown) | |
| if confidence < 0.3: | |
| appliance = "Unknown" | |
| # ---------------- ENERGY CALC ---------------- | |
| time_seconds = 40 * 0.04 # 40 samples ร 40ms = 1.6 sec | |
| energy = (data.power * time_seconds) / 3600.0 | |
| # ---------------- STORE IN SUPABASE ---------------- | |
| supabase.table("energy_logs").insert({ | |
| "timestamp": datetime.utcnow().isoformat(), | |
| "appliance": appliance, | |
| "confidence": confidence, | |
| "mean": data.mean, | |
| "max": data.max, | |
| "min": data.min, | |
| "std": data.std, | |
| "range": data.range, | |
| "peak_count": data.peak_count, | |
| "slope": data.slope, | |
| "energy": energy, | |
| "power": data.power, | |
| "relay": data.relay, | |
| }).execute() | |
| return { | |
| "appliance": appliance, | |
| "confidence": round(confidence, 3), | |
| "relay": data.relay | |
| } | |
| # ---------------- GET LATEST ---------------- | |
| def latest(): | |
| res = supabase.table("energy_logs") \ | |
| .select("*") \ | |
| .order("timestamp", desc=True) \ | |
| .limit(1) \ | |
| .execute() | |
| return res.data[0] if res.data else {} | |
| # ---------------- GET HISTORY ---------------- | |
| def history(): | |
| res = supabase.table("energy_logs") \ | |
| .select("*") \ | |
| .order("timestamp", desc=True) \ | |
| .limit(50) \ | |
| .execute() | |
| return res.data | |
| # ---------------- MONTHLY ENERGY ---------------- | |
| def monthly_energy(): | |
| res = supabase.table("energy_logs") \ | |
| .select("energy") \ | |
| .execute() | |
| total = sum([r["energy"] for r in res.data]) | |
| return { | |
| "total_energy": total | |
| } | |
| # ---------------- SERVER ---------------- | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run("app:app", host="0.0.0.0", port=7860) |