Created
May 5, 2023 06:22
-
-
Save mabry1985/6c2412d4d3d1360276b9d95f44548815 to your computer and use it in GitHub Desktop.
This file contains 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
/* | |
# 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