-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdesktop_activity_worker.py
More file actions
145 lines (118 loc) · 4.55 KB
/
Copy pathdesktop_activity_worker.py
File metadata and controls
145 lines (118 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import ctypes
import subprocess
import sys
import time
from datetime import datetime
from app import create_app
from app.models import ActivityEvent, db
from app.services.wellbeing import summarize_activity
CHECK_SECONDS = 10
MIN_LOG_SECONDS = 60
def get_active_window_title():
if sys.platform != "win32":
return get_linux_active_window_title()
user32 = ctypes.windll.user32
hwnd = user32.GetForegroundWindow()
length = user32.GetWindowTextLengthW(hwnd)
buffer = ctypes.create_unicode_buffer(length + 1)
user32.GetWindowTextW(hwnd, buffer, length + 1)
return buffer.value.strip() or "Unknown window"
def get_linux_active_window_title():
try:
result = subprocess.run(
["xdotool", "getactivewindow", "getwindowname"],
capture_output=True,
text=True,
timeout=2,
check=False,
)
except (OSError, subprocess.TimeoutExpired):
return ""
return result.stdout.strip() or "Unknown window"
def categorize_window(title):
text = title.lower()
if any(term in text for term in ["visual studio", "vs code", "pycharm", "terminal", "powershell"]):
return "coding"
if any(term in text for term in ["youtube", "netflix", "prime video", "hotstar"]):
return "entertainment"
if any(term in text for term in ["instagram", "x.com", "twitter", "reddit", "facebook"]):
return "social"
if any(term in text for term in ["leetcode", "geeksforgeeks", "hackerrank"]):
return "dsa"
if any(term in text for term in ["gmail", "outlook", "mail"]):
return "email"
if any(term in text for term in ["docs", "notion", "obsidian", "onenote"]):
return "study"
return "unknown"
def activity_label(category):
return {
"coding": "Coding activity",
"entertainment": "Entertainment activity",
"social": "Social activity",
"dsa": "Problem-solving activity",
"email": "Email activity",
"study": "Study activity",
}.get(category, "Desktop activity")
def log_activity(app, category, started_at, ended_at):
duration_seconds = int((ended_at - started_at).total_seconds())
if duration_seconds < MIN_LOG_SECONDS:
return
duration_minutes = max(1, round(duration_seconds / 60))
label = activity_label(category)
summary = summarize_activity(category, duration_minutes, actual_task=label)
with app.app_context():
db.session.add(
ActivityEvent(
source="desktop activity worker",
app_name=label,
category=category,
actual_task=label,
duration_minutes=duration_minutes,
started_at=started_at,
ended_at=ended_at,
agent_summary=summary,
)
)
db.session.commit()
def scan_once(app, state):
current_title = get_active_window_title()
if not current_title:
return
current_category = state.get("current_category") or categorize_window(current_title)
started_at = state.get("started_at") or datetime.utcnow().isoformat()
next_title = get_active_window_title()
next_category = categorize_window(next_title) if next_title else current_category
if not next_title or next_category == current_category:
state["current_category"] = current_category
state["started_at"] = started_at
return
ended_at = datetime.utcnow()
try:
started_at_dt = datetime.fromisoformat(started_at)
except ValueError:
started_at_dt = ended_at
log_activity(app, current_category, started_at_dt, ended_at)
state["current_category"] = next_category
state["started_at"] = ended_at.isoformat()
def main():
app = create_app()
current_title = get_active_window_title()
current_category = categorize_window(current_title)
started_at = datetime.utcnow()
print("AiOS desktop activity worker is running. Press Ctrl+C to stop.")
try:
while True:
time.sleep(CHECK_SECONDS)
next_title = get_active_window_title()
next_category = categorize_window(next_title)
if next_category == current_category:
continue
ended_at = datetime.utcnow()
log_activity(app, current_category, started_at, ended_at)
current_title = next_title
current_category = next_category
started_at = ended_at
except KeyboardInterrupt:
log_activity(app, current_category, started_at, datetime.utcnow())
if __name__ == "__main__":
main()