Id like to create a dashboard with the following KPIs. Each section will be its own unique tab: 1. Knowledge Inventory : Tracks the volume, status, and lifecycle of content in the knowledge base. Example KPIs: Number of Published KBAs Number of Active Articles Number of Articles Retired % of Articles Reviewed Time to Publish (SLA) — if tracked 2. Usage & Adoption: Shows how often knowledge is being used and integrated into workflows. Example KPIs: KBA Views % of KBAs in Use % of KBAs Attached to Tickets Articles Created from Ticket Management Most Viewed/Used KBAs % of Tickets Closed with a KBA (to be added) 3. Outcome Indicators Represents impact and effectiveness of knowledge — in quality, resolution, and reuse. Example KPIs: Article Quality Index (AQI) Helpful % Contribution Index FCR (First Contact Resolution) Ticket Deflection Rate & Count
Drop files here
or click to upload
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
# Set page configuration
st.set_page_config(
page_title="Knowledge Base Analytics Dashboard",
page_icon="📚",
layout="wide"
)
# Utility functions
def generate_sample_data():
"""Generate sample data for the dashboard"""
# Set seed for reproducibility
np.random.seed(42)
# Date range for the data
end_date = datetime.now()
start_date = end_date - timedelta(days=365)
date_range = pd.date_range(start=start_date, end=end_date, freq='D')
# Knowledge Inventory data
inventory_data = {
'Date': date_range,
'Published': np.cumsum(np.random.randint(0, 5, size=len(date_range))),
'Active': np.cumsum(np.random.randint(0, 4, size=len(date_range))),
'Retired': np.cumsum(np.random.randint(0, 2, size=len(date_range))),
'Reviewed': np.random.randint(50, 100, size=len(date_range))
}
inventory_df = pd.DataFrame(inventory_data)
inventory_df['Total'] = inventory_df['Published'] + inventory_df['Active'] - inventory_df['Retired']
inventory_df['% Reviewed'] = inventory_df['Reviewed'] / 100
# Time to Publish SLA data
sla_data = {
'Date': date_range,
'Time to Publish (hours)': np.random.normal(24, 5, size=len(date_range))
}
sla_df = pd.DataFrame(sla_data)
# Usage & Adoption data
usage_data = {
'Date': date_range,
'Views': np.cumsum(np.random.randint(10, 100, size=len(date_range))),
'KBAs in Use %': np.random.randint(50, 95, size=len(date_range)) / 100,
'KBAs Attached to Tickets %': np.random.randint(40, 90, size=len(date_range)) / 100,
'Articles Created from Tickets': np.cumsum(np.random.randint(0, 3, size=len(date_range))),
'Tickets Closed with KBA %': np.random.randint(30, 85, size=len(date_range)) / 100
}
usage_df = pd.DataFrame(usage_data)
# Most viewed KBAs
kb_titles = [
"Password Reset Procedure",
"VPN Connection Troubleshooting",
"Email Configuration Guide",
"Printer Setup Instructions",
"Software Installation Steps",
"Network Connectivity Issues",
"Mobile Device Registration",
"Account Access Management",
"Data Backup Procedures",
"System Upgrade Guidelines"
]
most_viewed = {
'Title': kb_titles,
'Views': np.random.randint(100, 5000, size=10),
'Category': np.random.choice(['IT', 'HR', 'Finance', 'Operations'], size=10)
}
most_viewed_df = pd.DataFrame(most_viewed)
most_viewed_df = most_viewed_df.sort_values('Views', ascending=False)
# Outcome indicators data
outcome_data = {
'Date': date_range,
'Article Quality Index': np.random.normal(85, 5, size=len(date_range)) / 100,
'Helpful %': np.random.normal(80, 10, size=len(date_range)) / 100,
'Contribution Index': np.random.normal(70, 15, size=len(date_range)) / 100,
'FCR %': np.random.normal(75, 8, size=len(date_range)) / 100,
'Ticket Deflection Count': np.cumsum(np.random.randint(1, 20, size=len(date_range))),
'Ticket Deflection Rate': np.random.normal(60, 10, size=len(date_range)) / 100
}
outcome_df = pd.DataFrame(outcome_data)
return inventory_df, sla_df, usage_df, most_viewed_df, outcome_df
# Main app
def main():
st.title("📚 Knowledge Base Analytics Dashboard")
# Generate sample data
inventory_df, sla_df, usage_df, most_viewed_df, outcome_df = generate_sample_data()
# Create tabs
tab1, tab2, tab3 = st.tabs([
"Knowledge Inventory",
"Usage & Adoption",
"Outcome Indicators"
])
# TAB 1: KNOWLEDGE INVENTORY
with tab1:
st.header("Knowledge Inventory")
st.subheader("Tracking volume, status, and lifecycle of content")
# Get the most recent data for the KPI cards
latest_data = inventory_df.iloc[-1]
# Top-level metrics row
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric(
label="Published KBAs",
value=f"{int(latest_data['Published']):,}",
delta=int(inventory_df.iloc[-7]['Published'] - inventory_df.iloc[-30]['Published']),
delta_color="normal"
)
with col2:
st.metric(
label="Active Articles",
value=f"{int(latest_data['Active']):,}",
delta=int(inventory_df.iloc[-7]['Active'] - inventory_df.iloc[-30]['Active']),
delta_color="normal"
)
with col3:
st.metric(
label="Retired Articles",
value=f"{int(latest_data['Retired']):,}",
delta=int(inventory_df.iloc[-7]['Retired'] - inventory_df.iloc[-30]['Retired']),
delta_color="inverse"
)
with col4:
st.metric(
label="% Articles Reviewed",
value=f"{latest_data['% Reviewed']:.1%}",
delta=f"{(latest_data['% Reviewed'] - inventory_df.iloc[-30]['% Reviewed']):.1%}",
delta_color="normal"
)
st.divider()
# Charts section
col1, col2 = st.columns(2)
with col1:
# Growth of KB articles over time
fig = px.area(
inventory_df,
x='Date',
y=['Published', 'Active', 'Retired'],
title="Knowledge Base Growth Over Time",
labels={"value": "Number of Articles", "variable": "Type"},
color_discrete_sequence=px.colors.qualitative.Bold
)
st.plotly_chart(fig, use_container_width=True)
with col2:
# Time to Publish SLA
fig = px.line(
sla_df,
x='Date',
y='Time to Publish (hours)',
title="Time to Publish (SLA)",
labels={"Time to Publish (hours)": "Hours"},
color_discrete_sequence=['#FF4B4B']
)
fig.add_hline(y=24, line_dash="dash", line_color="green", annotation_text="Target SLA (24h)")
st.plotly_chart(fig, use_container_width=True)
# Percentage of articles reviewed over time
fig = px.line(
inventory_df,
x='Date',
y='% Reviewed',
title="Percentage of Articles Reviewed Over Time",
labels={"% Reviewed": "Percentage Reviewed"},
color_discrete_sequence=['#FFA500']
)
fig.update_layout(yaxis_tickformat='.0%')
st.plotly_chart(fig, use_container_width=True)
# Data table
with st.expander("View Raw Inventory Data"):
st.dataframe(
inventory_df.tail(30).reset_index(drop=True),
column_config={
"Date": st.column_config.DateColumn("Date"),
"% Reviewed": st.column_config.ProgressColumn(
"% Reviewed",
format="%.2f%%",
min_value=0,
max_value=1
)
}
)
# TAB 2: USAGE & ADOPTION
with tab2:
st.header("Usage & Adoption")
st.subheader("Analyzing how knowledge is being utilized and integrated")
# Get the most recent data for the KPI cards
latest_usage = usage_df.iloc[-1]
# Top-level metrics row
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric(
label="Total KBA Views",
value=f"{int(latest_usage['Views']):,}",
delta=int(usage_df.iloc[-7]['Views'] - usage_df.iloc[-30]['Views']),
delta_color="normal"
)
with col2:
st.metric(
label="% of KBAs in Use",
value=f"{latest_usage['KBAs in Use %']:.1%}",
delta=f"{(latest_usage['KBAs in Use %'] - usage_df.iloc[-30]['KBAs in Use %']):.1%}",
delta_color="normal"
)
with col3:
st.metric(
label="% KBAs Attached to Tickets",
value=f"{latest_usage['KBAs Attached to Tickets %']:.1%}",
delta=f"{(latest_usage['KBAs Attached to Tickets %'] - usage_df.iloc[-30]['KBAs Attached to Tickets %']):.1%}",
delta_color="normal"
)
with col4:
st.metric(
label="Articles from Tickets",
value=f"{int(latest_usage['Articles Created from Tickets']):,}",
delta=int(usage_df.iloc[-7]['Articles Created from Tickets'] - usage_df.iloc[-30]['Articles Created from Tickets']),
delta_color="normal"
)
st.divider()
# Charts section
col1, col2 = st.columns(2)
with col1:
# KBA Views trend
fig = px.area(
usage_df,
x='Date',
y='Views',
title="Knowledge Base Article Views Over Time",
labels={"Views": "Number of Views"},
color_discrete_sequence=['#3366CC']
)
st.plotly_chart(fig, use_container_width=True)
# Most Viewed KBAs
fig = px.bar(
most_viewed_df.head(10),
x='Views',
y='Title',
color='Category',
title="Top 10 Most Viewed Knowledge Base Articles",
labels={"Views": "Number of Views", "Title": "Article Title"},
orientation='h'
)
fig.update_layout(yaxis={'categoryorder':'total ascending'})
st.plotly_chart(fig, use_container_width=True)
with col2:
# KBAs in Use % and Attached to Tickets %
fig = px.line(
usage_df,
x='Date',
y=['KBAs in Use %', 'KBAs Attached to Tickets %', 'Tickets Closed with KBA %'],
title="Knowledge Base Usage Metrics",
labels={
"value": "Percentage",
"variable": "Metric",
"KBAs in Use %": "KBAs in Use",
"KBAs Attached to Tickets %": "KBAs Attached to Tickets",
"Tickets Closed with KBA %": "Tickets Closed with KBA"
},
color_discrete_sequence=px.colors.qualitative.Plotly
)
fig.update_layout(yaxis_tickformat='.0%')
st.plotly_chart(fig, use_container_width=True)
# Articles Created from Tickets
fig = px.line(
usage_df,
x='Date',
y='Articles Created from Tickets',
title="Articles Created from Ticket Management",
labels={"Articles Created from Tickets": "Number of Articles"},
color_discrete_sequence=['#FF6692']
)
st.plotly_chart(fig, use_container_width=True)
# Data table
with st.expander("View Raw Usage Data"):
st.dataframe(
usage_df.tail(30).reset_index(drop=True),
column_config={
"Date": st.column_config.DateColumn("Date"),
"KBAs in Use %": st.column_config.ProgressColumn(
"KBAs in Use %",
format="%.2f%%",
min_value=0,
max_value=1
),
"KBAs Attached to Tickets %": st.column_config.ProgressColumn(
"KBAs Attached to Tickets %",
format="%.2f%%",
min_value=0,
max_value=1
),
"Tickets Closed with KBA %": st.column_config.ProgressColumn(
"Tickets Closed with KBA %",
format="%.2f%%",
min_value=0,
max_value=1
)
}
)
# TAB 3: OUTCOME INDICATORS
with tab3:
st.header("Outcome Indicators")
st.subheader("Measuring impact and effectiveness of knowledge")
# Get the most recent data for the KPI cards
latest_outcome = outcome_df.iloc[-1]
# Top-level metrics row
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric(
label="Article Quality Index",
value=f"{latest_outcome['Article Quality Index']:.1%}",
delta=f"{(latest_outcome['Article Quality Index'] - outcome_df.iloc[-30]['Article Quality Index']):.1%}",
delta_color="normal"
)
with col2:
st.metric(
label="Helpful %",
value=f"{latest_outcome['Helpful %']:.1%}",
delta=f"{(latest_outcome['Helpful %'] - outcome_df.iloc[-30]['Helpful %']):.1%}",
delta_color="normal"
)
with col3:
st.metric(
label="First Contact Resolution",
value=f"{latest_outcome['FCR %']:.1%}",
delta=f"{(latest_outcome['FCR %'] - outcome_df.iloc[-30]['FCR %']):.1%}",
delta_color="normal"
)
with col4:
st.metric(
label="Ticket Deflection Rate",
value=f"{latest_outcome['Ticket Deflection Rate']:.1%}",
delta=f"{(latest_outcome['Ticket Deflection Rate'] - outcome_df.iloc[-30]['Ticket Deflection Rate']):.1%}",
delta_color="normal"
)
st.divider()
# Charts section
col1, col2 = st.columns(2)
with col1:
# Article Quality and Helpful % trends
fig = px.line(
outcome_df,
x='Date',
y=['Article Quality Index', 'Helpful %', 'Contribution Index'],
title="Knowledge Quality Metrics Over Time",
labels={
"value": "Score",
"variable": "Metric",
"Article Quality Index": "Article Quality Index",
"Helpful %": "Helpful %",
"Contribution Index": "Contribution Index"
},
color_discrete_sequence=px.colors.qualitative.Safe
)
fig.update_layout(yaxis_tickformat='.0%')
st.plotly_chart(fig, use_container_width=True)
with col2:
# FCR trend
fig = px.line(
outcome_df,
x='Date',
y='FCR %',
title="First Contact Resolution (FCR) Rate",
labels={"FCR %": "FCR Rate"},
color_discrete_sequence=['#AB63FA']
)
fig.update_layout(yaxis_tickformat='.0%')
st.plotly_chart(fig, use_container_width=True)
# Ticket Deflection
col1, col2 = st.columns(2)
with col1:
# Ticket Deflection Count
fig = px.area(
outcome_df,
x='Date',
y='Ticket Deflection Count',
title="Ticket Deflection Count (Cumulative)",
labels={"Ticket Deflection Count": "Number of Tickets Deflected"},
color_discrete_sequence=['#00CC96']
)
st.plotly_chart(fig, use_container_width=True)
with col2:
# Ticket Deflection Rate
fig = px.line(
outcome_df,
x='Date',
y='Ticket Deflection Rate',
title="Ticket Deflection Rate",
labels={"Ticket Deflection Rate": "Deflection Rate"},
color_discrete_sequence=['#EF553B']
)
fig.update_layout(yaxis_tickformat='.0%')
st.plotly_chart(fig, use_container_width=True)
# Data table
with st.expander("View Raw Outcome Data"):
st.dataframe(
outcome_df.tail(30).reset_index(drop=True),
column_config={
"Date": st.column_config.DateColumn("Date"),
"Article Quality Index": st.column_config.ProgressColumn(
"Article Quality Index",
format="%.2f%%",
min_value=0,
max_value=1
),
"Helpful %": st.column_config.ProgressColumn(
"Helpful %",
format="%.2f%%",
min_value=0,
max_value=1
),
"Contribution Index": st.column_config.ProgressColumn(
"Contribution Index",
format="%.2f%%",
min_value=0,
max_value=1
),
"FCR %": st.column_config.ProgressColumn(
"FCR %",
format="%.2f%%",
min_value=0,
max_value=1
),
"Ticket Deflection Rate": st.column_config.ProgressColumn(
"Ticket Deflection Rate",
format="%.2f%%",
min_value=0,
max_value=1
)
}
)
# Run the app
if __name__ == '__main__':
main()
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?