Skip to content

Commit

Permalink
Merge pull request #62 from yatikakain/main
Browse files Browse the repository at this point in the history
[Feature] Implemented "Generate Quiz from Selected Text" Context Menu Feature
  • Loading branch information
Aditya062003 authored Nov 5, 2024
2 parents 61fd93d + d7fb041 commit 646d02b
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 28 deletions.
100 changes: 100 additions & 0 deletions extension/public/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Create context menu on installation
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "askExtension",
title: "Generate Quiz with Selected Text",
contexts: ["selection"]
});
});

// Handle context menu clicks
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
if (info.menuItemId === "askExtension" && info.selectionText) {
try {
// Store the selected text first
await chrome.storage.local.set({
selectedText: info.selectionText
});

// Inject content script if needed
await chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["contentScript.js"]
});

// Send message to content script
await chrome.tabs.sendMessage(tab.id, {
selectedText: info.selectionText
});

// Open the popup
// Note: Chrome extensions can't programmatically open the popup,
// but we can show the user where to click
chrome.action.setPopup({
popup: "src/popup/popup.html"
});

// Show a badge to indicate text was captured
chrome.action.setBadgeText({
text: "!"
});
chrome.action.setBadgeBackgroundColor({
color: "#FF005C"
});

// Clear the badge after 2 seconds
setTimeout(() => {
chrome.action.setBadgeText({ text: "" });
}, 2000);

} catch (error) {
console.error("Error in context menu handler:", error);
}
}
});

// Listen for messages from content script
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === "TEXT_SELECTED") {
chrome.storage.local.set({
selectedText: request.text
}, () => {
console.log("Text saved to storage:", request.text);
sendResponse({ status: "success" });
});
return true; // Required for async sendResponse
}
});

//Clear badge when popup is opened
chrome.action.onClicked.addListener(() => {
chrome.action.setBadgeText({ text: "" });
});

chrome.storage.onChanged.addListener((changes, namespace) => {
for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
console.log(
`Storage key "${key}" in namespace "${namespace}" changed.`,
`Old value was "${oldValue}", new value is "${newValue}".`
);

// Store the key-value pair in local storage
chrome.storage.local.set({ [key]: newValue }, () => {
if (chrome.runtime.lastError) {
console.error("Error storing data:", chrome.runtime.lastError);
} else {
console.log(`Stored key-value pair: { ${key}: ${newValue} }`);
}
});
}
});


// Optional: Handle extension install/update
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === "install") {
console.log("Extension installed");
} else if (details.reason === "update") {
console.log("Extension updated");
}
});
13 changes: 13 additions & 0 deletions extension/public/contentScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.selectedText) {
generateQuestions(request.selectedText);
}
});

function generateQuestions(text) {
console.log("Generating questions for:", text);
chrome.storage.local.set({ "selectedText": text }, () => {
console.log('Questions stored in local storage:', text);
});
}

13 changes: 11 additions & 2 deletions extension/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
"name": "EduAid: AI Quiz Generator",
"version": "1.0",
"description": "Generate quizzes with AI-powered questions.",
"permissions": ["activeTab", "storage","sidePanel", "contextMenus"],
"permissions": ["activeTab", "storage", "sidePanel", "contextMenus", "scripting"],
"background": {
"service_worker": "background.js"
},
"side_panel": {
"default_path":"/src/pages/question/sidePanel.html"
},
Expand All @@ -26,5 +29,11 @@
"resources": ["static/js/*", "static/css/*", "src/assets/*"],
"matches": ["<all_urls>"]
}
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentScript.js"]
}
]
}
}
16 changes: 14 additions & 2 deletions extension/src/pages/answer/Answer.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "../../index.css";
import logo from "../../assets/aossie_logo.webp";
Expand All @@ -15,7 +15,16 @@ const Answer = () => {

const [isToggleOn, setIsToggleOn] = useState(1);
const [mode, setMode] = useState("ask_question"); // Dropdown state


useEffect(() => {
chrome.storage.local.get(["selectedText"], (result) => {
if (result.selectedText) {
console.log("Selected Text: ", result.selectedText);
setContext(result.selectedText);
localStorage.setItem("textContent", result.selectedText);
}
});
},[])

// const toggleSwitch = () => {
// window.location.href = "/src/pages/home/home.html";
Expand Down Expand Up @@ -112,6 +121,9 @@ const Answer = () => {
console.error("Error:", error);
} finally {
setLoading(false);
chrome.storage.local.remove(["selectedText"], () => {
console.log("Chrome storage cleared");
});
}
};

Expand Down
61 changes: 37 additions & 24 deletions extension/src/pages/text_input/TextInput.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useRef } from "react";
import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import "../../index.css";
import logo from "../../assets/aossie_logo.webp";
Expand All @@ -18,8 +18,19 @@ function Second() {
const [docUrl, setDocUrl] = useState('');
const [isToggleOn, setIsToggleOn] = useState(0);

useEffect(() => {
chrome.storage.local.get(["selectedText"], (result) => {
if (result.selectedText) {
console.log("Selected Text: ", result.selectedText);
setText(result.selectedText);
localStorage.setItem("textContent", result.selectedText);
}
});
}, [])


const toggleSwitch = () => {
setIsToggleOn((isToggleOn+1)%2);
setIsToggleOn((isToggleOn + 1) % 2);
};

const handleFileUpload = async (event) => {
Expand Down Expand Up @@ -52,7 +63,7 @@ function Second() {

const handleSaveToLocalStorage = async () => {
setLoading(true);

// Check if a Google Doc URL is provided
if (docUrl) {
try {
Expand All @@ -63,7 +74,7 @@ function Second() {
},
body: JSON.stringify({ document_url: docUrl })
});

if (response.ok) {
const data = await response.json();
setDocUrl("")
Expand All @@ -77,13 +88,16 @@ function Second() {
setText('Error retrieving Google Doc content');
} finally {
setLoading(false);
chrome.storage.local.remove(["selectedText"], () => {
console.log("Chrome storage cleared");
});
}
} else if (text) {
// Proceed with existing functionality for local storage
localStorage.setItem("textContent", text);
localStorage.setItem("difficulty", difficulty);
localStorage.setItem("numQuestions", numQuestions);

await sendToBackend(
text,
difficulty,
Expand Down Expand Up @@ -121,7 +135,7 @@ function Second() {
const formData = JSON.stringify({
input_text: data,
max_questions: numQuestions,
use_mediawiki : isToggleOn
use_mediawiki: isToggleOn
});
const response = await fetch(`http://localhost:5000/${endpoint}`, {
method: "POST",
Expand All @@ -130,26 +144,26 @@ function Second() {
"Content-Type": "application/json",
},
});

if (response.ok) {
const responseData = await response.json();
localStorage.setItem("qaPairs", JSON.stringify(responseData));

// Save quiz details to local storage
const quizDetails = {
difficulty,
numQuestions,
date: new Date().toLocaleDateString(),
qaPair:responseData
qaPair: responseData
};

let last5Quizzes = JSON.parse(localStorage.getItem('last5Quizzes')) || [];
last5Quizzes.push(quizDetails);
if (last5Quizzes.length > 5) {
last5Quizzes.shift(); // Keep only the last 5 quizzes
}
localStorage.setItem('last5Quizzes', JSON.stringify(last5Quizzes));

window.location.href = "/src/pages/question/question.html";
} else {
console.error("Backend request failed.");
Expand All @@ -160,7 +174,7 @@ function Second() {
setLoading(false);
}
};


return (
<div className="popup w-42rem h-35rem bg-[#02000F] flex justify-center items-center">
Expand All @@ -170,9 +184,8 @@ function Second() {
</div>
)}
<div
className={`w-full h-full bg-cust bg-opacity-50 bg-custom-gradient ${
loading ? "pointer-events-none" : ""
}`}
className={`w-full h-full bg-cust bg-opacity-50 bg-custom-gradient ${loading ? "pointer-events-none" : ""
}`}
>
<div className="flex items-end gap-[2px]">
<img src={logo} alt="logo" className="w-16 my-4 ml-4 block" />
Expand Down Expand Up @@ -285,15 +298,15 @@ function Second() {
</button>
</div>
<div className="items-center bg-[#202838] text-white rounded-xl px-2 py-2">
<Switch
checked={isToggleOn}
onChange={toggleSwitch}
offColor="#FF005C"
onColor="#00CBE7"
height={24}
width={44}
/>
</div>
<Switch
checked={isToggleOn}
onChange={toggleSwitch}
offColor="#FF005C"
onColor="#00CBE7"
height={24}
width={44}
/>
</div>
</div>
<div className="flex my-2 justify-center gap-6 items-start">
<div className="">
Expand Down

0 comments on commit 646d02b

Please sign in to comment.