import streamlit as st
import warnings
warnings.filterwarnings("ignore")
from config import get_css_styles, get_settings, get_translation
from data_handler import load_preset_data, load_uploaded_data, data_health_check
from analytics import get_material_stats, detect_outliers, create_total_production_chart, create_materials_trend_chart, create_shift_trend_chart
from ai_engine import init_ai_model
from typing import Dict
from datetime import datetime
from utils import init_session_state
st.set_page_config(
page_title="Production Monitor with AI Insights | Nilsen Service & Consulting",
page_icon="🏭",
layout="wide",
initial_sidebar_state="expanded"
)
def render_welcome_screen(t: Dict):
st.markdown(f'
', unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
st.markdown(f"### {t['welcome_quick_start']}")
st.markdown(t['welcome_steps'])
with col2:
st.markdown(f"### {t['welcome_features']}")
st.markdown(t['welcome_features_list'])
st.info(t['welcome_ready'])
def main():
st.markdown(get_css_styles(), unsafe_allow_html=True)
lang = st.sidebar.selectbox("Language", ["English", "Norsk"], index=1)
t = get_translation(lang)
st.markdown(f"""
{t['page_title']}
{t['page_subtitle']}
""", unsafe_allow_html=True)
init_session_state()
model = init_ai_model()
settings = get_settings()
with st.sidebar:
st.markdown(f"### {t['sidebar_data_source']}")
uploaded_file = st.file_uploader(t['sidebar_upload'], type=['csv'])
st.markdown("---")
st.markdown(f"### {t['sidebar_quick_load']}")
col1, col2 = st.columns(2)
with col1:
if st.button("2024 Data", type="primary", key="load_2024"):
st.session_state.load_preset = "2024"
with col2:
if st.button("2025 Data", type="primary", key="load_2025"):
st.session_state.load_preset = "2025"
st.markdown("---")
st.markdown(t['sidebar_format_hint'])
if model:
st.success(f"{t['ai_ready']} ({settings.environment})")
else:
st.warning(t['ai_unavailable'])
st.info(t['ai_config_hint'])
df = st.session_state.current_df
stats = st.session_state.current_stats
if uploaded_file:
try:
df = load_uploaded_data(uploaded_file)
stats = get_material_stats(df)
st.session_state.current_df = df
st.session_state.current_stats = stats
st.success(t['data_uploaded'])
except Exception as e:
st.error(f"Error loading uploaded file: {str(e)}")
elif 'load_preset' in st.session_state:
year = st.session_state.load_preset
try:
with st.spinner(f"Loading {year} data..."):
df = load_preset_data(year)
if df is not None:
stats = get_material_stats(df)
st.session_state.current_df = df
st.session_state.current_stats = stats
st.success(f"{year} {t['data_loaded']}")
except Exception as e:
st.error(f"Error loading {year} data: {str(e)}")
finally:
del st.session_state.load_preset
if df is not None and stats is not None:
health = data_health_check(df)
with st.expander(t['data_health']):
cols = st.columns(4)
for i, (key, value) in enumerate(health.items()):
with cols[i]:
st.metric(key, value)
st.markdown(f'', unsafe_allow_html=True)
materials = [k for k in stats.keys() if k != '_total_']
cols = st.columns(4)
for i, material in enumerate(materials[:3]):
info = stats[material]
with cols[i]:
st.metric(
label=material.replace('_', ' ').title(),
value=f"{info['total']:,.0f} kg",
delta=f"{info['percentage']:.1f}% of total"
)
st.caption(f"{t['metric_daily_avg']}: {info['daily_avg']:,.0f} kg")
if len(materials) >= 3:
total_info = stats['_total_']
with cols[3]:
st.metric(
label=t['metric_total'],
value=f"{total_info['total']:,.0f} kg",
delta="100% of total"
)
st.caption(f"{t['metric_daily_avg']}: {total_info['daily_avg']:,.0f} kg")
st.markdown(f'', unsafe_allow_html=True)
col1, col2 = st.columns([3, 1])
with col2:
time_view = st.selectbox(t['time_period'], ["daily", "weekly", "monthly"], key="time_view_select")
with col1:
with st.container():
st.markdown('', unsafe_allow_html=True)
total_chart = create_total_production_chart(df, time_view, lang)
st.plotly_chart(total_chart, use_container_width=True)
st.markdown('
', unsafe_allow_html=True)
st.markdown(f'', unsafe_allow_html=True)
col1, col2 = st.columns([3, 1])
with col2:
selected_materials = st.multiselect(
t['select_materials'],
options=materials,
default=materials,
key="materials_select"
)
with col1:
if selected_materials:
with st.container():
st.markdown('', unsafe_allow_html=True)
materials_chart = create_materials_trend_chart(df, time_view, selected_materials, lang)
st.plotly_chart(materials_chart, use_container_width=True)
st.markdown('
', unsafe_allow_html=True)
if 'shift' in df.columns:
st.markdown(f'', unsafe_allow_html=True)
with st.container():
st.markdown('', unsafe_allow_html=True)
shift_chart = create_shift_trend_chart(df, time_view, lang)
st.plotly_chart(shift_chart, use_container_width=True)
st.markdown('
', unsafe_allow_html=True)
outliers = detect_outliers(df)
st.markdown(f'', unsafe_allow_html=True)
cols = st.columns(len(outliers))
for i, (material, info) in enumerate(outliers.items()):
with cols[i]:
if info['count'] > 0:
dates_str = ", ".join(info['dates'])
st.markdown(f'''
{material.title()}
{info["count"]} {t['quality_outliers']}
{t['quality_normal_range']}: {info["range"]}
Dates: {dates_str}
''', unsafe_allow_html=True)
else:
st.markdown(f'{material.title()}
{t["quality_normal"]}
',
unsafe_allow_html=True)
st.markdown(f'', unsafe_allow_html=True)
col1, col2, col3 = st.columns(3)
with col1:
if st.button(t['btn_generate_pdf'], key="generate_pdf_btn", type="primary"):
try:
with st.spinner(t['pdf_generating']):
from pdf_generator import create_enhanced_pdf_report
st.session_state.pdf_buffer = create_enhanced_pdf_report(df, stats, outliers, model, lang)
st.session_state.export_ready = True
st.success(t['pdf_success'])
except Exception as e:
st.error(f"{t['pdf_failed']}: {str(e)}")
st.session_state.export_ready = False
if st.session_state.export_ready and st.session_state.pdf_buffer:
st.download_button(
label=t['btn_download_pdf'],
data=st.session_state.pdf_buffer,
file_name=f"production_report_{datetime.now().strftime('%Y%m%d_%H%M')}.pdf",
mime="application/pdf",
key="download_pdf_btn"
)
with col2:
if st.button(t['btn_generate_csv'], key="generate_csv_btn", type="primary"):
try:
from pdf_generator import create_csv_export
st.session_state.csv_data = create_csv_export(df, stats)
st.success(t['csv_success'])
except Exception as e:
st.error(f"{t['csv_failed']}: {str(e)}")
if st.session_state.csv_data is not None:
csv_string = st.session_state.csv_data.to_csv(index=False)
st.download_button(
label=t['btn_download_csv'],
data=csv_string,
file_name=f"production_summary_{datetime.now().strftime('%Y%m%d_%H%M')}.csv",
mime="text/csv",
key="download_csv_btn"
)
with col3:
csv_string = df.to_csv(index=False)
st.download_button(
label=t['btn_download_raw'],
data=csv_string,
file_name=f"raw_production_data_{datetime.now().strftime('%Y%m%d_%H%M')}.csv",
mime="text/csv",
key="download_raw_btn"
)
if model:
st.markdown(f'', unsafe_allow_html=True)
quick_questions = [t['ai_quick_q1'], t['ai_quick_q2'], t['ai_quick_q3']]
cols = st.columns(len(quick_questions))
for i, q in enumerate(quick_questions):
with cols[i]:
if st.button(q, key=f"ai_q_{i}"):
from ai_engine import query_ai
with st.spinner(t['ai_analyzing']):
answer = query_ai(model, stats, q, df, lang)
st.info(answer)
custom_question = st.text_input(
t['ai_ask_label'],
placeholder=t['ai_custom_placeholder'],
key="custom_ai_question"
)
if custom_question and st.button(t['ai_ask_btn'], key="ask_ai_btn"):
from ai_engine import query_ai
with st.spinner(t['ai_analyzing']):
answer = query_ai(model, stats, custom_question, df, lang)
st.success(f"**Q:** {custom_question}")
st.write(f"**A:** {answer}")
else:
st.markdown(f'', unsafe_allow_html=True)
st.info(t['ai_config_info'])
else:
render_welcome_screen(t)
if __name__ == "__main__":
main()