import numpy as np
import pandas as pd
import plotly.express as px
import streamlit as st
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error,r2_score
from sklearn.model_selection import train_test_split
st.set_page_config(page_title='AIMPACT | Generation Predictor',page_icon='⚡',layout='wide')
st.title('⚡ Power Generation Predictor')
st.caption('Combined-cycle-inspired SYNTHETIC demonstration; not a coal-fired plant heat-rate or dispatch model.')
@st.cache_data
def sample():
 rng=np.random.default_rng(9);n=1800
 t=rng.uniform(3,36,n);v=rng.uniform(25,82,n);p=rng.normal(1013,12,n);h=rng.uniform(25,100,n)
 pe=490-1.9*t-.19*v+.07*(p-1013)-.04*h+rng.normal(0,3.2,n)
 return pd.DataFrame({'AT':t,'V':v,'AP':p,'RH':h,'PE':pe})
with st.expander('Optional: use real UCI Combined Cycle Power Plant data'):
 st.markdown('Download a CSV or XLSX from [UCI](https://archive.ics.uci.edu/dataset/294/combined%2Bcycle%2Bpower%2Bplant). Expected columns: AT, V, AP, RH, PE. Only upload public or approved data.')
 upload=st.file_uploader('CSV or Excel',type=['csv','xlsx'])
if upload:
 try:
  df=pd.read_csv(upload) if upload.name.lower().endswith('.csv') else pd.read_excel(upload)
  df.columns=[str(c).strip().upper() for c in df.columns]
  df=df[['AT','V','AP','RH','PE']].apply(pd.to_numeric,errors='coerce').dropna()
  if len(df)<50: st.error('At least 50 complete records are required.');st.stop()
  origin='Uploaded dataset'
 except Exception as exc: st.error(f'Could not read data: {exc}');st.stop()
else: df=sample();origin='SYNTHETIC demo data'
X=df[['AT','V','AP','RH']];y=df['PE']
Xtr,Xte,ytr,yte=train_test_split(X,y,test_size=.2,random_state=42)
model=RandomForestRegressor(n_estimators=100,min_samples_leaf=2,random_state=42,n_jobs=-1).fit(Xtr,ytr)
with st.sidebar:
 st.header('Operating conditions')
 vals={c:st.slider(c,float(X[c].min()),float(X[c].max()),float(X[c].median())) for c in X.columns}
pred=float(model.predict(pd.DataFrame([vals]))[0]);testpred=model.predict(Xte)
a,b,c=st.columns(3);a.metric('Predicted output',f'{pred:.1f} MW');b.metric('Test MAE',f'{mean_absolute_error(yte,testpred):.2f} MW');c.metric('Test R²',f'{r2_score(yte,testpred):.2f}')
st.info('Data origin: '+origin+' • No causal or operational guarantee')
plot=pd.DataFrame({'Measured':yte.values[:200],'Predicted':testpred[:200]})
st.plotly_chart(px.scatter(plot,x='Measured',y='Predicted',title='Held-out observed vs predicted'),use_container_width=True)
st.bar_chart(pd.Series(model.feature_importances_,index=X.columns))
st.download_button('Download predictions',pd.DataFrame({'observed':yte.values,'predicted':testpred}).to_csv(index=False),'power_predictions.csv')
