Files
t6_mem0/examples/yt-assistant-chrome/src/options.js
2025-04-10 22:14:57 +05:30

453 lines
12 KiB
JavaScript

// Options page functionality for AI Chat Assistant
import { MemoryClient } from "mem0ai";
// Default configuration
const defaultConfig = {
model: "gpt-4o",
maxTokens: 2000,
temperature: 0.7,
enabledSites: ["youtube.com"],
};
// Initialize Mem0AI client
let mem0client = null;
// Initialize when the DOM is fully loaded
document.addEventListener("DOMContentLoaded", init);
// Initialize options page
async function init() {
// Set up event listeners
document
.getElementById("save-options")
.addEventListener("click", saveOptions);
document
.getElementById("reset-defaults")
.addEventListener("click", resetToDefaults);
document.getElementById("add-memory").addEventListener("click", addMemory);
// Set up slider value display
const temperatureSlider = document.getElementById("temperature");
const temperatureValue = document.getElementById("temperature-value");
temperatureSlider.addEventListener("input", () => {
temperatureValue.textContent = temperatureSlider.value;
});
// Set up memories sidebar functionality
document
.getElementById("refresh-memories")
.addEventListener("click", fetchMemories);
document
.getElementById("delete-all-memories")
.addEventListener("click", deleteAllMemories);
document
.getElementById("close-edit-modal")
.addEventListener("click", closeEditModal);
document.getElementById("save-memory").addEventListener("click", saveMemory);
document
.getElementById("delete-memory")
.addEventListener("click", deleteMemory);
// Load current configuration
await loadConfig();
// Initialize Mem0AI and load memories
await initializeMem0AI();
await fetchMemories();
}
// Initialize Mem0AI with API key from storage
async function initializeMem0AI() {
try {
const response = await chrome.runtime.sendMessage({ action: "getConfig" });
const mem0ApiKey = response.config.mem0ApiKey;
if (!mem0ApiKey) {
showMemoriesError("Please configure your Mem0 API key in the popup");
return false;
}
mem0client = new MemoryClient({
apiKey: mem0ApiKey,
projectId: "youtube-assistant",
isExtension: true,
});
return true;
} catch (error) {
console.error("Error initializing Mem0AI:", error);
showMemoriesError("Failed to initialize Mem0AI");
return false;
}
}
// Load configuration from storage
async function loadConfig() {
try {
const response = await chrome.runtime.sendMessage({ action: "getConfig" });
const config = response.config;
// Update form fields with current values
if (config.model) {
document.getElementById("model").value = config.model;
}
if (config.maxTokens) {
document.getElementById("max-tokens").value = config.maxTokens;
}
if (config.temperature !== undefined) {
const temperatureSlider = document.getElementById("temperature");
temperatureSlider.value = config.temperature;
document.getElementById("temperature-value").textContent =
config.temperature;
}
} catch (error) {
showStatus(`Error loading configuration: ${error.message}`, "error");
}
}
// Save options to storage
async function saveOptions() {
// Get values from form
const model = document.getElementById("model").value;
const maxTokens = parseInt(document.getElementById("max-tokens").value);
const temperature = parseFloat(document.getElementById("temperature").value);
// Validate inputs
if (maxTokens < 50 || maxTokens > 4000) {
showStatus("Maximum tokens must be between 50 and 4000", "error");
return;
}
if (temperature < 0 || temperature > 1) {
showStatus("Temperature must be between 0 and 1", "error");
return;
}
// Prepare config object
const config = {
model,
maxTokens,
temperature,
};
// Show loading status
showStatus("Saving options...", "warning");
try {
// Send to background script for saving
const response = await chrome.runtime.sendMessage({
action: "saveConfig",
config,
});
if (response.error) {
showStatus(`Error: ${response.error}`, "error");
} else {
showStatus("Options saved successfully", "success");
loadConfig(); // Refresh the UI with the latest saved values
}
} catch (error) {
showStatus(`Error: ${error.message}`, "error");
}
}
// Reset options to defaults
function resetToDefaults() {
if (
confirm(
"Are you sure you want to reset all options to their default values?"
)
) {
// Set form fields to default values
document.getElementById("model").value = defaultConfig.model;
document.getElementById("max-tokens").value = defaultConfig.maxTokens;
const temperatureSlider = document.getElementById("temperature");
temperatureSlider.value = defaultConfig.temperature;
document.getElementById("temperature-value").textContent =
defaultConfig.temperature;
showStatus("Restored default values. Click Save to apply.", "warning");
}
}
// Memories functionality
let currentMemory = null;
async function fetchMemories() {
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
const memories = await mem0client.getAll({
user_id: "youtube-assistant-mem0",
page: 1,
page_size: 50,
});
displayMemories(memories.results);
} catch (error) {
console.error("Error fetching memories:", error);
showMemoriesError("Failed to load memories");
}
}
function displayMemories(memories) {
const memoriesList = document.getElementById("memories-list");
memoriesList.innerHTML = "";
if (memories.length === 0) {
memoriesList.innerHTML = `
<div class="memory-item">
<div class="memory-content">No memories found. Your memories will appear here.</div>
</div>
`;
return;
}
memories.forEach((memory) => {
const memoryElement = document.createElement("div");
memoryElement.className = "memory-item";
memoryElement.innerHTML = `
<div class="memory-content">${memory.memory}</div>
<div class="memory-meta">Last updated: ${new Date(
memory.updated_at
).toLocaleString()}</div>
<div class="memory-actions">
<button class="memory-action-btn edit" data-id="${
memory.id
}">Edit</button>
<button class="memory-action-btn delete" data-id="${
memory.id
}">Delete</button>
</div>
`;
// Add event listeners
memoryElement
.querySelector(".edit")
.addEventListener("click", () => editMemory(memory));
memoryElement
.querySelector(".delete")
.addEventListener("click", () => deleteMemory(memory.id));
memoriesList.appendChild(memoryElement);
});
}
function showMemoriesError(message) {
const memoriesList = document.getElementById("memories-list");
memoriesList.innerHTML = `
<div class="memory-item">
<div class="memory-content">${message}</div>
</div>
`;
}
async function deleteAllMemories() {
if (
!confirm(
"Are you sure you want to delete all memories? This action cannot be undone."
)
) {
return;
}
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
await mem0client.deleteAll({
user_id: "youtube-assistant-mem0",
});
showStatus("All memories deleted successfully", "success");
await fetchMemories();
} catch (error) {
console.error("Error deleting memories:", error);
showStatus("Failed to delete memories", "error");
}
}
function editMemory(memory) {
currentMemory = memory;
const modal = document.getElementById("edit-memory-modal");
const textarea = document.getElementById("edit-memory-text");
textarea.value = memory.memory;
modal.classList.add("open");
}
function closeEditModal() {
const modal = document.getElementById("edit-memory-modal");
modal.classList.remove("open");
currentMemory = null;
}
async function saveMemory() {
if (!currentMemory) return;
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
const textarea = document.getElementById("edit-memory-text");
const updatedMemory = textarea.value.trim();
if (!updatedMemory) {
showStatus("Memory cannot be empty", "error");
return;
}
await mem0client.update(currentMemory.id, updatedMemory);
showStatus("Memory updated successfully", "success");
closeEditModal();
await fetchMemories();
} catch (error) {
console.error("Error updating memory:", error);
showStatus("Failed to update memory", "error");
}
}
async function deleteMemory(memoryId) {
if (
!confirm(
"Are you sure you want to delete this memory? This action cannot be undone."
)
) {
return;
}
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
await mem0client.delete(memoryId);
showStatus("Memory deleted successfully", "success");
await fetchMemories();
} catch (error) {
console.error("Error deleting memory:", error);
showStatus("Failed to delete memory", "error");
}
}
// Show status message
function showStatus(message, type = "info") {
const statusContainer = document.getElementById("status-container");
// Clear previous status
statusContainer.innerHTML = "";
// Create status element
const statusElement = document.createElement("div");
statusElement.className = `status ${type}`;
statusElement.textContent = message;
// Add to container
statusContainer.appendChild(statusElement);
// Auto-clear success messages after 3 seconds
if (type === "success") {
setTimeout(() => {
statusElement.style.opacity = "0";
setTimeout(() => {
if (statusContainer.contains(statusElement)) {
statusContainer.removeChild(statusElement);
}
}, 300);
}, 3000);
}
}
// Add memory to Mem0
async function addMemory() {
const memoryInput = document.getElementById("memory-input");
const addButton = document.getElementById("add-memory");
const memoryResult = document.getElementById("memory-result");
const buttonText = addButton.querySelector(".button-text");
const content = memoryInput.value.trim();
if (!content) {
showMemoryResult(
"Please enter some information to add as a memory",
"error"
);
return;
}
// Show loading state
addButton.disabled = true;
buttonText.textContent = "Adding...";
addButton.innerHTML =
'<div class="loading-spinner"></div><span class="button-text">Adding...</span>';
memoryResult.style.display = "none";
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
const result = await mem0client.add(
[
{
role: "user",
content: content,
},
],
{
user_id: "youtube-assistant-mem0",
}
);
// Show success message with number of memories added
showMemoryResult(
`Added ${result.length || 0} new ${
result.length === 1 ? "memory" : "memories"
}`,
"success"
);
// Clear the input
memoryInput.value = "";
// Refresh the memories list
await fetchMemories();
} catch (error) {
showMemoryResult(`Error adding memory: ${error.message}`, "error");
} finally {
// Reset button state
addButton.disabled = false;
buttonText.textContent = "Add Memory";
addButton.innerHTML = '<span class="button-text">Add Memory</span>';
}
}
// Show memory result message
function showMemoryResult(message, type) {
const memoryResult = document.getElementById("memory-result");
memoryResult.textContent = message;
memoryResult.className = `memory-result ${type}`;
memoryResult.style.display = "block";
// Auto-clear success messages after 3 seconds
if (type === "success") {
setTimeout(() => {
memoryResult.style.opacity = "0";
setTimeout(() => {
memoryResult.style.display = "none";
memoryResult.style.opacity = "1";
}, 300);
}, 3000);
}
}