diff --git a/background.js b/background.js
index 9c53644..ea1be09 100644
--- a/background.js
+++ b/background.js
@@ -1,7 +1,3 @@
-// General Bots - Background Service Worker
-// Handles authentication, LLM communication, and message processing
-
-// Default configuration
const DEFAULT_CONFIG = {
serverUrl: "https://api.generalbots.com",
gbServerUrl: "https://api.pragmatismo.com.br",
@@ -14,15 +10,12 @@ const DEFAULT_CONFIG = {
instanceId: "",
};
-// Initialize extension on install
chrome.runtime.onInstalled.addListener(async (details) => {
console.log("General Bots: Extension installed/updated", details.reason);
- // Set default settings on installation
const existing = await chrome.storage.sync.get(DEFAULT_CONFIG);
await chrome.storage.sync.set({ ...DEFAULT_CONFIG, ...existing });
- // Create context menu items
chrome.contextMenus?.create({
id: "gb-correct-grammar",
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) => {
if (
changeInfo.status === "complete" &&
@@ -44,17 +36,12 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
) {
console.log("General Bots: WhatsApp Web detected, initializing...");
- // Notify content script that tab is ready
- chrome.tabs.sendMessage(tabId, { action: "tabReady" }).catch(() => {
- // Content script may not be loaded yet, that's okay
- });
+ chrome.tabs.sendMessage(tabId, { action: "tabReady" }).catch(() => {});
- // Check for auto-authentication
checkAutoAuth(tabId);
}
});
-// Handle messages from content script and popup
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log("General Bots: Received message", message.action);
@@ -63,7 +50,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
handleProcessText(message.text, message.options)
.then(sendResponse)
.catch((err) => sendResponse({ error: err.message }));
- return true; // Will respond asynchronously
+ return true;
case "correctGrammar":
handleGrammarCorrection(message.text)
@@ -109,7 +96,6 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
return false;
});
-// Context menu click handler
chrome.contextMenus?.onClicked.addListener(async (info, tab) => {
if (!info.selectionText) return;
@@ -125,12 +111,10 @@ chrome.contextMenus?.onClicked.addListener(async (info, tab) => {
break;
case "gb-translate":
- // Could implement translation here
break;
}
});
-// Process text through LLM
async function handleProcessText(text, options = {}) {
const settings = await chrome.storage.sync.get(DEFAULT_CONFIG);
@@ -167,12 +151,10 @@ async function handleProcessText(text, options = {}) {
};
} catch (error) {
console.error("General Bots: Process text error", error);
- // Fallback - return original text
return { processedText: text, changed: false, error: error.message };
}
}
-// Grammar correction specifically
async function handleGrammarCorrection(text) {
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 = []) {
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) {
const settings = await chrome.storage.sync.get(DEFAULT_CONFIG);
try {
- // Request authentication via General Bots WhatsApp bot
const response = await fetch(
`${settings.gbServerUrl}/api/v1/auth/whatsapp/request`,
{
@@ -276,21 +255,18 @@ async function handleAuthentication(whatsappNumber) {
const data = await response.json();
- // Save pending auth state
await chrome.storage.sync.set({
whatsappNumber,
authPending: true,
authRequestId: data.requestId,
});
- // Show notification to user
showNotification(
"Authentication Requested",
"Check your WhatsApp for a message from General Bots to complete authentication.",
"info",
);
- // Start polling for auth completion
pollAuthCompletion(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) {
if (attempts > 60) {
- // 5 minutes max
await chrome.storage.sync.set({ authPending: false });
showNotification("Authentication Timeout", "Please try again.", "error");
return;
@@ -333,7 +307,6 @@ async function pollAuthCompletion(requestId, attempts = 0) {
"success",
);
- // Broadcast to all tabs
broadcastSettingsUpdate({ authenticated: true });
return;
} else if (data.status === "failed") {
@@ -350,11 +323,9 @@ async function pollAuthCompletion(requestId, attempts = 0) {
console.error("General Bots: Poll auth error", error);
}
- // Continue polling
setTimeout(() => pollAuthCompletion(requestId, attempts + 1), 5000);
}
-// Check auth status
async function getAuthStatus() {
const settings = await chrome.storage.sync.get([
"authToken",
@@ -367,7 +338,6 @@ async function getAuthStatus() {
return { authenticated: false };
}
- // Verify token is still valid
try {
const response = await fetch(
`${DEFAULT_CONFIG.gbServerUrl}/api/v1/auth/verify`,
@@ -389,7 +359,6 @@ async function getAuthStatus() {
console.error("General Bots: Verify auth error", error);
}
- // Token invalid, clear auth
await chrome.storage.sync.set({
authToken: "",
authenticated: false,
@@ -398,7 +367,6 @@ async function getAuthStatus() {
return { authenticated: false };
}
-// Check for auto-authentication when WhatsApp loads
async function checkAutoAuth(tabId) {
const settings = await chrome.storage.sync.get([
"authenticated",
@@ -407,7 +375,6 @@ async function checkAutoAuth(tabId) {
]);
if (settings.authenticated && settings.autoMode) {
- // Notify content script that auto mode is active
setTimeout(() => {
chrome.tabs
.sendMessage(tabId, {
@@ -419,7 +386,6 @@ async function checkAutoAuth(tabId) {
}
}
-// Broadcast settings update to all WhatsApp tabs
async function broadcastSettingsUpdate(settings) {
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") {
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?.onAlarm.addListener(async (alarm) => {
diff --git a/content.js b/content.js
index dfd83e3..dc6e307 100644
--- a/content.js
+++ b/content.js
@@ -1,10 +1,6 @@
-// General Bots - Content Script for WhatsApp Web
-// Provides grammar correction, auto-mode, contact hiding, and LLM integration
-
(function () {
"use strict";
- // Global settings
let settings = {
serverUrl: "https://api.generalbots.com",
enableProcessing: true,
@@ -15,7 +11,6 @@
authenticated: false,
};
- // State management
const state = {
initialized: false,
currentContact: null,
@@ -25,7 +20,6 @@
isProcessing: false,
};
- // Selectors for WhatsApp Web elements
const SELECTORS = {
contactList: "#pane-side",
chatContainer: ".copyable-area",
@@ -40,31 +34,22 @@
searchBox: 'div[data-tab="3"]',
};
- // Initialize the extension
async function init() {
if (state.initialized) return;
console.log("General Bots: Initializing content script...");
- // Load settings from storage
await loadSettings();
-
- // Apply initial UI modifications
applyUIModifications();
-
- // Setup observers and listeners
setupInputListener();
setupMessageObserver();
setupContactObserver();
-
- // Inject custom UI elements
injectControlPanel();
state.initialized = true;
console.log("General Bots: Content script initialized");
}
- // Load settings from chrome storage
async function loadSettings() {
return new Promise((resolve) => {
chrome.storage.sync.get(settings, (items) => {
@@ -75,13 +60,11 @@
});
}
- // Apply UI modifications based on settings
function applyUIModifications() {
applyContactVisibility();
applyAutoModeIndicator();
}
- // Hide/show contact list
function applyContactVisibility() {
const contactList = document.querySelector(SELECTORS.contactList);
if (contactList) {
@@ -97,7 +80,6 @@
}
}
- // Show auto-mode indicator
function applyAutoModeIndicator() {
let indicator = document.getElementById("gb-auto-mode-indicator");
@@ -118,7 +100,6 @@
}
}
- // Setup input field listener for message processing
function setupInputListener() {
const observer = new MutationObserver(() => {
const inputField = document.querySelector(SELECTORS.messageInput);
@@ -133,7 +114,6 @@
subtree: true,
});
- // Check immediately
const inputField = document.querySelector(SELECTORS.messageInput);
if (inputField && !inputField.getAttribute("gb-monitored")) {
setupFieldMonitoring(inputField);
@@ -141,11 +121,9 @@
}
}
- // Monitor input field for messages
function setupFieldMonitoring(inputField) {
console.log("General Bots: Setting up input field monitoring");
- // Listen for keydown events
inputField.addEventListener("keydown", async (event) => {
if (event.key === "Enter" && !event.shiftKey) {
const originalText = inputField.textContent.trim();
@@ -163,7 +141,6 @@
result.processedText &&
result.processedText !== originalText
) {
- // Show correction preview
const shouldSend = await showCorrectionPreview(
originalText,
result.processedText,
@@ -172,7 +149,6 @@
if (shouldSend) {
setInputText(inputField, result.processedText);
- // Store original for reference
state.originalMessages.set(Date.now(), {
original: originalText,
corrected: result.processedText,
@@ -181,7 +157,6 @@
}
hideProcessingIndicator();
- // Send the message
simulateEnterPress(inputField);
} catch (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");
}
- // Process message through LLM for grammar correction
async function processMessageWithLLM(text) {
return new Promise((resolve) => {
chrome.runtime.sendMessage(
@@ -220,10 +193,8 @@
});
}
- // Show correction preview modal
async function showCorrectionPreview(original, corrected, inputField) {
return new Promise((resolve) => {
- // If texts are very similar, auto-accept
if (levenshteinDistance(original, corrected) < 3) {
resolve(true);
return;
@@ -258,7 +229,6 @@
document.body.appendChild(modal);
- // Auto-close after 5 seconds with corrected text
const autoClose = setTimeout(() => {
modal.remove();
resolve(true);
@@ -278,7 +248,6 @@
});
}
- // Setup observer for incoming messages (for auto-reply)
function setupMessageObserver() {
const observer = new MutationObserver((mutations) => {
if (!settings.autoMode) return;
@@ -300,7 +269,6 @@
}
});
- // Start observing when chat container is available
const waitForChat = setInterval(() => {
const chatContainer = document.querySelector(SELECTORS.chatContainer);
if (chatContainer) {
@@ -314,14 +282,12 @@
}, 1000);
}
- // Handle incoming message for auto-reply
async function handleIncomingMessage(messageElement) {
if (!settings.autoMode || !settings.authenticated) return;
const currentContact = getCurrentContactName();
if (!currentContact) return;
- // Check if auto-mode is enabled for this contact
if (!state.autoModeContacts.has(currentContact)) return;
const messageText = messageElement.querySelector(SELECTORS.messageText);
@@ -335,10 +301,8 @@
text,
);
- // Get conversation context
const context = getConversationContext();
- // Request auto-reply from LLM
chrome.runtime.sendMessage(
{
action: "generateAutoReply",
@@ -356,7 +320,6 @@
);
}
- // Get conversation context (last few messages)
function getConversationContext() {
const messages = [];
const messageElements = document.querySelectorAll(
@@ -378,20 +341,17 @@
return messages;
}
- // Send auto-reply
async function sendAutoReply(text) {
const inputField = document.querySelector(SELECTORS.messageInput);
if (!inputField) return;
setInputText(inputField, text);
- // Small delay before sending
await new Promise((r) => setTimeout(r, 500));
simulateEnterPress(inputField);
}
- // Setup contact observer for auto-mode toggle per contact
function setupContactObserver() {
const observer = new MutationObserver(() => {
const header = document.querySelector(SELECTORS.chatHeader);
@@ -406,7 +366,6 @@
});
}
- // Inject control buttons for current contact
function injectContactControls(header) {
const contactName = getCurrentContactName();
if (!contactName) return;
@@ -442,7 +401,6 @@
});
}
- // Inject main control panel
function injectControlPanel() {
const panel = document.createElement("div");
panel.id = "gb-control-panel";
@@ -494,14 +452,10 @@
`;
document.body.appendChild(panel);
-
- // Setup panel event listeners
setupPanelListeners();
}
- // Setup control panel event listeners
function setupPanelListeners() {
- // Panel toggle
document
.getElementById("gb-panel-toggle")
?.addEventListener("click", function () {
@@ -515,7 +469,6 @@
}
});
- // Grammar toggle
document
.getElementById("gb-grammar-toggle")
?.addEventListener("change", function () {
@@ -523,7 +476,6 @@
saveSettings();
});
- // Contacts toggle
document
.getElementById("gb-contacts-toggle")
?.addEventListener("change", function () {
@@ -532,7 +484,6 @@
saveSettings();
});
- // Auto mode toggle
document
.getElementById("gb-auto-toggle")
?.addEventListener("change", function () {
@@ -541,7 +492,6 @@
saveSettings();
});
- // Auth button
document
.getElementById("gb-auth-btn")
?.addEventListener("click", async function () {
@@ -576,7 +526,6 @@
});
}
- // Save settings to storage
function saveSettings() {
chrome.storage.sync.set(settings);
chrome.runtime.sendMessage({
@@ -585,19 +534,16 @@
});
}
- // Get current contact name
function getCurrentContactName() {
const nameEl = document.querySelector(SELECTORS.contactName);
return nameEl ? nameEl.textContent.trim() : null;
}
- // Set text in input field
function setInputText(inputField, text) {
inputField.textContent = text;
inputField.dispatchEvent(new InputEvent("input", { bubbles: true }));
}
- // Simulate Enter key press
function simulateEnterPress(element) {
const enterEvent = new KeyboardEvent("keydown", {
key: "Enter",
@@ -610,7 +556,6 @@
element.dispatchEvent(enterEvent);
}
- // Show processing indicator
function showProcessingIndicator(inputField) {
let indicator = document.getElementById("gb-processing");
if (!indicator) {
@@ -626,7 +571,6 @@
indicator.style.display = "flex";
}
- // Hide processing indicator
function hideProcessingIndicator() {
const indicator = document.getElementById("gb-processing");
if (indicator) {
@@ -634,14 +578,12 @@
}
}
- // Utility: Escape HTML
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
- // Utility: Levenshtein distance for text comparison
function levenshteinDistance(str1, str2) {
const m = str1.length;
const n = str2.length;
@@ -665,7 +607,6 @@
return dp[m][n];
}
- // Listen for messages from background script
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
switch (message.action) {
case "tabReady":
@@ -694,7 +635,6 @@
case "authCompleted":
settings.authenticated = true;
- // Refresh control panel
const panel = document.getElementById("gb-control-panel");
if (panel) {
panel.remove();
@@ -707,13 +647,11 @@
return true;
});
- // Initialize on DOM ready
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
- // Also try to initialize after a delay (WhatsApp Web loads dynamically)
setTimeout(init, 2000);
})();
diff --git a/popup.js b/popup.js
index a035d47..8b1ca11 100644
--- a/popup.js
+++ b/popup.js
@@ -1,8 +1,4 @@
-// General Bots - Popup Script
-// Handles settings management, authentication, and UI updates
-
document.addEventListener("DOMContentLoaded", async function () {
- // Default settings
const DEFAULT_SETTINGS = {
serverUrl: "https://api.generalbots.com",
gbServerUrl: "https://api.pragmatismo.com.br",
@@ -21,19 +17,15 @@ document.addEventListener("DOMContentLoaded", async function () {
},
};
- // Load settings and update UI
await loadSettings();
await checkAuthStatus();
loadStats();
- // Event listeners
setupEventListeners();
- // Load saved settings
async function loadSettings() {
return new Promise((resolve) => {
chrome.storage.sync.get(DEFAULT_SETTINGS, function (items) {
- // Update form fields
document.getElementById("server-url").value =
items.serverUrl || DEFAULT_SETTINGS.serverUrl;
document.getElementById("whatsapp-number").value =
@@ -50,7 +42,6 @@ document.addEventListener("DOMContentLoaded", async function () {
});
}
- // Check authentication status
async function checkAuthStatus() {
return new Promise((resolve) => {
chrome.runtime.sendMessage({ action: "getAuthStatus" }, (response) => {
@@ -78,7 +69,6 @@ document.addEventListener("DOMContentLoaded", async function () {
});
}
- // Load statistics
function loadStats() {
chrome.storage.local.get(["stats"], function (result) {
const stats = result.stats || DEFAULT_SETTINGS.stats;
@@ -91,24 +81,19 @@ document.addEventListener("DOMContentLoaded", async function () {
});
}
- // Setup event listeners
function setupEventListeners() {
- // Save settings button
document
.getElementById("save-settings")
.addEventListener("click", saveSettings);
- // Auth button
document
.getElementById("auth-btn")
.addEventListener("click", handleAuthentication);
- // Open options page
document.getElementById("open-options").addEventListener("click", () => {
chrome.runtime.openOptionsPage();
});
- // Toggle switches - save immediately on change
const toggles = [
"grammar-correction",
"enable-processing",
@@ -117,12 +102,11 @@ document.addEventListener("DOMContentLoaded", async function () {
];
toggles.forEach((id) => {
document.getElementById(id).addEventListener("change", function () {
- saveSettings(true); // silent save
+ saveSettings(true);
});
});
}
- // Save settings
async function saveSettings(silent = false) {
const settings = {
serverUrl: document.getElementById("server-url").value.trim(),
@@ -135,7 +119,6 @@ document.addEventListener("DOMContentLoaded", async function () {
return new Promise((resolve) => {
chrome.storage.sync.set(settings, function () {
- // Notify content script about settings change
chrome.tabs.query(
{ url: "https://web.whatsapp.com/*" },
function (tabs) {
@@ -157,32 +140,26 @@ document.addEventListener("DOMContentLoaded", async function () {
});
}
- // Handle authentication
async function handleAuthentication() {
const numberInput = document.getElementById("whatsapp-number");
const authBtn = document.getElementById("auth-btn");
const number = numberInput.value.trim();
- // Validate number
if (!number) {
showError(numberInput, "Please enter your WhatsApp number");
return;
}
- // Clean number (remove spaces, dashes)
const cleanNumber = number.replace(/[\s\-\(\)]/g, "");
- // Basic validation
if (!/^\+?[0-9]{10,15}$/.test(cleanNumber)) {
showError(numberInput, "Invalid phone number format");
return;
}
- // Update button state
authBtn.disabled = true;
authBtn.innerHTML = '⏳ Sending request...';
- // Send auth request
chrome.runtime.sendMessage(
{
action: "authenticate",
@@ -194,7 +171,6 @@ document.addEventListener("DOMContentLoaded", async function () {
'📱 Check your WhatsApp';
authBtn.classList.add("btn-success");
- // Start polling for auth completion
pollAuthStatus();
} else {
authBtn.disabled = false;
@@ -208,10 +184,8 @@ document.addEventListener("DOMContentLoaded", async function () {
);
}
- // Poll for authentication status
function pollAuthStatus(attempts = 0) {
if (attempts > 60) {
- // 5 minutes max
showNotification("Authentication timed out. Please try again.", "error");
resetAuthButton();
return;
@@ -229,7 +203,6 @@ document.addEventListener("DOMContentLoaded", async function () {
}, 5000);
}
- // Reset auth button
function resetAuthButton() {
const authBtn = document.getElementById("auth-btn");
authBtn.disabled = false;
@@ -238,7 +211,6 @@ document.addEventListener("DOMContentLoaded", async function () {
'🤖 Authenticate via WhatsApp';
}
- // Show error on input
function showError(input, message) {
input.classList.add("error");
const small = input.parentElement.querySelector("small");
@@ -256,7 +228,6 @@ document.addEventListener("DOMContentLoaded", async function () {
}, 3000);
}
- // Show feedback on button
function showFeedback(buttonId, message, type = "success") {
const button = document.getElementById(buttonId);
const originalHTML = button.innerHTML;
@@ -273,9 +244,7 @@ document.addEventListener("DOMContentLoaded", async function () {
}, 1500);
}
- // Show notification
function showNotification(message, type = "info") {
- // Remove existing notification
const existing = document.querySelector(".popup-notification");
if (existing) existing.remove();