sonuprasad23 commited on
Commit
48a476c
·
1 Parent(s): fe564a7
Files changed (3) hide show
  1. Dockerfile +21 -10
  2. index.js +13 -114
  3. package.json +1 -1
Dockerfile CHANGED
@@ -4,18 +4,29 @@ FROM node:18
4
  # Set working directory
5
  WORKDIR /usr/src/app
6
 
7
- # Set environment variable to skip Puppeteer chromium download
8
- ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
9
-
10
- # Update and install dependencies for Chrome
11
  RUN apt-get update && apt-get install -y \
12
- wget \
13
- gnupg \
14
  ca-certificates \
15
- && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
16
- && echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list \
17
- && apt-get update \
18
- && apt-get install -y google-chrome-stable \
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  && rm -rf /var/lib/apt/lists/*
20
 
21
  # Copy package files
 
4
  # Set working directory
5
  WORKDIR /usr/src/app
6
 
7
+ # Install system dependencies for Puppeteer
 
 
 
8
  RUN apt-get update && apt-get install -y \
 
 
9
  ca-certificates \
10
+ fonts-liberation \
11
+ libappindicator3-1 \
12
+ libasound2 \
13
+ libatk-bridge2.0-0 \
14
+ libatk1.0-0 \
15
+ libcups2 \
16
+ libdbus-1-3 \
17
+ libdrm2 \
18
+ libgbm1 \
19
+ libgtk-3-0 \
20
+ libnspr4 \
21
+ libnss3 \
22
+ libx11-xcb1 \
23
+ libxcomposite1 \
24
+ libxdamage1 \
25
+ libxrandr2 \
26
+ libxss1 \
27
+ libxtst6 \
28
+ lsb-release \
29
+ xdg-utils \
30
  && rm -rf /var/lib/apt/lists/*
31
 
32
  # Copy package files
index.js CHANGED
@@ -2,7 +2,7 @@ const express = require('express');
2
  const http = require('http');
3
  const path = require('path');
4
  const WebSocket = require('ws');
5
- const puppeteer = require('puppeteer-core');
6
 
7
  const app = express();
8
  const server = http.createServer(app);
@@ -33,13 +33,7 @@ const bookmarkletCode = `
33
  function wait(ms){return new Promise(r=>setTimeout(r,ms));}
34
  var stopFlag=false,isRunning=false,timerId=null,timerLeft=0,timerBtn=null,processedRows=new Set();
35
 
36
- function log(){
37
- console.log.apply(console,arguments);
38
- // Send logs to Node.js if the function is available
39
- if(typeof window.logToNode === 'function') {
40
- window.logToNode('STATUS', Array.from(arguments).join(' '));
41
- }
42
- }
43
 
44
  function setTimer(s){
45
  timerLeft=s;
@@ -65,9 +59,6 @@ const bookmarkletCode = `
65
  timerBtn.onclick=function(){
66
  stopFlag=true;
67
  alert("Stopped by Stop button");
68
- if(typeof window.logToNode === 'function') {
69
- window.logToNode('STATUS', 'Automation stopped by user via Stop button');
70
- }
71
  };
72
  document.body.appendChild(timerBtn);
73
  updateTimerBtn();
@@ -90,9 +81,6 @@ const bookmarkletCode = `
90
  if(e.ctrlKey&&e.key==='Enter'){
91
  stopFlag=true;
92
  alert('Automation stopped (Ctrl+Enter)');
93
- if(typeof window.logToNode === 'function') {
94
- window.logToNode('STATUS', 'Automation stopped by user via Ctrl+Enter');
95
- }
96
  }
97
  }
98
 
@@ -219,13 +207,13 @@ const bookmarkletCode = `
219
 
220
  const row=getBottomAutoReceiptRow();
221
  if(!row){
222
- log('No Auto-Receipt row found, refreshing...');
223
  await clickRefreshAndWait();
224
  return false;
225
  }
226
 
227
  processedRows.add(row);
228
- let expandIcon=row.querySelector('.icon.collapse_icon.expand')||row.querySelector('[ng-click="openItem"]');
229
  if(!expandIcon)return false;
230
 
231
  expandIcon.click();
@@ -235,9 +223,6 @@ const bookmarkletCode = `
235
  let messageText=document.querySelector('.message-text');
236
  if(!messageText||!messageText.textContent.trim()){
237
  log('Blank message text - discarding');
238
- if(typeof window.logToNode === 'function') {
239
- window.logToNode('DISCARD', { reason: 'Blank message text', value: '' });
240
- }
241
  await clickDiscardButton();
242
  return false;
243
  }
@@ -245,18 +230,11 @@ const bookmarkletCode = `
245
  let[val,mode]=extractSearchValue(messageText);
246
  if(!val){
247
  log('No Phone/CustomerID/Name - discarding');
248
- if(typeof window.logToNode === 'function') {
249
- window.logToNode('DISCARD', { reason: 'No Phone/CustomerID/Name found', value: '' });
250
- }
251
  await clickDiscardButton();
252
  return false;
253
  }
254
 
255
- if(typeof window.logToNode === 'function') {
256
- window.logToNode('PROCESS_START', { value: val, type: mode });
257
- }
258
-
259
- let sendBtn=row.querySelector('button.sendItem[data-qa="send"]');
260
  if(!sendBtn){
261
  for(let b of row.querySelectorAll('button')){
262
  if(b.textContent.includes('Send Item')){
@@ -286,9 +264,6 @@ const bookmarkletCode = `
286
  let noRes=document.querySelector('.category .title');
287
  if(noRes&&noRes.textContent.includes('No results')){
288
  log('No results - discarding');
289
- if(typeof window.logToNode === 'function') {
290
- window.logToNode('DISCARD', { reason: 'No search results found', value: val });
291
- }
292
  await clickDiscardButton();
293
  return false;
294
  }
@@ -322,13 +297,7 @@ const bookmarkletCode = `
322
  await wait(300);
323
  if(stopFlag)return false;
324
 
325
- let sendSuccess = await clickSendButton();
326
- if(sendSuccess && typeof window.logToNode === 'function') {
327
- window.logToNode('PROCESS_COMPLETE', { value: val });
328
- } else if(typeof window.logToNode === 'function') {
329
- window.logToNode('PROCESS_FAIL', { value: val });
330
- }
331
-
332
  await clickRefreshAndWait();
333
  return true;
334
  }
@@ -340,11 +309,6 @@ const bookmarkletCode = `
340
  ensureTimerBtn();
341
  addStopHotkey();
342
 
343
- log('Starting automation main loop...');
344
- if(typeof window.logToNode === 'function') {
345
- window.logToNode('STATUS', 'Automation main loop started');
346
- }
347
-
348
  try{
349
  while(!stopFlag){
350
  let did=await automateAutoReceiptOnce();
@@ -359,10 +323,6 @@ const bookmarkletCode = `
359
  removeStopHotkey();
360
  if(timerId)clearInterval(timerId);
361
  if(timerBtn&&document.body.contains(timerBtn))timerBtn.remove();
362
- log('Automation loop ended');
363
- if(typeof window.logToNode === 'function') {
364
- window.logToNode('STATUS', 'Automation main loop ended');
365
- }
366
  }
367
  }
368
 
@@ -381,52 +341,13 @@ async function runAndSuperviseAutomation() {
381
  throw new Error("LOGIN_EMAIL or LOGIN_PASSWORD secret is not set in Hugging Face Space settings.");
382
  }
383
 
384
- const possiblePaths = [
385
- '/usr/bin/google-chrome-stable',
386
- '/usr/bin/google-chrome',
387
- '/usr/bin/chromium-browser',
388
- '/usr/bin/chromium'
389
- ];
390
-
391
- let executablePath;
392
- for (const path of possiblePaths) {
393
- try {
394
- require('fs').accessSync(path);
395
- executablePath = path;
396
- console.log(`Found Chrome at: ${path}`);
397
- break;
398
- } catch (err) {
399
- continue;
400
- }
401
- }
402
-
403
- if (!executablePath) {
404
- throw new Error('Chrome executable not found. Please ensure Chrome is installed.');
405
- }
406
-
407
  browser = await puppeteer.launch({
408
  headless: true,
409
- executablePath: executablePath,
410
- args: [
411
- '--no-sandbox',
412
- '--disable-setuid-sandbox',
413
- '--disable-dev-shm-usage',
414
- '--disable-web-security',
415
- '--disable-features=VizDisplayCompositor',
416
- '--disable-background-timer-throttling',
417
- '--disable-backgrounding-occluded-windows',
418
- '--disable-renderer-backgrounding',
419
- '--disable-gpu',
420
- '--disable-extensions',
421
- '--no-first-run',
422
- '--no-default-browser-check'
423
- ]
424
  });
425
 
426
  const page = await browser.newPage();
427
 
428
- await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
429
-
430
  await page.exposeFunction('logToNode', (event, data) => {
431
  console.log(`LOG FROM BROWSER: ${event}`, data || '');
432
  broadcast(event, data);
@@ -434,41 +355,19 @@ async function runAndSuperviseAutomation() {
434
 
435
  console.log('Navigating to login page...');
436
  broadcast('STATUS', 'Navigating to login page...');
437
- await page.goto(LOGIN_URL, { waitUntil: 'domcontentloaded', timeout: 45000 });
438
-
439
- await page.waitForSelector('#inputUsername', { timeout: 15000 });
440
- await page.waitForSelector('#inputPswd', { timeout: 15000 });
441
- await page.waitForSelector('#loginButton', { timeout: 15000 });
442
 
443
  console.log('Entering credentials...');
444
  broadcast('STATUS', 'Entering credentials...');
445
-
446
- await page.click('#inputUsername');
447
- await page.evaluate(() => document.querySelector('#inputUsername').value = '');
448
- await page.type('#inputUsername', LOGIN_EMAIL, { delay: 50 });
449
-
450
- await page.click('#inputPswd');
451
- await page.evaluate(() => document.querySelector('#inputPswd').value = '');
452
- await page.type('#inputPswd', LOGIN_PASSWORD, { delay: 50 });
453
 
454
  console.log('Clicking login button...');
455
  broadcast('STATUS', 'Attempting to log in...');
456
-
457
  await page.click('#loginButton');
458
-
459
- try {
460
- await page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 60000 });
461
- } catch (navError) {
462
- console.log('Navigation timeout, checking if login succeeded...');
463
- await page.waitForTimeout(3000);
464
-
465
- const currentUrl = page.url();
466
- if (currentUrl.includes('practicefusion.com') && !currentUrl.includes('/auth/')) {
467
- console.log('Login appears successful despite navigation timeout');
468
- } else {
469
- throw navError;
470
- }
471
- }
472
 
473
  console.log('Login successful. Injecting automation script.');
474
  broadcast('STATUS', 'Login successful. Starting automation script...');
 
2
  const http = require('http');
3
  const path = require('path');
4
  const WebSocket = require('ws');
5
+ const puppeteer = require('puppeteer');
6
 
7
  const app = express();
8
  const server = http.createServer(app);
 
33
  function wait(ms){return new Promise(r=>setTimeout(r,ms));}
34
  var stopFlag=false,isRunning=false,timerId=null,timerLeft=0,timerBtn=null,processedRows=new Set();
35
 
36
+ function log(){console.log.apply(console,arguments);}
 
 
 
 
 
 
37
 
38
  function setTimer(s){
39
  timerLeft=s;
 
59
  timerBtn.onclick=function(){
60
  stopFlag=true;
61
  alert("Stopped by Stop button");
 
 
 
62
  };
63
  document.body.appendChild(timerBtn);
64
  updateTimerBtn();
 
81
  if(e.ctrlKey&&e.key==='Enter'){
82
  stopFlag=true;
83
  alert('Automation stopped (Ctrl+Enter)');
 
 
 
84
  }
85
  }
86
 
 
207
 
208
  const row=getBottomAutoReceiptRow();
209
  if(!row){
210
+ log('No Auto-Receipt row found, refreshing in 5s...');
211
  await clickRefreshAndWait();
212
  return false;
213
  }
214
 
215
  processedRows.add(row);
216
+ let expandIcon=row.querySelector('.icon.collapse_icon.expand')||row.querySelector('[ng-click*="openItem"]');
217
  if(!expandIcon)return false;
218
 
219
  expandIcon.click();
 
223
  let messageText=document.querySelector('.message-text');
224
  if(!messageText||!messageText.textContent.trim()){
225
  log('Blank message text - discarding');
 
 
 
226
  await clickDiscardButton();
227
  return false;
228
  }
 
230
  let[val,mode]=extractSearchValue(messageText);
231
  if(!val){
232
  log('No Phone/CustomerID/Name - discarding');
 
 
 
233
  await clickDiscardButton();
234
  return false;
235
  }
236
 
237
+ let sendBtn=row.querySelector('button.sendItem[data-qa*="send"]');
 
 
 
 
238
  if(!sendBtn){
239
  for(let b of row.querySelectorAll('button')){
240
  if(b.textContent.includes('Send Item')){
 
264
  let noRes=document.querySelector('.category .title');
265
  if(noRes&&noRes.textContent.includes('No results')){
266
  log('No results - discarding');
 
 
 
267
  await clickDiscardButton();
268
  return false;
269
  }
 
297
  await wait(300);
298
  if(stopFlag)return false;
299
 
300
+ await clickSendButton();
 
 
 
 
 
 
301
  await clickRefreshAndWait();
302
  return true;
303
  }
 
309
  ensureTimerBtn();
310
  addStopHotkey();
311
 
 
 
 
 
 
312
  try{
313
  while(!stopFlag){
314
  let did=await automateAutoReceiptOnce();
 
323
  removeStopHotkey();
324
  if(timerId)clearInterval(timerId);
325
  if(timerBtn&&document.body.contains(timerBtn))timerBtn.remove();
 
 
 
 
326
  }
327
  }
328
 
 
341
  throw new Error("LOGIN_EMAIL or LOGIN_PASSWORD secret is not set in Hugging Face Space settings.");
342
  }
343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  browser = await puppeteer.launch({
345
  headless: true,
346
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  });
348
 
349
  const page = await browser.newPage();
350
 
 
 
351
  await page.exposeFunction('logToNode', (event, data) => {
352
  console.log(`LOG FROM BROWSER: ${event}`, data || '');
353
  broadcast(event, data);
 
355
 
356
  console.log('Navigating to login page...');
357
  broadcast('STATUS', 'Navigating to login page...');
358
+ await page.goto(LOGIN_URL, { waitUntil: 'networkidle2' });
 
 
 
 
359
 
360
  console.log('Entering credentials...');
361
  broadcast('STATUS', 'Entering credentials...');
362
+ await page.type('#inputUsername', LOGIN_EMAIL);
363
+ await page.type('#inputPswd', LOGIN_PASSWORD);
 
 
 
 
 
 
364
 
365
  console.log('Clicking login button...');
366
  broadcast('STATUS', 'Attempting to log in...');
 
367
  await page.click('#loginButton');
368
+
369
+ await page.waitForNavigation({ waitUntil: 'networkidle2' });
370
+ console.log('Login successful. Current URL:', page.url());
 
 
 
 
 
 
 
 
 
 
 
371
 
372
  console.log('Login successful. Injecting automation script.');
373
  broadcast('STATUS', 'Login successful. Starting automation script...');
package.json CHANGED
@@ -8,7 +8,7 @@
8
  },
9
  "dependencies": {
10
  "express": "^4.19.2",
11
- "puppeteer-core": "^21.0.0",
12
  "ws": "^8.17.0"
13
  },
14
  "engines": {
 
8
  },
9
  "dependencies": {
10
  "express": "^4.19.2",
11
+ "puppeteer": "^21.0.0",
12
  "ws": "^8.17.0"
13
  },
14
  "engines": {