From c39e2fcec40b655b0d4116398f11dd33c42a68ab Mon Sep 17 00:00:00 2001 From: Lukas Werner Date: Sun, 31 Aug 2025 23:16:24 -0700 Subject: [PATCH] feat: make interactive default flow --- chrome-extension/src/background.js | 204 ------------------------- chrome-extension/src/manifest.json | 4 +- chrome-extension/src/options.html | 13 -- chrome-extension/src/options.js | 5 - chrome-extension/src/popup.js | 95 ++---------- chrome-extension/src/tag_generation.js | 74 +++++++++ 6 files changed, 90 insertions(+), 305 deletions(-) create mode 100644 chrome-extension/src/tag_generation.js diff --git a/chrome-extension/src/background.js b/chrome-extension/src/background.js index cb109d1..515646b 100644 --- a/chrome-extension/src/background.js +++ b/chrome-extension/src/background.js @@ -1,21 +1,3 @@ -import { Ollama } from "ollama/browser"; -import { ollama_schema } from "./schema"; - -// Initialize Ollama client -let ollamaClient = null; -let ollamaTemperature = 0.3; - -chrome.runtime.onInstalled.addListener(async () => { - chrome.contextMenus.create({ - id: "saveWithTags", - title: "Save with Tags", - contexts: ["action"], - }); - - // Initialize Ollama client on install - await initOllamaClient(); -}); - // Add listener for tab activation and update events chrome.tabs.onActivated.addListener((activeInfo) => { console.log("Tab activated:", activeInfo.tabId); @@ -63,8 +45,6 @@ async function checkIfBookmarked(tabId) { }, ); - console.log("Response status:", response.status); - if (response.ok) { // URL is bookmarked setFilledIcon(); @@ -87,191 +67,7 @@ async function checkIfBookmarked(tabId) { ); } -async function initOllamaClient() { - try { - const { - ollamaEndpoint, - ollamaModel, - ollamaTemperature: temperature, - } = await chrome.storage.sync.get([ - "ollamaEndpoint", - "ollamaModel", - "ollamaTemperature", - ]); - - // Default to local Ollama instance and a general model if not configured - const endpoint = ollamaEndpoint || "http://localhost:11434"; - const model = ollamaModel || "lukasmwerner/mark-tagger:1b"; - - ollamaClient = new Ollama({ - host: endpoint, - }); - - ollamaTemperature = temperature; - - console.log("Ollama client initialized"); - } catch (error) { - console.error("Error initializing Ollama client:", error); - } -} - -chrome.action.onClicked.addListener((tab) => { - quickSave(tab); -}); - -chrome.contextMenus.onClicked.addListener(async (info, tab) => { - if (info.menuItemId === "saveWithTags") { - // First get the page info - try { - const response = await chrome.tabs.sendMessage(tab.id, { - action: "getPageInfo", - }); - // Store the data temporarily - await chrome.storage.local.set({ tempPageInfo: response }); - - // Open the popup with the tab id - chrome.windows.create({ - url: "popup.html", - type: "popup", - width: 400, - height: 500, - }); - } catch (error) { - console.error("Error getting page info:", error); - } - } -}); - -async function generateTagsWithOllama(url, title, description) { - if (!ollamaClient) { - await initOllamaClient(); - - if (!ollamaClient) { - console.error("Failed to initialize Ollama client"); - return []; - } - } - - try { - const { ollamaModel, ollamaPrompt } = await chrome.storage.sync.get([ - "ollamaModel", - "ollamaPrompt", - ]); - const model = ollamaModel || "lukasmwerner/mark-tagger:1b"; - // Use custom prompt if available, otherwise use default - let promptTemplate = ollamaPrompt || - `Generate 3 or more relevant tags for this content. - return as JSON - - Title: {{title}} - URL: {{url}} - Description: {{description}}`; - - // Replace placeholders with actual content - const prompt = promptTemplate - .replace(/{{url}}/g, url) - .replace(/{{title}}/g, title) - .replace(/{{description}}/g, description); - - const response = await ollamaClient.generate({ - model: model, - prompt: prompt, - options: { - temperature: ollamaTemperature, - }, - format: ollama_schema, - }); - - return JSON.parse(response.response).tags; - } catch (error) { - console.error("Error generating tags with Ollama:", error); - return []; - } -} - -async function quickSave(tab) { - try { - // Check for token - const { apiToken, enableAutoTagging } = await chrome.storage.sync.get([ - "apiToken", - "enableAutoTagging", - ]); - if (!apiToken) { - chrome.runtime.openOptionsPage(); - return; - } - - // Get page info from content script - chrome.tabs.sendMessage( - tab.id, - { action: "getPageInfo" }, - async function(response) { - if (chrome.runtime.lastError) { - console.error("Could not connect to page"); - return; - } - - // Generate tags using Ollama only if auto-tagging is enabled - let autoTags = []; - if (enableAutoTagging !== false) { - // Default to enabled if not set - autoTags = await generateTagsWithOllama( - response.url, - response.title, - response.description, - ); - } - - // Prepare bookmark data - const bookmark = { - Url: response.url, - Title: response.title, - Description: response.description, - Tags: autoTags || [], // Use generated tags - }; - - try { - // Send to API - const apiResponse = await fetch( - "http://localhost:1990/api/bookmarks", - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiToken}`, - }, - body: JSON.stringify(bookmark), - }, - ); - - if (!apiResponse.ok) { - throw new Error( - `HTTP error! status: ${apiResponse.status}`, - ); - } - - // Show success badge - chrome.action.setBadgeText({ text: "✓" }); - chrome.action.setBadgeBackgroundColor({ color: "#4CAF50" }); - setTimeout(() => { - chrome.action.setBadgeText({ text: "" }); - }, 2000); - } catch (error) { - console.error("Error:", error); - // Show error badge - chrome.action.setBadgeText({ text: "!" }); - chrome.action.setBadgeBackgroundColor({ color: "#F44336" }); - setTimeout(() => { - chrome.action.setBadgeText({ text: "" }); - }, 2000); - } - }, - ); - } catch (error) { - console.error("Error:", error); - } -} function setFilledIcon() { chrome.action.setIcon({ diff --git a/chrome-extension/src/manifest.json b/chrome-extension/src/manifest.json index 5ff3689..dfcd678 100644 --- a/chrome-extension/src/manifest.json +++ b/chrome-extension/src/manifest.json @@ -16,7 +16,9 @@ "js": ["content.js"] } ], - "action": {}, + "action": { + "default_popup": "popup.html" + }, "options_ui": { "page": "options.html", "open_in_tab": true diff --git a/chrome-extension/src/options.html b/chrome-extension/src/options.html index 9c4cc8d..bf74fa2 100644 --- a/chrome-extension/src/options.html +++ b/chrome-extension/src/options.html @@ -63,19 +63,6 @@

Ollama Auto-Tagging Settings

-
- - -
v.toLowerCase()) - return tags; - } catch (error) { - // Hide loading indicator - document.getElementById("tagsLoading").style.display = "none"; - - console.error("Error generating tags with Ollama:", error); - updateStatus(`Error generating tags: ${error.message}`); - return []; - } -} let pageInfo = null; let tags = new Set(); async function initializeDetailedSave() { try { - // Get the stored page info - const data = await chrome.storage.local.get("tempPageInfo"); - if (data.tempPageInfo) { - pageInfo = data.tempPageInfo; - document.getElementById("title").value = pageInfo.title; - document.getElementById("description").value = pageInfo.description; - - // Clean up the stored data - chrome.storage.local.remove("tempPageInfo"); - } else { - updateStatus("Error: No page data available"); - } + const tabs = await chrome.tabs.query({ active: true, currentWindow: true }); + if (!tabs[0]) return; + const response = await chrome.tabs.sendMessage(tabs[0].id, { + action: "getPageInfo", + }); + pageInfo = response; + document.getElementById("title").value = pageInfo.title; + document.getElementById("description").value = pageInfo.description; } catch (error) { updateStatus("Error: Could not load page data"); console.error(error); @@ -210,4 +138,7 @@ async function initializeDetailedSave() { }); } -document.addEventListener("DOMContentLoaded", initializeDetailedSave); +document.addEventListener("DOMContentLoaded", function() { + console.log("dom loaded!") + initializeDetailedSave() +}); diff --git a/chrome-extension/src/tag_generation.js b/chrome-extension/src/tag_generation.js new file mode 100644 index 0000000..9539c00 --- /dev/null +++ b/chrome-extension/src/tag_generation.js @@ -0,0 +1,74 @@ +import { Ollama } from "ollama/browser"; +import { ollama_schema } from "./schema"; + +async function generateTagsWithOllama(url, title, description) { + try { + // Show loading indicator + document.getElementById("tagsLoading").style.display = "flex"; + + // Get Ollama settings + const { + ollamaEndpoint, + ollamaModel, + ollamaPrompt, + ollamaTemperature: temperature, + } = await chrome.storage.sync.get([ + "ollamaEndpoint", + "ollamaModel", + "ollamaPrompt", + "ollamaTemperature", + ]); + + const endpoint = ollamaEndpoint || "http://localhost:11434"; + const model = ollamaModel || "lukasmwerner/mark-tagger:1b"; + + // Use custom prompt if available, otherwise use default + let promptTemplate = ollamaPrompt || + `Generate 3 or more relevant tags for this content. + return as JSON + + Title: {{title}} + URL: {{url}} + Description: {{description}}`; + + // Replace placeholders with actual content + const prompt = promptTemplate + .replace(/{{title}}/g, title) + .replace(/{{url}}/g, url) + .replace(/{{description}}/g, description); + + // Initialize Ollama client + const ollamaClient = new Ollama({ + host: endpoint, + }); + + const response = await ollamaClient.generate({ + model: model, + prompt: prompt, + options: { + temperature: temperature || 0.3, + }, + format: ollama_schema, + }); + + // Hide loading indicator + document.getElementById("tagsLoading").style.display = "none"; + + console.log(response); + let tags = JSON.parse(response.response).tags; + + tags = tags.map(v => v.toLowerCase()) + return tags; + } catch (error) { + // Hide loading indicator + document.getElementById("tagsLoading").style.display = "none"; + + console.error("Error generating tags with Ollama:", error); + updateStatus(`Error generating tags: ${error.message}`); + return []; + } +} + +export { + generateTagsWithOllama, +} -- 2.51.2