JavaScript · 5433 bytes Raw Blame History
1 // Background script for LooseCannon
2 console.log('[LooseCannon Background] Initialized');
3
4 class LooseCannonBackground {
5 constructor() {
6 this.serverUrl = 'http://localhost:8765'; // Local server URL
7 this.isConnected = false;
8 this.activeTabs = new Map();
9 this.personalities = [];
10 this.currentPersonality = 'default';
11 this.init();
12 }
13
14 init() {
15 this.setupMessageListeners();
16 this.checkServerConnection();
17 this.loadSettings();
18 }
19
20 setupMessageListeners() {
21 browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
22 console.log('[LooseCannon Background] Received message:', message.type);
23
24 switch (message.type) {
25 case 'NEW_MESSAGE':
26 this.handleNewMessage(message.data, sender.tab.id)
27 .then(sendResponse)
28 .catch(error => {
29 console.error('Error handling message:', error);
30 sendResponse({ error: error.message });
31 });
32 return true; // Keep channel open for async response
33
34 case 'TOGGLE_ACTIVE':
35 this.handleToggleActive(sender.tab.id, message.data.isActive);
36 sendResponse({ success: true });
37 break;
38
39 case 'GET_SERVER_STATUS':
40 sendResponse({ connected: this.isConnected });
41 break;
42
43 case 'GET_PERSONALITIES':
44 sendResponse({ personalities: this.personalities });
45 break;
46
47 case 'SET_PERSONALITY':
48 this.currentPersonality = message.data.personality;
49 this.saveSettings();
50 sendResponse({ success: true });
51 break;
52
53 default:
54 console.warn('Unknown message type:', message.type);
55 }
56 });
57 }
58
59 async handleNewMessage(data, tabId) {
60 if (!this.isConnected) {
61 console.warn('[LooseCannon] Server not connected, cannot process message');
62 return { error: 'Server not connected' };
63 }
64
65 try {
66 // Send message to local server for LLM processing
67 const response = await fetch(`${this.serverUrl}/generate`, {
68 method: 'POST',
69 headers: {
70 'Content-Type': 'application/json',
71 },
72 body: JSON.stringify({
73 message: data.text,
74 personality: this.currentPersonality,
75 chatId: data.chatId,
76 timestamp: data.timestamp
77 })
78 });
79
80 if (!response.ok) {
81 throw new Error(`Server error: ${response.status}`);
82 }
83
84 const result = await response.json();
85 console.log('[LooseCannon] Generated response:', result.reply);
86
87 // Log conversation for debugging
88 this.logConversation(data.chatId, data.text, result.reply);
89
90 return { reply: result.reply };
91 } catch (error) {
92 console.error('[LooseCannon] Error generating response:', error);
93 return { error: error.message };
94 }
95 }
96
97 handleToggleActive(tabId, isActive) {
98 if (isActive) {
99 this.activeTabs.set(tabId, {
100 activated: new Date().toISOString(),
101 messageCount: 0
102 });
103 console.log(`[LooseCannon] Activated for tab ${tabId}`);
104 } else {
105 this.activeTabs.delete(tabId);
106 console.log(`[LooseCannon] Deactivated for tab ${tabId}`);
107 }
108 }
109
110 async checkServerConnection() {
111 try {
112 const response = await fetch(`${this.serverUrl}/status`);
113 if (response.ok) {
114 const data = await response.json();
115 this.isConnected = true;
116 this.personalities = data.personalities || [];
117 console.log('[LooseCannon] Server connected, personalities:', this.personalities);
118 } else {
119 this.isConnected = false;
120 console.warn('[LooseCannon] Server responded with error:', response.status);
121 }
122 } catch (error) {
123 this.isConnected = false;
124 console.error('[LooseCannon] Could not connect to server:', error);
125 }
126
127 // Retry connection every 5 seconds if not connected
128 if (!this.isConnected) {
129 setTimeout(() => this.checkServerConnection(), 5000);
130 }
131 }
132
133 async loadSettings() {
134 try {
135 const settings = await browser.storage.local.get(['personality', 'serverUrl']);
136 if (settings.personality) {
137 this.currentPersonality = settings.personality;
138 }
139 if (settings.serverUrl) {
140 this.serverUrl = settings.serverUrl;
141 }
142 console.log('[LooseCannon] Settings loaded:', settings);
143 } catch (error) {
144 console.error('[LooseCannon] Error loading settings:', error);
145 }
146 }
147
148 async saveSettings() {
149 try {
150 await browser.storage.local.set({
151 personality: this.currentPersonality,
152 serverUrl: this.serverUrl
153 });
154 console.log('[LooseCannon] Settings saved');
155 } catch (error) {
156 console.error('[LooseCannon] Error saving settings:', error);
157 }
158 }
159
160 logConversation(chatId, userMessage, botReply) {
161 const log = {
162 timestamp: new Date().toISOString(),
163 chatId,
164 userMessage,
165 botReply
166 };
167
168 // Store conversation logs (with limit to prevent storage overflow)
169 browser.storage.local.get('conversationLogs').then(result => {
170 let logs = result.conversationLogs || [];
171 logs.push(log);
172
173 // Keep only last 100 messages
174 if (logs.length > 100) {
175 logs = logs.slice(-100);
176 }
177
178 browser.storage.local.set({ conversationLogs: logs });
179 });
180 }
181 }
182
183 // Initialize background script
184 const looseCannonBg = new LooseCannonBackground();