Spaces:
Build error
Build error
Commit ·
035002c
1
Parent(s): 0e752fc
changes
Browse files- .dockerignore +0 -5
- Dockerfile +22 -20
- Dockerfile.alternative +0 -54
- index.js +31 -25
- package.json +2 -3
.dockerignore
CHANGED
|
@@ -6,9 +6,4 @@ Dockerfile*
|
|
| 6 |
.gitignore
|
| 7 |
README.md
|
| 8 |
.env
|
| 9 |
-
.nyc_output
|
| 10 |
-
coverage
|
| 11 |
-
.nyc_output
|
| 12 |
-
.coverage
|
| 13 |
-
.coverage/
|
| 14 |
*.md
|
|
|
|
| 6 |
.gitignore
|
| 7 |
README.md
|
| 8 |
.env
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
*.md
|
Dockerfile
CHANGED
|
@@ -1,32 +1,34 @@
|
|
| 1 |
-
# Use
|
| 2 |
-
FROM
|
| 3 |
|
| 4 |
-
# Set
|
| 5 |
WORKDIR /usr/src/app
|
| 6 |
|
| 7 |
-
#
|
|
|
|
|
|
|
|
|
|
| 8 |
RUN apt-get update && apt-get install -y \
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
&& rm -rf /var/lib/apt/lists/*
|
| 12 |
|
| 13 |
-
# Copy package
|
| 14 |
COPY package*.json ./
|
| 15 |
|
| 16 |
-
# Install
|
| 17 |
-
RUN npm install
|
| 18 |
-
|
| 19 |
-
# Copy the public directory containing the UI into the container
|
| 20 |
-
COPY public ./public
|
| 21 |
-
|
| 22 |
-
# Copy the main application file
|
| 23 |
-
COPY index.js .
|
| 24 |
|
| 25 |
-
#
|
| 26 |
-
|
| 27 |
|
| 28 |
-
# Expose
|
| 29 |
EXPOSE 7860
|
| 30 |
|
| 31 |
-
#
|
| 32 |
-
CMD [
|
|
|
|
| 1 |
+
# Use official Node.js image
|
| 2 |
+
FROM node:18
|
| 3 |
|
| 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
|
| 22 |
COPY package*.json ./
|
| 23 |
|
| 24 |
+
# Install Node.js dependencies
|
| 25 |
+
RUN npm install
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
+
# Copy application code
|
| 28 |
+
COPY . .
|
| 29 |
|
| 30 |
+
# Expose port
|
| 31 |
EXPOSE 7860
|
| 32 |
|
| 33 |
+
# Start application
|
| 34 |
+
CMD ["npm", "start"]
|
Dockerfile.alternative
DELETED
|
@@ -1,54 +0,0 @@
|
|
| 1 |
-
# Alternative Dockerfile for Hugging Face Spaces
|
| 2 |
-
# Use Ubuntu 22.04 LTS with Node.js pre-installed
|
| 3 |
-
FROM ubuntu:22.04
|
| 4 |
-
|
| 5 |
-
# Set environment variables
|
| 6 |
-
ENV DEBIAN_FRONTEND=noninteractive
|
| 7 |
-
ENV NODE_VERSION=20.11.1
|
| 8 |
-
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
| 9 |
-
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable
|
| 10 |
-
|
| 11 |
-
# Set the working directory
|
| 12 |
-
WORKDIR /usr/src/app
|
| 13 |
-
|
| 14 |
-
# Install system dependencies
|
| 15 |
-
RUN apt-get update && apt-get install -y \
|
| 16 |
-
curl \
|
| 17 |
-
wget \
|
| 18 |
-
gnupg \
|
| 19 |
-
ca-certificates \
|
| 20 |
-
apt-transport-https \
|
| 21 |
-
software-properties-common \
|
| 22 |
-
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
| 23 |
-
&& apt-get install -y nodejs \
|
| 24 |
-
&& wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \
|
| 25 |
-
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
|
| 26 |
-
&& apt-get update \
|
| 27 |
-
&& apt-get install -y google-chrome-stable \
|
| 28 |
-
&& apt-get clean \
|
| 29 |
-
&& rm -rf /var/lib/apt/lists/*
|
| 30 |
-
|
| 31 |
-
# Copy package files
|
| 32 |
-
COPY package*.json ./
|
| 33 |
-
|
| 34 |
-
# Install Node.js dependencies
|
| 35 |
-
RUN npm ci --only=production && npm cache clean --force
|
| 36 |
-
|
| 37 |
-
# Copy application files
|
| 38 |
-
COPY public ./public
|
| 39 |
-
COPY index.js .
|
| 40 |
-
|
| 41 |
-
# Create user for security
|
| 42 |
-
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
|
| 43 |
-
&& mkdir -p /home/pptruser/Downloads \
|
| 44 |
-
&& chown -R pptruser:pptruser /home/pptruser \
|
| 45 |
-
&& chown -R pptruser:pptruser /usr/src/app
|
| 46 |
-
|
| 47 |
-
# Switch to non-root user
|
| 48 |
-
USER pptruser
|
| 49 |
-
|
| 50 |
-
# Expose port
|
| 51 |
-
EXPOSE 7860
|
| 52 |
-
|
| 53 |
-
# Start the application
|
| 54 |
-
CMD ["npm", "start"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
index.js
CHANGED
|
@@ -2,27 +2,22 @@ const express = require('express');
|
|
| 2 |
const http = require('http');
|
| 3 |
const path = require('path');
|
| 4 |
const WebSocket = require('ws');
|
| 5 |
-
const puppeteer = require('puppeteer');
|
| 6 |
|
| 7 |
-
// --- Setup Express App & Server ---
|
| 8 |
const app = express();
|
| 9 |
const server = http.createServer(app);
|
| 10 |
const wss = new WebSocket.Server({ server });
|
| 11 |
|
| 12 |
-
// Serve static files from the 'public' directory
|
| 13 |
app.use(express.static(path.join(__dirname, 'public')));
|
| 14 |
|
| 15 |
-
// Health check endpoint for Hugging Face Spaces
|
| 16 |
app.get('/health', (req, res) => {
|
| 17 |
res.status(200).json({ status: 'healthy', timestamp: new Date().toISOString() });
|
| 18 |
});
|
| 19 |
|
| 20 |
-
// --- Environment Variables ---
|
| 21 |
const LOGIN_EMAIL = process.env.LOGIN_EMAIL;
|
| 22 |
const LOGIN_PASSWORD = process.env.LOGIN_PASSWORD;
|
| 23 |
const LOGIN_URL = 'https://static.practicefusion.com/apps/auth/?sessionId=48a4227f-b3a3-49ed-bc72-6df4b0533d56&state=vn7gnwhM9JcNhBkBGJEffcseDaCaealLLV3pVktV0RA.iLHD0UfE0jM.Catalyst&clientId=l7xxb2e568db27ed45a5908aaf31f7ce9651';
|
| 24 |
|
| 25 |
-
// --- WebSocket Logic ---
|
| 26 |
function broadcast(event, data) {
|
| 27 |
const message = JSON.stringify({ event, data });
|
| 28 |
console.log(`Broadcasting: ${event} - ${typeof data === 'string' ? data : JSON.stringify(data)}`);
|
|
@@ -33,7 +28,6 @@ function broadcast(event, data) {
|
|
| 33 |
});
|
| 34 |
}
|
| 35 |
|
| 36 |
-
// --- Fixed Puppeteer Bookmarklet Code ---
|
| 37 |
const bookmarkletCode = `
|
| 38 |
(function(){
|
| 39 |
function wait(ms){return new Promise(r=>setTimeout(r,ms));}
|
|
@@ -387,8 +381,32 @@ async function runAndSuperviseAutomation() {
|
|
| 387 |
throw new Error("LOGIN_EMAIL or LOGIN_PASSWORD secret is not set in Hugging Face Space settings.");
|
| 388 |
}
|
| 389 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
browser = await puppeteer.launch({
|
| 391 |
headless: true,
|
|
|
|
| 392 |
args: [
|
| 393 |
'--no-sandbox',
|
| 394 |
'--disable-setuid-sandbox',
|
|
@@ -397,16 +415,18 @@ async function runAndSuperviseAutomation() {
|
|
| 397 |
'--disable-features=VizDisplayCompositor',
|
| 398 |
'--disable-background-timer-throttling',
|
| 399 |
'--disable-backgrounding-occluded-windows',
|
| 400 |
-
'--disable-renderer-backgrounding'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 401 |
]
|
| 402 |
});
|
| 403 |
|
| 404 |
const page = await browser.newPage();
|
| 405 |
|
| 406 |
-
// Set user agent to avoid detection
|
| 407 |
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');
|
| 408 |
|
| 409 |
-
// Expose logging function to the page
|
| 410 |
await page.exposeFunction('logToNode', (event, data) => {
|
| 411 |
console.log(`LOG FROM BROWSER: ${event}`, data || '');
|
| 412 |
broadcast(event, data);
|
|
@@ -416,7 +436,6 @@ async function runAndSuperviseAutomation() {
|
|
| 416 |
broadcast('STATUS', 'Navigating to login page...');
|
| 417 |
await page.goto(LOGIN_URL, { waitUntil: 'networkidle2', timeout: 30000 });
|
| 418 |
|
| 419 |
-
// Wait for login form elements
|
| 420 |
await page.waitForSelector('#inputUsername', { timeout: 10000 });
|
| 421 |
await page.waitForSelector('#inputPswd', { timeout: 10000 });
|
| 422 |
await page.waitForSelector('#loginButton', { timeout: 10000 });
|
|
@@ -424,12 +443,10 @@ async function runAndSuperviseAutomation() {
|
|
| 424 |
console.log('Entering credentials...');
|
| 425 |
broadcast('STATUS', 'Entering credentials...');
|
| 426 |
|
| 427 |
-
// Clear and type email
|
| 428 |
await page.click('#inputUsername');
|
| 429 |
await page.evaluate(() => document.querySelector('#inputUsername').value = '');
|
| 430 |
await page.type('#inputUsername', LOGIN_EMAIL, { delay: 100 });
|
| 431 |
|
| 432 |
-
// Clear and type password
|
| 433 |
await page.click('#inputPswd');
|
| 434 |
await page.evaluate(() => document.querySelector('#inputPswd').value = '');
|
| 435 |
await page.type('#inputPswd', LOGIN_PASSWORD, { delay: 100 });
|
|
@@ -437,7 +454,6 @@ async function runAndSuperviseAutomation() {
|
|
| 437 |
console.log('Clicking login button...');
|
| 438 |
broadcast('STATUS', 'Attempting to log in...');
|
| 439 |
|
| 440 |
-
// Click login and wait for navigation
|
| 441 |
await Promise.all([
|
| 442 |
page.click('#loginButton'),
|
| 443 |
page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 30000 })
|
|
@@ -446,19 +462,15 @@ async function runAndSuperviseAutomation() {
|
|
| 446 |
console.log('Login successful. Injecting automation script.');
|
| 447 |
broadcast('STATUS', 'Login successful. Starting automation script...');
|
| 448 |
|
| 449 |
-
// Inject the automation script
|
| 450 |
await page.evaluate(bookmarkletCode);
|
| 451 |
|
| 452 |
-
// Keep the browser alive and monitor
|
| 453 |
console.log('Automation script running. Monitoring...');
|
| 454 |
broadcast('STATUS', 'Automation is now running in the background');
|
| 455 |
|
| 456 |
-
// Keep the process alive by checking page status periodically
|
| 457 |
while (true) {
|
| 458 |
-
await new Promise(resolve => setTimeout(resolve, 30000));
|
| 459 |
|
| 460 |
try {
|
| 461 |
-
// Check if page is still alive
|
| 462 |
await page.evaluate(() => document.title);
|
| 463 |
} catch (error) {
|
| 464 |
console.log('Page became unresponsive, restarting...');
|
|
@@ -473,19 +485,16 @@ async function runAndSuperviseAutomation() {
|
|
| 473 |
if (browser) {
|
| 474 |
await browser.close();
|
| 475 |
}
|
| 476 |
-
// If the process ever dies, wait 30 seconds and then restart it.
|
| 477 |
console.log('Restarting automation in 30 seconds...');
|
| 478 |
setTimeout(schedule, 30 * 1000);
|
| 479 |
}
|
| 480 |
}
|
| 481 |
|
| 482 |
-
// --- Scheduler ---
|
| 483 |
function schedule() {
|
| 484 |
const now = new Date();
|
| 485 |
const timeZone = 'America/New_York';
|
| 486 |
const currentHour = parseInt(now.toLocaleString('en-US', { hour: '2-digit', hour12: false, timeZone }), 10);
|
| 487 |
|
| 488 |
-
// Only run during business hours (8 AM - 6 PM ET)
|
| 489 |
if (currentHour >= 8 && currentHour < 18) {
|
| 490 |
console.log(`Starting automation at ${now.toLocaleString('en-US', { timeZone })}`);
|
| 491 |
runAndSuperviseAutomation();
|
|
@@ -494,7 +503,6 @@ function schedule() {
|
|
| 494 |
console.log(message);
|
| 495 |
broadcast('STATUS', message);
|
| 496 |
|
| 497 |
-
// Check again in 30 minutes to see if we've entered business hours
|
| 498 |
setTimeout(schedule, 30 * 60 * 1000);
|
| 499 |
}
|
| 500 |
}
|
|
@@ -513,13 +521,11 @@ wss.on('connection', (ws) => {
|
|
| 513 |
});
|
| 514 |
});
|
| 515 |
|
| 516 |
-
// --- Start Server ---
|
| 517 |
const PORT = process.env.PORT || 7860;
|
| 518 |
server.listen(PORT, '0.0.0.0', () => {
|
| 519 |
console.log(`Server is running on port ${PORT}`);
|
| 520 |
console.log('UI is available at the root path');
|
| 521 |
console.log('Automation will start if within business hours (8 AM - 6 PM ET)');
|
| 522 |
|
| 523 |
-
// Start the first check immediately
|
| 524 |
schedule();
|
| 525 |
});
|
|
|
|
| 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);
|
| 9 |
const wss = new WebSocket.Server({ server });
|
| 10 |
|
|
|
|
| 11 |
app.use(express.static(path.join(__dirname, 'public')));
|
| 12 |
|
|
|
|
| 13 |
app.get('/health', (req, res) => {
|
| 14 |
res.status(200).json({ status: 'healthy', timestamp: new Date().toISOString() });
|
| 15 |
});
|
| 16 |
|
|
|
|
| 17 |
const LOGIN_EMAIL = process.env.LOGIN_EMAIL;
|
| 18 |
const LOGIN_PASSWORD = process.env.LOGIN_PASSWORD;
|
| 19 |
const LOGIN_URL = 'https://static.practicefusion.com/apps/auth/?sessionId=48a4227f-b3a3-49ed-bc72-6df4b0533d56&state=vn7gnwhM9JcNhBkBGJEffcseDaCaealLLV3pVktV0RA.iLHD0UfE0jM.Catalyst&clientId=l7xxb2e568db27ed45a5908aaf31f7ce9651';
|
| 20 |
|
|
|
|
| 21 |
function broadcast(event, data) {
|
| 22 |
const message = JSON.stringify({ event, data });
|
| 23 |
console.log(`Broadcasting: ${event} - ${typeof data === 'string' ? data : JSON.stringify(data)}`);
|
|
|
|
| 28 |
});
|
| 29 |
}
|
| 30 |
|
|
|
|
| 31 |
const bookmarkletCode = `
|
| 32 |
(function(){
|
| 33 |
function wait(ms){return new Promise(r=>setTimeout(r,ms));}
|
|
|
|
| 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',
|
|
|
|
| 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);
|
|
|
|
| 436 |
broadcast('STATUS', 'Navigating to login page...');
|
| 437 |
await page.goto(LOGIN_URL, { waitUntil: 'networkidle2', timeout: 30000 });
|
| 438 |
|
|
|
|
| 439 |
await page.waitForSelector('#inputUsername', { timeout: 10000 });
|
| 440 |
await page.waitForSelector('#inputPswd', { timeout: 10000 });
|
| 441 |
await page.waitForSelector('#loginButton', { timeout: 10000 });
|
|
|
|
| 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: 100 });
|
| 449 |
|
|
|
|
| 450 |
await page.click('#inputPswd');
|
| 451 |
await page.evaluate(() => document.querySelector('#inputPswd').value = '');
|
| 452 |
await page.type('#inputPswd', LOGIN_PASSWORD, { delay: 100 });
|
|
|
|
| 454 |
console.log('Clicking login button...');
|
| 455 |
broadcast('STATUS', 'Attempting to log in...');
|
| 456 |
|
|
|
|
| 457 |
await Promise.all([
|
| 458 |
page.click('#loginButton'),
|
| 459 |
page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 30000 })
|
|
|
|
| 462 |
console.log('Login successful. Injecting automation script.');
|
| 463 |
broadcast('STATUS', 'Login successful. Starting automation script...');
|
| 464 |
|
|
|
|
| 465 |
await page.evaluate(bookmarkletCode);
|
| 466 |
|
|
|
|
| 467 |
console.log('Automation script running. Monitoring...');
|
| 468 |
broadcast('STATUS', 'Automation is now running in the background');
|
| 469 |
|
|
|
|
| 470 |
while (true) {
|
| 471 |
+
await new Promise(resolve => setTimeout(resolve, 30000));
|
| 472 |
|
| 473 |
try {
|
|
|
|
| 474 |
await page.evaluate(() => document.title);
|
| 475 |
} catch (error) {
|
| 476 |
console.log('Page became unresponsive, restarting...');
|
|
|
|
| 485 |
if (browser) {
|
| 486 |
await browser.close();
|
| 487 |
}
|
|
|
|
| 488 |
console.log('Restarting automation in 30 seconds...');
|
| 489 |
setTimeout(schedule, 30 * 1000);
|
| 490 |
}
|
| 491 |
}
|
| 492 |
|
|
|
|
| 493 |
function schedule() {
|
| 494 |
const now = new Date();
|
| 495 |
const timeZone = 'America/New_York';
|
| 496 |
const currentHour = parseInt(now.toLocaleString('en-US', { hour: '2-digit', hour12: false, timeZone }), 10);
|
| 497 |
|
|
|
|
| 498 |
if (currentHour >= 8 && currentHour < 18) {
|
| 499 |
console.log(`Starting automation at ${now.toLocaleString('en-US', { timeZone })}`);
|
| 500 |
runAndSuperviseAutomation();
|
|
|
|
| 503 |
console.log(message);
|
| 504 |
broadcast('STATUS', message);
|
| 505 |
|
|
|
|
| 506 |
setTimeout(schedule, 30 * 60 * 1000);
|
| 507 |
}
|
| 508 |
}
|
|
|
|
| 521 |
});
|
| 522 |
});
|
| 523 |
|
|
|
|
| 524 |
const PORT = process.env.PORT || 7860;
|
| 525 |
server.listen(PORT, '0.0.0.0', () => {
|
| 526 |
console.log(`Server is running on port ${PORT}`);
|
| 527 |
console.log('UI is available at the root path');
|
| 528 |
console.log('Automation will start if within business hours (8 AM - 6 PM ET)');
|
| 529 |
|
|
|
|
| 530 |
schedule();
|
| 531 |
});
|
package.json
CHANGED
|
@@ -4,12 +4,11 @@
|
|
| 4 |
"description": "Automates a task on Practice Fusion with a web UI for Hugging Face Spaces.",
|
| 5 |
"main": "index.js",
|
| 6 |
"scripts": {
|
| 7 |
-
"start": "node index.js"
|
| 8 |
-
"dev": "node index.js"
|
| 9 |
},
|
| 10 |
"dependencies": {
|
| 11 |
"express": "^4.19.2",
|
| 12 |
-
"puppeteer": "^
|
| 13 |
"ws": "^8.17.0"
|
| 14 |
},
|
| 15 |
"engines": {
|
|
|
|
| 4 |
"description": "Automates a task on Practice Fusion with a web UI for Hugging Face Spaces.",
|
| 5 |
"main": "index.js",
|
| 6 |
"scripts": {
|
| 7 |
+
"start": "node index.js"
|
|
|
|
| 8 |
},
|
| 9 |
"dependencies": {
|
| 10 |
"express": "^4.19.2",
|
| 11 |
+
"puppeteer-core": "^21.0.0",
|
| 12 |
"ws": "^8.17.0"
|
| 13 |
},
|
| 14 |
"engines": {
|