Update botplugin

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-12-21 23:40:43 -03:00
parent 59fa200776
commit 17a3caebab
3 changed files with 3 additions and 132 deletions

View file

@ -1,7 +1,3 @@
// General Bots - Background Service Worker
// Handles authentication, LLM communication, and message processing
// Default configuration
const DEFAULT_CONFIG = { const DEFAULT_CONFIG = {
serverUrl: "https://api.generalbots.com", serverUrl: "https://api.generalbots.com",
gbServerUrl: "https://api.pragmatismo.com.br", gbServerUrl: "https://api.pragmatismo.com.br",
@ -14,15 +10,12 @@ const DEFAULT_CONFIG = {
instanceId: "", instanceId: "",
}; };
// Initialize extension on install
chrome.runtime.onInstalled.addListener(async (details) => { chrome.runtime.onInstalled.addListener(async (details) => {
console.log("General Bots: Extension installed/updated", details.reason); console.log("General Bots: Extension installed/updated", details.reason);
// Set default settings on installation
const existing = await chrome.storage.sync.get(DEFAULT_CONFIG); const existing = await chrome.storage.sync.get(DEFAULT_CONFIG);
await chrome.storage.sync.set({ ...DEFAULT_CONFIG, ...existing }); await chrome.storage.sync.set({ ...DEFAULT_CONFIG, ...existing });
// Create context menu items
chrome.contextMenus?.create({ chrome.contextMenus?.create({
id: "gb-correct-grammar", id: "gb-correct-grammar",
title: "Correct Grammar with AI", title: "Correct Grammar with AI",
@ -36,7 +29,6 @@ chrome.runtime.onInstalled.addListener(async (details) => {
}); });
}); });
// Listen for tab updates
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if ( if (
changeInfo.status === "complete" && changeInfo.status === "complete" &&
@ -44,17 +36,12 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
) { ) {
console.log("General Bots: WhatsApp Web detected, initializing..."); console.log("General Bots: WhatsApp Web detected, initializing...");
// Notify content script that tab is ready chrome.tabs.sendMessage(tabId, { action: "tabReady" }).catch(() => {});
chrome.tabs.sendMessage(tabId, { action: "tabReady" }).catch(() => {
// Content script may not be loaded yet, that's okay
});
// Check for auto-authentication
checkAutoAuth(tabId); checkAutoAuth(tabId);
} }
}); });
// Handle messages from content script and popup
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log("General Bots: Received message", message.action); console.log("General Bots: Received message", message.action);
@ -63,7 +50,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
handleProcessText(message.text, message.options) handleProcessText(message.text, message.options)
.then(sendResponse) .then(sendResponse)
.catch((err) => sendResponse({ error: err.message })); .catch((err) => sendResponse({ error: err.message }));
return true; // Will respond asynchronously return true;
case "correctGrammar": case "correctGrammar":
handleGrammarCorrection(message.text) handleGrammarCorrection(message.text)
@ -109,7 +96,6 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
return false; return false;
}); });
// Context menu click handler
chrome.contextMenus?.onClicked.addListener(async (info, tab) => { chrome.contextMenus?.onClicked.addListener(async (info, tab) => {
if (!info.selectionText) return; if (!info.selectionText) return;
@ -125,12 +111,10 @@ chrome.contextMenus?.onClicked.addListener(async (info, tab) => {
break; break;
case "gb-translate": case "gb-translate":
// Could implement translation here
break; break;
} }
}); });
// Process text through LLM
async function handleProcessText(text, options = {}) { async function handleProcessText(text, options = {}) {
const settings = await chrome.storage.sync.get(DEFAULT_CONFIG); const settings = await chrome.storage.sync.get(DEFAULT_CONFIG);
@ -167,12 +151,10 @@ async function handleProcessText(text, options = {}) {
}; };
} catch (error) { } catch (error) {
console.error("General Bots: Process text error", error); console.error("General Bots: Process text error", error);
// Fallback - return original text
return { processedText: text, changed: false, error: error.message }; return { processedText: text, changed: false, error: error.message };
} }
} }
// Grammar correction specifically
async function handleGrammarCorrection(text) { async function handleGrammarCorrection(text) {
const settings = await chrome.storage.sync.get(DEFAULT_CONFIG); const settings = await chrome.storage.sync.get(DEFAULT_CONFIG);
@ -207,7 +189,6 @@ async function handleGrammarCorrection(text) {
} }
} }
// Auto-reply generation
async function handleAutoReply(context, lastMessages = []) { async function handleAutoReply(context, lastMessages = []) {
const settings = await chrome.storage.sync.get(DEFAULT_CONFIG); const settings = await chrome.storage.sync.get(DEFAULT_CONFIG);
@ -249,12 +230,10 @@ async function handleAutoReply(context, lastMessages = []) {
} }
} }
// Authentication with General Bots via WhatsApp
async function handleAuthentication(whatsappNumber) { async function handleAuthentication(whatsappNumber) {
const settings = await chrome.storage.sync.get(DEFAULT_CONFIG); const settings = await chrome.storage.sync.get(DEFAULT_CONFIG);
try { try {
// Request authentication via General Bots WhatsApp bot
const response = await fetch( const response = await fetch(
`${settings.gbServerUrl}/api/v1/auth/whatsapp/request`, `${settings.gbServerUrl}/api/v1/auth/whatsapp/request`,
{ {
@ -276,21 +255,18 @@ async function handleAuthentication(whatsappNumber) {
const data = await response.json(); const data = await response.json();
// Save pending auth state
await chrome.storage.sync.set({ await chrome.storage.sync.set({
whatsappNumber, whatsappNumber,
authPending: true, authPending: true,
authRequestId: data.requestId, authRequestId: data.requestId,
}); });
// Show notification to user
showNotification( showNotification(
"Authentication Requested", "Authentication Requested",
"Check your WhatsApp for a message from General Bots to complete authentication.", "Check your WhatsApp for a message from General Bots to complete authentication.",
"info", "info",
); );
// Start polling for auth completion
pollAuthCompletion(data.requestId); pollAuthCompletion(data.requestId);
return { success: true, requestId: data.requestId }; return { success: true, requestId: data.requestId };
@ -300,10 +276,8 @@ async function handleAuthentication(whatsappNumber) {
} }
} }
// Poll for authentication completion
async function pollAuthCompletion(requestId, attempts = 0) { async function pollAuthCompletion(requestId, attempts = 0) {
if (attempts > 60) { if (attempts > 60) {
// 5 minutes max
await chrome.storage.sync.set({ authPending: false }); await chrome.storage.sync.set({ authPending: false });
showNotification("Authentication Timeout", "Please try again.", "error"); showNotification("Authentication Timeout", "Please try again.", "error");
return; return;
@ -333,7 +307,6 @@ async function pollAuthCompletion(requestId, attempts = 0) {
"success", "success",
); );
// Broadcast to all tabs
broadcastSettingsUpdate({ authenticated: true }); broadcastSettingsUpdate({ authenticated: true });
return; return;
} else if (data.status === "failed") { } else if (data.status === "failed") {
@ -350,11 +323,9 @@ async function pollAuthCompletion(requestId, attempts = 0) {
console.error("General Bots: Poll auth error", error); console.error("General Bots: Poll auth error", error);
} }
// Continue polling
setTimeout(() => pollAuthCompletion(requestId, attempts + 1), 5000); setTimeout(() => pollAuthCompletion(requestId, attempts + 1), 5000);
} }
// Check auth status
async function getAuthStatus() { async function getAuthStatus() {
const settings = await chrome.storage.sync.get([ const settings = await chrome.storage.sync.get([
"authToken", "authToken",
@ -367,7 +338,6 @@ async function getAuthStatus() {
return { authenticated: false }; return { authenticated: false };
} }
// Verify token is still valid
try { try {
const response = await fetch( const response = await fetch(
`${DEFAULT_CONFIG.gbServerUrl}/api/v1/auth/verify`, `${DEFAULT_CONFIG.gbServerUrl}/api/v1/auth/verify`,
@ -389,7 +359,6 @@ async function getAuthStatus() {
console.error("General Bots: Verify auth error", error); console.error("General Bots: Verify auth error", error);
} }
// Token invalid, clear auth
await chrome.storage.sync.set({ await chrome.storage.sync.set({
authToken: "", authToken: "",
authenticated: false, authenticated: false,
@ -398,7 +367,6 @@ async function getAuthStatus() {
return { authenticated: false }; return { authenticated: false };
} }
// Check for auto-authentication when WhatsApp loads
async function checkAutoAuth(tabId) { async function checkAutoAuth(tabId) {
const settings = await chrome.storage.sync.get([ const settings = await chrome.storage.sync.get([
"authenticated", "authenticated",
@ -407,7 +375,6 @@ async function checkAutoAuth(tabId) {
]); ]);
if (settings.authenticated && settings.autoMode) { if (settings.authenticated && settings.autoMode) {
// Notify content script that auto mode is active
setTimeout(() => { setTimeout(() => {
chrome.tabs chrome.tabs
.sendMessage(tabId, { .sendMessage(tabId, {
@ -419,7 +386,6 @@ async function checkAutoAuth(tabId) {
} }
} }
// Broadcast settings update to all WhatsApp tabs
async function broadcastSettingsUpdate(settings) { async function broadcastSettingsUpdate(settings) {
const tabs = await chrome.tabs.query({ url: "https://web.whatsapp.com/*" }); const tabs = await chrome.tabs.query({ url: "https://web.whatsapp.com/*" });
@ -433,7 +399,6 @@ async function broadcastSettingsUpdate(settings) {
} }
} }
// Show browser notification
function showNotification(title, message, type = "info") { function showNotification(title, message, type = "info") {
const iconPath = type === "error" ? "icons/icon48.png" : "icons/icon48.png"; const iconPath = type === "error" ? "icons/icon48.png" : "icons/icon48.png";
@ -446,7 +411,6 @@ function showNotification(title, message, type = "info") {
}); });
} }
// Alarm for periodic tasks
chrome.alarms?.create("checkAuth", { periodInMinutes: 30 }); chrome.alarms?.create("checkAuth", { periodInMinutes: 30 });
chrome.alarms?.onAlarm.addListener(async (alarm) => { chrome.alarms?.onAlarm.addListener(async (alarm) => {

View file

@ -1,10 +1,6 @@
// General Bots - Content Script for WhatsApp Web
// Provides grammar correction, auto-mode, contact hiding, and LLM integration
(function () { (function () {
"use strict"; "use strict";
// Global settings
let settings = { let settings = {
serverUrl: "https://api.generalbots.com", serverUrl: "https://api.generalbots.com",
enableProcessing: true, enableProcessing: true,
@ -15,7 +11,6 @@
authenticated: false, authenticated: false,
}; };
// State management
const state = { const state = {
initialized: false, initialized: false,
currentContact: null, currentContact: null,
@ -25,7 +20,6 @@
isProcessing: false, isProcessing: false,
}; };
// Selectors for WhatsApp Web elements
const SELECTORS = { const SELECTORS = {
contactList: "#pane-side", contactList: "#pane-side",
chatContainer: ".copyable-area", chatContainer: ".copyable-area",
@ -40,31 +34,22 @@
searchBox: 'div[data-tab="3"]', searchBox: 'div[data-tab="3"]',
}; };
// Initialize the extension
async function init() { async function init() {
if (state.initialized) return; if (state.initialized) return;
console.log("General Bots: Initializing content script..."); console.log("General Bots: Initializing content script...");
// Load settings from storage
await loadSettings(); await loadSettings();
// Apply initial UI modifications
applyUIModifications(); applyUIModifications();
// Setup observers and listeners
setupInputListener(); setupInputListener();
setupMessageObserver(); setupMessageObserver();
setupContactObserver(); setupContactObserver();
// Inject custom UI elements
injectControlPanel(); injectControlPanel();
state.initialized = true; state.initialized = true;
console.log("General Bots: Content script initialized"); console.log("General Bots: Content script initialized");
} }
// Load settings from chrome storage
async function loadSettings() { async function loadSettings() {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.storage.sync.get(settings, (items) => { chrome.storage.sync.get(settings, (items) => {
@ -75,13 +60,11 @@
}); });
} }
// Apply UI modifications based on settings
function applyUIModifications() { function applyUIModifications() {
applyContactVisibility(); applyContactVisibility();
applyAutoModeIndicator(); applyAutoModeIndicator();
} }
// Hide/show contact list
function applyContactVisibility() { function applyContactVisibility() {
const contactList = document.querySelector(SELECTORS.contactList); const contactList = document.querySelector(SELECTORS.contactList);
if (contactList) { if (contactList) {
@ -97,7 +80,6 @@
} }
} }
// Show auto-mode indicator
function applyAutoModeIndicator() { function applyAutoModeIndicator() {
let indicator = document.getElementById("gb-auto-mode-indicator"); let indicator = document.getElementById("gb-auto-mode-indicator");
@ -118,7 +100,6 @@
} }
} }
// Setup input field listener for message processing
function setupInputListener() { function setupInputListener() {
const observer = new MutationObserver(() => { const observer = new MutationObserver(() => {
const inputField = document.querySelector(SELECTORS.messageInput); const inputField = document.querySelector(SELECTORS.messageInput);
@ -133,7 +114,6 @@
subtree: true, subtree: true,
}); });
// Check immediately
const inputField = document.querySelector(SELECTORS.messageInput); const inputField = document.querySelector(SELECTORS.messageInput);
if (inputField && !inputField.getAttribute("gb-monitored")) { if (inputField && !inputField.getAttribute("gb-monitored")) {
setupFieldMonitoring(inputField); setupFieldMonitoring(inputField);
@ -141,11 +121,9 @@
} }
} }
// Monitor input field for messages
function setupFieldMonitoring(inputField) { function setupFieldMonitoring(inputField) {
console.log("General Bots: Setting up input field monitoring"); console.log("General Bots: Setting up input field monitoring");
// Listen for keydown events
inputField.addEventListener("keydown", async (event) => { inputField.addEventListener("keydown", async (event) => {
if (event.key === "Enter" && !event.shiftKey) { if (event.key === "Enter" && !event.shiftKey) {
const originalText = inputField.textContent.trim(); const originalText = inputField.textContent.trim();
@ -163,7 +141,6 @@
result.processedText && result.processedText &&
result.processedText !== originalText result.processedText !== originalText
) { ) {
// Show correction preview
const shouldSend = await showCorrectionPreview( const shouldSend = await showCorrectionPreview(
originalText, originalText,
result.processedText, result.processedText,
@ -172,7 +149,6 @@
if (shouldSend) { if (shouldSend) {
setInputText(inputField, result.processedText); setInputText(inputField, result.processedText);
// Store original for reference
state.originalMessages.set(Date.now(), { state.originalMessages.set(Date.now(), {
original: originalText, original: originalText,
corrected: result.processedText, corrected: result.processedText,
@ -181,7 +157,6 @@
} }
hideProcessingIndicator(); hideProcessingIndicator();
// Send the message
simulateEnterPress(inputField); simulateEnterPress(inputField);
} catch (error) { } catch (error) {
console.error("General Bots: Error processing message", error); console.error("General Bots: Error processing message", error);
@ -193,11 +168,9 @@
} }
}); });
// Add visual indicator that field is being monitored
inputField.classList.add("gb-monitored-input"); inputField.classList.add("gb-monitored-input");
} }
// Process message through LLM for grammar correction
async function processMessageWithLLM(text) { async function processMessageWithLLM(text) {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.runtime.sendMessage( chrome.runtime.sendMessage(
@ -220,10 +193,8 @@
}); });
} }
// Show correction preview modal
async function showCorrectionPreview(original, corrected, inputField) { async function showCorrectionPreview(original, corrected, inputField) {
return new Promise((resolve) => { return new Promise((resolve) => {
// If texts are very similar, auto-accept
if (levenshteinDistance(original, corrected) < 3) { if (levenshteinDistance(original, corrected) < 3) {
resolve(true); resolve(true);
return; return;
@ -258,7 +229,6 @@
document.body.appendChild(modal); document.body.appendChild(modal);
// Auto-close after 5 seconds with corrected text
const autoClose = setTimeout(() => { const autoClose = setTimeout(() => {
modal.remove(); modal.remove();
resolve(true); resolve(true);
@ -278,7 +248,6 @@
}); });
} }
// Setup observer for incoming messages (for auto-reply)
function setupMessageObserver() { function setupMessageObserver() {
const observer = new MutationObserver((mutations) => { const observer = new MutationObserver((mutations) => {
if (!settings.autoMode) return; if (!settings.autoMode) return;
@ -300,7 +269,6 @@
} }
}); });
// Start observing when chat container is available
const waitForChat = setInterval(() => { const waitForChat = setInterval(() => {
const chatContainer = document.querySelector(SELECTORS.chatContainer); const chatContainer = document.querySelector(SELECTORS.chatContainer);
if (chatContainer) { if (chatContainer) {
@ -314,14 +282,12 @@
}, 1000); }, 1000);
} }
// Handle incoming message for auto-reply
async function handleIncomingMessage(messageElement) { async function handleIncomingMessage(messageElement) {
if (!settings.autoMode || !settings.authenticated) return; if (!settings.autoMode || !settings.authenticated) return;
const currentContact = getCurrentContactName(); const currentContact = getCurrentContactName();
if (!currentContact) return; if (!currentContact) return;
// Check if auto-mode is enabled for this contact
if (!state.autoModeContacts.has(currentContact)) return; if (!state.autoModeContacts.has(currentContact)) return;
const messageText = messageElement.querySelector(SELECTORS.messageText); const messageText = messageElement.querySelector(SELECTORS.messageText);
@ -335,10 +301,8 @@
text, text,
); );
// Get conversation context
const context = getConversationContext(); const context = getConversationContext();
// Request auto-reply from LLM
chrome.runtime.sendMessage( chrome.runtime.sendMessage(
{ {
action: "generateAutoReply", action: "generateAutoReply",
@ -356,7 +320,6 @@
); );
} }
// Get conversation context (last few messages)
function getConversationContext() { function getConversationContext() {
const messages = []; const messages = [];
const messageElements = document.querySelectorAll( const messageElements = document.querySelectorAll(
@ -378,20 +341,17 @@
return messages; return messages;
} }
// Send auto-reply
async function sendAutoReply(text) { async function sendAutoReply(text) {
const inputField = document.querySelector(SELECTORS.messageInput); const inputField = document.querySelector(SELECTORS.messageInput);
if (!inputField) return; if (!inputField) return;
setInputText(inputField, text); setInputText(inputField, text);
// Small delay before sending
await new Promise((r) => setTimeout(r, 500)); await new Promise((r) => setTimeout(r, 500));
simulateEnterPress(inputField); simulateEnterPress(inputField);
} }
// Setup contact observer for auto-mode toggle per contact
function setupContactObserver() { function setupContactObserver() {
const observer = new MutationObserver(() => { const observer = new MutationObserver(() => {
const header = document.querySelector(SELECTORS.chatHeader); const header = document.querySelector(SELECTORS.chatHeader);
@ -406,7 +366,6 @@
}); });
} }
// Inject control buttons for current contact
function injectContactControls(header) { function injectContactControls(header) {
const contactName = getCurrentContactName(); const contactName = getCurrentContactName();
if (!contactName) return; if (!contactName) return;
@ -442,7 +401,6 @@
}); });
} }
// Inject main control panel
function injectControlPanel() { function injectControlPanel() {
const panel = document.createElement("div"); const panel = document.createElement("div");
panel.id = "gb-control-panel"; panel.id = "gb-control-panel";
@ -494,14 +452,10 @@
`; `;
document.body.appendChild(panel); document.body.appendChild(panel);
// Setup panel event listeners
setupPanelListeners(); setupPanelListeners();
} }
// Setup control panel event listeners
function setupPanelListeners() { function setupPanelListeners() {
// Panel toggle
document document
.getElementById("gb-panel-toggle") .getElementById("gb-panel-toggle")
?.addEventListener("click", function () { ?.addEventListener("click", function () {
@ -515,7 +469,6 @@
} }
}); });
// Grammar toggle
document document
.getElementById("gb-grammar-toggle") .getElementById("gb-grammar-toggle")
?.addEventListener("change", function () { ?.addEventListener("change", function () {
@ -523,7 +476,6 @@
saveSettings(); saveSettings();
}); });
// Contacts toggle
document document
.getElementById("gb-contacts-toggle") .getElementById("gb-contacts-toggle")
?.addEventListener("change", function () { ?.addEventListener("change", function () {
@ -532,7 +484,6 @@
saveSettings(); saveSettings();
}); });
// Auto mode toggle
document document
.getElementById("gb-auto-toggle") .getElementById("gb-auto-toggle")
?.addEventListener("change", function () { ?.addEventListener("change", function () {
@ -541,7 +492,6 @@
saveSettings(); saveSettings();
}); });
// Auth button
document document
.getElementById("gb-auth-btn") .getElementById("gb-auth-btn")
?.addEventListener("click", async function () { ?.addEventListener("click", async function () {
@ -576,7 +526,6 @@
}); });
} }
// Save settings to storage
function saveSettings() { function saveSettings() {
chrome.storage.sync.set(settings); chrome.storage.sync.set(settings);
chrome.runtime.sendMessage({ chrome.runtime.sendMessage({
@ -585,19 +534,16 @@
}); });
} }
// Get current contact name
function getCurrentContactName() { function getCurrentContactName() {
const nameEl = document.querySelector(SELECTORS.contactName); const nameEl = document.querySelector(SELECTORS.contactName);
return nameEl ? nameEl.textContent.trim() : null; return nameEl ? nameEl.textContent.trim() : null;
} }
// Set text in input field
function setInputText(inputField, text) { function setInputText(inputField, text) {
inputField.textContent = text; inputField.textContent = text;
inputField.dispatchEvent(new InputEvent("input", { bubbles: true })); inputField.dispatchEvent(new InputEvent("input", { bubbles: true }));
} }
// Simulate Enter key press
function simulateEnterPress(element) { function simulateEnterPress(element) {
const enterEvent = new KeyboardEvent("keydown", { const enterEvent = new KeyboardEvent("keydown", {
key: "Enter", key: "Enter",
@ -610,7 +556,6 @@
element.dispatchEvent(enterEvent); element.dispatchEvent(enterEvent);
} }
// Show processing indicator
function showProcessingIndicator(inputField) { function showProcessingIndicator(inputField) {
let indicator = document.getElementById("gb-processing"); let indicator = document.getElementById("gb-processing");
if (!indicator) { if (!indicator) {
@ -626,7 +571,6 @@
indicator.style.display = "flex"; indicator.style.display = "flex";
} }
// Hide processing indicator
function hideProcessingIndicator() { function hideProcessingIndicator() {
const indicator = document.getElementById("gb-processing"); const indicator = document.getElementById("gb-processing");
if (indicator) { if (indicator) {
@ -634,14 +578,12 @@
} }
} }
// Utility: Escape HTML
function escapeHtml(text) { function escapeHtml(text) {
const div = document.createElement("div"); const div = document.createElement("div");
div.textContent = text; div.textContent = text;
return div.innerHTML; return div.innerHTML;
} }
// Utility: Levenshtein distance for text comparison
function levenshteinDistance(str1, str2) { function levenshteinDistance(str1, str2) {
const m = str1.length; const m = str1.length;
const n = str2.length; const n = str2.length;
@ -665,7 +607,6 @@
return dp[m][n]; return dp[m][n];
} }
// Listen for messages from background script
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
switch (message.action) { switch (message.action) {
case "tabReady": case "tabReady":
@ -694,7 +635,6 @@
case "authCompleted": case "authCompleted":
settings.authenticated = true; settings.authenticated = true;
// Refresh control panel
const panel = document.getElementById("gb-control-panel"); const panel = document.getElementById("gb-control-panel");
if (panel) { if (panel) {
panel.remove(); panel.remove();
@ -707,13 +647,11 @@
return true; return true;
}); });
// Initialize on DOM ready
if (document.readyState === "loading") { if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init); document.addEventListener("DOMContentLoaded", init);
} else { } else {
init(); init();
} }
// Also try to initialize after a delay (WhatsApp Web loads dynamically)
setTimeout(init, 2000); setTimeout(init, 2000);
})(); })();

View file

@ -1,8 +1,4 @@
// General Bots - Popup Script
// Handles settings management, authentication, and UI updates
document.addEventListener("DOMContentLoaded", async function () { document.addEventListener("DOMContentLoaded", async function () {
// Default settings
const DEFAULT_SETTINGS = { const DEFAULT_SETTINGS = {
serverUrl: "https://api.generalbots.com", serverUrl: "https://api.generalbots.com",
gbServerUrl: "https://api.pragmatismo.com.br", gbServerUrl: "https://api.pragmatismo.com.br",
@ -21,19 +17,15 @@ document.addEventListener("DOMContentLoaded", async function () {
}, },
}; };
// Load settings and update UI
await loadSettings(); await loadSettings();
await checkAuthStatus(); await checkAuthStatus();
loadStats(); loadStats();
// Event listeners
setupEventListeners(); setupEventListeners();
// Load saved settings
async function loadSettings() { async function loadSettings() {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.storage.sync.get(DEFAULT_SETTINGS, function (items) { chrome.storage.sync.get(DEFAULT_SETTINGS, function (items) {
// Update form fields
document.getElementById("server-url").value = document.getElementById("server-url").value =
items.serverUrl || DEFAULT_SETTINGS.serverUrl; items.serverUrl || DEFAULT_SETTINGS.serverUrl;
document.getElementById("whatsapp-number").value = document.getElementById("whatsapp-number").value =
@ -50,7 +42,6 @@ document.addEventListener("DOMContentLoaded", async function () {
}); });
} }
// Check authentication status
async function checkAuthStatus() { async function checkAuthStatus() {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.runtime.sendMessage({ action: "getAuthStatus" }, (response) => { chrome.runtime.sendMessage({ action: "getAuthStatus" }, (response) => {
@ -78,7 +69,6 @@ document.addEventListener("DOMContentLoaded", async function () {
}); });
} }
// Load statistics
function loadStats() { function loadStats() {
chrome.storage.local.get(["stats"], function (result) { chrome.storage.local.get(["stats"], function (result) {
const stats = result.stats || DEFAULT_SETTINGS.stats; const stats = result.stats || DEFAULT_SETTINGS.stats;
@ -91,24 +81,19 @@ document.addEventListener("DOMContentLoaded", async function () {
}); });
} }
// Setup event listeners
function setupEventListeners() { function setupEventListeners() {
// Save settings button
document document
.getElementById("save-settings") .getElementById("save-settings")
.addEventListener("click", saveSettings); .addEventListener("click", saveSettings);
// Auth button
document document
.getElementById("auth-btn") .getElementById("auth-btn")
.addEventListener("click", handleAuthentication); .addEventListener("click", handleAuthentication);
// Open options page
document.getElementById("open-options").addEventListener("click", () => { document.getElementById("open-options").addEventListener("click", () => {
chrome.runtime.openOptionsPage(); chrome.runtime.openOptionsPage();
}); });
// Toggle switches - save immediately on change
const toggles = [ const toggles = [
"grammar-correction", "grammar-correction",
"enable-processing", "enable-processing",
@ -117,12 +102,11 @@ document.addEventListener("DOMContentLoaded", async function () {
]; ];
toggles.forEach((id) => { toggles.forEach((id) => {
document.getElementById(id).addEventListener("change", function () { document.getElementById(id).addEventListener("change", function () {
saveSettings(true); // silent save saveSettings(true);
}); });
}); });
} }
// Save settings
async function saveSettings(silent = false) { async function saveSettings(silent = false) {
const settings = { const settings = {
serverUrl: document.getElementById("server-url").value.trim(), serverUrl: document.getElementById("server-url").value.trim(),
@ -135,7 +119,6 @@ document.addEventListener("DOMContentLoaded", async function () {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.storage.sync.set(settings, function () { chrome.storage.sync.set(settings, function () {
// Notify content script about settings change
chrome.tabs.query( chrome.tabs.query(
{ url: "https://web.whatsapp.com/*" }, { url: "https://web.whatsapp.com/*" },
function (tabs) { function (tabs) {
@ -157,32 +140,26 @@ document.addEventListener("DOMContentLoaded", async function () {
}); });
} }
// Handle authentication
async function handleAuthentication() { async function handleAuthentication() {
const numberInput = document.getElementById("whatsapp-number"); const numberInput = document.getElementById("whatsapp-number");
const authBtn = document.getElementById("auth-btn"); const authBtn = document.getElementById("auth-btn");
const number = numberInput.value.trim(); const number = numberInput.value.trim();
// Validate number
if (!number) { if (!number) {
showError(numberInput, "Please enter your WhatsApp number"); showError(numberInput, "Please enter your WhatsApp number");
return; return;
} }
// Clean number (remove spaces, dashes)
const cleanNumber = number.replace(/[\s\-\(\)]/g, ""); const cleanNumber = number.replace(/[\s\-\(\)]/g, "");
// Basic validation
if (!/^\+?[0-9]{10,15}$/.test(cleanNumber)) { if (!/^\+?[0-9]{10,15}$/.test(cleanNumber)) {
showError(numberInput, "Invalid phone number format"); showError(numberInput, "Invalid phone number format");
return; return;
} }
// Update button state
authBtn.disabled = true; authBtn.disabled = true;
authBtn.innerHTML = '<span class="btn-icon">⏳</span> Sending request...'; authBtn.innerHTML = '<span class="btn-icon">⏳</span> Sending request...';
// Send auth request
chrome.runtime.sendMessage( chrome.runtime.sendMessage(
{ {
action: "authenticate", action: "authenticate",
@ -194,7 +171,6 @@ document.addEventListener("DOMContentLoaded", async function () {
'<span class="btn-icon">📱</span> Check your WhatsApp'; '<span class="btn-icon">📱</span> Check your WhatsApp';
authBtn.classList.add("btn-success"); authBtn.classList.add("btn-success");
// Start polling for auth completion
pollAuthStatus(); pollAuthStatus();
} else { } else {
authBtn.disabled = false; authBtn.disabled = false;
@ -208,10 +184,8 @@ document.addEventListener("DOMContentLoaded", async function () {
); );
} }
// Poll for authentication status
function pollAuthStatus(attempts = 0) { function pollAuthStatus(attempts = 0) {
if (attempts > 60) { if (attempts > 60) {
// 5 minutes max
showNotification("Authentication timed out. Please try again.", "error"); showNotification("Authentication timed out. Please try again.", "error");
resetAuthButton(); resetAuthButton();
return; return;
@ -229,7 +203,6 @@ document.addEventListener("DOMContentLoaded", async function () {
}, 5000); }, 5000);
} }
// Reset auth button
function resetAuthButton() { function resetAuthButton() {
const authBtn = document.getElementById("auth-btn"); const authBtn = document.getElementById("auth-btn");
authBtn.disabled = false; authBtn.disabled = false;
@ -238,7 +211,6 @@ document.addEventListener("DOMContentLoaded", async function () {
'<span class="btn-icon">🤖</span> Authenticate via WhatsApp'; '<span class="btn-icon">🤖</span> Authenticate via WhatsApp';
} }
// Show error on input
function showError(input, message) { function showError(input, message) {
input.classList.add("error"); input.classList.add("error");
const small = input.parentElement.querySelector("small"); const small = input.parentElement.querySelector("small");
@ -256,7 +228,6 @@ document.addEventListener("DOMContentLoaded", async function () {
}, 3000); }, 3000);
} }
// Show feedback on button
function showFeedback(buttonId, message, type = "success") { function showFeedback(buttonId, message, type = "success") {
const button = document.getElementById(buttonId); const button = document.getElementById(buttonId);
const originalHTML = button.innerHTML; const originalHTML = button.innerHTML;
@ -273,9 +244,7 @@ document.addEventListener("DOMContentLoaded", async function () {
}, 1500); }, 1500);
} }
// Show notification
function showNotification(message, type = "info") { function showNotification(message, type = "info") {
// Remove existing notification
const existing = document.querySelector(".popup-notification"); const existing = document.querySelector(".popup-notification");
if (existing) existing.remove(); if (existing) existing.remove();