Skip to content

Commit 49d71d1

Browse files
feat(browser_extension) add browser_extension and openadapt.browser (#744)
* add old chrome extension files * add old changes back, related to chrome extension, in openadapt dir * try web socket solution, add asyncio and websockets libraries to poetry * now we can log the dom changes ina a desctop running python process * remove the old nativeMessaging extension code * rename dir * save the dom chages into dummy db: chrome.db * fix actions tests * ran `poetry run black --preview . --exclude 'alembic'` * remove sockets.py * fix falke8 formatting issues * ran `poetry run black --preview . --exclude 'alembic'` * add browser event code * chrome extension work wip * fix reset_db python file. * now, extension messages can be seen in logs when the recording is started. * till trying to fix the issue: record functione execution gets stuck at read_browser_events due to asyncio.runForever * browser_events can be seen in db * ran black and flake8 * add documentation in extension side js files and remove unused files * #744 (review) Update readme.md * #744 (comment) remove mlds logo * #744 (comment) add todo * #744 (comment) add NAMED_CONSTANT * #744 (comment) remove unused lines in content.js * #744 (comment) uncomment for `alembic upgrade` * #744 (comment) resolve this * #744 (comment) remove unwanted obfuscate keys * #744 (comment) used joinedload * #744 (comment) remove unwanted return * #744 (comment) Ran the following: - `alembic revision --autogenerate -m "regenrate with browser_event table"` - `alembic upgrade head` * #744 (comment) remove unwanted commetns lines * #744 (comment) remove commented lines * https://github.com/OpenAdaptAI/OpenAdapt/pull/744/files#r1668802201 added this todo * #744 (comment) optimize browser events record by adding an option to include to record or not like audio * #744 (comment) move constants to config * #744 (comment) update readme * update readme again * #744 (comment) update config default for RECORD_BROWSER_EVENTS * #744 (comment) removed unessary comment in events.py * Update openadapt/models.py #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * #744 (comment) resolve d * https://github.com/OpenAdaptAI/OpenAdapt/pull/744/files/3836c3d165bb11c5615c83a0df65f6cdc155f93f#r1676068390 resolved * ran black on openadapt dir `poetry run black --preview openadapt/` * #744 (comment) fixed faiing tests * update the form type script * add the record browser flag in classification group * #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * Update openadapt/config.py: #744 (comment) #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * Update openadapt/record.py #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * Update openadapt/config.py: https://github.com/OpenAdaptAI/OpenAdapt/pull/744/files/aa7b1ae7df8fb7045abb5d71d1d41a09f2d8bea2#r1691430453 https://github.com/OpenAdaptAI/OpenAdapt/pull/744/files/aa7b1ae7df8fb7045abb5d71d1d41a09f2d8bea2#r1691430453 Co-authored-by: Richard Abrich <[email protected]> * Remove 3 unused functions owing to: #744 (comment) #744 (comment) #744 (comment) * Update openadapt/record.py: #744 (comment) #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * Rename owing to: #744 (comment) * Rename const: #744 (comment) * Remove unused: #744 (comment) * Use ClassVar again: #744 (comment) * Update openadapt/models.py: #744 (comment) #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * Update openadapt/record.py: #744 (comment) #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * Update openadapt/record.py: #744 (comment) #744 (comment) Co-authored-by: Richard Abrich <[email protected]> * Move string to const: #744 (comment) * Correct Grammatical errors: #744 (comment) * fix visualize and reformat * fix alembic migrations * Intersection/MutationObserver; _repr_ignore_attrs; fix process_events * synchronize timestamps * attachWindowEventListeners * recreate alembic migration * sync; buffer * add dtw.py (wip) * remove sorting and syncing; working experiments/dtw.py * fix content.js * report screenX/screenY; fix getScreenCoordinates; compute coordinate differences * wip * remove observers; composite distance; task_by_name * replace eventBuffer with coordMappings; compute tlbr-screen in browser.py * assign_browser_events in events.py * black; docstrings * flake8 * update test * black * add test_browser.py --------- Co-authored-by: pate1595 <[email protected]> Co-authored-by: Krish Patel <[email protected]>
1 parent 1476966 commit 49d71d1

File tree

27 files changed

+2152
-75
lines changed

27 files changed

+2152
-75
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,38 @@ possible memory leak
164164
pointing the cursor and left or right clicking, as described in this
165165
[open issue](https://github.com/OpenAdaptAI/OpenAdapt/issues/145)
166166

167+
168+
### Capturing Browser Events
169+
170+
To capture (record) browser events in Chrome, follow these steps:
171+
172+
1. Go to: [Chrome Extension Page](chrome://extensions/)
173+
174+
2. Enable `Developer mode` (located at the top right):
175+
176+
![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/c97eb9fb-05d6-465d-85b3-332694556272)
177+
178+
3. Click `Load unpacked` (located at the top left).
179+
180+
![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/00c8adf5-074a-4655-b132-fd87644007fc)
181+
182+
4. Select the `chrome_extension` directory:
183+
184+
![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/71610ed3-f8d4-431a-9a22-d901127b7b0c)
185+
186+
5. You should see the following confirmation, indicating that the extension is loaded:
187+
188+
![image](https://github.com/OpenAdaptAI/OpenAdapt/assets/65433817/7ee19da9-37e0-448f-b9ab-08ef99110e85)
189+
190+
6. Set the flag to `true` if it is currently `false`:
191+
192+
![image](https://github.com/user-attachments/assets/8eba24a3-7c68-4deb-8fbe-9d03cece1482)
193+
194+
7. Start recording. Once recording begins, navigate to the Chrome browser, browse some pages, and perform a few clicks. Then, stop the recording and let it complete successfully.
195+
196+
8. After recording, check the `openadapt.db` table `browser_event`. It should contain all your browser activity logs. You can verify the data's correctness using the `sqlite3` CLI or an extension like `SQLite Viewer` in VS Code to open `data/openadapt.db`.
197+
198+
167199
### Visualize
168200

169201
Quickly visualize the latest recording you created by running the following command:

chrome_extension/background.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* @file background.js
3+
* @description Creates a new background script that listens for messages from the content script
4+
* and sends them to a WebSocket server.
5+
*/
6+
7+
let socket;
8+
let timeOffset = 0; // Global variable to store the time offset
9+
10+
/*
11+
* TODO:
12+
* Ideally we read `WS_SERVER_PORT`, `WS_SERVER_ADDRESS` and
13+
* `RECONNECT_TIMEOUT_INTERVAL` from config.py,
14+
* or it gets passed in somehow.
15+
*/
16+
let RECONNECT_TIMEOUT_INTERVAL = 1000; // ms
17+
let WS_SERVER_PORT = 8765;
18+
let WS_SERVER_ADDRESS = "localhost";
19+
let WS_SERVER_URL = "ws://" + WS_SERVER_ADDRESS + ":" + WS_SERVER_PORT;
20+
21+
22+
function socketSend(socket, message) {
23+
console.log({ message });
24+
socket.send(JSON.stringify(message));
25+
}
26+
27+
28+
/*
29+
* Function to connect to the WebSocket server.
30+
*/
31+
function connectWebSocket() {
32+
socket = new WebSocket(WS_SERVER_URL);
33+
34+
socket.onopen = function() {
35+
console.log("WebSocket connection established");
36+
};
37+
38+
socket.onmessage = function(event) {
39+
console.log("Message from server:", event.data);
40+
const message = JSON.parse(event.data);
41+
};
42+
43+
socket.onclose = function(event) {
44+
console.log("WebSocket connection closed", event);
45+
// Reconnect after 5 seconds if the connection is lost
46+
setTimeout(connectWebSocket, RECONNECT_TIMEOUT_INTERVAL);
47+
};
48+
49+
socket.onerror = function(error) {
50+
console.error("WebSocket error:", error);
51+
socket.close();
52+
};
53+
}
54+
55+
// Create a connection to the WebSocket server
56+
connectWebSocket();
57+
58+
/* Listen for messages from the content script */
59+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
60+
const tabId = sender.tab.id;
61+
message.tabId = tabId;
62+
if (socket && socket.readyState === WebSocket.OPEN) {
63+
socketSend(socket, message);
64+
sendResponse({ status: "Message sent to WebSocket" });
65+
} else {
66+
sendResponse({ status: "WebSocket connection not open" });
67+
}
68+
});

0 commit comments

Comments
 (0)