checklist / pages /analytics.py
Abimael Torcate
Initial commit: Complete checklist management app with AI reporting
d54ba19
"""Página de análises de tempo e movimentos do checklist"""
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from utils.database import get_checklist_analytics, get_checklist_with_items
from datetime import datetime, timedelta
st.set_page_config(
page_title="Análises de Tempo",
page_icon="📊",
layout="wide"
)
def format_time(seconds):
"""Formata segundos em formato legível"""
if seconds is None or seconds == 0:
return "0s"
if seconds < 60:
return f"{int(seconds)}s"
elif seconds < 3600:
minutes = int(seconds // 60)
secs = int(seconds % 60)
return f"{minutes}m {secs}s"
else:
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
return f"{hours}h {minutes}m"
def main():
if 'current_checklist_id' not in st.session_state or st.session_state.current_checklist_id is None:
st.error("Nenhum checklist selecionado!")
if st.button("← Voltar para Início"):
st.switch_page("app.py")
return
checklist_id = st.session_state.current_checklist_id
try:
# Buscar dados do checklist
checklist = get_checklist_with_items(checklist_id)
analytics = get_checklist_analytics(checklist_id)
if not checklist:
st.error("Checklist não encontrado!")
return
# Header
col1, col2 = st.columns([5, 1])
with col1:
st.title(f"📊 Análises: {checklist['name']}")
if checklist['numero_processo']:
st.caption(f"🔢 Processo: {checklist['numero_processo']}")
with col2:
if st.button("← Voltar"):
st.switch_page("pages/dashboard.py")
st.markdown("---")
# Estatísticas gerais
stats = analytics['stats']
time_analysis = analytics['time_analysis']
if stats['first_interaction'] and stats['last_interaction']:
total_time = stats['last_interaction'] - stats['first_interaction']
total_minutes = total_time.total_seconds() / 60
else:
total_minutes = 0
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Total de Items", stats['total_items'])
with col2:
st.metric("Items Concluídos", stats['completed_items'])
with col3:
completion_rate = (stats['completed_items'] / stats['total_items']) * 100 if stats['total_items'] > 0 else 0
st.metric("Taxa de Conclusão", f"{completion_rate:.1f}%")
with col4:
st.metric("Tempo Total", format_time(total_minutes * 60))
st.markdown("---")
# Análise por item
if time_analysis:
st.markdown("### 📈 Análise de Tempo por Item")
# Criar DataFrame para visualização
df_time = pd.DataFrame(time_analysis)
# Converter colunas para tipos numéricos corretos
df_time['total_seconds_spent'] = pd.to_numeric(df_time['total_seconds_spent'], errors='coerce').fillna(0)
df_time['avg_seconds_per_completion'] = pd.to_numeric(df_time['avg_seconds_per_completion'], errors='coerce').fillna(0)
df_time['times_worked'] = pd.to_numeric(df_time['times_worked'], errors='coerce').fillna(0).astype(int)
df_time['tempo_formatado'] = df_time['total_seconds_spent'].apply(lambda x: format_time(x) if x else "0s")
df_time['tempo_medio_formatado'] = df_time['avg_seconds_per_completion'].apply(lambda x: format_time(x) if x else "0s")
df_time['vezes_trabalhado'] = df_time['times_worked']
# Gráfico de barras - Tempo total por item
if not df_time.empty and df_time['total_seconds_spent'].sum() > 0:
fig_time = px.bar(
df_time.sort_values('total_seconds_spent', ascending=False),
x='item_text',
y='total_seconds_spent',
title="Tempo Total Gasto por Item",
labels={'total_seconds_spent': 'Tempo (segundos)', 'item_text': 'Item'}
)
fig_time.update_layout(xaxis_tickangle=-45)
st.plotly_chart(fig_time, use_container_width=True)
# Gráfico de pizza - Distribuição do tempo
df_positive = df_time[df_time['total_seconds_spent'] > 0]
if not df_positive.empty:
fig_pie = px.pie(
df_positive,
values='total_seconds_spent',
names='item_text',
title="Distribuição do Tempo por Item"
)
st.plotly_chart(fig_pie, use_container_width=True)
# Tabela detalhada
st.markdown("### 📋 Detalhes por Item")
df_display = df_time[['item_text', 'vezes_trabalhado', 'tempo_formatado', 'tempo_medio_formatado']].copy()
df_display.columns = ['Item', 'Vezes Trabalhado', 'Tempo Total', 'Tempo Médio']
# Ordenar pela coluna numérica original
df_display = df_display.loc[df_time.sort_values('total_seconds_spent', ascending=False).index]
st.dataframe(df_display, use_container_width=True)
# Insights automáticos
st.markdown("### 🔍 Insights")
col1, col2 = st.columns(2)
with col1:
st.markdown("#### Items mais demorados")
if not df_time.empty and df_time['total_seconds_spent'].sum() > 0:
top_slow = df_time.sort_values('total_seconds_spent', ascending=False).head(3)
for _, item in top_slow.iterrows():
if item['total_seconds_spent'] > 0:
st.write(f"• **{item['item_text']}**: {item['tempo_formatado']}")
else:
st.info("Nenhum dado de tempo disponível ainda.")
with col2:
st.markdown("#### Items mais retrabalhados")
if not df_time.empty and df_time['times_worked'].sum() > 0:
top_rework = df_time.sort_values('times_worked', ascending=False).head(3)
for _, item in top_rework.iterrows():
if item['times_worked'] > 1:
st.write(f"• **{item['item_text']}**: {item['times_worked']} vezes")
else:
st.info("Nenhum retrabalho identificado.")
# Recomendações
st.markdown("#### 💡 Recomendações")
if not df_time.empty and df_time['total_seconds_spent'].sum() > 0:
mean_time = df_time['total_seconds_spent'].mean()
slow_items = df_time[df_time['total_seconds_spent'] > mean_time]['item_text'].tolist()
rework_items = df_time[df_time['times_worked'] > 1]['item_text'].tolist()
if slow_items:
st.warning(f"**Items que demandam mais tempo:** {', '.join(slow_items[:3])}")
st.write("💡 Considere revisar estes items ou dividir em subtarefas menores.")
if rework_items:
st.info(f"**Items com retrabalho:** {', '.join(rework_items[:3])}")
st.write("💡 Analise se estes items precisam de mais clareza ou recursos adicionais.")
if not slow_items and not rework_items:
st.success("✅ Ótimo trabalho! O checklist está sendo executado de forma eficiente.")
elif not df_time.empty:
st.info("📊 Marque e desmarque alguns items para gerar recomendações baseadas no tempo de execução.")
else:
st.info("📊 Ainda não há dados suficientes para análise. Continue marcando os items do checklist para gerar insights.")
# Mostrar checklist atual
st.markdown("### 📋 Status Atual dos Items")
for item in checklist['items']:
status = "✅" if item['is_checked'] else "⏳"
st.write(f"{status} {item['text']}")
except Exception as e:
st.error(f"Erro ao carregar análises: {str(e)}")
if st.button("← Voltar para Dashboard"):
st.switch_page("pages/dashboard.py")
if __name__ == "__main__":
main()