Files
OpenQode/qwen-automation-extension/background.js

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}`);
}
});