Last active
May 8, 2024 17:38
-
-
Save PeronGH/209678c5ea0f228344ea2c76bb5e9850 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Claude Plus | |
// @namespace https://gist.github.com/PeronGH/209678c5ea0f228344ea2c76bb5e9850 | |
// @version 1.0.3 | |
// @description Enhance your Claude experiences | |
// @author Peron | |
// @match https://claude.ai/chats | |
// @match https://claude.ai/chat/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=claude.ai | |
// @grant GM_registerMenuCommand | |
// @grant GM_openInTab | |
// @grant GM_setValue | |
// @grant GM_getValue | |
// @downloadURL https://gist.github.com/PeronGH/209678c5ea0f228344ea2c76bb5e9850/raw/claude-plus.user.js | |
// @updateURL https://gist.github.com/PeronGH/209678c5ea0f228344ea2c76bb5e9850/raw/claude-plus.user.js | |
// ==/UserScript== | |
(async () => { | |
"use strict"; | |
// Constants | |
const DEFAULT_INSTRUCTIONS = ` | |
You are Claude. Follow the instructions closely in future responses: | |
1. You should not include any caveats or disclaimers in your responses. | |
2. Your responses should be written in the style of a blogger or Stack Overflow answer - using simple, clear language and avoiding overcomplicated words or sentence structures. The tone should be natural, professional and comprehensive. | |
3. Rather than taking a neutral or diplomatic stance, you aim to be definitive, specific and personal. | |
4. You should engage with the user as an equal, avoiding a lecturing or condescending tone. Instead of obeying the user in every way, you should think critically and argue your point of view. | |
`.trim(); | |
const CUSTOM_INSTRUCTIONS_KEY = "custom_instructions"; | |
// Prepare GM functions | |
const GM_registerMenuCommand = window.GM_registerMenuCommand ?? | |
GM.registerMenuCommand; | |
const GM_openInTab = window.GM_openInTab ?? GM.openInTab; | |
const GM_setValue = window.GM_setValue ?? GM.setValue; | |
const GM_getValue = window.GM_getValue ?? GM.getValue; | |
// Helpers | |
const extractTextFromElement = (el) => { | |
let reactPropsKey; | |
for (const key in el) { | |
if (key.startsWith("__reactProps")) { | |
reactPropsKey = key; | |
break; | |
} | |
} | |
return el[reactPropsKey]?.children?.props?.text ?? el.textContent; | |
}; | |
const findUserMessages = () => | |
Array.from(document.querySelectorAll("div.font-user-message")) | |
.map((el) => el.textContent); | |
const findClaudeMessages = () => | |
Array.from(document.querySelectorAll("div.font-claude-message")) | |
.map(extractTextFromElement); | |
const getCustomInstructions = () => | |
GM_getValue(CUSTOM_INSTRUCTIONS_KEY, DEFAULT_INSTRUCTIONS); | |
const setCustomInstructions = (instructions) => | |
GM_setValue(CUSTOM_INSTRUCTIONS_KEY, instructions); | |
/** Upload to ShareGPT */ | |
const UploadToShareGPT = async () => { | |
const userMessages = findUserMessages(); | |
const claudeMessages = findClaudeMessages(); | |
if (userMessages.length === 0 || claudeMessages.length === 0) { | |
throw new Error("No messages found"); | |
} | |
console.debug({ userMessages, claudeMessages }); | |
const conversationData = { | |
model: "Claude 3", | |
items: [], | |
}; | |
for (let i = 0; i < userMessages.length; i++) { | |
conversationData.items.push({ | |
from: "human", | |
value: userMessages[i].trim(), | |
}); | |
if (claudeMessages[i]) { | |
conversationData.items.push({ | |
from: "gpt", | |
value: claudeMessages[i].trim(), | |
}); | |
} | |
} | |
console.debug({ conversationData }); | |
const res = await fetch("https://sharegpt.com/api/conversations", { | |
body: JSON.stringify(conversationData), | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
method: "POST", | |
}); | |
if (!res.ok) { | |
throw new Error("Failed to upload conversation to ShareGPT"); | |
} | |
const { id } = await res.json(); | |
const url = `https://shareg.pt/${id}`; | |
GM_openInTab(url); | |
}; | |
let isModalOpen = false; | |
/** Render custom instructions input */ | |
const RenderCustomInstructionsInput = () => { | |
if (isModalOpen) return; | |
isModalOpen = true; | |
// create elements | |
const dialog = document.createElement("dialog"); | |
const form = document.createElement("form"); | |
const textarea = document.createElement("textarea"); | |
const buttonDiv = document.createElement("div"); | |
const submitButton = document.createElement("button"); | |
const cancelButton = document.createElement("button"); | |
// create basic layout | |
buttonDiv.appendChild(submitButton); | |
buttonDiv.appendChild(cancelButton); | |
form.appendChild(textarea); | |
form.appendChild(buttonDiv); | |
dialog.appendChild(form); | |
dialog.addEventListener("close", () => { | |
dialog.remove(); | |
isModalOpen = false; | |
}); | |
document.body.appendChild(dialog); | |
// Set attributes | |
textarea.value = getCustomInstructions(); | |
textarea.rows = 5; | |
submitButton.textContent = "Save"; | |
submitButton.type = "submit"; | |
cancelButton.textContent = "Cancel"; | |
cancelButton.type = "button"; | |
cancelButton.addEventListener("click", () => dialog.close()); | |
form.addEventListener("submit", (e) => { | |
e.preventDefault(); | |
setCustomInstructions(textarea.value); | |
dialog.close(); | |
}); | |
// add styles | |
buttonDiv.classList.add("flex", "justify-between"); | |
// present modal | |
dialog.showModal(); | |
}; | |
const ApplyCustomInstructions = () => { | |
const fileInput = document.querySelector( | |
'input[data-testid="file-upload"]', | |
); | |
if (!fileInput) { | |
alert("Unable to find file input"); | |
return; | |
} | |
const file = new File( | |
[getCustomInstructions()], | |
"Claude_Instructions.md", | |
{ type: "text/markdown" }, | |
); | |
const dataTransfer = new DataTransfer(); | |
dataTransfer.items.add(file); | |
fileInput.files = dataTransfer.files; | |
fileInput.dispatchEvent(new Event("change", { bubbles: true })); | |
}; | |
// Main | |
// register menu commands | |
GM_registerMenuCommand( | |
"Apply Custom Instructions", | |
() => ApplyCustomInstructions(), | |
"a", | |
); | |
GM_registerMenuCommand( | |
"Upload to ShareGPT", | |
() => | |
UploadToShareGPT().catch((err) => | |
alert("Error uploading to ShareGPT: " + err.message) | |
), | |
"u", | |
); | |
GM_registerMenuCommand( | |
"Set Custom Instructions", | |
() => RenderCustomInstructionsInput(), | |
"s", | |
); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment