219 lines
6.5 KiB
JavaScript
219 lines
6.5 KiB
JavaScript
// Background script for Qwen AI Automation Extension
|
|
let isAuthenticated = false;
|
|
let qwenToken = null;
|
|
|
|
// Handle extension installation
|
|
chrome.runtime.onInstalled.addListener(() => {
|
|
console.log('Qwen AI Automation Extension installed');
|
|
});
|
|
|
|
// Handle messages from popup
|
|
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
|
|
switch (message.action) {
|
|
case 'checkAuth':
|
|
sendResponse({ authenticated: isAuthenticated });
|
|
break;
|
|
|
|
case 'openAuth':
|
|
// Open Qwen authentication in a new tab
|
|
try {
|
|
await chrome.tabs.create({
|
|
url: 'https://chat.qwen.ai'
|
|
});
|
|
sendResponse({ success: true });
|
|
} catch (error) {
|
|
sendResponse({ success: false, error: error.message });
|
|
}
|
|
break;
|
|
|
|
case 'executeTask':
|
|
if (!isAuthenticated) {
|
|
sendResponse({ error: 'Not authenticated with Qwen' });
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
const result = await executeBrowserTask(message.task);
|
|
sendResponse({ success: true, result: result });
|
|
} catch (error) {
|
|
sendResponse({ success: false, error: error.message });
|
|
}
|
|
break;
|
|
|
|
case 'updateAuthStatus':
|
|
isAuthenticated = message.authenticated;
|
|
qwenToken = message.token || null;
|
|
|
|
// Notify popup about auth status change
|
|
chrome.runtime.sendMessage({ action: 'authStatusUpdated' });
|
|
sendResponse({ success: true });
|
|
break;
|
|
}
|
|
|
|
return true; // Keep message channel open for async response
|
|
});
|
|
|
|
// Execute browser automation task
|
|
async function executeBrowserTask(task) {
|
|
// Get current active tab
|
|
const [activeTab] = await chrome.tabs.query({
|
|
active: true,
|
|
currentWindow: true
|
|
});
|
|
|
|
if (!activeTab) {
|
|
throw new Error('No active tab found');
|
|
}
|
|
|
|
try {
|
|
// Analyze the task and determine appropriate automation steps
|
|
const automationSteps = await analyzeTaskWithQwen(task, activeTab.url);
|
|
|
|
// Execute each step
|
|
let results = [];
|
|
for (const step of automationSteps) {
|
|
const result = await executeAutomationStep(step, activeTab.id);
|
|
results.push(result);
|
|
}
|
|
|
|
return `Task completed successfully. Performed ${automationSteps.length} steps.`;
|
|
} catch (error) {
|
|
throw new Error(`Task execution failed: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
// Analyze task with Qwen AI (simplified for this example)
|
|
async function analyzeTaskWithQwen(task, currentUrl) {
|
|
// This would normally call the Qwen API
|
|
// For now, we'll use a simple rule-based approach
|
|
// In a real implementation, this would send the task to Qwen API
|
|
|
|
console.log(`Analyzing task: ${task} on page: ${currentUrl}`);
|
|
|
|
// Simple rule-based analysis (would be replaced with Qwen API call)
|
|
if (task.toLowerCase().includes('search') || task.toLowerCase().includes('google')) {
|
|
return [
|
|
{
|
|
action: 'fill',
|
|
selector: 'textarea[name="q"], input[name="q"], [name="search"], #search',
|
|
value: extractSearchQuery(task)
|
|
},
|
|
{
|
|
action: 'press',
|
|
key: 'Enter'
|
|
}
|
|
];
|
|
} else if (task.toLowerCase().includes('click') || task.toLowerCase().includes('click on')) {
|
|
const element = extractElementFromTask(task);
|
|
return [
|
|
{
|
|
action: 'click',
|
|
selector: element
|
|
}
|
|
];
|
|
} else {
|
|
// Default: just return the task as is for Qwen to process
|
|
return [
|
|
{
|
|
action: 'analyze',
|
|
task: task,
|
|
url: currentUrl
|
|
}
|
|
];
|
|
}
|
|
}
|
|
|
|
// Extract search query from task
|
|
function extractSearchQuery(task) {
|
|
const match = task.match(/search for ["']?([^"']+)["']?/i) ||
|
|
task.match(/google ["']?([^"']+)["']?/i) ||
|
|
task.match(/find ["']?([^"']+)["']?/i);
|
|
return match ? match[1] : task.replace(/(search|google|find)\s*/i, '').trim();
|
|
}
|
|
|
|
// Extract element from task
|
|
function extractElementFromTask(task) {
|
|
// Simple extraction - in reality would be more sophisticated
|
|
const lowerTask = task.toLowerCase();
|
|
if (lowerTask.includes('search') || lowerTask.includes('google')) return 'textarea[name="q"], input[name="q"]';
|
|
if (lowerTask.includes('button')) return 'button';
|
|
if (lowerTask.includes('link')) return 'a';
|
|
return '*'; // generic selector
|
|
}
|
|
|
|
// Execute a single automation step
|
|
async function executeAutomationStep(step, tabId) {
|
|
try {
|
|
switch (step.action) {
|
|
case 'click':
|
|
return await chrome.scripting.executeScript({
|
|
target: { tabId: tabId },
|
|
func: clickElement,
|
|
args: [step.selector]
|
|
});
|
|
|
|
case 'fill':
|
|
return await chrome.scripting.executeScript({
|
|
target: { tabId: tabId },
|
|
func: fillElement,
|
|
args: [step.selector, step.value]
|
|
});
|
|
|
|
case 'press':
|
|
// For key press, we'll inject a script to simulate the key
|
|
return await chrome.scripting.executeScript({
|
|
target: { tabId: tabId },
|
|
func: pressKey,
|
|
args: [step.key]
|
|
});
|
|
|
|
default:
|
|
console.log('Unknown action:', step.action);
|
|
return { success: false, error: `Unknown action: ${step.action}` };
|
|
}
|
|
} catch (error) {
|
|
console.error('Step execution error:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Helper functions to be injected into the page
|
|
function clickElement(selector) {
|
|
const element = document.querySelector(selector);
|
|
if (element) {
|
|
element.click();
|
|
return { success: true, message: `Clicked element: ${selector}` };
|
|
} else {
|
|
return { success: false, error: `Element not found: ${selector}` };
|
|
}
|
|
}
|
|
|
|
function fillElement(selector, value) {
|
|
const element = document.querySelector(selector);
|
|
if (element) {
|
|
element.value = value;
|
|
element.dispatchEvent(new Event('input', { bubbles: true }));
|
|
element.dispatchEvent(new Event('change', { bubbles: true }));
|
|
return { success: true, message: `Filled element: ${selector} with value: ${value}` };
|
|
} else {
|
|
return { success: false, error: `Element not found: ${selector}` };
|
|
}
|
|
}
|
|
|
|
function pressKey(key) {
|
|
const event = new KeyboardEvent('keydown', {
|
|
key: key,
|
|
code: key.toUpperCase(),
|
|
bubbles: true
|
|
});
|
|
document.activeElement.dispatchEvent(event);
|
|
return { success: true, message: `Pressed key: ${key}` };
|
|
}
|
|
|
|
// Listen for tab updates to manage state
|
|
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
|
if (changeInfo.status === 'complete' && tab.active) {
|
|
// Tab loaded completely, extension is ready for new tasks
|
|
console.log(`Tab ${tabId} loaded: ${tab.url}`);
|
|
}
|
|
}); |