mona / pages /analytics.py
mrradix's picture
Upload 48 files
8e4018d verified
import gradio as gr
import datetime
from typing import Dict, List, Any, Union, Optional
import random
import os
import json
# Import utilities
from utils.storage import load_data, save_data, safe_get
from utils.state import generate_id, get_timestamp, record_activity
from utils.ai_models import analyze_sentiment, summarize_text
from utils.config import FILE_PATHS
from utils.logging import setup_logger
from utils.error_handling import handle_exceptions
from utils.data_analysis import (
filter_data_by_time_period,
create_completion_rate_chart,
create_status_distribution_chart,
create_priority_distribution_chart,
create_time_series_chart,
create_completion_time_chart,
create_tags_distribution_chart,
create_activity_heatmap,
create_calendar_heatmap,
create_sentiment_chart,
create_model_usage_distribution,
create_model_usage_over_time
)
# Initialize logger
logger = setup_logger(__name__)
@handle_exceptions
def create_analytics_page(state: Dict[str, Any]) -> None:
"""
Create the Analytics page with data visualizations and insights
Args:
state: Application state
"""
logger.info("Creating analytics page")
# Create the analytics page layout
with gr.Column(elem_id="analytics-page"):
gr.Markdown("# 📊 Analytics")
gr.Markdown("*Insights and visualizations of your productivity data*")
# Time period selector
with gr.Row():
time_period = gr.Dropdown(
choices=["Last 7 Days", "Last 30 Days", "Last 90 Days", "All Time"],
value="Last 30 Days",
label="Time Period",
elem_id="time-period-selector"
)
refresh_btn = gr.Button("Refresh Data")
# Dashboard tabs
with gr.Tabs():
# Task Analytics
with gr.TabItem("Tasks"):
with gr.Row():
# Task completion rate
with gr.Column(scale=1):
task_completion_chart = gr.Plot(
label="Task Completion Rate",
elem_id="task-completion-chart"
)
# Task status distribution
with gr.Column(scale=1):
task_status_chart = gr.Plot(
label="Task Status Distribution",
elem_id="task-status-chart"
)
with gr.Row():
# Task priority distribution
with gr.Column(scale=1):
task_priority_chart = gr.Plot(
label="Task Priority Distribution",
elem_id="task-priority-chart"
)
# Task creation over time
with gr.Column(scale=1):
task_creation_chart = gr.Plot(
label="Task Creation Over Time",
elem_id="task-creation-chart"
)
with gr.Row():
# Task completion time
with gr.Column(scale=1):
task_completion_time_chart = gr.Plot(
label="Average Completion Time",
elem_id="task-completion-time-chart"
)
# Task tags distribution
with gr.Column(scale=1):
task_tags_chart = gr.Plot(
label="Task Tags Distribution",
elem_id="task-tags-chart"
)
# Notes Analytics
with gr.TabItem("Notes"):
with gr.Row():
# Notes creation over time
with gr.Column(scale=1):
notes_creation_chart = gr.Plot(
label="Notes Creation Over Time",
elem_id="notes-creation-chart"
)
# Notes length distribution
with gr.Column(scale=1):
notes_length_chart = gr.Plot(
label="Notes Length Distribution",
elem_id="notes-length-chart"
)
with gr.Row():
# Notes tags distribution
with gr.Column(scale=1):
notes_tags_chart = gr.Plot(
label="Notes Tags Distribution",
elem_id="notes-tags-chart"
)
# Notes sentiment analysis
with gr.Column(scale=1):
notes_sentiment_chart = gr.Plot(
label="Notes Sentiment Analysis",
elem_id="notes-sentiment-chart"
)
# Goals Analytics
with gr.TabItem("Goals"):
with gr.Row():
# Goal completion rate
with gr.Column(scale=1):
goal_completion_chart = gr.Plot(
label="Goal Completion Rate",
elem_id="goal-completion-chart"
)
# Goal progress distribution
with gr.Column(scale=1):
goal_progress_chart = gr.Plot(
label="Goal Progress Distribution",
elem_id="goal-progress-chart"
)
with gr.Row():
# Goal creation over time
with gr.Column(scale=1):
goal_creation_chart = gr.Plot(
label="Goal Creation Over Time",
elem_id="goal-creation-chart"
)
# Goal completion time
with gr.Column(scale=1):
goal_completion_time_chart = gr.Plot(
label="Average Goal Completion Time",
elem_id="goal-completion-time-chart"
)
# Activity Analytics
with gr.TabItem("Activity"):
with gr.Row():
# Activity by day of week
with gr.Column(scale=1):
activity_dow_chart = gr.Plot(
label="Activity by Day of Week",
elem_id="activity-dow-chart"
)
# Activity by hour of day
with gr.Column(scale=1):
activity_hour_chart = gr.Plot(
label="Activity by Hour of Day",
elem_id="activity-hour-chart"
)
with gr.Row():
# Activity by type
with gr.Column(scale=1):
activity_type_chart = gr.Plot(
label="Activity by Type",
elem_id="activity-type-chart"
)
# Activity over time
with gr.Column(scale=1):
activity_time_chart = gr.Plot(
label="Activity Over Time",
elem_id="activity-time-chart"
)
# AI Usage Analytics
with gr.TabItem("AI Usage"):
with gr.Row():
# AI model usage distribution
with gr.Column(scale=1):
ai_model_chart = gr.Plot(
label="AI Model Usage Distribution",
elem_id="ai-model-chart"
)
# AI usage over time
with gr.Column(scale=1):
ai_usage_chart = gr.Plot(
label="AI Usage Over Time",
elem_id="ai-usage-chart"
)
# Key metrics
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Key Metrics")
metrics_md = gr.Markdown("*Loading metrics...*")
# Function to update metrics
@handle_exceptions
def update_metrics(period):
"""Update metrics based on selected time period"""
logger.debug(f"Updating metrics for period: {period}")
# Get data
tasks = safe_get(state, "tasks", [])
notes = safe_get(state, "notes", [])
goals = safe_get(state, "goals", [])
activity = safe_get(state, "activity_feed", [])
# Calculate metrics
total_tasks = len(tasks)
completed_tasks = len([t for t in tasks if safe_get(t, "completed", False)])
total_notes = len(notes)
total_goals = len(goals)
completed_goals = len([g for g in goals if safe_get(g, "completed", False)])
total_activity = len(activity)
# Format metrics
metrics = [
f"**Total Tasks:** {total_tasks}",
f"**Completed Tasks:** {completed_tasks}",
f"**Task Completion Rate:** {(completed_tasks/total_tasks*100):.1f}% if total_tasks > 0 else '0%'",
f"**Total Notes:** {total_notes}",
f"**Total Goals:** {total_goals}",
f"**Goal Completion Rate:** {(completed_goals/total_goals*100):.1f}% if total_goals > 0 else '0%'",
f"**Total Activities:** {total_activity}"
]
return "\n\n".join(metrics)
# Function to update all charts
@handle_exceptions
def update_charts(period):
"""Update all charts based on selected time period"""
logger.debug(f"Updating charts for period: {period}")
# Get data
tasks = safe_get(state, "tasks", [])
notes = safe_get(state, "notes", [])
goals = safe_get(state, "goals", [])
activity = safe_get(state, "activity_feed", [])
# Filter data by time period
filtered_tasks = filter_data_by_time_period(tasks, period)
filtered_notes = filter_data_by_time_period(notes, period)
filtered_goals = filter_data_by_time_period(goals, period)
filtered_activity = filter_data_by_time_period(activity, period)
# Update task charts
task_completion_fig = create_completion_rate_chart(
filtered_tasks,
title="Task Completion Rate",
completed_key="completed"
)
task_status_fig = create_status_distribution_chart(
filtered_tasks,
title="Task Status Distribution"
)
task_priority_fig = create_priority_distribution_chart(
filtered_tasks,
title="Task Priority Distribution"
)
task_creation_fig = create_time_series_chart(
filtered_tasks,
title="Task Creation Over Time",
timestamp_key="created_at"
)
task_completion_time_fig = create_completion_time_chart(
filtered_tasks,
title="Task Completion Time Distribution",
created_key="created_at",
completed_key="completed_at"
)
task_tags_fig = create_tags_distribution_chart(
filtered_tasks,
title="Task Tags Distribution",
tags_key="tags"
)
# Update notes charts
notes_creation_fig = create_time_series_chart(
filtered_notes,
title="Notes Creation Over Time",
timestamp_key="created_at"
)
# Create notes length distribution chart
notes_with_length = []
for note in filtered_notes:
content = safe_get(note, "content", "")
if content:
notes_with_length.append({
**note,
"length": len(content)
})
# Sort notes by length
notes_with_length.sort(key=lambda x: x["length"])
# Create a simple bar chart for notes length
import plotly.graph_objects as go
notes_length_fig = go.Figure(data=go.Bar(
x=[i for i in range(len(notes_with_length))],
y=[note["length"] for note in notes_with_length],
marker_color="#4CAF50"
))
notes_length_fig.update_layout(
title="Notes Length Distribution",
xaxis_title="Note Index",
yaxis_title="Character Count",
margin=dict(l=20, r=20, t=40, b=20),
height=300
)
notes_tags_fig = create_tags_distribution_chart(
filtered_notes,
title="Notes Tags Distribution",
tags_key="tags"
)
notes_sentiment_fig = create_sentiment_chart(
filtered_notes,
title="Notes Sentiment Analysis",
content_key="content",
timestamp_key="created_at"
)
# Update goals charts
goal_completion_fig = create_completion_rate_chart(
filtered_goals,
title="Goal Completion Rate",
completed_key="completed"
)
# Create goal progress distribution chart
# This is a placeholder - you might want to implement a more specific chart
goal_progress_fig = create_status_distribution_chart(
filtered_goals,
title="Goal Progress Distribution",
status_key="status"
)
goal_creation_fig = create_time_series_chart(
filtered_goals,
title="Goal Creation Over Time",
timestamp_key="created_at"
)
goal_completion_time_fig = create_completion_time_chart(
filtered_goals,
title="Goal Completion Time Distribution",
created_key="created_at",
completed_key="completed_at"
)
# Update activity charts
activity_dow_hour_fig = create_activity_heatmap(
filtered_activity,
title="Activity by Day and Hour",
timestamp_key="timestamp"
)
# Split the heatmap into two separate charts for day of week and hour of day
import numpy as np
import plotly.graph_objects as go
# Day of week activity
day_counts = np.zeros(7) # 7 days
for item in filtered_activity:
timestamp = item.get("timestamp")
if not timestamp:
continue
# Convert timestamp to datetime
if isinstance(timestamp, str):
try:
date = datetime.datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
except ValueError:
continue
else:
date = datetime.datetime.fromtimestamp(timestamp)
# Get day of week (0 = Monday, 6 = Sunday)
day_of_week = date.weekday()
day_counts[day_of_week] += 1
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
activity_dow_fig = go.Figure(data=go.Bar(
x=days,
y=day_counts,
marker_color="#2196F3"
))
activity_dow_fig.update_layout(
title="Activity by Day of Week",
xaxis_title="Day",
yaxis_title="Count",
margin=dict(l=20, r=20, t=40, b=20),
height=300
)
# Hour of day activity
hour_counts = np.zeros(24) # 24 hours
for item in filtered_activity:
timestamp = item.get("timestamp")
if not timestamp:
continue
# Convert timestamp to datetime
if isinstance(timestamp, str):
try:
date = datetime.datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
except ValueError:
continue
else:
date = datetime.datetime.fromtimestamp(timestamp)
# Get hour
hour = date.hour
hour_counts[hour] += 1
hours = [f"{h:02d}:00" for h in range(24)]
activity_hour_fig = go.Figure(data=go.Bar(
x=hours,
y=hour_counts,
marker_color="#9C27B0"
))
activity_hour_fig.update_layout(
title="Activity by Hour of Day",
xaxis_title="Hour",
yaxis_title="Count",
margin=dict(l=20, r=20, t=40, b=20),
height=300
)
# Activity by type
activity_types = {}
for item in filtered_activity:
activity_type = safe_get(item, "type", "unknown")
# Clean up the activity type for better display
display_type = activity_type.replace("_", " ").title()
activity_types[display_type] = activity_types.get(display_type, 0) + 1
# Sort by count
sorted_types = sorted(activity_types.items(), key=lambda x: x[1], reverse=True)
types = [t[0] for t in sorted_types[:10]] # Top 10 types
type_counts = [t[1] for t in sorted_types[:10]]
activity_type_fig = go.Figure(data=go.Bar(
x=types,
y=type_counts,
marker_color="#FF9800"
))
activity_type_fig.update_layout(
title="Activity by Type",
xaxis_title="Type",
yaxis_title="Count",
margin=dict(l=20, r=20, t=40, b=20),
height=300
)
# Activity over time
activity_time_fig = create_time_series_chart(
filtered_activity,
title="Activity Over Time",
timestamp_key="timestamp"
)
# Update AI usage charts
ai_model_fig = create_model_usage_distribution(
filtered_activity,
title="AI Model Usage Distribution"
)
ai_usage_fig = create_model_usage_over_time(
filtered_activity,
title="AI Usage Over Time",
timestamp_key="timestamp"
)
# Return all updated charts
return (
task_completion_fig, task_status_fig, task_priority_fig, task_creation_fig,
task_completion_time_fig, task_tags_fig, notes_creation_fig, notes_length_fig,
notes_tags_fig, notes_sentiment_fig, goal_completion_fig, goal_progress_fig,
goal_creation_fig, goal_completion_time_fig, activity_dow_fig, activity_hour_fig,
activity_type_fig, activity_time_fig, ai_model_fig, ai_usage_fig
)
# Set up refresh button
refresh_btn.click(
fn=lambda period: (update_metrics(period), *update_charts(period)),
inputs=[time_period],
outputs=[
metrics_md,
task_completion_chart, task_status_chart, task_priority_chart, task_creation_chart,
task_completion_time_chart, task_tags_chart, notes_creation_chart, notes_length_chart,
notes_tags_chart, notes_sentiment_chart, goal_completion_chart, goal_progress_chart,
goal_creation_chart, goal_completion_time_chart, activity_dow_chart, activity_hour_chart,
activity_type_chart, activity_time_chart, ai_model_chart, ai_usage_chart
]
)
# Initialize metrics and charts
metrics_md.value = update_metrics("Last 30 Days")
(
task_completion_chart.value, task_status_chart.value, task_priority_chart.value, task_creation_chart.value,
task_completion_time_chart.value, task_tags_chart.value, notes_creation_chart.value, notes_length_chart.value,
notes_tags_chart.value, notes_sentiment_chart.value, goal_completion_chart.value, goal_progress_chart.value,
goal_creation_chart.value, goal_completion_time_chart.value, activity_dow_chart.value, activity_hour_chart.value,
activity_type_chart.value, activity_time_chart.value, ai_model_chart.value, ai_usage_chart.value
) = update_charts("Last 30 Days")