mrradix commited on
Commit
d1e9503
·
verified ·
1 Parent(s): 052657c

Update pages/dashboard.py

Browse files
Files changed (1) hide show
  1. pages/dashboard.py +144 -395
pages/dashboard.py CHANGED
@@ -1,408 +1,157 @@
1
- import gradio as gr
2
- import datetime
3
- from typing import Dict, List, Any, Union, Optional
4
- import random
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- # Import utilities
7
- from utils.storage import load_data, save_data
8
- from utils.state import generate_id, get_timestamp, record_activity
9
- from utils.ai_models import generate_motivation_quote, generate_daily_plan, get_weather
10
- from utils.ui_components import (
11
- create_card, create_stat_card, create_progress_ring, create_activity_item,
12
- create_deadline_item, create_streak_counter, create_weather_widget
13
- )
14
- from utils.config import FILE_PATHS
15
- from utils.logging import get_logger
16
- from utils.error_handling import handle_exceptions, ValidationError, safe_get
17
 
18
  # Initialize logger
19
  logger = get_logger(__name__)
20
 
21
- @handle_exceptions
22
- def create_dashboard_page(state: Dict[str, Any]) -> None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  """
24
- Create the dashboard page with various widgets
25
 
26
  Args:
27
- state: Application state
28
  """
29
- logger.info("Creating dashboard page")
 
 
30
 
31
- # Create the dashboard layout
32
- with gr.Column(elem_id="dashboard-page"):
33
- gr.Markdown("# 🏠 Dashboard")
 
 
 
 
 
 
 
 
 
 
34
 
35
- # Top row - Today's Focus and Quick Stats
36
- with gr.Row():
37
- # Today's Focus Widget
38
- with gr.Column(scale=2):
39
- with gr.Group(elem_classes=["focus-widget"]):
40
- gr.Markdown("### 🎯 Today's Focus")
41
- focus_input = gr.Textbox(
42
- placeholder="What's your main focus for today?",
43
- label="",
44
- elem_id="focus-input"
45
- )
46
- motivation_text = gr.Markdown(
47
- "*Set your focus for today to get an AI-powered motivation boost!*"
48
- )
49
-
50
- @handle_exceptions
51
- def update_focus(focus_text):
52
- """Update the focus and generate motivation"""
53
- if not focus_text.strip():
54
- logger.debug("Empty focus text submitted")
55
- return "*Set your focus for today to get an AI-powered motivation boost!*"
56
-
57
- logger.info(f"Setting focus: {focus_text[:30]}...")
58
-
59
- # Generate a motivational response
60
- motivation = generate_motivation_quote()
61
-
62
- # Record the activity
63
- record_activity({
64
- "type": "focus_set",
65
- "title": focus_text,
66
- "timestamp": datetime.datetime.now().isoformat()
67
- })
68
-
69
- return f"*{motivation}*"
70
-
71
- focus_input.change(update_focus, inputs=[focus_input], outputs=[motivation_text])
72
-
73
- # Quick Stats Cards
74
- with gr.Column(scale=2):
75
- with gr.Row():
76
- create_stat_card("Tasks", safe_get(state, ["stats", "tasks_total"], 0), icon="📋", color="blue")
77
- create_stat_card("Completed", safe_get(state, ["stats", "tasks_completed"], 0), icon="✅", color="green")
78
-
79
- with gr.Row():
80
- create_stat_card("Notes", safe_get(state, ["stats", "notes_total"], 0), icon="📝", color="yellow")
81
- create_stat_card("Goals", safe_get(state, ["stats", "goals_total"], 0), icon="🎯", color="purple")
82
 
83
- # Middle row - Activity Feed, AI Daily Planner, and Weather
84
- with gr.Row():
85
- # Activity Feed
86
- with gr.Column(scale=2):
87
- with gr.Group(elem_classes=["activity-feed"]):
88
- gr.Markdown("### 📊 Activity Feed")
89
-
90
- # Display activity items
91
- if safe_get(state, "activity_feed", []):
92
- for activity in state["activity_feed"][:10]: # Show up to 10 activities
93
- create_activity_item(activity)
94
- else:
95
- gr.Markdown("*No recent activity*")
96
-
97
- # Right column - AI Daily Planner and Weather
98
- with gr.Column(scale=2):
99
- # AI Daily Planner
100
- with gr.Group(elem_classes=["daily-planner"]):
101
- gr.Markdown("### 📅 AI Daily Planner")
102
-
103
- # Generate a daily plan based on tasks and goals
104
- daily_plan = generate_daily_plan(
105
- safe_get(state, "tasks", []),
106
- safe_get(state, "goals", [])
107
- )
108
-
109
- gr.Markdown(daily_plan)
110
-
111
- refresh_plan_btn = gr.Button("Refresh Plan")
112
-
113
- @handle_exceptions
114
- def refresh_daily_plan():
115
- """Refresh the daily plan"""
116
- logger.debug("Refreshing daily plan")
117
- return generate_daily_plan(
118
- safe_get(state, "tasks", []),
119
- safe_get(state, "goals", [])
120
- )
121
-
122
- refresh_plan_btn.click(refresh_daily_plan, inputs=[], outputs=[gr.Markdown(visible=False)])
123
-
124
- # Weather Widget
125
- weather_data = get_weather("New York") # Default city
126
- create_weather_widget(weather_data)
127
-
128
- # City input for weather
129
- with gr.Row():
130
- city_input = gr.Textbox(
131
- placeholder="Enter city name",
132
- label="Change Location",
133
- elem_id="weather-city-input"
134
- )
135
- update_weather_btn = gr.Button("Update")
136
-
137
- @handle_exceptions
138
- def update_weather(city):
139
- """Update weather for the specified city"""
140
- if not city.strip():
141
- logger.debug("Empty city name, using default")
142
- city = "New York" # Default city
143
-
144
- logger.info(f"Updating weather for city: {city}")
145
- weather_data = get_weather(city)
146
- return create_weather_widget(weather_data)
147
-
148
- update_weather_btn.click(
149
- update_weather,
150
- inputs=[city_input],
151
- outputs=[gr.Group(visible=False)]
152
- )
153
 
154
- # Bottom row - Motivation Quotes, Quick Entry, Deadline Tracker, Progress, Streak
155
- with gr.Row():
156
- # Left column - Motivation Quotes and Quick Entry
157
- with gr.Column(scale=2):
158
- # Motivation Quotes
159
- with gr.Group(elem_classes=["motivation-quotes"]):
160
- gr.Markdown("### ✨ Daily Inspiration")
161
-
162
- # Generate a motivational quote
163
- quote = generate_motivation_quote()
164
- quote_display = gr.Markdown(f"*\"{quote}\"*")
165
-
166
- refresh_quote_btn = gr.Button("New Quote")
167
-
168
- @handle_exceptions
169
- def refresh_quote():
170
- """Refresh the motivational quote"""
171
- logger.debug("Refreshing motivational quote")
172
- return f"*\"{generate_motivation_quote()}\"*"
173
-
174
- refresh_quote_btn.click(refresh_quote, inputs=[], outputs=[quote_display])
175
-
176
- # Quick Entry Panel
177
- with gr.Group(elem_classes=["quick-entry"]):
178
- gr.Markdown("### ⚡ Quick Add")
179
-
180
- quick_entry_tabs = gr.Tabs([
181
- ("Task", "task"),
182
- ("Note", "note"),
183
- ("Goal", "goal")
184
- ])
185
-
186
- with quick_entry_tabs.select("task"):
187
- task_title = gr.Textbox(placeholder="Task title", label="Title")
188
- task_desc = gr.Textbox(placeholder="Task description (optional)", label="Description")
189
- task_priority = gr.Dropdown(
190
- choices=["High", "Medium", "Low"],
191
- value="Medium",
192
- label="Priority"
193
- )
194
- add_task_btn = gr.Button("Add Task")
195
-
196
- with quick_entry_tabs.select("note"):
197
- note_title = gr.Textbox(placeholder="Note title", label="Title")
198
- note_content = gr.Textbox(
199
- placeholder="Note content",
200
- label="Content",
201
- lines=3
202
- )
203
- add_note_btn = gr.Button("Add Note")
204
-
205
- with quick_entry_tabs.select("goal"):
206
- goal_title = gr.Textbox(placeholder="Goal title", label="Title")
207
- goal_desc = gr.Textbox(placeholder="Goal description (optional)", label="Description")
208
- goal_deadline = gr.Textbox(
209
- placeholder="YYYY-MM-DD (optional)",
210
- label="Target Date"
211
- )
212
- add_goal_btn = gr.Button("Add Goal")
213
-
214
- # Add task function
215
- @handle_exceptions
216
- def add_task(title, description, priority):
217
- """Add a new task"""
218
- if not title.strip():
219
- logger.warning("Attempted to add task with empty title")
220
- return "Please enter a task title", task_title, task_desc
221
-
222
- logger.info(f"Adding new task: {title}")
223
-
224
- # Create new task
225
- new_task = {
226
- "id": generate_id(),
227
- "title": title.strip(),
228
- "description": description.strip(),
229
- "priority": priority.lower(),
230
- "status": "todo",
231
- "completed": False,
232
- "created_at": get_timestamp()
233
- }
234
-
235
- # Add to state
236
- state["tasks"].append(new_task)
237
- state["stats"]["tasks_total"] += 1
238
-
239
- # Record activity
240
- record_activity({
241
- "type": "task_created",
242
- "title": title,
243
- "timestamp": datetime.datetime.now().isoformat()
244
- })
245
-
246
- # Save to file
247
- save_data(FILE_PATHS["tasks"], state["tasks"])
248
-
249
- return "Task added successfully!", gr.update(value=""), gr.update(value="")
250
-
251
- add_task_btn.click(
252
- add_task,
253
- inputs=[task_title, task_desc, task_priority],
254
- outputs=[gr.Markdown(visible=False), task_title, task_desc]
255
- )
256
-
257
- # Add note function
258
- @handle_exceptions
259
- def add_note(title, content):
260
- """Add a new note"""
261
- if not title.strip():
262
- logger.warning("Attempted to add note with empty title")
263
- return "Please enter a note title", note_title, note_content
264
-
265
- logger.info(f"Adding new note: {title}")
266
-
267
- # Create new note
268
- new_note = {
269
- "id": generate_id(),
270
- "title": title.strip(),
271
- "content": content.strip(),
272
- "created_at": get_timestamp(),
273
- "updated_at": get_timestamp()
274
- }
275
-
276
- # Add to state
277
- state["notes"].append(new_note)
278
- state["stats"]["notes_total"] += 1
279
-
280
- # Record activity
281
- record_activity({
282
- "type": "note_created",
283
- "title": title,
284
- "timestamp": datetime.datetime.now().isoformat()
285
- })
286
-
287
- # Save to file
288
- save_data(FILE_PATHS["notes"], state["notes"])
289
-
290
- return "Note added successfully!", gr.update(value=""), gr.update(value="")
291
-
292
- add_note_btn.click(
293
- add_note,
294
- inputs=[note_title, note_content],
295
- outputs=[gr.Markdown(visible=False), note_title, note_content]
296
- )
297
-
298
- # Add goal function
299
- @handle_exceptions
300
- def add_goal(title, description, deadline):
301
- """Add a new goal"""
302
- if not title.strip():
303
- logger.warning("Attempted to add goal with empty title")
304
- return "Please enter a goal title", goal_title, goal_desc, goal_deadline
305
-
306
- logger.info(f"Adding new goal: {title}")
307
-
308
- # Validate deadline format if provided
309
- deadline_iso = None
310
- if deadline.strip():
311
- try:
312
- deadline_date = datetime.datetime.strptime(deadline.strip(), "%Y-%m-%d")
313
- deadline_iso = deadline_date.isoformat()
314
- except ValueError as e:
315
- logger.warning(f"Invalid date format: {deadline}, error: {str(e)}")
316
- return "Invalid date format. Use YYYY-MM-DD", goal_title, goal_desc, goal_deadline
317
-
318
- # Create new goal
319
- new_goal = {
320
- "id": generate_id(),
321
- "title": title.strip(),
322
- "description": description.strip(),
323
- "completed": False,
324
- "created_at": get_timestamp()
325
- }
326
-
327
- if deadline_iso:
328
- new_goal["deadline"] = deadline_iso
329
-
330
- # Add to state
331
- state["goals"].append(new_goal)
332
- state["stats"]["goals_total"] += 1
333
-
334
- # Record activity
335
- record_activity({
336
- "type": "goal_created",
337
- "title": title,
338
- "timestamp": datetime.datetime.now().isoformat()
339
- })
340
-
341
- # Save to file
342
- save_data(FILE_PATHS["goals"], state["goals"])
343
-
344
- return "Goal added successfully!", gr.update(value=""), gr.update(value=""), gr.update(value="")
345
-
346
- add_goal_btn.click(
347
- add_goal,
348
- inputs=[goal_title, goal_desc, goal_deadline],
349
- outputs=[gr.Markdown(visible=False), goal_title, goal_desc, goal_deadline]
350
- )
351
-
352
- # Right column - Deadline Tracker, Progress Rings, Streak Counter
353
- with gr.Column(scale=2):
354
- # Deadline Tracker
355
- with gr.Group(elem_classes=["deadline-tracker"]):
356
- gr.Markdown("### ⏰ Upcoming Deadlines")
357
-
358
- # Get tasks with deadlines
359
- tasks_with_deadlines = []
360
- for task in safe_get(state, "tasks", []):
361
- if "deadline" in task and not safe_get(task, "completed", False):
362
- tasks_with_deadlines.append(task)
363
-
364
- # Sort by deadline (closest first)
365
- tasks_with_deadlines.sort(key=lambda x: x["deadline"])
366
-
367
- # Display deadline items
368
- if tasks_with_deadlines:
369
- for task in tasks_with_deadlines[:5]: # Show up to 5 deadlines
370
- create_deadline_item(task)
371
- else:
372
- gr.Markdown("*No upcoming deadlines*")
373
-
374
- # Progress Rings
375
- with gr.Group(elem_classes=["progress-rings"]):
376
- gr.Markdown("### 📊 Progress")
377
-
378
- with gr.Row():
379
- # Task completion progress
380
- task_completion = 0
381
- tasks_total = safe_get(state, ["stats", "tasks_total"], 0)
382
- if tasks_total > 0:
383
- task_completion = (safe_get(state, ["stats", "tasks_completed"], 0) / tasks_total) * 100
384
-
385
- create_progress_ring(
386
- value=task_completion,
387
- max_value=100,
388
- size=120,
389
- color="blue",
390
- label="Tasks"
391
- )
392
-
393
- # Goal completion progress
394
- goal_completion = 0
395
- goals_total = safe_get(state, ["stats", "goals_total"], 0)
396
- if goals_total > 0:
397
- goal_completion = (safe_get(state, ["stats", "goals_completed"], 0) / goals_total) * 100
398
-
399
- create_progress_ring(
400
- value=goal_completion,
401
- max_value=100,
402
- size=120,
403
- color="purple",
404
- label="Goals"
405
- )
406
-
407
- # Streak Counter
408
- create_streak_counter(safe_get(state, ["stats", "streak_days"], 0))
 
1
+ """
2
+ Dashboard page for the MONA application
3
+ Fixed version with proper imports and error handling
4
+ """
5
+
6
+ import streamlit as st
7
+ import pandas as pd
8
+ import plotly.express as px
9
+ import plotly.graph_objects as go
10
+ from datetime import datetime, timedelta
11
+ from typing import Dict, List, Optional, Any
12
+
13
+ from utils.storage import load_data, save_data, get_cached_data, set_cached_data
14
+ from utils.error_handling import handle_data_exceptions, ErrorHandler, ValidationError, DataError
15
+ from utils.logging import get_logger, log_info, log_error, log_warning
16
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  # Initialize logger
19
  logger = get_logger(__name__)
20
 
21
+
22
+ @handle_data_exceptions
23
+ def load_dashboard_data() -> Dict[str, Any]:
24
+ """
25
+ Load dashboard data with caching
26
+
27
+ Returns:
28
+ Dict: Dashboard data including metrics, charts data, etc.
29
+ """
30
+ # Try to get from cache first
31
+ cached_data = get_cached_data("dashboard_data")
32
+ if cached_data:
33
+ log_info("Using cached dashboard data")
34
+ return cached_data
35
+
36
+ try:
37
+ # Load data from storage
38
+ data = {
39
+ "metrics": load_data("dashboard_metrics.json", default={}),
40
+ "user_activity": load_data("user_activity.json", default=[]),
41
+ "system_stats": load_data("system_stats.json", default={}),
42
+ "recent_events": load_data("recent_events.json", default=[]),
43
+ "performance_data": load_data("performance_data.json", default=[])
44
+ }
45
+
46
+ # Cache the data
47
+ set_cached_data("dashboard_data", data)
48
+ log_info("Dashboard data loaded and cached successfully")
49
+
50
+ return data
51
+
52
+ except Exception as e:
53
+ log_error("Failed to load dashboard data", error=e)
54
+ return {
55
+ "metrics": {},
56
+ "user_activity": [],
57
+ "system_stats": {},
58
+ "recent_events": [],
59
+ "performance_data": []
60
+ }
61
+
62
+
63
+ @handle_data_exceptions
64
+ def create_metrics_cards(metrics: Dict[str, Any]) -> None:
65
+ """
66
+ Create and display metrics cards
67
+
68
+ Args:
69
+ metrics: Dictionary containing metric values
70
+ """
71
+ if not metrics:
72
+ st.warning("No metrics data available")
73
+ return
74
+
75
+ # Create columns for metrics
76
+ cols = st.columns(4)
77
+
78
+ # Total Users
79
+ with cols[0]:
80
+ total_users = metrics.get("total_users", 0)
81
+ st.metric(
82
+ label="Total Users",
83
+ value=f"{total_users:,}",
84
+ delta=metrics.get("users_change", 0)
85
+ )
86
+
87
+ # Active Sessions
88
+ with cols[1]:
89
+ active_sessions = metrics.get("active_sessions", 0)
90
+ st.metric(
91
+ label="Active Sessions",
92
+ value=f"{active_sessions:,}",
93
+ delta=metrics.get("sessions_change", 0)
94
+ )
95
+
96
+ # System Health
97
+ with cols[2]:
98
+ system_health = metrics.get("system_health", 0)
99
+ st.metric(
100
+ label="System Health",
101
+ value=f"{system_health:.1f}%",
102
+ delta=f"{metrics.get('health_change', 0):.1f}%"
103
+ )
104
+
105
+ # Response Time
106
+ with cols[3]:
107
+ response_time = metrics.get("avg_response_time", 0)
108
+ st.metric(
109
+ label="Avg Response Time",
110
+ value=f"{response_time:.0f}ms",
111
+ delta=f"{metrics.get('response_change', 0):.0f}ms",
112
+ delta_color="inverse"
113
+ )
114
+
115
+
116
+ @handle_data_exceptions
117
+ def create_activity_chart(activity_data: List[Dict]) -> None:
118
  """
119
+ Create user activity chart
120
 
121
  Args:
122
+ activity_data: List of activity data points
123
  """
124
+ if not activity_data:
125
+ st.warning("No activity data available")
126
+ return
127
 
128
+ try:
129
+ df = pd.DataFrame(activity_data)
130
+
131
+ if df.empty:
132
+ st.warning("Activity data is empty")
133
+ return
134
+
135
+ # Ensure required columns exist
136
+ if 'timestamp' not in df.columns:
137
+ df['timestamp'] = pd.date_range(start='2024-01-01', periods=len(df), freq='H')
138
+
139
+ if 'users' not in df.columns:
140
+ df['users'] = [0] * len(df)
141
 
142
+ # Convert timestamp to datetime if it's not already
143
+ df['timestamp'] = pd.to_datetime(df['timestamp'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
+ # Create the chart
146
+ fig = px.line(
147
+ df,
148
+ x='timestamp',
149
+ y='users',
150
+ title='User Activity Over Time',
151
+ labels={'users': 'Active Users', 'timestamp': 'Time'}
152
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
+ fig.update_layout(
155
+ xaxis_title="Time",
156
+ yaxis_title="Active Users",
157
+ h