wayne-chi commited on
Commit
581c13d
·
verified ·
1 Parent(s): 1c17c57

Update streamlit_app.py

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