Skip to content

Commit 96682d1

Browse files
authored
Add files via upload
1 parent 0439780 commit 96682d1

File tree

8 files changed

+726
-0
lines changed

8 files changed

+726
-0
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
OPENAI_API_KEY="YOUR API KEY GOES HERE. MAKE SURE TO LEAVE THE "" OR IT WILL NOT WORK"

ai.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import tkinter as tk
2+
from tkinter import messagebox
3+
from PIL import ImageGrab, Image
4+
import openai
5+
import base64
6+
import io
7+
from config import get_openai_api_key
8+
9+
class AIScreenReader:
10+
11+
def __init__(self, parent_app, logger):
12+
self.parent_app = parent_app
13+
self.logger = logger
14+
try:
15+
self.client = openai.OpenAI(api_key=get_openai_api_key())
16+
except Exception as e:
17+
self.logger.error(f"Failed to initialize OpenAI client: {e}")
18+
messagebox.showerror("OpenAI Error", f"Failed to initialize OpenAI client. Please check your API key.\n\n{e}")
19+
self.client = None
20+
21+
def _analyze_image(self, image: Image.Image, model: str, prompt: str):
22+
if not self.client:
23+
return "OpenAI client not initialized."
24+
25+
self.logger.info(f"Sending image to OpenAI for analysis using model: {model}...")
26+
27+
buffered = io.BytesIO()
28+
image.save(buffered, format="PNG")
29+
base64_image = base64.b64encode(buffered.getvalue()).decode('utf-8')
30+
31+
try:
32+
response = self.client.chat.completions.create(
33+
model=model,
34+
messages=[
35+
{
36+
"role": "user",
37+
"content": [
38+
{"type": "text", "text": prompt},
39+
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}},
40+
],
41+
}
42+
],
43+
max_tokens=1000,
44+
)
45+
self.logger.info("Received analysis from OpenAI.")
46+
return response.choices[0].message.content
47+
except Exception as e:
48+
self.logger.error(f"OpenAI API call failed: {e}")
49+
messagebox.showerror("OpenAI Error", f"API call failed: {e}")
50+
return f"Error analyzing image: {e}"
51+
52+
def analyze_full_screen(self, model: str, prompt: str):
53+
self.logger.info("Capturing full screen...")
54+
55+
self.parent_app.withdraw()
56+
self.parent_app.update_idletasks()
57+
58+
screenshot = ImageGrab.grab(all_screens=True)
59+
60+
self.parent_app.deiconify()
61+
62+
return self._analyze_image(screenshot, model, prompt)
63+
64+
def analyze_screen_area(self, model: str, prompt: str):
65+
self.logger.info("Starting screen area selection...")
66+
selector = ScreenAreaSelector(self.parent_app)
67+
68+
self.parent_app.withdraw()
69+
self.parent_app.wait_window(selector.master)
70+
71+
screenshot = None
72+
if selector.bbox:
73+
self.logger.info(f"Area selected: {selector.bbox}")
74+
75+
screen_width = self.parent_app.winfo_screenwidth()
76+
screen_height = self.parent_app.winfo_screenheight()
77+
78+
x1 = max(0, selector.bbox[0])
79+
y1 = max(0, selector.bbox[1])
80+
x2 = min(screen_width, selector.bbox[2])
81+
y2 = min(screen_height, selector.bbox[3])
82+
83+
if x1 >= x2 or y1 >= y2:
84+
self.logger.warning("Invalid area selected (zero or negative size). Aborting.")
85+
else:
86+
clamped_bbox = (x1, y1, x2, y2)
87+
self.logger.info(f"Clamped bbox to: {clamped_bbox}")
88+
full_screenshot = ImageGrab.grab(all_screens=True)
89+
screenshot = full_screenshot.crop(clamped_bbox)
90+
91+
self.parent_app.deiconify()
92+
93+
if screenshot:
94+
return self._analyze_image(screenshot, model, prompt)
95+
else:
96+
self.logger.info("Area selection cancelled.")
97+
return None
98+
99+
100+
class ScreenAreaSelector:
101+
def __init__(self, parent_app):
102+
self.parent_app = parent_app
103+
self.master = tk.Toplevel(parent_app)
104+
self.master.title("Screen Selector")
105+
self.master.attributes("-fullscreen", True)
106+
self.master.attributes("-alpha", 0.3)
107+
self.master.bind("<ButtonPress-1>", self.on_press)
108+
self.master.bind("<B1-Motion>", self.on_drag)
109+
self.master.bind("<ButtonRelease-1>", self.on_release)
110+
111+
self.canvas = tk.Canvas(self.master, cursor="cross", bg="grey")
112+
self.canvas.pack(fill=tk.BOTH, expand=True)
113+
114+
if hasattr(self.parent_app, 'apply_privacy_settings_to_window'):
115+
self.parent_app.apply_privacy_settings_to_window(self.master, apply_transparency=False)
116+
117+
self.start_x = None
118+
self.start_y = None
119+
self.rect = None
120+
self.bbox = None
121+
122+
def on_press(self, event):
123+
self.start_x = self.canvas.canvasx(event.x)
124+
self.start_y = self.canvas.canvasy(event.y)
125+
if self.rect:
126+
self.canvas.delete(self.rect)
127+
self.rect = self.canvas.create_rectangle(self.start_x, self.start_y, self.start_x, self.start_y, outline='red', width=2)
128+
129+
def on_drag(self, event):
130+
cur_x, cur_y = (self.canvas.canvasx(event.x), self.canvas.canvasy(event.y))
131+
self.canvas.coords(self.rect, self.start_x, self.start_y, cur_x, cur_y)
132+
133+
def on_release(self, event):
134+
end_x, end_y = (self.canvas.canvasx(event.x), self.canvas.canvasy(event.y))
135+
self.bbox = (min(self.start_x, end_x), min(self.start_y, end_y),
136+
max(self.start_x, end_x), max(self.start_y, end_y))
137+
self.master.destroy()

config.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import configparser
2+
import os
3+
from dotenv import load_dotenv
4+
5+
def load_settings():
6+
config = configparser.ConfigParser()
7+
if os.path.exists('settings.ini'):
8+
config.read('settings.ini')
9+
defaults = config['DEFAULT']
10+
else:
11+
config['DEFAULT'] = {}
12+
defaults = config['DEFAULT']
13+
14+
defaults.setdefault('hide_from_screen', 'False')
15+
defaults.setdefault('hide_from_taskbar', 'False')
16+
defaults.setdefault('always_on_top', 'False')
17+
defaults.setdefault('transparency', '1.0')
18+
defaults.setdefault('theme', 'light')
19+
20+
return config
21+
22+
def save_settings(settings):
23+
with open('settings.ini', 'w') as configfile:
24+
settings.write(configfile)
25+
26+
def get_username():
27+
load_dotenv()
28+
username = os.getenv('USERNAME') or os.getenv('USER')
29+
if not username:
30+
try:
31+
username = os.getlogin()
32+
except Exception:
33+
username = 'User'
34+
return username
35+
36+
def get_openai_api_key():
37+
load_dotenv()
38+
api_key = os.getenv("OPENAI_API_KEY")
39+
if not api_key:
40+
print("Warning: OPENAI_API_KEY not found in .env file.")
41+
return api_key

0 commit comments

Comments
 (0)