Update src/streamlit_app.py
Browse files- src/streamlit_app.py +294 -0
src/streamlit_app.py
CHANGED
|
@@ -761,5 +761,299 @@ with tabs[8]:
|
|
| 761 |
else:
|
| 762 |
st.info("No logs yet — run AutoML once.")
|
| 763 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 764 |
st.markdown("---")
|
| 765 |
st.markdown("**Note:** Synthetic demo dataset for educational use only. Real deployment requires plant data, NDA, and safety validation.")
|
|
|
|
| 761 |
else:
|
| 762 |
st.info("No logs yet — run AutoML once.")
|
| 763 |
|
| 764 |
+
|
| 765 |
+
# ----- Smart Advisor tab (Role-based Insights)
|
| 766 |
+
with tabs[9]:
|
| 767 |
+
st.subheader(" Smart Advisor — Role-Based Insights")
|
| 768 |
+
|
| 769 |
+
# -------------------------
|
| 770 |
+
# 1. Role hierarchy and descriptions
|
| 771 |
+
# -------------------------
|
| 772 |
+
roles = {
|
| 773 |
+
# --- Ground-level ---
|
| 774 |
+
"Furnace Operator": "Runs daily EAF heats, manages electrodes, slag foaming, and tap timing.",
|
| 775 |
+
"Shift Engineer": "Coordinates furnace, casting, and maintenance operations during the shift.",
|
| 776 |
+
"Process Metallurgist": "Optimizes chemistry, refining, and metallurgical balance across heats.",
|
| 777 |
+
"Maintenance Engineer": "Monitors vibration, bearings, and schedules preventive maintenance.",
|
| 778 |
+
"Quality Engineer": "Tracks billet surface, composition, and defect rates from casting to rolling.",
|
| 779 |
+
|
| 780 |
+
# --- Mid-level / Plant ---
|
| 781 |
+
"Energy Manager": "Analyzes power, load factor, and energy cost per ton of steel.",
|
| 782 |
+
"Production Head": "Supervises throughput, yield, and adherence to shift-level production targets.",
|
| 783 |
+
"Reliability Manager": "Oversees equipment reliability, predictive maintenance, and downtime prevention.",
|
| 784 |
+
"Chief Process Engineer": "Links metallurgical parameters to standard operating conditions.",
|
| 785 |
+
"Process Optimization Head (PP&C)": "Balances yield, power, and reliability across EAF, caster, and rolling units.",
|
| 786 |
+
"Chief General Manager – PP&C": "Oversees planning, process, and control at plant level — coordinating all shops for optimal energy, yield, and reliability.",
|
| 787 |
+
"Deputy General Manager (Operations)": "Supervises multi-shop coordination, productivity, and manpower scheduling.",
|
| 788 |
+
"Plant Head": "Oversees plant-wide KPIs — production, energy, quality, and modernization progress.",
|
| 789 |
+
|
| 790 |
+
# --- Strategic / Corporate ---
|
| 791 |
+
"Executive Director (Works)": "Integrates operations, people, and safety across all plants.",
|
| 792 |
+
"Chief Operating Officer (COO)": "Ensures alignment between production efficiency and business goals.",
|
| 793 |
+
"Chief Sustainability Officer (CSO)": "Monitors CO₂ intensity, waste recovery, and environmental compliance.",
|
| 794 |
+
"Chief Financial Officer (CFO)": "Links operational performance to cost efficiency and ROI.",
|
| 795 |
+
"Chief Executive Officer (CEO)": "Focuses on long-term performance, modernization, and shareholder impact."
|
| 796 |
+
}
|
| 797 |
+
|
| 798 |
+
# -------------------------
|
| 799 |
+
# 2. Role-specific reasoning prompts for LLM
|
| 800 |
+
# -------------------------
|
| 801 |
+
role_prompts = {
|
| 802 |
+
"Furnace Operator": """
|
| 803 |
+
You are the EAF furnace operator responsible for maintaining a stable arc and safe melting.
|
| 804 |
+
Translate model recommendations into clear, actionable controls: electrode movement, oxygen flow,
|
| 805 |
+
slag foaming, or power adjustment. Focus on operational safety and tap timing.
|
| 806 |
+
""",
|
| 807 |
+
"Shift Engineer": """
|
| 808 |
+
You are the shift engineer overseeing melting, casting, and maintenance coordination.
|
| 809 |
+
Interpret model insights for operational actions — mention if inter-shop coordination is required.
|
| 810 |
+
""",
|
| 811 |
+
"Process Metallurgist": """
|
| 812 |
+
You are the process metallurgist. Evaluate the data-driven SHAP patterns to interpret metallurgical
|
| 813 |
+
balance, oxidation behavior, and refining efficiency. Suggest chemistry or process tuning.
|
| 814 |
+
""",
|
| 815 |
+
"Maintenance Engineer": """
|
| 816 |
+
You are the maintenance engineer responsible for reliability. Identify potential failure risks
|
| 817 |
+
(e.g., vibration anomalies, overheating, current imbalance) and propose proactive checks.
|
| 818 |
+
""",
|
| 819 |
+
"Quality Engineer": """
|
| 820 |
+
You are the quality engineer monitoring casting and rolling outcomes. Translate process variables
|
| 821 |
+
into expected surface or composition quality impacts and preventive measures.
|
| 822 |
+
""",
|
| 823 |
+
"Energy Manager": """
|
| 824 |
+
You are the energy manager. Interpret how SHAP signals influence energy per ton and power factor.
|
| 825 |
+
Quantify efficiency deviations and suggest scheduling or load adjustments.
|
| 826 |
+
""",
|
| 827 |
+
"Production Head": """
|
| 828 |
+
You are the production head tracking yield and throughput. Connect SHAP insights to bottlenecks
|
| 829 |
+
in productivity, heat timing, or equipment utilization. Suggest optimization steps.
|
| 830 |
+
""",
|
| 831 |
+
"Reliability Manager": """
|
| 832 |
+
You are the reliability manager. Evaluate if process trends suggest equipment stress, overheating,
|
| 833 |
+
or wear. Recommend intervention plans and projected downtime avoidance.
|
| 834 |
+
""",
|
| 835 |
+
"Chief Process Engineer": """
|
| 836 |
+
You are the chief process engineer. Convert SHAP outputs into process standardization insights.
|
| 837 |
+
Flag anomalies that require SOP review and coordinate with metallurgical and control teams.
|
| 838 |
+
""",
|
| 839 |
+
"Process Optimization Head (PP&C)": """
|
| 840 |
+
You are the Process Optimization Head in PP&C. Assess SHAP signals across multiple units to improve
|
| 841 |
+
system-level yield, energy, and reliability. Recommend balanced actions and inter-shop alignment.
|
| 842 |
+
""",
|
| 843 |
+
"Chief General Manager – PP&C": """
|
| 844 |
+
You are the Chief General Manager (PP&C) responsible for overall plant coordination,
|
| 845 |
+
planning, process control, and modernization. Interpret model insights as if briefing
|
| 846 |
+
senior management and section heads before a shift review.
|
| 847 |
+
|
| 848 |
+
Your response must:
|
| 849 |
+
- Translate technical terms into operational themes (e.g., “arc instability”)
|
| 850 |
+
- Identify cross-functional effects (EAF ↔ Caster ↔ Rolling)
|
| 851 |
+
- Suggest coordination steps (maintenance, power, metallurgist)
|
| 852 |
+
- Conclude with KPI or strategic impact (yield, energy, reliability)
|
| 853 |
+
- If any data pattern seems implausible, mention it and propose review.
|
| 854 |
+
""",
|
| 855 |
+
"Deputy General Manager (Operations)": """
|
| 856 |
+
You are the DGM (Operations). Summarize SHAP-derived insights into actionable instructions
|
| 857 |
+
for shop heads. Emphasize throughput, manpower planning, and heat plan adherence.
|
| 858 |
+
""",
|
| 859 |
+
"Plant Head": """
|
| 860 |
+
You are the Plant Head. Translate technical findings into KPI performance trends and upcoming
|
| 861 |
+
operational risks. Recommend cross-departmental actions and expected impact on production targets.
|
| 862 |
+
""",
|
| 863 |
+
"Executive Director (Works)": """
|
| 864 |
+
You are the Executive Director (Works). Summarize how the plant is performing overall and where
|
| 865 |
+
immediate leadership attention is required. Use a governance-level tone, referencing key KPIs.
|
| 866 |
+
""",
|
| 867 |
+
"Chief Operating Officer (COO)": """
|
| 868 |
+
You are the COO. Interpret model insights at a strategic level — efficiency, tonnage, cost, reliability.
|
| 869 |
+
Highlight systemic improvements, risk areas, and financial implications across plants.
|
| 870 |
+
""",
|
| 871 |
+
"Chief Sustainability Officer (CSO)": """
|
| 872 |
+
You are the CSO. Relate operational insights to environmental impact, carbon efficiency,
|
| 873 |
+
and sustainability metrics. Quantify potential emission reduction.
|
| 874 |
+
""",
|
| 875 |
+
"Chief Financial Officer (CFO)": """
|
| 876 |
+
You are the CFO. Interpret operational SHAP findings in terms of cost efficiency, asset utilization,
|
| 877 |
+
and ROI. Provide an executive financial perspective on potential savings or risks.
|
| 878 |
+
""",
|
| 879 |
+
"Chief Executive Officer (CEO)": """
|
| 880 |
+
You are the CEO of a major integrated steel producer.
|
| 881 |
+
Provide a concise narrative (2–3 paragraphs) summarizing plant performance trends,
|
| 882 |
+
operational risks, and opportunities — linking them to strategic goals in the annual report:
|
| 883 |
+
productivity, sustainability, cost leadership, and modernization.
|
| 884 |
+
"""
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
# -------------------------
|
| 888 |
+
# 3. Role selection and contextual info
|
| 889 |
+
# -------------------------
|
| 890 |
+
role = st.selectbox("Select Your Role", list(roles.keys()), index=10)
|
| 891 |
+
st.caption(f" Context: {roles[role]}")
|
| 892 |
+
|
| 893 |
+
if "recs" not in locals() or not isinstance(recs, list) or not recs:
|
| 894 |
+
st.warning("Please run the AutoML + SHAP step first to generate recommendations.")
|
| 895 |
+
else:
|
| 896 |
+
if st.button("Generate Role-Based Advisory"):
|
| 897 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 898 |
+
if not HF_TOKEN:
|
| 899 |
+
st.error("HF_TOKEN not found. Please set it as an environment variable or in secrets.toml.")
|
| 900 |
+
else:
|
| 901 |
+
import requests, textwrap
|
| 902 |
+
|
| 903 |
+
API_URL = "https://router.huggingface.co/v1/chat/completions"
|
| 904 |
+
headers = {"Authorization": f"Bearer {HF_TOKEN}", "Content-Type": "application/json"}
|
| 905 |
+
|
| 906 |
+
# Add CGM-style reasoning context for cross-functional roles
|
| 907 |
+
if role in ["Chief General Manager – PP&C", "Process Optimization Head (PP&C)", "Plant Head"]:
|
| 908 |
+
reasoning_context = """
|
| 909 |
+
Think like a systems integrator balancing EAF, caster, and rolling mill performance.
|
| 910 |
+
Evaluate interdependencies and recommend coordinated actions across departments.
|
| 911 |
+
"""
|
| 912 |
+
elif role in ["COO", "CFO", "CEO"]:
|
| 913 |
+
reasoning_context = """
|
| 914 |
+
Think strategically. Connect operational drivers to business KPIs,
|
| 915 |
+
and quantify financial or sustainability implications.
|
| 916 |
+
"""
|
| 917 |
+
else:
|
| 918 |
+
reasoning_context = ""
|
| 919 |
+
|
| 920 |
+
# Build final prompt
|
| 921 |
+
prompt = textwrap.dedent(f"""
|
| 922 |
+
Role: {role}
|
| 923 |
+
Use case: {use_case}
|
| 924 |
+
Target variable: {target}
|
| 925 |
+
Ensemble model confidence (R²): {final_r2:.3f}
|
| 926 |
+
|
| 927 |
+
{reasoning_context}
|
| 928 |
+
|
| 929 |
+
Model-derived recommendations:
|
| 930 |
+
{json.dumps(recs, indent=2)}
|
| 931 |
+
|
| 932 |
+
{role_prompts.get(role, "Provide a professional metallurgical advisory summary.")}
|
| 933 |
+
|
| 934 |
+
Your response should cover:
|
| 935 |
+
1. What’s happening (interpreted simply)
|
| 936 |
+
2. What should be done
|
| 937 |
+
3. What outcomes to expect and why
|
| 938 |
+
""")
|
| 939 |
+
|
| 940 |
+
payload = {
|
| 941 |
+
"model": "meta-llama/Meta-Llama-3-8B-Instruct",
|
| 942 |
+
"messages": [
|
| 943 |
+
{"role": "system", "content": "You are a multi-role metallurgical advisor connecting data to human decisions."},
|
| 944 |
+
{"role": "user", "content": prompt}
|
| 945 |
+
],
|
| 946 |
+
"temperature": 0.4,
|
| 947 |
+
"max_tokens": 350,
|
| 948 |
+
}
|
| 949 |
+
|
| 950 |
+
with st.spinner(f"Generating role-based advisory for {role}..."):
|
| 951 |
+
resp = requests.post(API_URL, headers=headers, json=payload, timeout=90)
|
| 952 |
+
if resp.status_code == 200:
|
| 953 |
+
data = resp.json()
|
| 954 |
+
msg = (
|
| 955 |
+
data.get("choices", [{}])[0]
|
| 956 |
+
.get("message", {})
|
| 957 |
+
.get("content", "")
|
| 958 |
+
.strip()
|
| 959 |
+
)
|
| 960 |
+
if msg:
|
| 961 |
+
st.markdown(f"### Advisory for {role}")
|
| 962 |
+
st.info(msg)
|
| 963 |
+
# ---- Dynamic Data-Driven Highlights ----
|
| 964 |
+
if role in ["Chief General Manager – PP&C", "Plant Head", "Process Optimization Head (PP&C)"]:
|
| 965 |
+
st.markdown("#### 🔍 Shift Highlights — Data-Driven Summary")
|
| 966 |
+
|
| 967 |
+
try:
|
| 968 |
+
# 1️⃣ Latest data snapshot (simulates "current shift")
|
| 969 |
+
latest_df = df.tail(500).copy() # last 500 rows = current shift snapshot
|
| 970 |
+
|
| 971 |
+
# 2️⃣ Basic KPIs computed from live data
|
| 972 |
+
furnace_temp_mean = latest_df["furnace_temp"].mean()
|
| 973 |
+
furnace_temp_std = latest_df["furnace_temp"].std()
|
| 974 |
+
energy_eff_mean = latest_df["energy_efficiency"].mean()
|
| 975 |
+
yield_mean = latest_df["yield_ratio"].mean()
|
| 976 |
+
downtime_proxy = np.mean(latest_df["refractory_limit_flag"]) * 8 # hours/shift (proxy)
|
| 977 |
+
|
| 978 |
+
# 3️⃣ Compare vs historical baseline (previous 500 rows)
|
| 979 |
+
if len(df) > 1000:
|
| 980 |
+
prev_df = df.tail(1000).head(500)
|
| 981 |
+
delta_temp = ((furnace_temp_mean - prev_df["furnace_temp"].mean()) /
|
| 982 |
+
prev_df["furnace_temp"].mean()) * 100
|
| 983 |
+
delta_eff = ((energy_eff_mean - prev_df["energy_efficiency"].mean()) /
|
| 984 |
+
prev_df["energy_efficiency"].mean()) * 100
|
| 985 |
+
delta_yield = ((yield_mean - prev_df["yield_ratio"].mean()) /
|
| 986 |
+
prev_df["yield_ratio"].mean()) * 100
|
| 987 |
+
else:
|
| 988 |
+
delta_temp, delta_eff, delta_yield = 0, 0, 0
|
| 989 |
+
|
| 990 |
+
# 4️⃣ Qualitative interpretation
|
| 991 |
+
def trend_symbol(val):
|
| 992 |
+
if val > 0.5:
|
| 993 |
+
return f"↑ +{val:.2f}%"
|
| 994 |
+
elif val < -0.5:
|
| 995 |
+
return f"↓ {val:.2f}%"
|
| 996 |
+
else:
|
| 997 |
+
return f"→ {val:.2f}%"
|
| 998 |
+
|
| 999 |
+
# 5️⃣ Build structured table
|
| 1000 |
+
highlights = pd.DataFrame([
|
| 1001 |
+
["Furnace Temp Stability",
|
| 1002 |
+
"Stable" if furnace_temp_std < 50 else "Fluctuating",
|
| 1003 |
+
f"Avg: {furnace_temp_mean:.1f}°C ({trend_symbol(delta_temp)})"],
|
| 1004 |
+
["Energy Efficiency",
|
| 1005 |
+
"Improved" if delta_eff > 0 else "Declined",
|
| 1006 |
+
f"{energy_eff_mean:.4f} ({trend_symbol(delta_eff)})"],
|
| 1007 |
+
["Yield Ratio",
|
| 1008 |
+
"Nominal" if abs(delta_yield) < 1 else ("↑" if delta_yield > 0 else "↓"),
|
| 1009 |
+
f"{yield_mean*100:.2f}% ({trend_symbol(delta_yield)})"],
|
| 1010 |
+
["Refractory Limit Flag",
|
| 1011 |
+
"Within Safe Limit" if downtime_proxy < 1 else "Check Lining",
|
| 1012 |
+
f"Active Alerts: {downtime_proxy:.1f}/shift"]
|
| 1013 |
+
], columns=["Parameter", "Status", "Observation"])
|
| 1014 |
+
|
| 1015 |
+
st.dataframe(highlights, use_container_width=True)
|
| 1016 |
+
st.caption("Derived from live dataset trends (last 500 vs previous 500 rows).")
|
| 1017 |
+
|
| 1018 |
+
# 6️⃣ Optional: Link to SHAP recs for validation
|
| 1019 |
+
if isinstance(recs, list) and recs:
|
| 1020 |
+
st.markdown("#### 🧭 Cross-Verification with SHAP Insights")
|
| 1021 |
+
matches = [r for r in recs if any(k in r for k in ["furnace", "energy", "yield", "slag", "power"])]
|
| 1022 |
+
if matches:
|
| 1023 |
+
st.info("Aligned SHAP Recommendations:\n\n- " + "\n- ".join(matches))
|
| 1024 |
+
else:
|
| 1025 |
+
st.warning("No direct SHAP alignment found — potential anomaly or unseen pattern.")
|
| 1026 |
+
except Exception as e:
|
| 1027 |
+
st.warning(f"Shift Highlights unavailable: {e}")
|
| 1028 |
+
|
| 1029 |
+
else:
|
| 1030 |
+
st.warning(f"Empty response.\nRaw: {data}")
|
| 1031 |
+
else:
|
| 1032 |
+
st.error(f"HF API error {resp.status_code}: {resp.text}")
|
| 1033 |
+
|
| 1034 |
+
# -------------------------
|
| 1035 |
+
# 4. Optional role-based KPIs
|
| 1036 |
+
# -------------------------
|
| 1037 |
+
if role == "Chief General Manager – PP&C":
|
| 1038 |
+
col1, col2, col3 = st.columns(3)
|
| 1039 |
+
col1.metric("Plant Yield (Rolling 24h)", "96.8%", "↑0.7% vs yesterday")
|
| 1040 |
+
col2.metric("Energy per ton", "4.92 MWh/t", "↓2.3% week-on-week")
|
| 1041 |
+
col3.metric("Unplanned Downtime", "3.1 hrs", "↓1.2 hrs")
|
| 1042 |
+
st.caption("KPIs aligned with PP&C Balanced Scorecard — Yield • Energy • Reliability")
|
| 1043 |
+
|
| 1044 |
+
elif role in ["CEO", "COO"]:
|
| 1045 |
+
col1, col2, col3 = st.columns(3)
|
| 1046 |
+
col1.metric("EBITDA per ton", "₹7,420", "↑3.1% QoQ")
|
| 1047 |
+
col2.metric("CO₂ Intensity", "1.79 tCO₂/t", "↓2.4% YoY")
|
| 1048 |
+
col3.metric("Modernization CapEx", "₹122 Cr", "On track")
|
| 1049 |
+
st.caption("Strategic alignment: cost leadership • sustainability • modernization")
|
| 1050 |
+
|
| 1051 |
+
elif role in ["Furnace Operator", "Shift Engineer"]:
|
| 1052 |
+
col1, col2, col3 = st.columns(3)
|
| 1053 |
+
col1.metric("Furnace Temp", f"{df['furnace_temp'].iloc[-1]:.1f} °C")
|
| 1054 |
+
col2.metric("Arc Power", f"{df['arc_power'].iloc[-1]:.0f} kW")
|
| 1055 |
+
col3.metric("Power Factor", f"{df['power_factor'].iloc[-1]:.2f}")
|
| 1056 |
+
st.caption("Live operational parameters — monitor stability and foaming balance.")
|
| 1057 |
+
|
| 1058 |
st.markdown("---")
|
| 1059 |
st.markdown("**Note:** Synthetic demo dataset for educational use only. Real deployment requires plant data, NDA, and safety validation.")
|