From 71278d18b3abfaaa3871946475e954c95aa199e1 Mon Sep 17 00:00:00 2001 From: tcsenpai Date: Tue, 11 Mar 2025 11:31:42 +0100 Subject: [PATCH] added a timeout --- .gitignore | 4 ++ background.js | 106 ++++++++++++++++++++++++++++---------------- build_xpi.sh | 26 +++++++++++ build_xpi_webext.sh | 6 +++ manifest.json | 2 +- 5 files changed, 104 insertions(+), 40 deletions(-) create mode 100755 build_xpi.sh create mode 100755 build_xpi_webext.sh diff --git a/.gitignore b/.gitignore index afadf7b..09f52ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ extension pack_extension.sh SpaceLLama.zip +yarn.lock +dist/*.xpi +dist/*.zip +node_modules diff --git a/background.js b/background.js index 21f2c91..1da39f6 100644 --- a/background.js +++ b/background.js @@ -1,7 +1,7 @@ console.log("Background script loaded"); -let isFirefox = typeof InstallTrigger !== 'undefined'; // Firefox has `InstallTrigger` -let browser = isFirefox ? window.browser : chrome; +let isFirefox = typeof InstallTrigger !== "undefined"; // Firefox has `InstallTrigger` +let browser = isFirefox ? window.browser : chrome; // Check if chrome.action or browser.action is available if (isFirefox && browser.browserAction) { @@ -16,32 +16,36 @@ if (isFirefox && browser.browserAction) { console.log("Injecting sidebar iframe into the page"); // Use the tab object properly here - browser.scripting.executeScript({ - target: { tabId: tab.id }, // Pass the tab ID correctly - function: injectSidebar - }, () => { - if (browser.runtime.lastError) { - console.error("Error injecting sidebar:", browser.runtime.lastError.message); - } else { - console.log("Sidebar injected successfully."); + browser.scripting.executeScript( + { + target: { tabId: tab.id }, // Pass the tab ID correctly + function: injectSidebar, + }, + () => { + if (browser.runtime.lastError) { + console.error( + "Error injecting sidebar:", + browser.runtime.lastError.message + ); + } else { + console.log("Sidebar injected successfully."); + } } - }); + ); }); } - - // Function to inject the sidebar as an iframe in browsers like Chrome function injectSidebar() { // Check if the sidebar iframe is already injected - if (document.getElementById('sidebar-frame')) { + if (document.getElementById("sidebar-frame")) { console.log("Sidebar is already injected."); return; } // Create an iframe for the sidebar - const sidebarFrame = document.createElement('iframe'); - sidebarFrame.id = 'sidebar-frame'; // Add an ID to prevent multiple injections - sidebarFrame.src = chrome.runtime.getURL('sidebar/sidebar.html'); // Use the sidebar.html + const sidebarFrame = document.createElement("iframe"); + sidebarFrame.id = "sidebar-frame"; // Add an ID to prevent multiple injections + sidebarFrame.src = chrome.runtime.getURL("sidebar/sidebar.html"); // Use the sidebar.html sidebarFrame.style.cssText = ` position: fixed; top: 0; @@ -74,7 +78,7 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => { tokenCount, }); }); - return true; // Indicates that we will send a response asynchronously + return true; // Indicates that we will send a response asynchronously } }); @@ -175,18 +179,49 @@ async function summarizeChunk( model, tokenLimit ) { - const response = await fetch(endpoint, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - prompt: `${systemPrompt}\n\nFollow the above instructions and summarize the following text:\n\n${chunk}`, - model: model, - stream: false, - num_ctx: tokenLimit, - }), - }); + let response; + let maxRetries = 3; + let retryCount = 0; + let retryDelay = 1000; + // We will retry the request if it fails (three times) + // Each time we will wait longer before retrying (1, 2, 4 seconds) + // Each request will timeout after 25 * retryDelay + while (retryCount < maxRetries) { + try { + response = await fetch(endpoint, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + prompt: `${systemPrompt}\n\nFollow the above instructions and summarize the following text:\n\n${chunk}`, + model: model, + stream: false, + num_ctx: tokenLimit, + }), + signal: AbortSignal.timeout(25 * retryDelay), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + break; // Success - exit the retry loop + } catch (error) { + console.error("Error in summarizeChunk:", error); + retryCount++; + + if (retryCount >= maxRetries) { + throw new Error( + `Failed to summarize chunk after ${maxRetries} retries: ${error.message}` + ); + } + + console.log(`Retry ${retryCount}/${maxRetries} after ${retryDelay}ms`); + await new Promise((resolve) => setTimeout(resolve, retryDelay)); + retryDelay *= 2; + } + } // TODO Add bespoke-minicheck validation here // LINK https://ollama.com/library/bespoke-minicheck @@ -196,13 +231,6 @@ async function summarizeChunk( console.log(bespokeResponse); } - if (!response.ok) { - const errorText = await response.text(); - throw new Error( - `HTTP error! status: ${response.status}, message: ${errorText}` - ); - } - const data = await response.json(); return data.response; } @@ -211,7 +239,7 @@ function estimateTokenCount(text) { return Math.ceil(text.length / 4); } -function splitContentIntoChunks(content, tokenLimit, systemPrompt) { +function splitContentIntoChunks(content, tokenLimit, systemPrompt) { const maxTokens = tokenLimit - estimateTokenCount(systemPrompt) - 100; // Reserve 100 tokens for safety const chunks = []; const words = content.split(/\s+/); @@ -259,5 +287,5 @@ async function bespokeMinicheck(chunk, summary) { }); // TODO Error handling let response_text = await bespoke_response.text(); - return response_text + return response_text; } diff --git a/build_xpi.sh b/build_xpi.sh new file mode 100755 index 0000000..b26b279 --- /dev/null +++ b/build_xpi.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Set extension name +EXTENSION_NAME="SpaceLLama" + +# Create a temporary directory for building +BUILD_DIR="./build" +mkdir -p $BUILD_DIR + +# Copy all necessary files to the build directory +echo "Copying files to build directory..." +cp -r background.js content_scripts icon.png manifest.json options sidebar model_tokens.json $BUILD_DIR + +# Navigate to the build directory +cd $BUILD_DIR + +# Create the XPI file (which is just a ZIP file with .xpi extension) +echo "Creating XPI file..." +zip -r ../${EXTENSION_NAME}.xpi * + +# Clean up +cd .. +echo "Cleaning up build directory..." +rm -rf $BUILD_DIR + +echo "XPI file created: ${EXTENSION_NAME}.xpi" \ No newline at end of file diff --git a/build_xpi_webext.sh b/build_xpi_webext.sh new file mode 100755 index 0000000..23f467d --- /dev/null +++ b/build_xpi_webext.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Build the extension using web-ext +web-ext build --source-dir ./ --artifacts-dir ./dist --overwrite-dest + +echo "XPI file created in ./dist directory" \ No newline at end of file diff --git a/manifest.json b/manifest.json index 2ce0eaa..27dcff3 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "SpaceLLama", - "version": "1.3", + "version": "1.4", "description": "Summarize web pages using Ollama. Supports custom models, token limits, system prompts, chunking, and more. See https://github.com/tcsenpai/spacellama for more information.", "permissions": ["activeTab", "storage", "", "tabs"], "browser_action": {