forecast1 / app.py
pranit144's picture
Upload 3 files
ae65591 verified
import streamlit as st
import pandas as pd
import plotly.graph_objects as go
import pickle
from statsmodels.tsa.arima.model import ARIMA
import os
from datetime import datetime, timedelta
# Page configuration with custom theme
st.set_page_config(
page_title="ERROR Log Analytics Dashboard",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS to enhance the UI
st.markdown("""
<style>
.main-header {
font-size: 2.5rem;
font-weight: 700;
color: #1E3A8A;
margin-bottom: 1rem;
}
.sub-header {
font-size: 1.5rem;
font-weight: 600;
color: #2563EB;
margin-top: 2rem;
}
.card {
background-color: #F8FAFC;
border-radius: 0.5rem;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
margin-bottom: 1rem;
}
.success-msg {
background-color: #DCFCE7;
color: #166534;
padding: 0.75rem;
border-radius: 0.375rem;
border-left: 4px solid #16A34A;
margin: 1rem 0;
}
.stButton>button {
background-color: #2563EB;
color: white;
border: none;
border-radius: 0.375rem;
padding: 0.5rem 1rem;
}
.metrics-container {
display: flex;
justify-content: space-between;
}
.metric-card {
background-color: #F0F9FF;
border-radius: 0.5rem;
padding: 1rem;
text-align: center;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
width: 32%;
}
</style>
""", unsafe_allow_html=True)
# Sidebar for controls and information
with st.sidebar:
st.image("https://www.svgrepo.com/show/374111/log.svg", width=100)
st.markdown("## ERROR Log Analytics")
st.markdown("---")
st.markdown("### Model Configuration")
# File selection (keeping default path but making it look configurable)
file_path = st.text_input("Log file path", value="augmented_logs.csv")
# ARIMA parameters
st.markdown("### ARIMA Parameters")
p = st.slider("Auto-regression (p)", min_value=0, max_value=5, value=1)
d = st.slider("Differencing (d)", min_value=0, max_value=2, value=1)
q = st.slider("Moving Average (q)", min_value=0, max_value=5, value=1)
# Forecast range
st.markdown("### Forecast Settings")
forecast_days = st.slider("Forecast Horizon (days)", min_value=1, max_value=30, value=7)
st.markdown("---")
st.markdown("*This dashboard analyzes ERROR logs and forecasts future error rates using ARIMA modeling.*")
# Main content
st.markdown('<div class="main-header">📊 ERROR Log Analysis & Forecasting</div>', unsafe_allow_html=True)
if not os.path.exists(file_path):
st.error(f"❌ File not found: {file_path}")
else:
try:
# Main app container
with st.container():
# Load and prep data
df = pd.read_csv(file_path)
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['date'] = df['timestamp'].dt.date
# Group by date and count ERRORs
daily_errors = df[df['log_level'] == 'ERROR'].groupby('date').size()
daily_errors_ts = daily_errors.asfreq('D').fillna(0)
# Display key metrics
st.markdown('<div class="sub-header">Key Metrics</div>', unsafe_allow_html=True)
col1, col2, col3 = st.columns(3)
with col1:
st.markdown('<div class="card">', unsafe_allow_html=True)
st.metric("Total ERRORs", f"{int(daily_errors_ts.sum())}")
st.markdown('</div>', unsafe_allow_html=True)
with col2:
st.markdown('<div class="card">', unsafe_allow_html=True)
st.metric("Average Daily ERRORs", f"{daily_errors_ts.mean():.2f}")
st.markdown('</div>', unsafe_allow_html=True)
with col3:
st.markdown('<div class="card">', unsafe_allow_html=True)
if len(daily_errors_ts) >= 7:
last_week = daily_errors_ts[-7:].mean()
previous_week = daily_errors_ts[-14:-7].mean()
delta = ((last_week - previous_week) / previous_week * 100) if previous_week > 0 else 0
st.metric("7-Day Trend", f"{last_week:.2f}", f"{delta:.1f}%")
else:
st.metric("7-Day Trend", "Insufficient data")
st.markdown('</div>', unsafe_allow_html=True)
# Historical data visualization
st.markdown('<div class="sub-header">Historical ERROR Trends</div>', unsafe_allow_html=True)
st.markdown('<div class="card">', unsafe_allow_html=True)
chart_tab1, chart_tab2 = st.tabs(["Line Chart", "Bar Chart"])
with chart_tab1:
st.line_chart(daily_errors_ts)
with chart_tab2:
st.bar_chart(daily_errors_ts)
st.markdown('</div>', unsafe_allow_html=True)
# Model training
st.markdown('<div class="sub-header">ARIMA Model Training</div>', unsafe_allow_html=True)
st.markdown('<div class="card">', unsafe_allow_html=True)
try:
with st.spinner("Training ARIMA model..."):
# Use the parameters from sidebar
model = ARIMA(daily_errors_ts, order=(p, d, q))
model_fit = model.fit()
# Save model
with open("arima_model.pkl", "wb") as f:
pickle.dump(model_fit, f)
st.markdown('<div class="success-msg">✅ ARIMA model trained and saved successfully!</div>',
unsafe_allow_html=True)
# Display model summary in expander
with st.expander("View Model Details"):
st.code(str(model_fit.summary()))
except Exception as arima_error:
st.error(f"⚠️ ARIMA training failed: {arima_error}")
st.markdown('</div>', unsafe_allow_html=True)
# Forecast visualization
st.markdown('<div class="sub-header">ERROR Forecast Analysis</div>', unsafe_allow_html=True)
st.markdown('<div class="card">', unsafe_allow_html=True)
forecast = model_fit.forecast(steps=forecast_days)
forecast_dates = pd.date_range(start=daily_errors_ts.index[-1] + pd.Timedelta(days=1),
periods=forecast_days)
# Create forecast dataframe for additional analysis
forecast_df = pd.DataFrame({
'date': forecast_dates,
'forecast': forecast.values,
# Use a fixed standard deviation estimate instead of se_mean
'lower_ci': forecast.values - 2 * forecast.values.std() if len(forecast) > 1 else forecast.values,
'upper_ci': forecast.values + 2 * forecast.values.std() if len(forecast) > 1 else forecast.values * 1.2
})
# Round negative values to 0 for logical consistency
forecast_df['lower_ci'] = forecast_df['lower_ci'].clip(lower=0)
forecast_df['forecast'] = forecast_df['forecast'].clip(lower=0)
# Enhanced plotly visualization
fig = go.Figure()
# Historical data
fig.add_trace(go.Scatter(
x=daily_errors_ts.index,
y=daily_errors_ts.values,
mode='lines+markers',
name='Historical ERRORs',
line=dict(color='#3B82F6', width=2)
))
# Forecast
fig.add_trace(go.Scatter(
x=forecast_df['date'],
y=forecast_df['forecast'],
mode='lines+markers',
name='Forecasted ERRORs',
line=dict(color='#EF4444', width=2, dash='dash')
))
# Confidence interval
fig.add_trace(go.Scatter(
x=forecast_df['date'].tolist() + forecast_df['date'].tolist()[::-1],
y=forecast_df['upper_ci'].tolist() + forecast_df['lower_ci'].tolist()[::-1],
fill='toself',
fillcolor='rgba(239, 68, 68, 0.1)',
line=dict(color='rgba(0,0,0,0)'),
hoverinfo='skip',
showlegend=False
))
fig.update_layout(
title='ERROR Log Forecast with Confidence Intervals',
xaxis_title='Date',
yaxis_title='ERROR Count',
hovermode='x unified',
legend=dict(x=0.01, y=0.99),
template='plotly_white',
height=500
)
st.plotly_chart(fig, use_container_width=True)
# Forecast data table
with st.expander("View Forecast Data"):
forecast_df['date'] = forecast_df['date'].dt.date
forecast_df['forecast'] = forecast_df['forecast'].round(2)
forecast_df['lower_ci'] = forecast_df['lower_ci'].round(2)
forecast_df['upper_ci'] = forecast_df['upper_ci'].round(2)
st.dataframe(forecast_df)
# Download forecast as CSV
csv = forecast_df.to_csv(index=False)
st.download_button(
label="Download Forecast CSV",
data=csv,
file_name=f"error_forecast_{datetime.now().strftime('%Y%m%d')}.csv",
mime="text/csv"
)
st.markdown('</div>', unsafe_allow_html=True)
except Exception as e:
st.error(f"❌ Error processing data: {e}")