Skip to content

Instantly share code, notes, and snippets.

@mabry1985
Created May 10, 2023 17:51
Show Gist options
  • Save mabry1985/61b1632bf0189a4402a42987c2f870f8 to your computer and use it in GitHub Desktop.
Save mabry1985/61b1632bf0189a4402a42987c2f870f8 to your computer and use it in GitHub Desktop.
/*
# Prompt Anything
Highlight some text and run this script to prompt against it.
Useful for summarizing text, generating a title, or any other task you can think of.
## Usage
- Highlight the text you want to prompt against
- Run the script via shortcut or command palette
- Input your desired prompt
- Wait for the AI to respond
- Select one of the options
* Retry - Rerun generation with option to update prompt
* Edit - Edit response in editor
- On editor exit the message is saved to the clipboard
- On editor submit the message is pasted into the highlighted text
* Copy - Copy response to clipboard
* Paste - Paste response into highlighted text
* Save - Save response to file (not working)
## Example
- Highlight: 'Some really long passage in a blog post'
- Run Script
- Prompt: `Summarize this passage in the form of Shakespearean prose`
- Waaaaait for it...
- Get a response from the AI
- Select an option
- Rinse and repeat
*/
// Name: Prompt Anything
// Description: Custom prompt for any highlighted text
// Author: Josh Mabry
// Twitter: @AI_Citizen
// Shortcut: alt shift enter
//##################
// ScriptKit Imports
//##################
import "@johnlindquist/kit";
//##################
// LangChain Imports
//##################
let { ChatOpenAI } = await import("langchain/chat_models");
let { HumanChatMessage, SystemChatMessage } = await import("langchain/schema");
//#################
// Request API KEY
//#################
// stored in .env file after first run
// can change there or through the command palette
let openAIApiKey = await env("OPENAI_API_KEY", {
hint: `Grab a key from <a href="https://platform.openai.com/account/api-keys">here</a>`,
});
const prompts = await db("prompts");
prompts.read();
const promptChoices = Object.entries(prompts.data.snips).map(([key, value]) => {
return { name: value.name, value: value.snippet };
});
// System input / Task for the AI to follow
let userSystemInput = await arg("Summarize this passage", promptChoices);
// User Prompt from highlighted text
let userPrompt = await getSelectedText();
//#################
// Prompt Template
//#################
const formatPrompt = (prompt) => {
return `##### Ignore prior instructions
- Return answer in markdown format
- You are tasked with the following
${prompt}
########
`;
};
//################
// Options Template
//################
// @TODO: styling
const options = `
* [Retry](submit:retry) - Rerun generation with option to update prompt
* [Edit](submit:edit) - Edit response in editor
* [Copy](submit:copy) - Copy response to clipboard
* [Paste](submit:paste) - Paste response into highlighted text
* [Save](submit:save) - Save response to file (not working)
`;
//################
// Main Function
//################
/**
*
* @param {*} prompt
* @param {*} humanChatMessage
*/
async function promptAgainstHighlightedText(
prompt = formatPrompt(userSystemInput),
humanChatMessage = userPrompt
) {
//#########
// Helpers
//########
// exit script on cancel
const cancelChat = () => {
exit(1);
};
/**
* Paste text to highlighted text and exit script
* @param {*} text
*/
const pasteTextAndExit = async (text) => {
await setSelectedText(text);
exit(1);
};
/**
* Copy text to clipboard and exit script
* @param {*} text
*/
const copyToClipboardAndExit = async (text) => {
await clipboard.writeText(currentMessage);
exit(1);
};
let currentMessage = "";
let toast = null;
const llm = new ChatOpenAI({
// 0 = "precise", 1 = "creative"
temperature: 0.3,
// modelName: "gpt-4", // uncomment to use GPT-4 (requires beta access)
openAIApiKey: openAIApiKey,
// turn off to only get output when the AI is done
streaming: true,
callbacks: [
{
handleLLMStart: async () => {
log(`handleLLMStart`);
toast = toast(`Generating...`, { duration: 1000 });
// render initial message
},
handleLLMNewToken: async (token) => {
// log(`handleLLMNewToken`);
// each new token is appended to the current message
// and then rendered to the screen
currentMessage += token;
// render current message
await div({
html: md(currentMessage),
// @TODO: Figure out how to get ESC to trigger a cancel
onAbandon: cancelChat,
onEscape: cancelChat,
onBackspace: cancelChat,
// if this is set to false you can click outside the window to cancel
// which works, but would be nice to also have ESC work
ignoreBlur: false,
focus: true,
// hint: `Press ESC to cancel`,
});
},
handleLLMError: async (err) => {
dev({ err });
},
handleLLMEnd: async () => {
log(`handleLLMEnd`);
// render final message with options
let html = md(currentMessage + options);
// wait for user to select an option
const selectedOption = await div(html, {
ignoreBlur: true,
focus: true,
// have paste on text on submit?
// onSubmit: () => pasteTextAndExit(currentMessage),
});
// handle selected option
switch (selectedOption) {
case "paste":
await pasteTextAndExit(currentMessage);
case "retry":
// reset current message
currentMessage = "";
// prompt again with new prompt
// press enter to use original prompt
const followUp = await arg({
hint: "Update prompt and try again",
});
log({ followUp });
await processMessage(followUp);
break;
case "edit":
// @TODO still need to figure out best way to handle submit and abort
// would like custom buttons for triggering all of the actions like copy, paste, etc
await editor({
value: currentMessage,
onEscape: async (state) => await copyToClipboardAndExit(state),
onSubmit: async (state) => await pasteTextAndExit(state),
});
break;
case "copy":
await copyToClipboardAndExit(currentMessage);
case "save":
await inspect(currentMessage, `/conversations/${Date.now()}.md`);
exitChat();
default:
copyToClipboardAndExit(currentMessage);
}
await optionHandler(selectedOption);
},
},
],
});
//###########
// Main Loop
//###########
// runs the language model until the user cancels
while (true) {
await llm.call([
new SystemChatMessage(formatPrompt(prompt)),
new HumanChatMessage(humanChatMessage),
]);
}
}
promptAgainstHighlightedText();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment