mrradix commited on
Commit
0545ba0
·
verified ·
1 Parent(s): 8071ef6

Update pages/dashboard.py

Browse files
Files changed (1) hide show
  1. pages/dashboard.py +221 -395
pages/dashboard.py CHANGED
@@ -1,408 +1,234 @@
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
+ import streamlit as st
2
+ import pandas as pd
3
+ import plotly.express as px
4
+ import plotly.graph_objects as go
5
+ from datetime import datetime, timedelta
6
+ import numpy as np
7
 
8
  # Import utilities
9
  from utils.storage import load_data, save_data
10
+ from utils.error_handling import show_error, show_success, show_warning
 
 
 
 
 
 
11
  from utils.logging import get_logger
 
12
 
 
13
  logger = get_logger(__name__)
14
 
15
+ def create_dashboard_page():
 
16
  """
17
+ Create the main dashboard page for MONA
 
 
 
18
  """
19
+ st.title("🤖 MONA - Monitoring & Analytics Dashboard")
20
 
21
+ # Sidebar for navigation
22
+ with st.sidebar:
23
+ st.header("📊 Dashboard Controls")
24
+
25
+ # Data source selection
26
+ data_source = st.selectbox(
27
+ "Select Data Source",
28
+ ["Sample Data", "Upload File", "Real-time Feed"]
29
+ )
30
 
31
+ # Time range selection
32
+ st.subheader("Time Range")
33
+ time_range = st.selectbox(
34
+ "Select Time Range",
35
+ ["Last 24 Hours", "Last 7 Days", "Last 30 Days", "Custom"]
36
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ if time_range == "Custom":
39
+ start_date = st.date_input("Start Date", datetime.now() - timedelta(days=7))
40
+ end_date = st.date_input("End Date", datetime.now())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ # Refresh button
43
+ if st.button("🔄 Refresh Data"):
44
+ st.rerun()
45
+
46
+ # Main dashboard content
47
+ col1, col2, col3, col4 = st.columns(4)
48
+
49
+ # Key metrics
50
+ with col1:
51
+ st.metric(
52
+ label="System Status",
53
+ value="Online",
54
+ delta=""
55
+ )
56
+
57
+ with col2:
58
+ st.metric(
59
+ label="Active Connections",
60
+ value="127",
61
+ delta="5",
62
+ delta_color="normal"
63
+ )
64
+
65
+ with col3:
66
+ st.metric(
67
+ label="Data Points",
68
+ value="1,234",
69
+ delta="156",
70
+ delta_color="normal"
71
+ )
72
+
73
+ with col4:
74
+ st.metric(
75
+ label="Success Rate",
76
+ value="99.8%",
77
+ delta="0.2%",
78
+ delta_color="normal"
79
+ )
80
+
81
+ # Charts section
82
+ st.header("📈 Analytics")
83
+
84
+ # Generate sample data for demonstration
85
+ sample_data = generate_sample_data()
86
+
87
+ # Time series chart
88
+ col1, col2 = st.columns(2)
89
+
90
+ with col1:
91
+ st.subheader("Time Series Analysis")
92
+ fig_line = px.line(
93
+ sample_data,
94
+ x='timestamp',
95
+ y='value',
96
+ title='Data Trends Over Time',
97
+ color_discrete_sequence=['#1f77b4']
98
+ )
99
+ fig_line.update_layout(
100
+ xaxis_title="Time",
101
+ yaxis_title="Value",
102
+ showlegend=False
103
+ )
104
+ st.plotly_chart(fig_line, use_container_width=True)
105
+
106
+ with col2:
107
+ st.subheader("Distribution Analysis")
108
+ fig_hist = px.histogram(
109
+ sample_data,
110
+ x='value',
111
+ bins=20,
112
+ title='Value Distribution',
113
+ color_discrete_sequence=['#ff7f0e']
114
+ )
115
+ fig_hist.update_layout(
116
+ xaxis_title="Value",
117
+ yaxis_title="Frequency",
118
+ showlegend=False
119
+ )
120
+ st.plotly_chart(fig_hist, use_container_width=True)
121
+
122
+ # Data table
123
+ st.header("📋 Data Overview")
124
+
125
+ # Data filtering options
126
+ col1, col2, col3 = st.columns(3)
127
+
128
+ with col1:
129
+ show_raw_data = st.checkbox("Show Raw Data", value=False)
130
+
131
+ with col2:
132
+ max_rows = st.number_input("Max Rows", min_value=10, max_value=1000, value=100)
133
+
134
+ with col3:
135
+ if st.button("Export Data"):
136
+ try:
137
+ success = save_data(sample_data.to_dict('records'), 'dashboard_export.json')
138
+ if success:
139
+ show_success("Data exported successfully!")
140
+ else:
141
+ show_error("Failed to export data")
142
+ except Exception as e:
143
+ show_error(f"Export error: {e}")
144
+
145
+ if show_raw_data:
146
+ st.dataframe(
147
+ sample_data.head(max_rows),
148
+ use_container_width=True,
149
+ hide_index=True
150
+ )
151
+
152
+ # System information
153
+ with st.expander("🔧 System Information"):
154
+ system_info = {
155
+ "Application": "MONA Dashboard",
156
+ "Version": "1.0.0",
157
+ "Last Updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
158
+ "Data Points": len(sample_data),
159
+ "Status": "Operational"
160
+ }
161
+
162
+ for key, value in system_info.items():
163
+ st.text(f"{key}: {value}")
164
+
165
+ # Footer
166
+ st.markdown("---")
167
+ st.markdown(
168
+ "**MONA Dashboard** - Monitoring & Analytics | "
169
+ f"Last updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
170
+ )
171
+
172
+ def generate_sample_data():
173
+ """
174
+ Generate sample data for demonstration
175
+ """
176
+ try:
177
+ # Create time series data
178
+ dates = pd.date_range(
179
+ start=datetime.now() - timedelta(days=30),
180
+ end=datetime.now(),
181
+ freq='H'
182
+ )
183
+
184
+ # Generate synthetic data with trend and noise
185
+ np.random.seed(42) # For reproducible results
186
+ trend = np.linspace(100, 200, len(dates))
187
+ noise = np.random.normal(0, 10, len(dates))
188
+ seasonal = 20 * np.sin(2 * np.pi * np.arange(len(dates)) / 24)
189
+
190
+ values = trend + seasonal + noise
191
+
192
+ df = pd.DataFrame({
193
+ 'timestamp': dates,
194
+ 'value': values,
195
+ 'category': np.random.choice(['A', 'B', 'C'], len(dates)),
196
+ 'status': np.random.choice(['Active', 'Inactive'], len(dates), p=[0.8, 0.2])
197
+ })
198
+
199
+ return df
200
+
201
+ except Exception as e:
202
+ logger.error(f"Error generating sample data: {e}")
203
+ # Return minimal fallback data
204
+ return pd.DataFrame({
205
+ 'timestamp': [datetime.now()],
206
+ 'value': [100],
207
+ 'category': ['A'],
208
+ 'status': ['Active']
209
+ })
210
+
211
+ def load_dashboard_config():
212
+ """
213
+ Load dashboard configuration
214
+ """
215
+ try:
216
+ config = load_data('dashboard_config.json')
217
+ if config is None:
218
+ # Create default config
219
+ default_config = {
220
+ 'theme': 'light',
221
+ 'refresh_interval': 30,
222
+ 'max_data_points': 1000,
223
+ 'charts_enabled': True
224
+ }
225
+ save_data(default_config, 'dashboard_config.json')
226
+ return default_config
227
+ return config
228
+ except Exception as e:
229
+ logger.error(f"Error loading dashboard config: {e}")
230
+ return {}
231
+
232
+ # Initialize when module is imported
233
+ if __name__ == "__main__":
234
+ create_dashboard_page()