1- import time
2- import os
3- import sys
4- import re
5- import platform
6- import subprocess
7- import threading
1+ import customtkinter as ctk
82import keyboard
93import clipboard
4+ import pygetwindow as gw
5+ import pyscreenshot as ImageGrab
6+ import time
107import markdown2
11- import customtkinter as ctk
8+ import threading
9+ import os
1210import ollama
1311
14- # Check the operating system and import necessary modules accordingly
15- if platform .system () == "Linux" :
16- import mss
17- import mss .tools
18- elif platform .system () == "Windows" :
19- import pyscreenshot as ImageGrab
20- import pygetwindow as gw
21-
22- def generate_answers (model_name , prompt , use_ollama ):
23- """
24- Generate answers using the Ollama model or return the prompt as is, while preserving the original prompt.
25-
26- Args:
27- model_name (str): The name of the Ollama model.
28- prompt (str): The prompt to generate answers for.
29- use_ollama (bool): Flag indicating whether to use Ollama for analysis.
30-
31- Returns:
32- tuple: A tuple containing the generated detailed description and the original prompt.
33- """
34- if not use_ollama :
35- return prompt , prompt # Return the prompt twice for consistency
36-
37- full_prompt = f"describe the following actions for this markdown documentation in short terms regarding and with context and also format in markdown for documentation purposes: { prompt } "
38- messages = [{'role' : 'user' , 'content' : full_prompt }]
12+ def generate_answers (model_name , prompt ):
13+ model_name = "vicuna:13b-16k"
14+ messages = [
15+ {
16+ 'role' : 'user' ,
17+ 'content' : prompt ,
18+ },
19+ ]
3920 try :
4021 response = ollama .chat (model = model_name , messages = messages )
41- # Return both the detailed description and the original prompt
42- return response ['message' ]['content' ], prompt
22+ return response ['message' ]['content' ]
4323 except Exception as e :
4424 print (f"There was an error communicating with the Ollama model: { e } " )
45- return None , prompt
46-
47- def get_active_window_title ():
48- """
49- Get the title of the active window.
50-
51- Returns:
52- str: The title of the active window.
53- """
54- if platform .system () == "Linux" :
55- try :
56- # Get the window ID of the currently focused window
57- window_id = subprocess .check_output (["xdotool" , "getactivewindow" ]).decode ().strip ()
58-
59- # Get the name of the window with this ID
60- window_name = subprocess .check_output (["xdotool" , "getwindowname" , window_id ]).decode ().strip ()
61-
62- return window_name
63- except subprocess .CalledProcessError as e :
64- print (f"Error retrieving window title: { e } " )
65- return None
66- elif platform .system () == "Windows" :
67- window = gw .getActiveWindow ()
68- return window .title if window else "No active window"
25+ return None
6926
7027class ActivityMonitor (ctk .CTk ):
71- """
72- Class representing an Activity Monitor application.
73- """
74- def __init__ (self , use_ollama = False ):
75- """
76- Initialize the ActivityMonitor object.
77-
78- Args:
79- use_ollama (bool): Flag indicating whether to use Ollama for analysis.
80- """
28+ def __init__ (self ):
8129 super ().__init__ ()
8230 self .title ("Activity Monitor" )
8331 self .geometry ("300x150" )
84- self . use_ollama = use_ollama
32+
8533 self .is_running = False
34+ self .text_buffer = ""
8635 self .markdown_log = ""
8736
88- # Create GUI elements
8937 self .start_button = ctk .CTkButton (self , text = "Start" , command = self .start_monitoring )
9038 self .start_button .pack (pady = 10 )
39+
9140 self .stop_button = ctk .CTkButton (self , text = "Stop" , command = self .stop_monitoring )
9241 self .stop_button .pack (pady = 10 )
42+
9343 self .ollama_button = ctk .CTkButton (self , text = "Analyze with Ollama" , command = self .analyze_with_ollama )
9444 self .ollama_button .pack (pady = 10 )
45+
9546 self .quit_button = ctk .CTkButton (self , text = "Quit" , command = self .quit_monitoring )
9647 self .quit_button .pack (pady = 10 )
9748
98- # Method to start monitoring activities
9949 def start_monitoring (self ):
100- """
101- Start monitoring activities.
102- """
10350 if not self .is_running :
10451 self .is_running = True
10552 threading .Thread (target = self .monitor_activities ).start ()
10653
107- # Method to stop monitoring activities
10854 def stop_monitoring (self ):
109- """
110- Stop monitoring activities.
111- """
11255 self .is_running = False
11356
114- # Method to analyze activities using Ollama
11557 def analyze_with_ollama (self ):
116- """
117- Analyze activities using Ollama.
118- """
119- detailed_description , original_prompt = generate_answers ("vicuna:13b-16k" , self .markdown_log , True )
58+ detailed_description = generate_answers ("vicuna:13b-16k" , self .markdown_log )
12059 if detailed_description :
121- comment = f"Original prompt preserved: { original_prompt } \n Ollama's enhanced description: { detailed_description } "
122- self .markdown_log += "\n " + comment
123- self .append_to_markdown (comment )
60+ self .markdown_log = detailed_description
61+ self .write_markdown_file ()
12462
125- # Method to quit monitoring and write the log to a file
12663 def quit_monitoring (self ):
127- """
128- Quit monitoring activities and write the log to a file.
129- """
13064 self .stop_monitoring ()
13165 self .write_markdown_file ()
13266 self .destroy ()
13367
134- # Method to continuously monitor activities
13568 def monitor_activities (self ):
136- """
137- Continuously monitor activities.
138- """
69+ previous_clipboard = ""
70+ previous_window = None
13971 screenshot_directory = "screenshots"
140- archive_directory = "archives"
14172 os .makedirs (screenshot_directory , exist_ok = True )
142- os .makedirs (archive_directory , exist_ok = True )
143- window_title = None
144- previous_window = None
73+
14574 while self .is_running :
75+ # Capture clipboard content
14676 current_clipboard = clipboard .paste ()
147- self .append_to_markdown (f"\n - **Clipboard Changed**: `{ current_clipboard } `" )
148- window_title = get_active_window_title ()
149- self .append_to_markdown (f"\n - **Window Selected**: { window_title } " )
150- if previous_window != window_title :
151- self .capture_screenshot (screenshot_directory )
152- previous_window = window_title
153- # Capture typed keys
77+ if current_clipboard != previous_clipboard :
78+ self .markdown_log += f"\n - **Clipboard Changed**: `{ current_clipboard } `"
79+ previous_clipboard = current_clipboard
80+
81+ # Capture active window and screenshot
82+ active_window = gw .getActiveWindow ()
83+ if active_window and (active_window != previous_window ):
84+ try :
85+ # save screenshot
86+ screenshot_path = os .path .join (screenshot_directory , f"{ time .time ()} _screenshot.png" )
87+ screenshot = ImageGrab .grab (bbox = active_window .box )
88+ screenshot .save (screenshot_path )
89+
90+ # save title and screenshot in markdown log
91+ window_title = active_window .title if active_window .title else "Unbekanntes Fenster"
92+ self .markdown_log += f"\n - **Window Selected**: { window_title } "
93+ previous_window = active_window
94+ except Exception as e :
95+ print (f"Error getting active window: { e } " )
96+
97+ # Capture typed keys (improved version)
15498 key_events = keyboard .record (until = 'enter' )
15599 typed_text = '' .join ([event .name for event in key_events if event .event_type == 'down' and len (event .name ) == 1 or event .name == 'space' ])
156100 if typed_text :
@@ -159,102 +103,10 @@ def monitor_activities(self):
159103
160104 time .sleep (1 ) # Reduce CPU usage
161105
162- # Method to capture screenshots
163- def capture_screenshot (self , directory ):
164- """
165- Capture screenshots.
166-
167- Args:
168- directory (str): The directory to save the screenshots.
169-
170- Returns:
171- str: The path of the captured screenshot.
172- """
173- if platform .system () == "Linux" :
174- try :
175- # Get the window ID of the currently focused window
176- window_id = subprocess .check_output (["xdotool" , "getactivewindow" ]).decode ().strip ()
177-
178- # Get the geometry of the window (position and size)
179- geom_output = subprocess .check_output (["xdotool" , "getwindowgeometry" , "--shell" , window_id ]).decode ()
180-
181- # Use a dictionary to store variables from the shell output
182- geom_vars = dict (re .findall (r'(\w+)=(\S+)' , geom_output ))
183-
184- # Convert values to integers
185- x = int (geom_vars ['X' ])
186- y = int (geom_vars ['Y' ])
187- width = int (geom_vars ['WIDTH' ])
188- height = int (geom_vars ['HEIGHT' ])
189-
190- with mss .mss () as sct :
191- # The screenshot region is a tuple: (x, y, width, height)
192- monitor = {"top" : y , "left" : x , "width" : width , "height" : height }
193- screenshot_path = os .path .join (directory , f"{ time .time ()} _screenshot.png" )
194- # Capture the specified region
195- sct_img = sct .grab (monitor )
196- mss .tools .to_png (sct_img .rgb , sct_img .size , output = screenshot_path )
197- return screenshot_path
198- except Exception as e :
199- print (f"Error capturing screenshot: { e } " )
200- return "Screenshot capture failed"
201-
202- elif platform .system () == "Windows" :
203- window = gw .getActiveWindow ()
204- if window :
205- screenshot_path = os .path .join (directory , f"{ time .time ()} _screenshot.png" )
206- screenshot = ImageGrab .grab (bbox = window .box )
207- screenshot .save (screenshot_path )
208- return screenshot_path
209-
210- return "No active window for screenshot"
211-
212- # Method to archive URLs
213- def archive_url (self , directory ):
214- """
215- Archive URLs.
216-
217- Args:
218- directory (str): The directory to save the archived URLs.
219- """
220- window_title = get_active_window_title ()
221- # Extend or adjust the list of browser window titles as needed
222- browsers = ["Brave" , "Firefox" , "Chrome" , "Chromium" , "Edge" , "Opera" ]
223- if any (browser in window_title for browser in browsers ):
224- # Set focus to the address bar and copy URL
225- keyboard .send ('ctrl+l' ) # Focus on address bar
226- time .sleep (0.1 ) # Briefly wait for focus to be set
227- keyboard .send ('ctrl+c' ) # Copy URL
228- time .sleep (0.1 ) # Wait for clipboard to update
229- keyboard .send ('esc' ) # Escape
230-
231- # Read URL from clipboard
232- url = clipboard .paste ()
233- if url .startswith ("http" ) or url .startswith ("https" ):
234- with open (os .path .join (self .directory , f"{ time .time ()} _url.txt" ), "w" , encoding = 'utf-8' ) as file :
235- file .write (url )
236- else :
237- print ("The active window is not a recognized browser window." )
238-
239- # Method to append content to the markdown log
240- def append_to_markdown (self , content ):
241- """
242- Append content to the markdown log.
243-
244- Args:
245- content (str): The content to append.
246- """
247- if content not in self .markdown_log :
248- self .markdown_log += content
249-
250- # Method to write the markdown log to a file
251106 def write_markdown_file (self ):
252- """
253- Write the markdown log to a file.
254- """
255107 with open ("activity_log.md" , "w" , encoding = 'utf-8' ) as md_file :
256- md_file .write (markdown2 . markdown ( self .markdown_log ) )
108+ md_file .write (self .markdown_log )
257109
258110if __name__ == "__main__" :
259- app = ActivityMonitor (use_ollama = False )
111+ app = ActivityMonitor ()
260112 app .mainloop ()
0 commit comments