wayne-chi commited on
Commit
0c78665
·
verified ·
1 Parent(s): 5a423c7

Update streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +813 -27
streamlit_app.py CHANGED
@@ -1,29 +1,815 @@
1
- import os
2
- import stat
3
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- def is_read_write_dir(path):
6
- return (
7
- os.path.isdir(path)
8
- and os.access(path, os.R_OK)
9
- and os.access(path, os.W_OK)
10
- )
11
-
12
- st.title("📂 Read + Write Directories")
13
-
14
- # Walk the filesystem starting from root
15
- rw_dirs = []
16
- for root, dirs, _ in os.walk("/"):
17
- for d in dirs:
18
- full_path = os.path.join(root, d)
19
- if is_read_write_dir(full_path):
20
- # Get permissions in ls -ld style
21
- mode = stat.filemode(os.stat(full_path).st_mode)
22
- rw_dirs.append(f"{mode} {full_path}")
23
-
24
- # Display them
25
- if rw_dirs:
26
- for d in sorted(rw_dirs):
27
- st.write(d)
28
- else:
29
- st.write("No read-write directories found for the current user.")
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import matplotlib
4
+ import matplotlib.pyplot as plt
5
+ import plotly.express as px
6
+ import numpy as np
7
+ import plotly.graph_objects as go
8
+ # from blend_logic import run_dummy_prediction
9
+
10
+ ##---- fucntions ------
11
+ import pandas as pd
12
+ import streamlit as st
13
+ import os
14
+
15
+ # Load fuel data from CSV (create this file if it doesn't exist)
16
+ FUEL_CSV_PATH = "fuel_properties.csv"
17
+
18
+ def load_fuel_data():
19
+ """Load fuel data from CSV or create default if not exists"""
20
+ try:
21
+ df = pd.read_csv(FUEL_CSV_PATH, index_col=0)
22
+ return df.to_dict('index')
23
+ except FileNotFoundError:
24
+ # Create default fuel properties if file doesn't exist
25
+ default_fuels = {
26
+ "Gasoline": {f"Property{i+1}": round(0.7 + (i*0.02), 1) for i in range(10)},
27
+ "Diesel": {f"Property{i+1}": round(0.8 + (i*0.02), 1) for i in range(10)},
28
+ "Ethanol": {f"Property{i+1}": round(0.75 + (i*0.02), 1) for i in range(10)},
29
+ "Biodiesel": {f"Property{i+1}": round(0.85 + (i*0.02), 1) for i in range(10)},
30
+ "Jet Fuel": {f"Property{i+1}": round(0.78 + (i*0.02), 1) for i in range(10)}
31
+ }
32
+ pd.DataFrame(default_fuels).T.to_csv(FUEL_CSV_PATH)
33
+ return default_fuels
34
+
35
+ # Initialize or load fuel data
36
+ if 'FUEL_PROPERTIES' not in st.session_state:
37
+ st.session_state.FUEL_PROPERTIES = load_fuel_data()
38
+
39
+ def save_fuel_data():
40
+ """Save current fuel data to CSV"""
41
+ pd.DataFrame(st.session_state.FUEL_PROPERTIES).T.to_csv(FUEL_CSV_PATH)
42
+
43
+ # FUEL_PROPERTIES = st.session_state.FUEL_PROPERTIES
44
+
45
+ # ---------------------- Page Config ----------------------
46
+ st.set_page_config(
47
+ layout="wide",
48
+ page_title="Eagle Blend Optimizer",
49
+ page_icon="🦅",
50
+ initial_sidebar_state="expanded"
51
+ )
52
+
53
+ # ---------------------- Custom Styling ---------------------- ##e0e0e0;
54
+
55
+ st.markdown("""
56
+ <style>
57
+
58
+ .block-container {
59
+ padding-top: 1rem;
60
+ }
61
+ /* Main app background */
62
+ .stApp {
63
+ background-color: #f8f5f0;
64
+ overflow: visible;
65
+ padding-top: 0
66
+
67
+ }
68
+ /* Remove unnecessary space at the top */
69
+ /* Remove any fixed headers */
70
+ .stApp > header {
71
+ position: static !important;
72
+ }
73
+
74
+ /* Header styling */
75
+ .header {
76
+ background: linear-gradient(135deg, #654321 0%, #8B4513 100%);
77
+ color: white;
78
+ padding: 2rem 1rem;
79
+ margin-bottom: 2rem;
80
+ border-radius: 0 0 15px 15px;
81
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
82
+ }
83
+
84
+ /* Metric card styling */
85
+ .metric-card {
86
+ background: #ffffff; /* Pure white cards for contrast */
87
+ border-radius: 10px;
88
+ padding: 1.5rem;
89
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
90
+ height: 100%;
91
+ transition: all 0.3s ease;
92
+ border: 1px solid #CFB53B;
93
+ }
94
+
95
+ .metric-card:hover {
96
+ transform: translateY(-3px);
97
+ background: #FFF8E1; /* Very light blue tint on hover */
98
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
99
+ border-color: #8B4513;
100
+ }
101
+
102
+ /* Metric value styling */
103
+ .metric-value {
104
+ color: #8B4513 !important; /* Deep, vibrant blue */
105
+ font-weight: 700;
106
+ font-size: 1.8rem;
107
+ text-shadow: 0 1px 2px rgba(0, 82, 204, 0.1);
108
+ }
109
+
110
+ /* Metric label styling */
111
+ .metric-label {
112
+ color: #654321; /* Navy blue-gray */
113
+ font-weight: 600;
114
+ letter-spacing: 0.5px;
115
+ }
116
+
117
+
118
+ /* Metric delta styling */
119
+ .metric-delta {
120
+ color: #A67C52; /* Medium blue-gray */
121
+ font-size: 0.9rem;
122
+ font-weight: 500;
123
+ }
124
+
125
+ /* Tab styling */
126
+ /* Main tab container */
127
+ .stTabs [data-baseweb="tab-list"] {
128
+ display: flex;
129
+ justify-content: center;
130
+ gap: 6px;
131
+ padding: 8px;
132
+ margin: 0 auto;
133
+ width: 95% !important;
134
+ }
135
+
136
+ /* Individual tabs */
137
+ .stTabs [data-baseweb="tab"] {
138
+ flex: 1; /* Equal width distribution */
139
+ min-width: 0; /* Allows flex to work */
140
+ height: 60px; /* Fixed height or use aspect ratio */
141
+ padding: 0 12px;
142
+ margin: 0;
143
+ font-weight: 600;
144
+ font-size: 1rem;
145
+ color: #654321;
146
+ background: #FFF8E1;
147
+ border: 2px solid #CFB53B;
148
+ border-radius: 12px;
149
+ transition: all 0.3s ease;
150
+ display: flex;
151
+ align-items: center;
152
+ justify-content: center;
153
+ text-align: center;
154
+ }
155
+
156
+ /* Hover state */
157
+ .stTabs [data-baseweb="tab"]:hover {
158
+ background: #FFE8A1;
159
+ transform: translateY(-2px);
160
+ }
161
+
162
+
163
+ /* Active tab */
164
+ .stTabs [aria-selected="true"] {
165
+ background: #654321;
166
+ color: #FFD700 !important;
167
+ border-color: #8B4513;
168
+ font-size: 1.05rem;
169
+ }
170
+
171
+ /* Icon sizing */
172
+ .stTabs [data-baseweb="tab"] svg {
173
+ width: 24px !important;
174
+ height: 24px !important;
175
+ margin-right: 8px !important;
176
+ }
177
+
178
+ /* Button styling */
179
+ .stButton>button {
180
+ background-color: #654321;
181
+ color: #FFD700 !important;
182
+ border-radius: 8px;
183
+ padding: 0.5rem 1rem;
184
+ transition: all 0.3s ease;
185
+ }
186
+
187
+ .stButton>button:hover {
188
+ background-color: #8B4513;
189
+ color: white;
190
+ }
191
+
192
+ /* Dataframe styling */
193
+ .table-container {
194
+ display: flex;
195
+ justify-content: center;
196
+ margin-top: 30px;
197
+ }
198
+ .table-inner {
199
+ width: 50%;
200
+ }
201
+
202
+
203
+ @media only screen and (max-width: 768px) {
204
+ .table-inner {
205
+ width: 90%; /* For mobile */
206
+ }
207
+ }
208
+
209
+ .stDataFrame {
210
+ border-radius: 10px;
211
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
212
+ background-color:white !important;
213
+ border: #CFB53B !important;
214
+ }
215
+
216
+
217
+
218
+ /* Section headers */
219
+ .st-emotion-cache-16txtl3 {
220
+ padding-top: 1rem;
221
+ }
222
+
223
+ /* Custom hr style */
224
+ .custom-divider {
225
+ border: 0;
226
+ height: 1px;
227
+ background: linear-gradient(90deg, transparent, #dee2e6, transparent);
228
+ margin: 2rem 0;
229
+ }
230
+
231
+
232
+ /* Consistent chart styling */
233
+ .stPlotlyChart {
234
+ border-radius: 10px;
235
+ background: white;
236
+ padding: 15px;
237
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
238
+ margin-bottom: 25px;
239
+ }
240
+
241
+
242
+
243
+ /* Match number inputs */
244
+ # .stNumberInput > div {
245
+ # padding: 0.25rem 0.5rem !important;
246
+ # }
247
+
248
+ #/* Better select widget alignment */
249
+ # .stSelectbox > div {
250
+ # margin-bottom: -15px;
251
+ # }
252
+
253
+
254
+ .custom-uploader > label div[data-testid="stFileUploadDropzone"] {
255
+ border: 2px solid #4CAF50;
256
+ background-color: #4CAF50;
257
+ color: white;
258
+ padding: 0.6em 1em;
259
+ border-radius: 0.5em;
260
+ text-align: center;
261
+ cursor: pointer;
262
+ }
263
+ .custom-uploader > label div[data-testid="stFileUploadDropzone"]:hover {
264
+ background-color: #45a049;
265
+ }
266
+
267
+
268
+
269
+
270
+
271
+ /* Color scale adjustments */
272
+ .plotly .colorbar {
273
+ padding: 10px !important;
274
+ color: #654321 !important;
275
+ }
276
+
277
+ </style>
278
+ """, unsafe_allow_html=True)
279
+
280
+ # ---------------------- App Header ----------------------
281
+ st.markdown("""
282
+ <div class="header">
283
+ <h1 style='text-align: center; margin-bottom: 0.5rem;'>🦅 Eagle Blend Optimizer</h1>
284
+ <h4 style='text-align: center; font-weight: 400; margin-top: 0;'>
285
+ AI-Powered Fuel Blend Property Prediction & Optimization
286
+ </h4>
287
+ </div>
288
+ """, unsafe_allow_html=True)
289
+ #------ universal variables
290
+
291
+
292
+ # ---------------------- Tabs ----------------------
293
+ tabs = st.tabs([
294
+ "📊 Dashboard",
295
+ "🎛️ Blend Designer",
296
+ "📤 Nothing For Now",
297
+ "⚙️ Optimization Engine",
298
+ "📚 Fuel Registry",
299
+ "🧠 Model Insights"
300
+ ])
301
+
302
+ # ---------------------- Dashboard Tab ----------------------
303
+
304
+ with tabs[0]:
305
+ st.subheader("Performance Metrics")
306
+ col1, col2, col3, col4 = st.columns(4)
307
+
308
+ with col1:
309
+ st.markdown("""
310
+ <div class="metric-card">
311
+ <div class="metric-label">Model Accuracy</div>
312
+ <div class="metric-value">94.7%</div>
313
+ <div class="metric-delta">R² Score</div>
314
+ </div>
315
+ """, unsafe_allow_html=True)
316
+
317
+ with col2:
318
+ st.markdown("""
319
+ <div class="metric-card">
320
+ <div class="metric-label">Predictions Made</div>
321
+ <div class="metric-value">12,847</div>
322
+ <div class="metric-delta">Today</div>
323
+ </div>
324
+ """, unsafe_allow_html=True)
325
+
326
+ with col3:
327
+ st.markdown("""
328
+ <div class="metric-card">
329
+ <div class="metric-label">Optimizations</div>
330
+ <div class="metric-value">156</div>
331
+ <div class="metric-delta">This Week</div>
332
+ </div>
333
+ """, unsafe_allow_html=True)
334
+
335
+ with col4:
336
+ st.markdown("""
337
+ <div class="metric-card">
338
+ <div class="metric-label">Cost Savings</div>
339
+ <div class="metric-value">$2.4M</div>
340
+ <div class="metric-delta">Estimated Annual</div>
341
+ </div>
342
+ """, unsafe_allow_html=True)
343
+
344
+
345
+
346
+ st.markdown('<hr class="custom-divider">', unsafe_allow_html=True)
347
+
348
+
349
+
350
+ st.subheader("Current Blend Properties")
351
+ blend_props = {
352
+ "Property 1": 0.847,
353
+ "Property 2": 0.623,
354
+ "Property 3": 0.734,
355
+ "Property 4": 0.912,
356
+ "Property 5": 0.456,
357
+ "Property 6": -1.234,
358
+ }
359
+
360
+ # Enhanced dataframe display
361
+ df = pd.DataFrame(blend_props.items(), columns=["Property", "Value"])
362
+ # st.dataframe(
363
+ # df.style
364
+ # .background_gradient(cmap="YlOrBr", subset=["Value"])
365
+ # .format({"Value": "{:.3f}"}),
366
+ # use_container_width=True
367
+ # )
368
+
369
+ st.markdown('<div class="table-container"><div class="table-inner">', unsafe_allow_html=True)
370
+ st.dataframe(df, use_container_width=True)
371
+ st.markdown('</div></div>', unsafe_allow_html=True)
372
+
373
+
374
+
375
+
376
+ with tabs[1]:
377
+ col_header = st.columns([0.8, 0.2])
378
+ with col_header[0]:
379
+ st.subheader("🎛️ Blend Designer")
380
+ with col_header[1]:
381
+ batch_blend = st.checkbox("Batch Blend Mode", value=False,
382
+ help="Switch between manual input and predefined fuel selection",
383
+ key="batch_blend_mode")
384
+
385
+ # Initialize session state
386
+ if 'show_visualization' not in st.session_state:
387
+ st.session_state.show_visualization = False
388
+ if 'blended_value' not in st.session_state:
389
+ st.session_state.blended_value = None
390
+ if 'selected_property' not in st.session_state:
391
+ st.session_state.selected_property = "Property1"
392
+
393
+ # Batch mode file upload
394
+ if batch_blend:
395
+ st.subheader("📤 Batch Processing")
396
+ uploaded_file = st.file_uploader("Upload CSV File", type=["csv"], key="Batch_upload")
397
+ weights = [0.1, 0.2, 0.25, 0.15, 0.3] # Default weights for batch mode
398
+
399
+ if not uploaded_file:
400
+ st.warning("Please upload a CSV file for batch processing")
401
+ data_input = None
402
+ else:
403
+ try:
404
+ data_input = pd.read_csv(uploaded_file)
405
+ st.success("File uploaded successfully")
406
+ st.dataframe(data_input.head())
407
+ except Exception as e:
408
+ st.error(f"Error reading file: {str(e)}")
409
+ data_input = None
410
+ else:
411
+ # Regular mode
412
+ data_input = None
413
+ weights, props = [], []
414
+ col1, col2 = st.columns(2)
415
+
416
+ with col1:
417
+ st.markdown("##### ⚖️ Component Weights")
418
+ for i in range(5):
419
+ weight = st.number_input(
420
+ f"Weight for Component {i+1}",
421
+ min_value=0.0,
422
+ max_value=1.0,
423
+ value=0.2,
424
+ step=0.01,
425
+ key=f"w_{i}"
426
+ )
427
+ weights.append(weight)
428
+
429
+ with col2:
430
+ st.markdown("##### Fuel Selection")
431
+ for i in range(5):
432
+ fuel = st.selectbox(
433
+ f"Component {i+1} Fuel Type",
434
+ options=list(st.session_state.FUEL_PROPERTIES.keys()),
435
+ key=f"fuel_{i}"
436
+ )
437
+ props.append(st.session_state.FUEL_PROPERTIES[fuel])
438
+
439
+ if st.button("⚙️ Predict Blended Property", key="predict_btn"):
440
+ if batch_blend:
441
+ if data_input is None:
442
+ st.error("⚠️ Please upload a valid CSV file first!")
443
+ st.session_state.show_visualization = False
444
+ else:
445
+ st.session_state.show_visualization = True
446
+ else:
447
+ if abs(sum(weights) - 1.0) > 0.01:
448
+ st.warning("⚠️ The total of weights must be **1.0**.")
449
+ st.session_state.show_visualization = False
450
+ else:
451
+ st.session_state.show_visualization = True
452
+
453
+ if st.session_state.show_visualization:
454
+ # Show calculation details
455
+ st.subheader("Blend Components Data")
456
+
457
+ if not batch_blend:
458
+ weights_data = {f"Component{i+1}_fraction": weights[i] for i in range(len(weights))}
459
+ props_data = {f"Component{i+1}_{j}": props[i][j] for j in props[i].keys() for i in range(len(props))}
460
+ combined = {**weights_data, **props_data}
461
+ data_input = pd.DataFrame([combined])
462
+
463
+ st.write("Properties:", data_input)
464
+
465
+ # Show visualization only if prediction was made
466
+ if st.session_state.show_visualization:
467
+ if not batch_blend:
468
+ st.markdown('<hr class="custom-divider">', unsafe_allow_html=True)
469
+ st.subheader("Blend Visualization")
470
+
471
+ components = [f"Component {i+1}" for i in range(5)]
472
+
473
+ # 1. Weight Distribution Pie Chart
474
+ col1, col2 = st.columns(2)
475
+ with col1:
476
+ fig1 = px.pie(
477
+ names=components,
478
+ values=weights,
479
+ title="Weight Distribution",
480
+ color_discrete_sequence=['#8B4513', '#CFB53B', '#654321'],
481
+ hole=0.4
482
+ )
483
+ fig1.update_layout(
484
+ margin=dict(t=50, b=10),
485
+ showlegend=False
486
+ )
487
+ fig1.update_traces(
488
+ textposition='inside',
489
+ textinfo='percent+label',
490
+ marker=dict(line=dict(color='#ffffff', width=1))
491
+ )
492
+ st.plotly_chart(fig1, use_container_width=True)
493
+
494
+ # 2. Property Comparison Bar Chart
495
+ with col2:
496
+ # Property selection for fuel mode
497
+ viz_property = st.selectbox(
498
+ "Select Property to View",
499
+ [f"Property{i+1}" for i in range(10)],
500
+ key="viz_property"
501
+ )
502
+ bar_values = [p[viz_property] for p in props]
503
+ blended_value = 123 #Modify
504
+
505
+ fig2 = px.bar(
506
+ x=components,
507
+ y=bar_values,
508
+ title=f"{viz_property} Values",
509
+ color=bar_values,
510
+ color_continuous_scale='YlOrBr'
511
+ )
512
+ fig2.update_layout(
513
+ yaxis_title=viz_property,
514
+ xaxis_title="Component",
515
+ margin=dict(t=50, b=10),
516
+ coloraxis_showscale=False
517
+ )
518
+
519
+ fig2.add_hline(
520
+ y=blended_value,
521
+ line_dash="dot",
522
+ line_color="#ff6600",
523
+ annotation_text="Blended Value",
524
+ annotation_position="top right"
525
+ )
526
+ st.plotly_chart(fig2, use_container_width=True)
527
+
528
+ # Display the calculated value prominently
529
+ st.markdown(f"""
530
+ <div style="
531
+ background-color: #FAF3E6;
532
+ border-left: 4px solid #8B4513;
533
+ border-radius: 4px;
534
+ padding: 12px;
535
+ margin: 12px 0;
536
+ ">
537
+ <p style="margin: 0; color: #654321;
538
+ font-size: 2.2rem;
539
+ font-weight: 800;
540
+ color: #000;
541
+ text-align:center;">
542
+ Calculated <strong>{viz_property}</strong> =
543
+ <strong style="color: #000">{blended_value:.4f}</strong>
544
+ </p>
545
+ </div>
546
+ """, unsafe_allow_html=True)
547
+ else:
548
+ # Batch mode visualization placeholder
549
+ st.markdown('<hr class="custom-divider">', unsafe_allow_html=True)
550
+ st.subheader("Batch Processing Results")
551
+ st.dataframe(data_input, use_container_width=True)
552
+ # st.info("Batch processing complete. Add custom visualizations here.")
553
+
554
+
555
+ with tabs[2]:
556
+ st.subheader("📤 Nothing FOr NOw")
557
+ # uploaded_file = st.file_uploader("Upload CSV File", type=["csv"])
558
+
559
+ # if uploaded_file:
560
+ # df = pd.read_csv(uploaded_file)
561
+ # st.success("File uploaded successfully")
562
+ # st.dataframe(df.head())
563
+
564
+ # if st.button("⚙️ Run Batch Prediction"):
565
+ # result_df = df.copy()
566
+ # # result_df["Predicted_Property"] = df.apply(
567
+ # # lambda row: run_dummy_prediction(row.values[:5], row.values[5:10]), axis=1
568
+ # # )
569
+ # st.success("Batch prediction completed")
570
+ # st.dataframe(result_df.head())
571
+ # csv = result_df.to_csv(index=False).encode("utf-8")
572
+ # st.download_button("Download Results", csv, "prediction_results.csv", "text/csv")
573
+
574
+
575
+
576
+ with tabs[3]:
577
+ st.subheader("⚙️ Optimization Engine")
578
+
579
+ # Pareto frontier demo
580
+ st.markdown("#### Cost vs Performance Trade-off")
581
+ np.random.seed(42)
582
+ optimization_data = pd.DataFrame({
583
+ 'Cost ($/ton)': np.random.uniform(100, 300, 50),
584
+ 'Performance Score': np.random.uniform(70, 95, 50)
585
+ })
586
+
587
+ fig3 = px.scatter(
588
+ optimization_data,
589
+ x='Cost ($/ton)',
590
+ y='Performance Score',
591
+ title="Potential Blend Formulations",
592
+ color='Performance Score',
593
+ color_continuous_scale='YlOrBr'
594
+ )
595
+
596
+ # Add dummy pareto frontier
597
+ x_pareto = np.linspace(100, 300, 10)
598
+ y_pareto = 95 - 0.1*(x_pareto-100)
599
+ fig3.add_trace(px.line(
600
+ x=x_pareto,
601
+ y=y_pareto,
602
+ color_discrete_sequence= ['#8B4513', '#CFB53B', '#654321']
603
+ ).data[0])
604
+
605
+ fig3.update_layout(
606
+ showlegend=False,
607
+ annotations=[
608
+ dict(
609
+ x=200,
610
+ y=88,
611
+ text="Pareto Frontier",
612
+ showarrow=True,
613
+ arrowhead=1,
614
+ ax=-50,
615
+ ay=-30
616
+ )
617
+ ]
618
+ )
619
+ st.plotly_chart(fig3, use_container_width=True)
620
+
621
+ # Blend optimization history
622
+ st.markdown("#### Optimization Progress")
623
+ iterations = np.arange(20)
624
+ performance = np.concatenate([np.linspace(70, 85, 10), np.linspace(85, 89, 10)])
625
+
626
+ fig4 = px.line(
627
+ x=iterations,
628
+ y=performance,
629
+ title="Best Performance by Iteration",
630
+ markers=True
631
+ )
632
+ fig4.update_traces(
633
+ line_color='#1d3b58',
634
+ marker_color='#2c5282',
635
+ line_width=2.5
636
+ )
637
+ fig4.update_layout(
638
+ yaxis_title="Performance Score",
639
+ xaxis_title="Iteration"
640
+ )
641
+ st.plotly_chart(fig4, use_container_width=True)
642
+
643
+
644
+
645
+ with tabs[4]:
646
+ st.subheader("📚 Fuel Registry") # Changed to book emoji for registry
647
+
648
+ # Button to add new fuel
649
+ st.markdown("#### ➕ Add a New Fuel Type")
650
+ with st.expander("Click to Add New Fuel", expanded=False):
651
+ with st.form("new_fuel_form", clear_on_submit=False):
652
+ fuel_name = st.text_input("Fuel Name", placeholder="e.g. Bioethanol")
653
+
654
+ cols = st.columns(5)
655
+ properties = {}
656
+ for i in range(10):
657
+ with cols[i % 5]:
658
+ prop_val = st.number_input(
659
+ f"Property {i+1}",
660
+ min_value=0.0,
661
+ step=0.1,
662
+ key=f"prop_{i}",
663
+ format="%.2f"
664
+ )
665
+ properties[f"Property{i+1}"] = round(prop_val, 2)
666
+
667
+ col1, col2 = st.columns(2)
668
+ with col1:
669
+ submitted = st.form_submit_button("💾 Save Fuel", use_container_width=True)
670
+ with col2:
671
+ cancelled = st.form_submit_button("❌ Cancel", use_container_width=True)
672
+
673
+ if submitted:
674
+ if not fuel_name.strip():
675
+ st.warning("Fuel name cannot be empty.")
676
+ elif fuel_name in st.session_state.FUEL_PROPERTIES:
677
+ st.error(f"{fuel_name} already exists in registry.")
678
+ else:
679
+ # Update both session state and CSV
680
+ st.session_state.FUEL_PROPERTIES[fuel_name] = properties
681
+ save_fuel_data()
682
+ st.success(f"{fuel_name} successfully added!")
683
+ st.rerun() # Refresh to show new fuel
684
+
685
+ if cancelled:
686
+ st.rerun()
687
+
688
+ with st.expander("Batch Add New Fuel", expanded=False):
689
+ uploaded_file = st.file_uploader(
690
+ "📤 Upload Fuel Batch (CSV)",
691
+ type=['csv'],
692
+ accept_multiple_files=False,
693
+ key="fuel_uploader",
694
+ help="Upload a CSV file with the same format as the exported registry"
695
+ )
696
+ if uploaded_file is not None:
697
+ try:
698
+ new_fuels = pd.read_csv(uploaded_file, index_col=0).to_dict('index')
699
+
700
+ # Check for duplicates
701
+ duplicates = [name for name in new_fuels if name in st.session_state.FUEL_PROPERTIES]
702
+
703
+ if duplicates:
704
+ st.warning(f"These fuels already exist and won't be updated: {', '.join(duplicates)}")
705
+ # Only add new fuels
706
+ new_fuels = {name: props for name, props in new_fuels.items()
707
+ if name not in st.session_state.FUEL_PROPERTIES}
708
+
709
+ if new_fuels:
710
+ st.session_state.FUEL_PROPERTIES.update(new_fuels)
711
+ save_fuel_data()
712
+ st.success(f"Added {len(new_fuels)} new fuel(s) to registry!")
713
+ st.rerun()
714
+ else:
715
+ st.info("No new fuels to add from the uploaded file.")
716
+
717
+ except Exception as e:
718
+ st.error(f"Error processing file: {str(e)}")
719
+ st.error("Please ensure the file matches the expected format")
720
+
721
+ # Display current fuel properties
722
+ st.markdown("#### 🔍 Current Fuel Properties")
723
+ st.dataframe(
724
+ pd.DataFrame(st.session_state.FUEL_PROPERTIES).T.style
725
+ .background_gradient(cmap="YlOrBr", axis=None)
726
+ .format(precision=2),
727
+ use_container_width=True,
728
+ height=(len(st.session_state.FUEL_PROPERTIES) + 1) * 35 + 3,
729
+ hide_index=False
730
+ )
731
+
732
+ # File operations section
733
+
734
+
735
+ st.download_button(
736
+ label="📥 Download Registry (CSV)",
737
+ data=pd.DataFrame(st.session_state.FUEL_PROPERTIES).T.to_csv().encode('utf-8'),
738
+ file_name='fuel_properties.csv',
739
+ mime='text/csv',
740
+ # use_container_width=True
741
+ )
742
+
743
+
744
+
745
+
746
+
747
+
748
+
749
+
750
+
751
+
752
+
753
+ with tabs[5]:
754
+ st.subheader("🧠 Model Insights")
755
+
756
+ # Feature importance
757
+ st.markdown("#### Property Importance")
758
+ features = ['Property 1', 'Property 2', 'Property 3', 'Property 4', 'Property 5']
759
+ importance = np.array([0.35, 0.25, 0.2, 0.15, 0.05])
760
+
761
+ fig5 = px.bar(
762
+ x=importance,
763
+ y=features,
764
+ orientation='h',
765
+ title="Feature Importance for Blend Prediction",
766
+ color=importance,
767
+ color_continuous_scale='YlOrBr'
768
+ )
769
+ fig5.update_layout(
770
+ xaxis_title="Importance Score",
771
+ yaxis_title="Property",
772
+ coloraxis_showscale=False
773
+ )
774
+ st.plotly_chart(fig5, use_container_width=True)
775
+
776
+ # SHAP values demo
777
+ st.markdown("#### Property Impact Direction")
778
+ fig6 = px.scatter(
779
+ x=np.random.randn(100),
780
+ y=np.random.randn(100),
781
+ color=np.random.choice(features, 100),
782
+ title="SHAP Values (Simulated)",
783
+ labels={'x': 'Impact on Prediction', 'y': 'Property Value'}
784
+ )
785
+ fig6.update_traces(
786
+ marker=dict(size=10, opacity=0.7),
787
+ selector=dict(mode='markers')
788
+ )
789
+ fig6.add_vline(x=0, line_width=1, line_dash="dash")
790
+ st.plotly_chart(fig6, use_container_width=True)
791
+
792
+
793
 
794
+ # st.markdown("""
795
+ # <style>
796
+ # /* Consistent chart styling */
797
+ # .stPlotlyChart {
798
+ # border-radius: 10px;
799
+ # background: white;
800
+ # padding: 15px;
801
+ # box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
802
+ # margin-bottom: 25px;
803
+ # }
804
+
805
+ # /* Better select widget alignment */
806
+ # .stSelectbox > div {
807
+ # margin-bottom: -15px;
808
+ # }
809
+
810
+ # /* Color scale adjustments */
811
+ # .plotly .colorbar {
812
+ # padding: 10px !important;
813
+ # }
814
+ # </style>
815
+ # """, unsafe_allow_html=True)