MatCod's picture
Update app.py
ddc4fd0 verified
import os
# Force CPU usage for XGBoost models
os.environ['CUDA_VISIBLE_DEVICES'] = ''
os.environ['OMP_NUM_THREADS'] = '1'
import gradio as gr
import json
import pickle
import pandas as pd
import numpy as np
from datetime import datetime
import glob
class EnergyMLPredictor:
def __init__(self):
self.rf_model = None
self.rf_preprocessor = None
self.xgb_model = None
self.xgb_encoders = None
self.threshold_model_83 = None
self.threshold_model_90 = None
self.threshold_preprocessor = None
self.models_loaded = False
def load_models(self):
"""Load all models with fixed names"""
try:
# Load Random Forest Energy Model
if os.path.exists('rf_energy_model.pkl'):
with open('rf_energy_model.pkl', 'rb') as f:
rf_data = pickle.load(f)
self.rf_model = rf_data['model']
self.rf_preprocessor = rf_data['preprocessor']
print("✅ Loaded Random Forest energy model")
else:
print("❌ rf_energy_model.pkl not found")
# Load XGBoost Energy Model (use same RF model for now)
if os.path.exists('xgboost_energy_model.pkl'):
with open('xgboost_energy_model.pkl', 'rb') as f:
xgb_data = pickle.load(f)
self.xgb_model = xgb_data['model']
self.xgb_encoders = xgb_data.get('preprocessor', None)
print("✅ Loaded XGBoost energy model")
else:
# Use RF model as fallback for XGBoost
self.xgb_model = self.rf_model
self.xgb_encoders = self.rf_preprocessor
print("⚠️ xgboost_energy_model.pkl not found, using RF model as fallback")
# Load Threshold Model 8300
if os.path.exists('xgboost_threshold_8300_model.pkl'):
with open('xgboost_threshold_8300_model.pkl', 'rb') as f:
threshold_data = pickle.load(f)
self.threshold_model_83 = threshold_data['model']
self.threshold_preprocessor = threshold_data.get('preprocessor', None)
# Fix XGBoost compatibility issues
try:
# Remove problematic attributes completely
problematic_attrs = ['use_label_encoder', 'gpu_id', 'predictor', 'tree_method']
for attr in problematic_attrs:
if hasattr(self.threshold_model_83, attr):
delattr(self.threshold_model_83, attr)
# Force CPU settings
self.threshold_model_83.device = 'cpu'
# Wrap predict_proba to handle errors
original_predict_proba = self.threshold_model_83.predict_proba
def safe_predict_proba(X):
try:
return original_predict_proba(X)
except Exception as e:
print(f"Prediction error: {e}")
# Return default probabilities if prediction fails
return [[0.5, 0.5] for _ in range(len(X))]
self.threshold_model_83.predict_proba = safe_predict_proba
except Exception as e:
print(f"Warning: 8300 model setup failed: {e}")
print("✅ Loaded 8300 threshold model (CPU mode)")
else:
print("❌ xgboost_threshold_8300_model.pkl not found")
# Load Threshold Model 9000
if os.path.exists('xgboost_threshold_9000_model.pkl'):
with open('xgboost_threshold_9000_model.pkl', 'rb') as f:
threshold_data = pickle.load(f)
self.threshold_model_90 = threshold_data['model']
# Fix XGBoost compatibility issues
try:
# Remove problematic attributes completely
problematic_attrs = ['use_label_encoder', 'gpu_id', 'predictor', 'tree_method']
for attr in problematic_attrs:
if hasattr(self.threshold_model_90, attr):
delattr(self.threshold_model_90, attr)
# Force CPU settings
self.threshold_model_90.device = 'cpu'
# Wrap predict_proba to handle errors
original_predict_proba = self.threshold_model_90.predict_proba
def safe_predict_proba(X):
try:
return original_predict_proba(X)
except Exception as e:
print(f"Prediction error: {e}")
# Return default probabilities if prediction fails
return [[0.5, 0.5] for _ in range(len(X))]
self.threshold_model_90.predict_proba = safe_predict_proba
except Exception as e:
print(f"Warning: 9000 model setup failed: {e}")
print("✅ Loaded 9000 threshold model (CPU mode)")
else:
print("❌ xgboost_threshold_9000_model.pkl not found")
self.models_loaded = True
return "Models loaded successfully"
except Exception as e:
print(f"Error details: {e}")
import traceback
traceback.print_exc()
return f"Error loading models: {str(e)}"
def predict_threshold(self, json_input):
"""Predict threshold exceedance"""
try:
if not self.models_loaded:
return "Error: Models not loaded"
if not self.threshold_model_83 or not self.threshold_model_90:
return "Error: Threshold models not available"
data = json.loads(json_input)
# Handle both single object and array formats
if not isinstance(data, list):
data = [data]
# Process all items
results_83 = []
results_90 = []
for item in data:
# Parse input data
date_obj = datetime.strptime(item['data'], '%Y-%m-%d')
# Color mapping
color_mapping = {0: 'incolor', 1: 'verde', 2: 'cinza', 3: 'bronze'}
if isinstance(item['cor'], str):
cor_str = item['cor'].lower()
else:
cor_str = color_mapping.get(item['cor'], 'incolor')
# Get ext_boosting for threshold model
ext_boosting_val = item.get('ext_boosting', item.get('pot_boost', 0.0))
# Create input features (NO temporal features for new models)
input_data = {
'espessura': item['espessura'],
'extracao_forno': item['extracao_forno'],
'porcentagem_caco': item['porcentagem_caco'],
'ext_boosting': ext_boosting_val,
'cor': cor_str,
'prod_e': item.get('Prod_E', item.get('prod_e', 1)),
'prod_l': item.get('Prod_L', item.get('prod_l', 1)),
'autoclave': item.get('autoclave', 1)
}
# Convert to DataFrame
input_df = pd.DataFrame([input_data])
# Preprocess (handle case where no preprocessor is available)
if self.threshold_preprocessor is not None:
X_processed = self.threshold_preprocessor.transform(input_df)
else:
# Manual encoding for XGBoost threshold models
X_processed = pd.get_dummies(input_df, columns=['cor'], prefix='cor')
# Make predictions with error handling
try:
prob_83_raw = self.threshold_model_83.predict_proba(X_processed)
prob_83 = prob_83_raw[0][1] if len(prob_83_raw[0]) > 1 else prob_83_raw[0][0]
# Ensure probability is between 0 and 1
prob_83 = max(0.0, min(1.0, float(prob_83)))
except Exception as e:
print(f"Error with threshold_83 prediction: {e}")
prob_83 = 0.0
pred_83 = int(prob_83 > 0.5)
try:
prob_90_raw = self.threshold_model_90.predict_proba(X_processed)
prob_90 = prob_90_raw[0][1] if len(prob_90_raw[0]) > 1 else prob_90_raw[0][0]
# Ensure probability is between 0 and 1
prob_90 = max(0.0, min(1.0, float(prob_90)))
except Exception as e:
print(f"Error with threshold_90 prediction: {e}")
prob_90 = 0.0
pred_90 = int(prob_90 > 0.5)
# Add to results (using correct threshold values 8300/9000)
results_83.append({
"datetime": item['data'],
"threshold": 8300,
"probabilidade_de_estouro": round(prob_83, 4),
"estouro_previsto": pred_83
})
results_90.append({
"datetime": item['data'],
"threshold": 9000,
"probabilidade_de_estouro": round(prob_90, 4),
"estouro_previsto": pred_90
})
# Format response
result = {
"predictions": {
"prediction_1": results_83,
"prediction_2": results_90
}
}
return json.dumps(result, indent=2)
except json.JSONDecodeError:
return "Error: Invalid JSON format"
except Exception as e:
return f"Error: {str(e)}"
def predict_energy_rf(self, json_input):
"""Predict energy using Random Forest"""
try:
if not self.models_loaded or not self.rf_model:
return "Error: Random Forest model not available"
data = json.loads(json_input)
if not isinstance(data, list):
data = [data]
results = []
for item in data:
# Parse input
date_obj = datetime.strptime(item['data'], '%Y-%m-%d')
# Get extracao_boosting (main feature for new models)
extracao_boosting_val = item.get('ext_boosting', item.get('extracao_boosting', 0.0))
# Handle extracao_forno field
if 'extracao_forno' in item:
extracao_val = float(str(item['extracao_forno']).replace(',', '.'))
else:
extracao_val = 800.0
# Create features (NEW MODEL FORMAT - no temporal features)
input_data = {
'boosting': 0.0, # Always 0 for compatibility (as requested)
'cor': str(item['cor']).lower() if isinstance(item['cor'], str) else {0: 'incolor', 1: 'verde', 2: 'cinza', 3: 'bronze'}.get(item['cor'], 'incolor'),
'espessura': item['espessura'],
'extracao_forno': extracao_val,
'porcentagem_caco': item['porcentagem_caco'],
'extracao_boosting': extracao_boosting_val
}
# Predict
input_df = pd.DataFrame([input_data])
X_processed = self.rf_preprocessor.transform(input_df)
prediction = self.rf_model.predict(X_processed)[0]
results.append({
"data": date_obj.strftime('%Y-%m-%d'),
"predicted_energy": float(prediction)
})
return json.dumps(results, indent=2)
except json.JSONDecodeError:
return "Error: Invalid JSON format"
except Exception as e:
return f"Error: {str(e)}"
def predict_energy_xgb(self, json_input):
"""Predict energy using XGBoost"""
try:
if not self.models_loaded or not self.xgb_model:
return "Error: XGBoost model not available"
data = json.loads(json_input)
if not isinstance(data, list):
data = [data]
results = []
for item in data:
# Parse input
date_obj = datetime.strptime(item['data'], '%Y-%m-%d')
# Get extracao_boosting (main feature for new models)
extracao_boosting_val = item.get('ext_boosting', item.get('extracao_boosting', 0.0))
# Handle extracao_forno field
if 'extracao_forno' in item:
extracao_val = float(str(item['extracao_forno']).replace(',', '.'))
else:
extracao_val = 800.0
# Create features (NEW MODEL FORMAT - no temporal features)
input_data = {
'boosting': 0.0, # Always 0 for compatibility (as requested)
'cor': str(item['cor']).lower() if isinstance(item['cor'], str) else {0: 'incolor', 1: 'verde', 2: 'cinza', 3: 'bronze'}.get(item['cor'], 'incolor'),
'espessura': item['espessura'],
'extracao_forno': extracao_val,
'porcentagem_caco': item['porcentagem_caco'],
'extracao_boosting': extracao_boosting_val
}
# Preprocess features
input_df = pd.DataFrame([input_data])
if self.xgb_encoders is not None:
X_processed = self.xgb_encoders.transform(input_df)
else:
# Manual encoding if no preprocessor available
X_processed = pd.get_dummies(input_df, columns=['cor'], prefix='cor')
# Predict
prediction = self.xgb_model.predict(X_processed)[0]
results.append({
"data": date_obj.strftime('%d-%m-%Y'),
"predicted_energy": float(prediction)
})
return json.dumps(results, indent=2)
except json.JSONDecodeError:
return "Error: Invalid JSON format"
except Exception as e:
return f"Error: {str(e)}"
# Initialize predictor
predictor = EnergyMLPredictor()
def make_prediction(model_choice, json_input):
"""Make prediction based on model choice"""
if not predictor.models_loaded:
load_msg = predictor.load_models()
if "Error" in load_msg:
return load_msg
if model_choice == "Threshold Detection":
return predictor.predict_threshold(json_input)
elif model_choice == "Energy Prediction (Random Forest)":
return predictor.predict_energy_rf(json_input)
elif model_choice == "Energy Prediction (XGBoost)":
return predictor.predict_energy_xgb(json_input)
else:
return "Error: Please select a model"
# Default examples (updated for new models)
threshold_example = """{
"data": "2025-01-01",
"cor": "incolor",
"espessura": 8.0,
"ext_boosting": 1.5,
"extracao_forno": 750.0,
"porcentagem_caco": 15.0,
"prod_e": 1,
"prod_l": 0,
"autoclave": 1
}"""
energy_example = """[
{
"data": "2025-01-01",
"boosting": 0.0,
"cor": "incolor",
"espessura": 8.0,
"extracao_forno": 750.0,
"porcentagem_caco": 15.0,
"extracao_boosting": 1.5
}
]"""
# Test data from holdout period (last 2 months used in training)
week_test_data = """[
{"data": "2025-04-19", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2007, "extracao_forno": 699.561202512973, "porcentagem_caco": 10.0062724674475, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-04-20", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2026, "extracao_forno": 699.169485837721, "porcentagem_caco": 9.99757589767354, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 0},
{"data": "2025-04-21", "cor": 0, "espessura": 8.0, "ext_boosting": 1.201, "extracao_forno": 699.134346519477, "porcentagem_caco": 9.99807838764974, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 0},
{"data": "2025-04-22", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2074, "extracao_forno": 701.318973743488, "porcentagem_caco": 9.99545180216949, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 1},
{"data": "2025-04-23", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2028, "extracao_forno": 702.765143096952, "porcentagem_caco": 9.97488288777139, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 1},
{"data": "2025-04-24", "cor": 0, "espessura": 8.0, "ext_boosting": 1.3973, "extracao_forno": 700.8439481142, "porcentagem_caco": 10.002226628142, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 1},
{"data": "2025-04-25", "cor": 0, "espessura": 8.0, "ext_boosting": 1.6005, "extracao_forno": 702.032548397562, "porcentagem_caco": 9.98529201530728, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1}
]"""
month_test_data = """[
{"data": "2025-04-19", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2007, "extracao_forno": 699.561202512973, "porcentagem_caco": 10.0062724674475, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-04-20", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2026, "extracao_forno": 699.169485837721, "porcentagem_caco": 9.99757589767354, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 0},
{"data": "2025-04-21", "cor": 0, "espessura": 8.0, "ext_boosting": 1.201, "extracao_forno": 699.134346519477, "porcentagem_caco": 9.99807838764974, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 0},
{"data": "2025-04-22", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2074, "extracao_forno": 701.318973743488, "porcentagem_caco": 9.99545180216949, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 1},
{"data": "2025-04-23", "cor": 0, "espessura": 8.0, "ext_boosting": 1.2028, "extracao_forno": 702.765143096952, "porcentagem_caco": 9.97488288777139, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 1},
{"data": "2025-04-24", "cor": 0, "espessura": 8.0, "ext_boosting": 1.3973, "extracao_forno": 700.8439481142, "porcentagem_caco": 10.002226628142, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 1},
{"data": "2025-04-25", "cor": 0, "espessura": 8.0, "ext_boosting": 1.6005, "extracao_forno": 702.032548397562, "porcentagem_caco": 9.98529201530728, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-04-26", "cor": 0, "espessura": 8.0, "ext_boosting": 1.7549, "extracao_forno": 703.33718364331, "porcentagem_caco": 9.96677008271902, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-04-27", "cor": 0, "espessura": 8.0, "ext_boosting": 1.8022, "extracao_forno": 698.519152270116, "porcentagem_caco": 10.0355158154479, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 0},
{"data": "2025-04-28", "cor": 0, "espessura": 8.0, "ext_boosting": 1.8023, "extracao_forno": 699.802291106822, "porcentagem_caco": 10.0171149610168, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 1},
{"data": "2025-04-29", "cor": 0, "espessura": 8.0, "ext_boosting": 1.803, "extracao_forno": 702.213883737496, "porcentagem_caco": 9.98271347568585, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 0},
{"data": "2025-04-30", "cor": 0, "espessura": 8.0, "ext_boosting": 1.801, "extracao_forno": 701.164091438783, "porcentagem_caco": 9.99765972843181, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 0},
{"data": "2025-05-01", "cor": 0, "espessura": 8.0, "ext_boosting": 1.7999, "extracao_forno": 701.096395285213, "porcentagem_caco": 9.99862507800837, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 0},
{"data": "2025-05-02", "cor": 0, "espessura": 8.0, "ext_boosting": 1.8016, "extracao_forno": 701.004721690124, "porcentagem_caco": 9.99993264396119, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 1, "autoclave": 0},
{"data": "2025-05-03", "cor": 0, "espessura": 8.0, "ext_boosting": 1.8023, "extracao_forno": 699.505291072901, "porcentagem_caco": 10.021368086077, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 0},
{"data": "2025-05-04", "cor": 0, "espessura": 8.0, "ext_boosting": 1.8036, "extracao_forno": 700.073447985429, "porcentagem_caco": 10.0132350686523, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 0},
{"data": "2025-05-05", "cor": 0, "espessura": 8.0, "ext_boosting": 0.689, "extracao_forno": 700.60585295748, "porcentagem_caco": 10.0056258028798, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-06", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 699.123418185867, "porcentagem_caco": 10.026841924692, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-07", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 699.086556585488, "porcentagem_caco": 10.0273706223712, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-08", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 698.120389195209, "porcentagem_caco": 10.0412480547676, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-09", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 697.228099576186, "porcentagem_caco": 9.9680434627127, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 0},
{"data": "2025-05-10", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 697.37935572186, "porcentagem_caco": 9.96588147179382, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 0},
{"data": "2025-05-11", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 699.563378916139, "porcentagem_caco": 10.0205359675357, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-12", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 698.733542903546, "porcentagem_caco": 10.0324366436888, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-13", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 699.509702244859, "porcentagem_caco": 10.0213048904162, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-14", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 701.657766576732, "porcentagem_caco": 9.99062553558067, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-15", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 674.645706945424, "porcentagem_caco": 10.0052515424159, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-16", "cor": 0, "espessura": 8.0, "ext_boosting": 0.0, "extracao_forno": 653.148421891636, "porcentagem_caco": 9.95179622600148, "pot_boost": 3.0, "Prod_E": 0, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-17", "cor": 0, "espessura": 6.0, "ext_boosting": 0.0, "extracao_forno": 611.090907286899, "porcentagem_caco": 9.98214819965588, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1},
{"data": "2025-05-18", "cor": 0, "espessura": 6.0, "ext_boosting": 0.0, "extracao_forno": 599.399563235682, "porcentagem_caco": 10.0100173040013, "pot_boost": 3.0, "Prod_E": 1, "Prod_L": 0, "autoclave": 1}
]"""
# Generate test data functions
def generate_energy_test_data(days=1):
"""Generate test data for energy models"""
from datetime import datetime, timedelta
base_date = datetime(2025, 1, 1)
test_data = []
for i in range(days):
current_date = base_date + timedelta(days=i)
test_data.append({
"data": current_date.strftime("%Y-%m-%d"),
"boosting": 0.0,
"cor": "incolor" if i % 3 == 0 else "verde" if i % 3 == 1 else "cinza",
"espessura": 8.0 + (i % 3),
"extracao_forno": 750.0 + (i * 10),
"porcentagem_caco": 15.0 + (i * 2),
"extracao_boosting": 1.5 + (i * 0.3)
})
return json.dumps(test_data, indent=2)
def generate_threshold_test_data(days=1):
"""Generate test data for threshold models"""
from datetime import datetime, timedelta
base_date = datetime(2025, 1, 1)
test_data = []
for i in range(days):
current_date = base_date + timedelta(days=i)
test_data.append({
"data": current_date.strftime("%Y-%m-%d"),
"cor": "incolor" if i % 3 == 0 else "verde" if i % 3 == 1 else "cinza",
"espessura": 8.0 + (i % 3),
"ext_boosting": 1.5 + (i * 0.3),
"extracao_forno": 750.0 + (i * 10),
"porcentagem_caco": 15.0 + (i * 2),
"prod_e": i % 2,
"prod_l": (i + 1) % 2,
"autoclave": 1 if i % 3 == 0 else 0
})
return json.dumps(test_data, indent=2)
# Create custom interfaces with test data buttons
def create_energy_interface(model_name, predict_fn, api_name):
with gr.Row():
with gr.Column():
gr.Markdown(f"### {model_name}")
gr.Markdown("Generate test data or enter your own JSON:")
with gr.Row():
btn_1_day = gr.Button("1 Day", size="sm")
btn_3_days = gr.Button("3 Days", size="sm")
btn_week = gr.Button("1 Week", size="sm")
btn_clear = gr.Button("Clear", size="sm")
json_input = gr.Textbox(
label="JSON Input",
lines=12,
value=generate_energy_test_data(1),
placeholder="Enter JSON data here..."
)
predict_btn = gr.Button("Predict Energy", variant="primary")
with gr.Column():
output = gr.Textbox(
label="Prediction Result",
lines=12,
interactive=False
)
# Event handlers
btn_1_day.click(lambda: generate_energy_test_data(1), outputs=json_input)
btn_3_days.click(lambda: generate_energy_test_data(3), outputs=json_input)
btn_week.click(lambda: generate_energy_test_data(7), outputs=json_input)
btn_clear.click(lambda: "", outputs=json_input)
predict_btn.click(predict_fn, inputs=json_input, outputs=output)
def create_threshold_interface(predict_fn, api_name):
with gr.Row():
with gr.Column():
gr.Markdown("### Threshold Detection")
gr.Markdown("Generate test data or enter your own JSON:")
with gr.Row():
btn_1_day = gr.Button("1 Day", size="sm")
btn_3_days = gr.Button("3 Days", size="sm")
btn_week = gr.Button("1 Week", size="sm")
btn_clear = gr.Button("Clear", size="sm")
json_input = gr.Textbox(
label="JSON Input",
lines=12,
value=generate_threshold_test_data(1),
placeholder="Enter JSON data here..."
)
predict_btn = gr.Button("Predict Thresholds", variant="primary")
with gr.Column():
output = gr.Textbox(
label="Prediction Result",
lines=12,
interactive=False
)
# Event handlers
btn_1_day.click(lambda: generate_threshold_test_data(1), outputs=json_input)
btn_3_days.click(lambda: generate_threshold_test_data(3), outputs=json_input)
btn_week.click(lambda: generate_threshold_test_data(7), outputs=json_input)
btn_clear.click(lambda: "", outputs=json_input)
predict_btn.click(predict_fn, inputs=json_input, outputs=output)
# Create Gradio interface with tabs
with gr.Blocks(title="Energy ML Cloud", theme=gr.themes.Default()) as app:
gr.Markdown("# Energy ML Prediction System")
#gr.Markdown("Cloud deployment with embedded models - Each tab has its own API endpoint")
with gr.Tabs():
with gr.TabItem("Energy Prediction (Random Forest)"):
create_energy_interface("Random Forest Energy Model", predictor.predict_energy_rf, "energy_random_forest")
with gr.TabItem("Energy Prediction (XGBoost)"):
create_energy_interface("XGBoost Energy Model", predictor.predict_energy_xgb, "energy_xgboost")
with gr.TabItem("Threshold Detection (XGClassifier)"):
create_threshold_interface(predictor.predict_threshold, "threshold_detection")
# Load models when app starts
predictor.load_models()
# with gr.Accordion("Model Information", open=False):
# gr.Markdown("""
# ## Available Models
# - **Threshold Detection**: Predict probability of exceeding 8300 and 9000 consumption thresholds
# - **Random Forest**: Energy prediction (R² = 0.50, MAE = 0.24 MWh)
# - **XGBoost**: Energy prediction (R² = 0.53, MAE = 0.24 MWh, best model)
# ## Input Formats
# See examples that change when you select different models.
# """)
if __name__ == "__main__":
app.launch(
#auth=("admin", "energy123"),
share=True,
ssr_mode=False
)