Update botplugin
This commit is contained in:
parent
59fa200776
commit
17a3caebab
3 changed files with 3 additions and 132 deletions
|
|
@ -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) => {
|
||||||
|
|
|
||||||
62
content.js
62
content.js
|
|
@ -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);
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
33
popup.js
33
popup.js
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue