Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions automation/computer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
computer.py

Handles all interaction with the local computer.
"""

import subprocess
from pathlib import Path

import mss
from PIL import Image


class Computer:
def __init__(self):
self.generated_file = Path("generated.py")
self.screenshot_file = Path("screenshot.png")

def take_screenshot(self) -> Path:
"""
Captures the current screen.
Returns the path to the screenshot.
"""

with mss.mss() as sct:
monitor = sct.monitors[1]
screenshot = sct.grab(monitor)

image = Image.frombytes(
"RGB",
screenshot.size,
screenshot.rgb,
)

image.save(self.screenshot_file)

return self.screenshot_file

def execute(self, code: str) -> dict:
"""
Saves and executes the Python code generated by the AI.
"""

self.generated_file.write_text(
code,
encoding="utf-8",
)

result = subprocess.run(
["python", str(self.generated_file)],
capture_output=True,
text=True,
)

return {
"stdout": result.stdout,
"stderr": result.stderr,
"returncode": result.returncode,
}
59 changes: 59 additions & 0 deletions automation/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
main.py

Friday's main loop.
"""

from computer import Computer
from model import Model
from prompt import SYSTEM_PROMPT


def main():
computer = Computer()
model = Model()

goal = input("What would you like Friday to do?\n> ")

while True:
# Take the latest screenshot
screenshot = computer.take_screenshot()

# Build the user prompt
user_prompt = f"""
Current Goal:
{goal}

This is the latest screenshot of the computer.

Figure out the next step.

If the task is complete, simply output:

TASK_COMPLETE

Otherwise, output ONLY executable Python code.
"""

# Ask Gemini what to do next
response = model.send(
SYSTEM_PROMPT,
user_prompt,
screenshot,
)

# Stop if the task is finished
if response.strip() == "TASK_COMPLETE":
print("Task completed.")
break

# Execute the generated Python
result = computer.execute(response)

# Optional: print any errors for debugging
if result["stderr"]:
print(result["stderr"])


if __name__ == "__main__":
main()
66 changes: 66 additions & 0 deletions automation/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
model.py

Maintains a continuous conversation with Gemini.

Its only job is to:
1. Send the goal and latest screenshot to Gemini.
2. Keep the conversation alive.
3. Return the Python code Gemini generates.
"""

import os

from google import genai


class Model:
def __init__(self):
api_key = os.getenv("GEMINI_API_KEY")

if not api_key:
raise ValueError("GEMINI_API_KEY not found.")

self.client = genai.Client(api_key=api_key)
self.model = "gemini-2.5-flash"

# Stores the conversation history so Gemini remembers
# the goal and previous screenshots.
self.history = []

def send(
self,
system_prompt: str,
user_prompt: str,
screenshot,
) -> str:
"""
Sends the latest computer state to Gemini and returns
the Python code it generates.
"""

self.history.append(
{
"role": "user",
"parts": [
{"text": f"{system_prompt}\n\n{user_prompt}"},
screenshot,
],
}
)

response = self.client.models.generate_content(
model=self.model,
contents=self.history,
)

self.history.append(
{
"role": "model",
"parts": [
{"text": response.text},
],
}
)

return response.text
28 changes: 28 additions & 0 deletions automation/prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
SYSTEM_PROMPT = """
You are Friday.

You are controlling a Windows computer.

The user will give you a goal.

You will continuously receive screenshots of the computer.

Your job is to accomplish the goal by writing Python code.

The code you write will be executed immediately.

After execution, you will receive another screenshot.

Based on the new screenshot, continue writing Python until the task is complete.

Guidelines:

- Use Python.
- Use any installed Python libraries.
- If another library is required, install it.
- Think step by step.
- Only output executable Python code.
- Do not explain your reasoning.
- Do not wrap your code in Markdown.
- Do not output anything except Python.
"""
Loading