import streamlit as st import pandas as pd import matplotlib import matplotlib.pyplot as plt import plotly.express as px import numpy as np import plotly.graph_objects as go # from blend_logic import run_dummy_prediction ##---- fucntions ------ import pandas as pd import streamlit as st # Load fuel data from CSV (create this file if it doesn't exist) FUEL_CSV_PATH = "fuel_properties.csv" def load_fuel_data(): """Load fuel data from CSV or create default if not exists""" try: df = pd.read_csv(FUEL_CSV_PATH, index_col=0) return df.to_dict('index') except FileNotFoundError: # Create default fuel properties if file doesn't exist default_fuels = { "Gasoline": {f"Property{i+1}": round(0.7 + (i*0.02), 1) for i in range(10)}, "Diesel": {f"Property{i+1}": round(0.8 + (i*0.02), 1) for i in range(10)}, "Ethanol": {f"Property{i+1}": round(0.75 + (i*0.02), 1) for i in range(10)}, "Biodiesel": {f"Property{i+1}": round(0.85 + (i*0.02), 1) for i in range(10)}, "Jet Fuel": {f"Property{i+1}": round(0.78 + (i*0.02), 1) for i in range(10)} } pd.DataFrame(default_fuels).T.to_csv(FUEL_CSV_PATH) return default_fuels # Initialize or load fuel data if 'FUEL_PROPERTIES' not in st.session_state: st.session_state.FUEL_PROPERTIES = load_fuel_data() def save_fuel_data(): """Save current fuel data to CSV""" pd.DataFrame(st.session_state.FUEL_PROPERTIES).T.to_csv(FUEL_CSV_PATH) # FUEL_PROPERTIES = st.session_state.FUEL_PROPERTIES # ---------------------- Page Config ---------------------- st.set_page_config( layout="wide", page_title="Eagle Blend Optimizer", page_icon="🦅", initial_sidebar_state="expanded" ) # ---------------------- Custom Styling ---------------------- ##e0e0e0; st.markdown(""" """, unsafe_allow_html=True) # ---------------------- App Header ---------------------- st.markdown("""

🦅 Eagle Blend Optimizer

AI-Powered Fuel Blend Property Prediction & Optimization

""", unsafe_allow_html=True) #------ universal variables # ---------------------- Tabs ---------------------- tabs = st.tabs([ "📊 Dashboard", "🎛️ Blend Designer", "📤 Nothing For Now", "⚙️ Optimization Engine", "📚 Fuel Registry", "🧠 Model Insights" ]) # ---------------------- Dashboard Tab ---------------------- with tabs[0]: st.subheader("Performance Metrics") col1, col2, col3, col4 = st.columns(4) with col1: st.markdown("""
Model Accuracy
94.7%
R² Score
""", unsafe_allow_html=True) with col2: st.markdown("""
Predictions Made
12,847
Today
""", unsafe_allow_html=True) with col3: st.markdown("""
Optimizations
156
This Week
""", unsafe_allow_html=True) with col4: st.markdown("""
Cost Savings
$2.4M
Estimated Annual
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.subheader("Current Blend Properties") blend_props = { "Property 1": 0.847, "Property 2": 0.623, "Property 3": 0.734, "Property 4": 0.912, "Property 5": 0.456, "Property 6": -1.234, } # Enhanced dataframe display df = pd.DataFrame(blend_props.items(), columns=["Property", "Value"]) # st.dataframe( # df.style # .background_gradient(cmap="YlOrBr", subset=["Value"]) # .format({"Value": "{:.3f}"}), # use_container_width=True # ) st.markdown('
', unsafe_allow_html=True) st.dataframe(df, use_container_width=True) st.markdown('
', unsafe_allow_html=True) with tabs[1]: col_header = st.columns([0.8, 0.2]) with col_header[0]: st.subheader("🎛️ Blend Designer") with col_header[1]: batch_blend = st.checkbox("Batch Blend Mode", value=False, help="Switch between manual input and predefined fuel selection", key="batch_blend_mode") # Initialize session state if 'show_visualization' not in st.session_state: st.session_state.show_visualization = False if 'blended_value' not in st.session_state: st.session_state.blended_value = None if 'selected_property' not in st.session_state: st.session_state.selected_property = "Property1" # Batch mode file upload if batch_blend: st.subheader("📤 Batch Processing") uploaded_file = st.file_uploader("Upload CSV File", type=["csv"], key="Batch_upload") weights = [0.1, 0.2, 0.25, 0.15, 0.3] # Default weights for batch mode if not uploaded_file: st.warning("Please upload a CSV file for batch processing") data_input = None else: try: data_input = pd.read_csv(uploaded_file) st.success("File uploaded successfully") st.dataframe(data_input.head()) except Exception as e: st.error(f"Error reading file: {str(e)}") data_input = None else: # Regular mode data_input = None weights, props = [], [] col1, col2 = st.columns(2) with col1: st.markdown("##### ⚖️ Component Weights") for i in range(5): weight = st.number_input( f"Weight for Component {i+1}", min_value=0.0, max_value=1.0, value=0.2, step=0.01, key=f"w_{i}" ) weights.append(weight) with col2: st.markdown("##### Fuel Selection") for i in range(5): fuel = st.selectbox( f"Component {i+1} Fuel Type", options=list(st.session_state.FUEL_PROPERTIES.keys()), key=f"fuel_{i}" ) props.append(st.session_state.FUEL_PROPERTIES[fuel]) if st.button("⚙️ Predict Blended Property", key="predict_btn"): if batch_blend: if data_input is None: st.error("⚠️ Please upload a valid CSV file first!") st.session_state.show_visualization = False else: st.session_state.show_visualization = True else: if abs(sum(weights) - 1.0) > 0.01: st.warning("⚠️ The total of weights must be **1.0**.") st.session_state.show_visualization = False else: st.session_state.show_visualization = True if st.session_state.show_visualization: # Show calculation details st.subheader("Blend Components Data") if not batch_blend: weights_data = {f"Component{i+1}_fraction": weights[i] for i in range(len(weights))} props_data = {f"Component{i+1}_{j}": props[i][j] for j in props[i].keys() for i in range(len(props))} combined = {**weights_data, **props_data} data_input = pd.DataFrame([combined]) st.write("Properties:", data_input) # Show visualization only if prediction was made if st.session_state.show_visualization: if not batch_blend: st.markdown('
', unsafe_allow_html=True) st.subheader("Blend Visualization") components = [f"Component {i+1}" for i in range(5)] # 1. Weight Distribution Pie Chart col1, col2 = st.columns(2) with col1: fig1 = px.pie( names=components, values=weights, title="Weight Distribution", color_discrete_sequence=['#8B4513', '#CFB53B', '#654321'], hole=0.4 ) fig1.update_layout( margin=dict(t=50, b=10), showlegend=False ) fig1.update_traces( textposition='inside', textinfo='percent+label', marker=dict(line=dict(color='#ffffff', width=1)) ) st.plotly_chart(fig1, use_container_width=True) # 2. Property Comparison Bar Chart with col2: # Property selection for fuel mode viz_property = st.selectbox( "Select Property to View", [f"Property{i+1}" for i in range(10)], key="viz_property" ) bar_values = [p[viz_property] for p in props] blended_value = 123 #Modify fig2 = px.bar( x=components, y=bar_values, title=f"{viz_property} Values", color=bar_values, color_continuous_scale='YlOrBr' ) fig2.update_layout( yaxis_title=viz_property, xaxis_title="Component", margin=dict(t=50, b=10), coloraxis_showscale=False ) fig2.add_hline( y=blended_value, line_dash="dot", line_color="#ff6600", annotation_text="Blended Value", annotation_position="top right" ) st.plotly_chart(fig2, use_container_width=True) # Display the calculated value prominently st.markdown(f"""

Calculated {viz_property} = {blended_value:.4f}

""", unsafe_allow_html=True) else: # Batch mode visualization placeholder st.markdown('
', unsafe_allow_html=True) st.subheader("Batch Processing Results") st.dataframe(data_input, use_container_width=True) # st.info("Batch processing complete. Add custom visualizations here.") with tabs[2]: st.subheader("📤 Nothing FOr NOw") # uploaded_file = st.file_uploader("Upload CSV File", type=["csv"]) # if uploaded_file: # df = pd.read_csv(uploaded_file) # st.success("File uploaded successfully") # st.dataframe(df.head()) # if st.button("⚙️ Run Batch Prediction"): # result_df = df.copy() # # result_df["Predicted_Property"] = df.apply( # # lambda row: run_dummy_prediction(row.values[:5], row.values[5:10]), axis=1 # # ) # st.success("Batch prediction completed") # st.dataframe(result_df.head()) # csv = result_df.to_csv(index=False).encode("utf-8") # st.download_button("Download Results", csv, "prediction_results.csv", "text/csv") with tabs[3]: st.subheader("⚙️ Optimization Engine") # Pareto frontier demo st.markdown("#### Cost vs Performance Trade-off") np.random.seed(42) optimization_data = pd.DataFrame({ 'Cost ($/ton)': np.random.uniform(100, 300, 50), 'Performance Score': np.random.uniform(70, 95, 50) }) fig3 = px.scatter( optimization_data, x='Cost ($/ton)', y='Performance Score', title="Potential Blend Formulations", color='Performance Score', color_continuous_scale='YlOrBr' ) # Add dummy pareto frontier x_pareto = np.linspace(100, 300, 10) y_pareto = 95 - 0.1*(x_pareto-100) fig3.add_trace(px.line( x=x_pareto, y=y_pareto, color_discrete_sequence= ['#8B4513', '#CFB53B', '#654321'] ).data[0]) fig3.update_layout( showlegend=False, annotations=[ dict( x=200, y=88, text="Pareto Frontier", showarrow=True, arrowhead=1, ax=-50, ay=-30 ) ] ) st.plotly_chart(fig3, use_container_width=True) # Blend optimization history st.markdown("#### Optimization Progress") iterations = np.arange(20) performance = np.concatenate([np.linspace(70, 85, 10), np.linspace(85, 89, 10)]) fig4 = px.line( x=iterations, y=performance, title="Best Performance by Iteration", markers=True ) fig4.update_traces( line_color='#1d3b58', marker_color='#2c5282', line_width=2.5 ) fig4.update_layout( yaxis_title="Performance Score", xaxis_title="Iteration" ) st.plotly_chart(fig4, use_container_width=True) with tabs[4]: st.subheader("📚 Fuel Registry") # Changed to book emoji for registry # Button to add new fuel st.markdown("#### ➕ Add a New Fuel Type") with st.expander("Click to Add New Fuel", expanded=False): with st.form("new_fuel_form", clear_on_submit=False): fuel_name = st.text_input("Fuel Name", placeholder="e.g. Bioethanol") cols = st.columns(5) properties = {} for i in range(10): with cols[i % 5]: prop_val = st.number_input( f"Property {i+1}", min_value=0.0, step=0.1, key=f"prop_{i}", format="%.2f" ) properties[f"Property{i+1}"] = round(prop_val, 2) col1, col2 = st.columns(2) with col1: submitted = st.form_submit_button("💾 Save Fuel", use_container_width=True) with col2: cancelled = st.form_submit_button("❌ Cancel", use_container_width=True) if submitted: if not fuel_name.strip(): st.warning("Fuel name cannot be empty.") elif fuel_name in st.session_state.FUEL_PROPERTIES: st.error(f"{fuel_name} already exists in registry.") else: # Update both session state and CSV st.session_state.FUEL_PROPERTIES[fuel_name] = properties save_fuel_data() st.success(f"{fuel_name} successfully added!") st.rerun() # Refresh to show new fuel if cancelled: st.rerun() with st.expander("Batch Add New Fuel", expanded=False): uploaded_file = st.file_uploader( "📤 Upload Fuel Batch (CSV)", type=['csv'], accept_multiple_files=False, key="fuel_uploader", help="Upload a CSV file with the same format as the exported registry" ) if uploaded_file is not None: try: new_fuels = pd.read_csv(uploaded_file, index_col=0).to_dict('index') # Check for duplicates duplicates = [name for name in new_fuels if name in st.session_state.FUEL_PROPERTIES] if duplicates: st.warning(f"These fuels already exist and won't be updated: {', '.join(duplicates)}") # Only add new fuels new_fuels = {name: props for name, props in new_fuels.items() if name not in st.session_state.FUEL_PROPERTIES} if new_fuels: st.session_state.FUEL_PROPERTIES.update(new_fuels) save_fuel_data() st.success(f"Added {len(new_fuels)} new fuel(s) to registry!") st.rerun() else: st.info("No new fuels to add from the uploaded file.") except Exception as e: st.error(f"Error processing file: {str(e)}") st.error("Please ensure the file matches the expected format") # Display current fuel properties st.markdown("#### 🔍 Current Fuel Properties") st.dataframe( pd.DataFrame(st.session_state.FUEL_PROPERTIES).T.style .background_gradient(cmap="YlOrBr", axis=None) .format(precision=2), use_container_width=True, height=(len(st.session_state.FUEL_PROPERTIES) + 1) * 35 + 3, hide_index=False ) # File operations section st.download_button( label="📥 Download Registry (CSV)", data=pd.DataFrame(st.session_state.FUEL_PROPERTIES).T.to_csv().encode('utf-8'), file_name='fuel_properties.csv', mime='text/csv', # use_container_width=True ) with tabs[5]: st.subheader("🧠 Model Insights") # Feature importance st.markdown("#### Property Importance") features = ['Property 1', 'Property 2', 'Property 3', 'Property 4', 'Property 5'] importance = np.array([0.35, 0.25, 0.2, 0.15, 0.05]) fig5 = px.bar( x=importance, y=features, orientation='h', title="Feature Importance for Blend Prediction", color=importance, color_continuous_scale='YlOrBr' ) fig5.update_layout( xaxis_title="Importance Score", yaxis_title="Property", coloraxis_showscale=False ) st.plotly_chart(fig5, use_container_width=True) # SHAP values demo st.markdown("#### Property Impact Direction") fig6 = px.scatter( x=np.random.randn(100), y=np.random.randn(100), color=np.random.choice(features, 100), title="SHAP Values (Simulated)", labels={'x': 'Impact on Prediction', 'y': 'Property Value'} ) fig6.update_traces( marker=dict(size=10, opacity=0.7), selector=dict(mode='markers') ) fig6.add_vline(x=0, line_width=1, line_dash="dash") st.plotly_chart(fig6, use_container_width=True) # st.markdown(""" # # """, unsafe_allow_html=True)