Skip to content

Instantly share code, notes, and snippets.

@mabry1985
Created May 5, 2023 06:22
Show Gist options
  • Save mabry1985/6c2412d4d3d1360276b9d95f44548815 to your computer and use it in GitHub Desktop.
Save mabry1985/6c2412d4d3d1360276b9d95f44548815 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 Import
//#################
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>`,
});
// System input / Task for the AI to follow
let userSystemInput = await arg("Summarize this passage");
// 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
//################
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)
`;
//#########
// Helpers
//########
// exit script on cancel
const cancelChat = () => {
process.exit(1);
};
//################
// Main Function
//################
/**
*
* @param {*} prompt
* @param {*} humanChatMessage
*/
async function promptAgainstHighlightedText(
prompt = formatPrompt(userSystemInput),
humanChatMessage = userPrompt
) {
let currentMessage = "";
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: [
{
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 + options),
// @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
// ignoreBlur: true,
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,
// onSubmit: () => setSelectedText(currentMessage),
});
// handle selected option
switch (selectedOption) {
case "paste":
// paste into highlighted text
await setSelectedText(currentMessage);
process.exit(1);
case "retry":
// reset current message
currentMessage = "";
// prompt again with new prompt
// press enter to use original prompt
const followUp = await arg({
placeholder: userSystemInput,
hint: "Press enter to use the same prompt",
});
await processMessage(followUp);
break;
case "edit":
// still need to figure out best way to handle submit and abort
// would like custom buttons for triggering all these same options such as save
await editor({
value: currentMessage,
onEscape: async (state) => {
// copy to clipboard when exiting the editor
await clipboard.writeText(state);
// exit script
process.exit(1);
},
onSubmit: async (state) => {
// paste into highlighted text when pressing enter
await setSelectedText(state);
// exit script
process.exit(1);
},
});
break;
case "copy":
// copy to clipboard
await clipboard.writeText(currentMessage);
// exit script
process.exit(1);
case "save":
await inspect(currentMessage, `conversations/${Date.now()}.md`);
// exit script
process.exit(1);
default:
// copy to clipboard
await clipboard.writeText(currentMessage);
process.exit(1);
}
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