First Upload
This commit is contained in:
commit
26fdcc9418
6
README.md
Normal file
6
README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
U need a working chatgpt with provisional chat function
|
||||||
|
Google Chrome tested
|
||||||
|
Not Settings yet
|
||||||
|
define your prompts in background.js for now
|
||||||
|
|
||||||
|
Samet G | 11/24
|
||||||
197
background.js
Normal file
197
background.js
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
let originTabId = null;
|
||||||
|
|
||||||
|
// Create context menu
|
||||||
|
chrome.runtime.onInstalled.addListener(() => {
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
id: "improveMail",
|
||||||
|
title: "Verbessere Mail",
|
||||||
|
contexts: ["selection"], // Show only when text is selected
|
||||||
|
});
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
id: "improveText",
|
||||||
|
title: "Verbessere Text",
|
||||||
|
contexts: ["selection"], // Show only when text is selected
|
||||||
|
});
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
id: "seoText",
|
||||||
|
title: "Erstelle ein SEO-Text",
|
||||||
|
contexts: ["selection"], // Show only when text is selected
|
||||||
|
});
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
id: "explainMe",
|
||||||
|
title: "Erkläre Text",
|
||||||
|
contexts: ["selection"], // Show only when text is selected
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Utility function to handle menu item click dynamically
|
||||||
|
function handleMenuItemClick(info, tab, prefixText) {
|
||||||
|
originTabId = tab.id;
|
||||||
|
|
||||||
|
if (info.selectionText) {
|
||||||
|
const selectedText = prefixText + info.selectionText;
|
||||||
|
|
||||||
|
chrome.tabs.create({ url: "https://chatgpt.com/?temporary-chat=true" }, (newTab) => {
|
||||||
|
chrome.tabs.onUpdated.addListener(function listener(tabId, info) {
|
||||||
|
if (tabId === newTab.id && info.status === "complete") {
|
||||||
|
chrome.tabs.onUpdated.removeListener(listener);
|
||||||
|
chrome.scripting.executeScript({
|
||||||
|
target: { tabId: newTab.id },
|
||||||
|
func: pasteToChatGPT,
|
||||||
|
args: [selectedText, newTab.id],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Handle context menu clicks
|
||||||
|
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||||
|
const menuActions = {
|
||||||
|
explainMe: 'Erkläre mir folgenden Text, fasse es kurz und gut lesbar zusammen. Erstelle keine eigenen Kommentare, zeige rein nur den text als Ausgabe: ',
|
||||||
|
improveMail: 'Verbessere folgende Mail, erstelle keine eigenen Kommentare, zeige rein nur den text als ausgabe: ',
|
||||||
|
improveText: 'Verbessere folgenden Text, mach es nicht viel länger oder kürzer als es jetzt schon ist, erstelle keine eigenen Kommentare, zeige rein nur den text als Ausgabe: ',
|
||||||
|
seoText: 'Du bist der Weltbeste SEO-Text Author. Schreibe einen SEO-optimierten Text mit 400-500 Wörtern basierend auf dem folgenden Inhalt. Identifiziere das Haupt-Keyword und integriere es mit einer Keyword-Dichte von 2-3 %. Strukturierte den Text mit HTML-Elementen (h1, h2, h3, p). Hebe das Keyword mit dem strong-Tag hervor. Gib nur den HTML-Code aus, ohne HTML-, Head- oder Body-Tags und ohne Kommentare. Die Ausgabe sollte als reiner Text erscheinen, nicht in einem Codefeld. Hier ist der relevante Text/Keyword: ',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (menuActions[info.menuItemId]) {
|
||||||
|
handleMenuItemClick(info, tab, menuActions[info.menuItemId]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Listen for a message to close the current tab and switch back
|
||||||
|
chrome.runtime.onMessage.addListener((message, sender) => {
|
||||||
|
if (message.action === "closeGPTAndSwitchBack") {
|
||||||
|
const currentTabId = sender.tab.id;
|
||||||
|
|
||||||
|
// Close the current tab
|
||||||
|
chrome.tabs.remove(currentTabId, () => {
|
||||||
|
console.log("Closed current tab:", currentTabId);
|
||||||
|
|
||||||
|
// Switch back to the original tab
|
||||||
|
if (originTabId) {
|
||||||
|
chrome.tabs.update(originTabId, { active: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Function to paste text into ChatGPT input and send it
|
||||||
|
function pasteToChatGPT(text, gptTab) {
|
||||||
|
const newChatButton = document.querySelector('a[href="/"]');
|
||||||
|
if (newChatButton) newChatButton.click();
|
||||||
|
let sendInterval;
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
const contentEditableDiv = document.querySelector('div[contenteditable="true"]');
|
||||||
|
if (contentEditableDiv) {
|
||||||
|
clearInterval(interval); // Stop retrying once the div is found
|
||||||
|
|
||||||
|
// Insert text into the contenteditable div
|
||||||
|
contentEditableDiv.innerHTML = `<p>${text}</p>`;
|
||||||
|
|
||||||
|
// Dispatch input events to trigger the mirroring mechanism
|
||||||
|
contentEditableDiv.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
|
||||||
|
sendInterval = setInterval(() => {
|
||||||
|
// Simulate clicking the Send button
|
||||||
|
const sendButton = document.querySelector('button[data-testid="send-button"]');
|
||||||
|
if (sendButton) {
|
||||||
|
clearInterval(sendInterval);
|
||||||
|
sendButton.click();
|
||||||
|
function fallbackCopyTextToClipboard(text) {
|
||||||
|
const textArea = document.createElement("textarea");
|
||||||
|
textArea.value = text;
|
||||||
|
textArea.style.position = "fixed"; // Prevent scrolling
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const successful = document.execCommand('copy');
|
||||||
|
console.log(successful ? "Fallback: Copied to clipboard!" : "Fallback: Failed to copy!");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Fallback: Could not copy text:", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
function waitForElement(selector, checkForDisappearance = false) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
const element = document.querySelector(selector);
|
||||||
|
if ((element && !checkForDisappearance) || (!element && checkForDisappearance)) {
|
||||||
|
observer.disconnect();
|
||||||
|
resolve(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Function to copy text to the clipboard with fallback
|
||||||
|
function copyTextToClipboard(text) {
|
||||||
|
function fallbackCopyTextToClipboard(text) {
|
||||||
|
const textArea = document.createElement("textarea");
|
||||||
|
textArea.value = text.trim(); // Ensure plain text without leading/trailing whitespace
|
||||||
|
textArea.style.position = "fixed"; // Prevent scrolling
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const successful = document.execCommand("copy");
|
||||||
|
console.log(successful ? "Fallback: Copied to clipboard!" : "Fallback: Failed to copy!");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Fallback: Could not copy text:", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (navigator.clipboard && document.hasFocus()) {
|
||||||
|
navigator.clipboard.writeText(text.trim())
|
||||||
|
.then(() => console.log("Copied to clipboard!"))
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Clipboard API failed, falling back:", err);
|
||||||
|
fallbackCopyTextToClipboard(text);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fallbackCopyTextToClipboard(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForElement('button[data-testid="stop-button"]').then(() => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
const stopButton = document.querySelector('button[data-testid="stop-button"]');
|
||||||
|
if (!stopButton) {
|
||||||
|
observer.disconnect();
|
||||||
|
setTimeout(() => { resolve(); }, 1500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
const assistantMessages = document.querySelectorAll('div[data-message-author-role="assistant"]');
|
||||||
|
const latestResponse = assistantMessages[assistantMessages.length - 1]?.innerText || "";
|
||||||
|
|
||||||
|
if (latestResponse) {
|
||||||
|
setTimeout(() => {
|
||||||
|
copyTextToClipboard(latestResponse)
|
||||||
|
console.log("Action complete. Closing tab...");
|
||||||
|
chrome.runtime.sendMessage({ action: "closeGPTAndSwitchBack" });
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Send button not found!");
|
||||||
|
}
|
||||||
|
}, 100); // Check every 100ms
|
||||||
|
}
|
||||||
|
}, 100); // Check every 100ms
|
||||||
|
let timeout = setTimeout(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
clearInterval(sendInterval);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
0
contentScript.css
Normal file
0
contentScript.css
Normal file
0
contentScript.js
Normal file
0
contentScript.js
Normal file
BIN
icon128.png
Normal file
BIN
icon128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
icon16.png
Normal file
BIN
icon16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1008 B |
BIN
icon48.png
Normal file
BIN
icon48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
44
manifest.json
Normal file
44
manifest.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "Real ChatGPT Extension",
|
||||||
|
"description": "Context Menu Action. Redirect selected text to ChatGPT browser tab, copy response, close tab & switch back to origin tab",
|
||||||
|
"author": "Samet G",
|
||||||
|
"permissions": [
|
||||||
|
"contextMenus",
|
||||||
|
"scripting",
|
||||||
|
"activeTab",
|
||||||
|
"tabs",
|
||||||
|
"clipboardWrite",
|
||||||
|
],
|
||||||
|
"host_permissions": [
|
||||||
|
"https://chatgpt.com/*"
|
||||||
|
],
|
||||||
|
"version": "0.1.1",
|
||||||
|
"manifest_version": 3,
|
||||||
|
"icons": {
|
||||||
|
"16": "icon16.png",
|
||||||
|
"48": "icon48.png",
|
||||||
|
"128": "icon128.png"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"default_popup": "popup.html",
|
||||||
|
"default_icon": {}
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"service_worker": "background.js"
|
||||||
|
},
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"matches": [
|
||||||
|
"http://*/*",
|
||||||
|
"https://*/*"
|
||||||
|
],
|
||||||
|
"run_at": "document_end",
|
||||||
|
"js": [
|
||||||
|
"contentScript.js"
|
||||||
|
],
|
||||||
|
"css": [
|
||||||
|
"contentScript.css"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
34
popup.css
Normal file
34
popup.css
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: Sora;
|
||||||
|
src: url(./dist/sora.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 500px;
|
||||||
|
height: 200px;
|
||||||
|
min-width: 500px;
|
||||||
|
min-height: 200px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: #F2DE62;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
padding: 30px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Sora';
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Sora';
|
||||||
|
}
|
||||||
16
popup.html
Normal file
16
popup.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Chrome extension</title>
|
||||||
|
<link rel="stylesheet" href="popup.css">
|
||||||
|
<script defer src="popup.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Great!</h1>
|
||||||
|
<p>Your extension is ready<br>you can go to <a target="_blank" href="https://developer.chrome.com/docs/extensions/">https://developer.chrome.com/docs/extensions/</a> to learn more about chrome extensions</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user