1+ #!/usr/bin/env python3
2+ """
3+ Demo script to showcase Tempo functionality.
4+ This simulates activity tracking and generates reports.
5+ """
6+ import time
7+ import random
8+ from pathlib import Path
9+
10+ # Import Tempo components
11+ from src .core .database import Database
12+ from src .core .session import SessionManager
13+ from src .core .categorizer import AppCategorizer
14+ from src .core .aggregator import DataAggregator
15+ from src .core .reports import ReportGenerator
16+
17+
18+ def create_sample_data ():
19+ """Create sample tracking data for demonstration."""
20+ print ("🚀 Creating sample data for demonstration..." )
21+
22+ # Setup database
23+ db_path = Path .home () / '.tempo' / 'demo.db'
24+ db_path .parent .mkdir (exist_ok = True )
25+
26+ # Initialize components
27+ db = Database (db_path )
28+ db .initialize ()
29+ categorizer = AppCategorizer ()
30+
31+ # Sample applications with realistic usage patterns
32+ apps = [
33+ ("Visual Studio Code" , 7200 ), # 2 hours
34+ ("Firefox" , 3600 ), # 1 hour
35+ ("Terminal" , 2400 ), # 40 minutes
36+ ("Slack" , 1800 ), # 30 minutes
37+ ("YouTube" , 900 ), # 15 minutes
38+ ("Discord" , 600 ), # 10 minutes
39+ ("Spotify" , 1200 ), # 20 minutes
40+ ]
41+
42+ print (f"📁 Database created at: { db_path } " )
43+
44+ # Add sessions for today
45+ current_time = time .time ()
46+ start_of_day = current_time - (current_time % 86400 )
47+
48+ print ("\n 📊 Adding sample sessions for today:" )
49+ session_time = start_of_day + (9 * 3600 ) # Start at 9 AM
50+
51+ for app_name , duration in apps :
52+ category = categorizer .get_category (app_name )
53+ app_id = db .save_application (app_name , category )
54+
55+ # Split into multiple sessions for realism
56+ remaining = duration
57+ while remaining > 0 :
58+ session_duration = min (remaining , random .randint (300 , 1800 )) # 5-30 min sessions
59+ db .save_session (app_id , session_time , session_time + session_duration )
60+
61+ print (f" ✓ { app_name :<20} { session_duration // 60 :3d} min [{ category } ]" )
62+
63+ session_time += session_duration + random .randint (60 , 300 ) # Small breaks
64+ remaining -= session_duration
65+
66+ db .close ()
67+ return db_path
68+
69+
70+ def demonstrate_reports (db_path ):
71+ """Demonstrate report generation."""
72+ print ("\n " + "=" * 60 )
73+ print ("📈 GENERATING REPORTS" )
74+ print ("=" * 60 )
75+
76+ generator = ReportGenerator (db_path )
77+
78+ # Daily Report
79+ print ("\n 📅 Daily Report:" )
80+ print ("-" * 40 )
81+ daily = generator .generate_daily_report ()
82+
83+ total_hours = daily ['total_time' ] / 3600
84+ print (f"Total Time: { total_hours :.1f} hours" )
85+ print (f"Productivity Score: { daily ['productivity_score' ]} /100" )
86+ print (f"Number of Sessions: { daily ['num_sessions' ]} " )
87+
88+ print ("\n ⏱️ Top Applications:" )
89+ for i , app in enumerate (daily ['top_apps' ][:5 ], 1 ):
90+ minutes = app ['duration' ] / 60
91+ print (f" { i } . { app ['name' ]:<20} { minutes :6.0f} min" )
92+
93+ print ("\n 📊 Time by Category:" )
94+ for category , seconds in daily ['category_breakdown' ].items ():
95+ minutes = seconds / 60
96+ percentage = (seconds / daily ['total_time' ] * 100 ) if daily ['total_time' ] > 0 else 0
97+ print (f" { category .capitalize ():<15} { minutes :6.0f} min ({ percentage :5.1f} %)" )
98+
99+ # Productivity Score Calculation
100+ print ("\n 🎯 Productivity Analysis:" )
101+ print ("-" * 40 )
102+ categorizer = AppCategorizer ()
103+ score = categorizer .calculate_productivity_score (
104+ daily ['category_breakdown' ]['productive' ],
105+ daily ['category_breakdown' ]['neutral' ],
106+ daily ['category_breakdown' ]['distracting' ]
107+ )
108+ print (f"Calculated Score: { score } /100" )
109+
110+ if score >= 80 :
111+ print ("Rating: Excellent! 🌟" )
112+ elif score >= 60 :
113+ print ("Rating: Good 👍" )
114+ elif score >= 40 :
115+ print ("Rating: Fair 📊" )
116+ else :
117+ print ("Rating: Needs Improvement 📈" )
118+
119+
120+ def demonstrate_aggregation (db_path ):
121+ """Demonstrate data aggregation features."""
122+ print ("\n " + "=" * 60 )
123+ print ("🔄 DATA AGGREGATION" )
124+ print ("=" * 60 )
125+
126+ db = Database (db_path )
127+ db .initialize ()
128+ aggregator = DataAggregator ()
129+
130+ # Get today's sessions
131+ current_time = time .time ()
132+ start_of_day = current_time - (current_time % 86400 )
133+ sessions = db .get_sessions_by_date (start_of_day , current_time )
134+
135+ # Merge consecutive sessions
136+ print (f"\n 📦 Original sessions: { len (sessions )} " )
137+ merged = aggregator .merge_consecutive_sessions (sessions )
138+ print (f"📦 After merging: { len (merged )} " )
139+
140+ # Create hourly summary
141+ hourly = aggregator .create_hourly_summary (sessions )
142+ print (f"\n ⏰ Hourly Summary ({ len (hourly )} active hours):" )
143+ for hour_data in hourly [:5 ]: # Show first 5 hours
144+ hour = time .strftime ("%H:00" , time .localtime (hour_data ['hour_start' ]))
145+ minutes = hour_data ['total_duration' ] / 60
146+ print (f" { hour } : { minutes :.0f} min - { len (hour_data ['apps' ])} apps" )
147+
148+ db .close ()
149+
150+
151+ def demonstrate_categorization ():
152+ """Demonstrate app categorization system."""
153+ print ("\n " + "=" * 60 )
154+ print ("🏷️ CATEGORIZATION SYSTEM" )
155+ print ("=" * 60 )
156+
157+ categorizer = AppCategorizer ()
158+
159+ test_apps = [
160+ "Visual Studio Code" ,
161+ "PyCharm" ,
162+ "Firefox" ,
163+ "YouTube" ,
164+ "Discord" ,
165+ "Terminal" ,
166+ "Spotify" ,
167+ "Microsoft Teams" ,
168+ "Steam" ,
169+ "Git"
170+ ]
171+
172+ print ("\n 📱 Default App Categories:" )
173+ print ("-" * 40 )
174+ for app in test_apps :
175+ category = categorizer .get_category (app )
176+ emoji = {"productive" : "✅" , "neutral" : "🔵" , "distracting" : "🔴" }[category ]
177+ print (f" { emoji } { app :<20} → { category } " )
178+
179+ # Custom categorization
180+ print ("\n 🔧 Custom Categorization:" )
181+ print ("-" * 40 )
182+ categorizer .set_category ("Discord" , "productive" )
183+ print (f" Discord recategorized: { categorizer .get_category ('Discord' )} " )
184+
185+
186+ def run_tests ():
187+ """Run the test suite."""
188+ print ("\n " + "=" * 60 )
189+ print ("🧪 RUNNING TEST SUITE" )
190+ print ("=" * 60 )
191+
192+ import subprocess
193+ result = subprocess .run (
194+ ["python" , "-m" , "pytest" , "tests/" , "-v" , "--tb=short" ],
195+ capture_output = True ,
196+ text = True
197+ )
198+
199+ # Parse output for summary
200+ lines = result .stdout .split ('\n ' )
201+ for line in lines :
202+ if 'passed' in line or 'failed' in line or 'error' in line :
203+ print (f" { line } " )
204+
205+ if result .returncode == 0 :
206+ print ("\n ✅ All tests passed!" )
207+ else :
208+ print ("\n ❌ Some tests failed" )
209+
210+ # Coverage report
211+ print ("\n 📊 Running coverage report..." )
212+ result = subprocess .run (
213+ ["python" , "-m" , "pytest" , "--cov=src" , "--cov-report=term-missing" , "--quiet" ],
214+ capture_output = True ,
215+ text = True
216+ )
217+
218+ # Extract coverage percentage
219+ for line in result .stdout .split ('\n ' ):
220+ if 'TOTAL' in line :
221+ print (f" { line } " )
222+
223+
224+ def main ():
225+ """Run the full demonstration."""
226+ print ("\n " + "=" * 60 )
227+ print (" TEMPO - Activity Tracker Demonstration" )
228+ print ("=" * 60 )
229+
230+ # Create sample data
231+ db_path = create_sample_data ()
232+
233+ # Demonstrate features
234+ demonstrate_categorization ()
235+ demonstrate_aggregation (db_path )
236+ demonstrate_reports (db_path )
237+
238+ # Run tests
239+ run_tests ()
240+
241+ print ("\n " + "=" * 60 )
242+ print (" ✨ Demonstration Complete!" )
243+ print ("=" * 60 )
244+ print (f"\n 💡 Try these commands:" )
245+ print (f" python -m src.cli start # Start tracking" )
246+ print (f" python -m src.cli status # Check status" )
247+ print (f" python -m src.cli today # View today's summary" )
248+ print (f" python -m src.cli stop # Stop tracking" )
249+ print (f"\n 📁 Demo database: { db_path } " )
250+
251+
252+ if __name__ == "__main__" :
253+ main ()
0 commit comments