Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Chrome browser event in database during recording #744

Merged
merged 99 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
1042fb5
add old chomre extension files
KrishPatel13 Jun 11, 2024
bcd647b
add old changes back, related to chrome extension, in openadapt dir
KrishPatel13 Jun 11, 2024
9c749ca
try web socket solution, add asyncio and websockets libraries to poetry
KrishPatel13 Jun 16, 2024
d9f9792
now we can log the dom changes ina a desctop running python process
KrishPatel13 Jun 16, 2024
fec777b
remove the old nativeMessaging extension code
KrishPatel13 Jun 16, 2024
9238316
rename dir
KrishPatel13 Jun 16, 2024
1b606fb
save the dom chages into dumy db: chrome.db
KrishPatel13 Jun 16, 2024
644a102
Merge branch 'main' into feat/chrome-extension
KrishPatel13 Jun 16, 2024
1246af4
try to fix actions tests
KrishPatel13 Jun 16, 2024
f782f5a
try 2 to fix actiosn
KrishPatel13 Jun 16, 2024
b1c9014
try 3 to fix github actions
KrishPatel13 Jun 16, 2024
a2126b1
ran `poetry run black --preview . --exclude 'alembic'`
KrishPatel13 Jun 16, 2024
86866b8
remove sockets.py
KrishPatel13 Jun 16, 2024
9d72328
fix falke8 formatting issues
KrishPatel13 Jun 17, 2024
b75d8ee
ran `poetry run black --preview . --exclude 'alembic'`
KrishPatel13 Jun 17, 2024
39e255a
Merge branch 'main' into feat/chrome-extension
KrishPatel13 Jun 22, 2024
205c433
add browser event code
KrishPatel13 Jun 22, 2024
31a5526
chrome extension work wip
KrishPatel13 Jun 22, 2024
3857dea
fix reset_db python file.
KrishPatel13 Jun 23, 2024
dc0f288
now, extension messages can be seen in logs when the recording is sta…
KrishPatel13 Jun 23, 2024
2abdd41
till trying to fix the issue: record functione execution gets stuck a…
KrishPatel13 Jun 23, 2024
da93ef5
browser_events can be seen in db
KrishPatel13 Jul 1, 2024
e8aff8a
ran black and flake8
KrishPatel13 Jul 7, 2024
c23ac7b
add documentation in extension side js files and remove unused files
KrishPatel13 Jul 7, 2024
b7eb18e
Merge branch 'main' into feat/chrome-extension
KrishPatel13 Jul 7, 2024
dffe40b
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#pullrequestreview-2…
KrishPatel13 Jul 8, 2024
32b6c8b
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668787418
KrishPatel13 Jul 8, 2024
dc5c699
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668782507
KrishPatel13 Jul 8, 2024
c06bb48
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668782930
KrishPatel13 Jul 8, 2024
fa9e458
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668785377
KrishPatel13 Jul 8, 2024
6643bc0
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668788679
KrishPatel13 Jul 8, 2024
8d187b0
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668788679
KrishPatel13 Jul 8, 2024
a73101d
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668790311
KrishPatel13 Jul 8, 2024
abaef76
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668791304
KrishPatel13 Jul 8, 2024
1bcc2ca
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668792409
KrishPatel13 Jul 8, 2024
c5f2495
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668793589
KrishPatel13 Jul 9, 2024
5dd341d
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668795476
KrishPatel13 Jul 9, 2024
6a3b74b
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668796268
KrishPatel13 Jul 9, 2024
9ca11a3
https://github.com/OpenAdaptAI/OpenAdapt/pull/744/files#r1668802201
KrishPatel13 Jul 9, 2024
bf5e43e
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668803476
KrishPatel13 Jul 9, 2024
3836c3d
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1668797431
KrishPatel13 Jul 9, 2024
ac65f13
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1676066028
KrishPatel13 Jul 13, 2024
392643d
update readme again
KrishPatel13 Jul 13, 2024
388156c
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1676066895
KrishPatel13 Jul 13, 2024
fe637f5
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1676069410
KrishPatel13 Jul 13, 2024
bb80c46
Update openadapt/models.py
KrishPatel13 Jul 13, 2024
98cdaa6
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1676071070
KrishPatel13 Jul 13, 2024
6154b2d
Merge branch 'feat/chrome-extension' of https://github.com/OpenAdaptA…
KrishPatel13 Jul 13, 2024
d82a77d
https://github.com/OpenAdaptAI/OpenAdapt/pull/744/files/3836c3d165bb1…
KrishPatel13 Jul 13, 2024
6c54099
ran black on openadapt dir
KrishPatel13 Jul 13, 2024
fbf7c77
Merge branch 'main' into feat/chrome-extension
KrishPatel13 Jul 13, 2024
e267384
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1676813676
KrishPatel13 Jul 13, 2024
20ce604
Merge branch 'feat/chrome-extension' of https://github.com/OpenAdaptA…
KrishPatel13 Jul 13, 2024
48af6c5
fran bklack
KrishPatel13 Jul 13, 2024
f0e0f2c
update the form type script
KrishPatel13 Jul 14, 2024
67528c1
add the record browser flag in classification group
KrishPatel13 Jul 14, 2024
aa7b1ae
Merge branch 'main' into feat/chrome-extension
abrichr Jul 25, 2024
f8a1216
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1691451352
KrishPatel13 Jul 25, 2024
ca55031
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1691417341
KrishPatel13 Jul 25, 2024
4323537
https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discussion_r1691424083
KrishPatel13 Jul 25, 2024
42bbf73
Update openadapt/config.py: https://github.com/OpenAdaptAI/OpenAdapt/…
KrishPatel13 Jul 27, 2024
ea89058
Update openadapt/record.py
KrishPatel13 Jul 27, 2024
64f20c3
Update openadapt/config.py: https://github.com/OpenAdaptAI/OpenAdapt/…
KrishPatel13 Jul 28, 2024
8e15ac9
Remove 3 unused functions owing to:
KrishPatel13 Jul 28, 2024
ba83cb9
Update openadapt/record.py: https://github.com/OpenAdaptAI/OpenAdapt/…
KrishPatel13 Jul 28, 2024
b9ef275
Rename owing to: https://github.com/OpenAdaptAI/OpenAdapt/pull/744#di…
KrishPatel13 Jul 28, 2024
eb1dd25
Merge branch 'feat/chrome-extension' of https://github.com/OpenAdaptA…
KrishPatel13 Jul 28, 2024
af181d1
Rename const: https://github.com/OpenAdaptAI/OpenAdapt/pull/744#discu…
KrishPatel13 Jul 28, 2024
995fc55
Remove unused: https://github.com/OpenAdaptAI/OpenAdapt/pull/744#disc…
KrishPatel13 Jul 28, 2024
96b415b
Use ClassVar again: https://github.com/OpenAdaptAI/OpenAdapt/pull/744…
KrishPatel13 Jul 28, 2024
c75e499
Update openadapt/models.py: https://github.com/OpenAdaptAI/OpenAdapt/…
KrishPatel13 Jul 28, 2024
c5d7e76
Update openadapt/record.py: https://github.com/OpenAdaptAI/OpenAdapt/…
KrishPatel13 Jul 28, 2024
6d2babd
Update openadapt/record.py: https://github.com/OpenAdaptAI/OpenAdapt/…
KrishPatel13 Jul 28, 2024
fad4143
Move string to const: https://github.com/OpenAdaptAI/OpenAdapt/pull/7…
KrishPatel13 Jul 28, 2024
0162cc8
Merge branch 'feat/chrome-extension' of https://github.com/OpenAdaptA…
KrishPatel13 Jul 28, 2024
b00ae8a
Correct Grammatical errors: https://github.com/OpenAdaptAI/OpenAdapt/…
KrishPatel13 Jul 28, 2024
b3d54eb
fix visualize and reformat
KrishPatel13 Aug 3, 2024
0347b3d
fix alembic migrations
abrichr Aug 26, 2024
7905a2c
Intersection/MutationObserver; _repr_ignore_attrs; fix process_events
abrichr Aug 27, 2024
1a3fde9
synchronize timestamps
abrichr Aug 28, 2024
329702b
attachWindowEventListeners
abrichr Aug 28, 2024
6571476
recreate alembic migration
abrichr Aug 28, 2024
798c806
sync; buffer
abrichr Sep 3, 2024
602f85c
add dtw.py (wip)
abrichr Sep 4, 2024
925db61
remove sorting and syncing; working experiments/dtw.py
abrichr Sep 4, 2024
3bcf036
fix content.js
abrichr Sep 4, 2024
2959293
report screenX/screenY; fix getScreenCoordinates; compute coordinate …
abrichr Sep 4, 2024
874c1ce
wip
abrichr Sep 6, 2024
2d62d5d
remove observers; composite distance; task_by_name
abrichr Sep 6, 2024
4c33af9
replace eventBuffer with coordMappings; compute tlbr-screen in browse…
abrichr Sep 10, 2024
4b9582e
assign_browser_events in events.py
abrichr Sep 11, 2024
dd1be17
merge to master
abrichr Sep 11, 2024
67c0cc4
black; docstrings
abrichr Sep 11, 2024
962549e
flake8
abrichr Sep 11, 2024
05410f9
update test
abrichr Sep 11, 2024
e40870a
black
abrichr Sep 11, 2024
8452b8b
add test_browser.py
abrichr Sep 11, 2024
b265a62
fix README grammar
abrichr Sep 11, 2024
0df8cc2
remove record.run_main
abrichr Sep 11, 2024
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
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,40 @@ possible memory leak
pointing the cursor and left or right clicking, as described in this
[open issue](https://github.com/OpenAdaptAI/OpenAdapt/issues/145)


### Capturing Browser Events

To capture (record) browser events on Chrome, follow the following steps:

1. Go To: [Chrome Extension Page](chrome://extensions/)

2. Turn on the `Developer mode` to on (near top right):

![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/c97eb9fb-05d6-465d-85b3-332694556272)

3. Click on `Load Unpacked` (near top left).

![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/00c8adf5-074a-4655-b132-fd87644007fc)

4. Select `chrome_extension` directory:

![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/71610ed3-f8d4-431a-9a22-d901127b7b0c)

5. You shall see this:

![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/7ee19da9-37e0-448f-b9ab-08ef99110e85)

Meaning that the extension is loaded !

6. Switch the flag to true (if it false):

![image](https://github.com/user-attachments/assets/8eba24a3-7c68-4deb-8fbe-9d03cece1482)

7. Finally, start recording, once Everything is started, then go to chrome browser and search for some page, do a few click and then stop the recording. Let it finish successfully.

8. Once done, you can check the `openadapt.db` -> table `browser_event` it should have all of your browser activity logs in it. You can check for correctness by using `sqlite3` cli or using an extension like SQLite Viewer in VS Code to open `openadapt.db`.
KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved


KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved
### Visualize

Quickly visualize the latest recording you created by running the following command:
Expand Down
49 changes: 49 additions & 0 deletions chrome_extension/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @file background.js
* @description Creates a new background script that listens for messages from the content script
* and sends them to a WebSocket server.
*/

let socket;
let TIMEOUT_INTERVAL = 5000; // ms
KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved

/*
* Function to connect to the WebSocket server.
*/
function connectWebSocket() {
// TODO: Ideally we read "ws://localhost:8765" and `TIMEOUT_INTERVAL` from config.py, or it gets passed in somehow.
socket = new WebSocket("ws://localhost:8765");
KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved
KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved

socket.onopen = function() {
console.log("WebSocket connection established");
};

socket.onmessage = function(event) {
console.log("Message from server:", event.data);
};

socket.onclose = function(event) {
console.log("WebSocket connection closed", event);
// Reconnect after 5 seconds if the connection is lost
setTimeout(connectWebSocket, TIMEOUT_INTERVAL);
};

socket.onerror = function(error) {
console.error("WebSocket error:", error);
socket.close();
};
}

// Create a connection to the WebSocket server
connectWebSocket();

/* Listen for messages from the content script */
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (socket && socket.readyState === WebSocket.OPEN) {
console.log(message);
socket.send(JSON.stringify(message));
sendResponse({status: "Message sent to WebSocket"});
} else {
sendResponse({status: "WebSocket connection not open"});
}
});
156 changes: 156 additions & 0 deletions chrome_extension/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/**
* @file content.js
* @description This file is injected into the web page and is responsible for
* capturing DOM changes and sending them to the background script.
*/


const elements = {};


/*
* Function to send a message to the background script
*/
function sendMessageToBackgroundScript(message) {
chrome.runtime.sendMessage(message);
}


/*
* Function to capture initial document state and
* send it to the background script
*/
function captureDocumentState() {
const documentBody = document.body.outerHTML;
const documentHead = document.head.outerHTML;
const page_url = window.location.href;

sendMessageToBackgroundScript({
action: "captureDocumentState",
documentBody: documentBody,
documentHead: documentHead,
elements: elements,
url: page_url,
timestamp: Date.now(),
});
}


/*
* Function to handle click events on any element on a web page.
* It sends the element details to the background script.
*/
function handleElementClick(event) {
const element = event.target;
const tagName = element.tagName;
const { x, y } = elements[element.id] || {};
const value = elements[element.id]?.value || "";
const attributes = {};

for (const attr of element.attributes) {
attributes[attr.name] = attr.value;
}

sendMessageToBackgroundScript({
action: "elementClicked",
tagName: tagName,
attributes: attributes,
x: x,
y: y,
value: value,
url: window.location.href,
timestamp: Date.now(),
});
}


/*
* Function to create a debounced version of a function.
* @param {Function} func - The function to be debounced.
* @param {number} delay - The delay in milliseconds.
*/
function debounce(func, delay) {
let timerId;
return function (...args) {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
func.apply(this, args);
timerId = null;
}, delay);
};
}


/*
* Function to handle input events on any element on a web page.
* It sends the element details to the background script.
* @param {Event} event - The input event.
* @param {Element} element - The element on which the input event occurred.
*/
function handleDebouncedInput(event) {
const element = event.target;
const { x, y } = elements[element.id];
const value = elements[element.id].element.value;
const tagName = element.tagName;
const attributes = {};

for (const attr of element.attributes) {
attributes[attr.name] = attr.value;
}

sendMessageToBackgroundScript({
action: "elementInput",
tagName: tagName,
attributes: attributes,
x: x,
y: y,
value: value,
url: window.location.href,
timestamp: Date.now(),
});
}

/* Debounce Input Handler */
const debouncedInputHandler = debounce(handleDebouncedInput, 500);

/* Call Debounce Input Handler */
function handleElementInput(event) {
debouncedInputHandler(event);
}


/*
* Add an click and input information of the element.
*/
function addElement(element) {
const rect = element.getBoundingClientRect();
const x = rect.left + window.scrollX;
const y = rect.top + window.scrollY;
const value = element.value;
if (!element.id) {
element.id = element.tagName + "_" + x + "_" + y;
}
elements[element.id] = { element, x, y, value };
element.addEventListener("click", handleElementClick);
KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved
element.addEventListener("input", debounce(handleDebouncedInput, 500));
}


/*
* Handle all events that occur on the page.
*/
function addEventListeners() {
const elements = document.getElementsByTagName("*");

for (const element of elements) {
addElement(element);
}
}


/* Function Calls */

addEventListeners(); // Adds listeners
captureDocumentState(); // Captures initial document state
Binary file added chrome_extension/icons/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions chrome_extension/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "openadapt",
"description": "Native messaging example add-on",
KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved
"version": "1.0",
"manifest_version": 3,
"icons": {
"48": "icons/logo.png"
KrishPatel13 marked this conversation as resolved.
Show resolved Hide resolved
},
"action": {
"default_icon": "icons/logo.png"
},
"background": {
"service_worker": "background.js"
},
"permissions": ["activeTab", "tabs", "nativeMessaging", "scripting"],
"host_permissions": ["<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""regenrate with browser_event table
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please:

  • run alembic downgrade -4 to revert the four existing alembic scripts
  • create a single new migration script with an appropriate description, e.g. "create BrowserEvent table"
  • remove the old existing alembic migration scripts and add the new one


Revision ID: 113f15863a33
Revises: bb25e889ad71
Create Date: 2024-07-08 19:59:44.713853

"""
from alembic import op
import sqlalchemy as sa

import openadapt


# revision identifiers, used by Alembic.
revision = '113f15863a33'
down_revision = 'bb25e889ad71'
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('replay',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('timestamp', openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True),
sa.Column('strategy_name', sa.String(), nullable=True),
sa.Column('strategy_args', sa.JSON(), nullable=True),
sa.Column('git_hash', sa.String(), nullable=True),
sa.PrimaryKeyConstraint('id', name=op.f('pk_replay'))
)
with op.batch_alter_table('action_event', schema=None) as batch_op:
batch_op.drop_constraint('fk_input_event_browser_event_timestamp_browser_event', type_='foreignkey')

# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('action_event', schema=None) as batch_op:
batch_op.create_foreign_key('fk_input_event_browser_event_timestamp_browser_event', 'browser_event', ['browser_event_timestamp'], ['timestamp'])

op.drop_table('replay')
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ def upgrade() -> None:
sa.Column("height", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint("id", name=op.f("pk_window_event")),
)
op.create_table(
"browser_event",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("recording_timestamp", sa.Integer(), nullable=True),
sa.Column("timestamp", sa.Integer(), nullable=True),
sa.Column("message", sa.String(), nullable=True),
sa.PrimaryKeyConstraint("id", name=op.f("pk_browser_event")),
)
op.create_table(
"input_event",
sa.Column("id", sa.Integer(), nullable=False),
Expand All @@ -61,6 +69,7 @@ def upgrade() -> None:
sa.Column("recording_timestamp", sa.Integer(), nullable=True),
sa.Column("screenshot_timestamp", sa.Integer(), nullable=True),
sa.Column("window_event_timestamp", sa.Integer(), nullable=True),
sa.Column("browser_event_timestamp", sa.Integer(), nullable=True),
sa.Column("mouse_x", sa.Numeric(asdecimal=False), nullable=True),
sa.Column("mouse_y", sa.Numeric(asdecimal=False), nullable=True),
sa.Column("mouse_dx", sa.Numeric(asdecimal=False), nullable=True),
Expand Down Expand Up @@ -94,6 +103,11 @@ def upgrade() -> None:
["window_event.timestamp"],
name=op.f("fk_input_event_window_event_timestamp_window_event"),
),
sa.ForeignKeyConstraint(
["browser_event_timestamp"],
["browser_event.timestamp"],
name=op.f("fk_input_event_browser_event_timestamp_browser_event"),
),
sa.PrimaryKeyConstraint("id", name=op.f("pk_input_event")),
)
# ### end Alembic commands ###
Expand All @@ -103,6 +117,7 @@ def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table("input_event")
op.drop_table("window_event")
op.drop_table("browser_event")
op.drop_table("screenshot")
op.drop_table("recording")
# ### end Alembic commands ###
Loading
Loading