A PopClip extension for ChatGPT

Hi! Is there any functional for replacing a selected text?

I have an idea: the extension for ChatGPT which sent a selected text with promts (I mean command for ChatGPT what it needs to do with text, for example “Simplify this text so that it’s easier to understand”) to ChatGPT via API and it will be replaced the selected text by the received response.

For example. I’m writing a email and select the text, then click the icon of the extension and the text will be replaced by the generated ChatGPT text.

May I get some advices how to do that?

7 Likes

Great idea; it could be really powerful. What PopClip would need is an API for sending queries to ChatGPT. So the first task is to research whether ChatGPT provides an API.

Edit: Had a look, yes it does, so the next step is to play with the API a bit to figure out how we will use it in PopClip. I’ll certainly take a look later.

2 Likes

There is Shortcut example what I use at the moment with PopClip. I hope it’ll be hopeful!

1 Like

OK wow, so this thing is amazing :sob:

CleanShot 2023-02-02 at 09.36.52

OpenAI has an API that is simple to use. It doesn’t offer access to ChatGPT itself yet, but it does offer the GPT-3 model, which is what ChatGPT is built on. There are so many capabilities and options you could go to town with it. But here, I have made a simple example that completes a prompt you give it. Have a go, let me know any feedback, and I’ll probably release it as a pre-packaged extension soon too.

You’ll need to get your own API key from https://platform.openai.com/account/api-keys.

(Update 1 Mar 2023: New API just dropped, see below updated script for ChatGPT)

// #popclip
// name: GPT-3
// icon: iconify:eos-icons:ai
// language: javascript
// after: paste-result
// entitlements: [network]
// options: [{identifier: apikey, label: API Key, type: string,
//   description: 'Obtain API key from https://platform.openai.com/account/api-keys'}] 
const axios = require("axios");
// base object for communicating with OpenAI
const openai = axios.create({
  baseURL: 'https://api.openai.com/v1/',
  headers: { Authorization: `Bearer ${popclip.options.apikey}` }
});
// use the GPT-3 model (note - can change/add other params here)
const data = {
  model: 'text-davinci-003',
  max_tokens: 512,
  prompt: popclip.input.text
};
// send query to OpenAI's `completions` service
const response = await openai.post('completions', data);
// return the first text in the response
return popclip.input.text + response.data.choices[0].text;

(The above block is an extension snippet - select the text it then click “Install Extension” when PopClip appears.)

How to install this:
CleanShot 2023-02-02 at 09.57.52

Test result :rofl::

When they release ChatGPT to the API, this could presumably be extended to make it maintain a dialogue with a series of invocations.

8 Likes

Hi nice idea !
i will try this code, but i have got a “invalid YAML” in popclip no install message.
thanks !

What PopClip version are your running? You will need the latest, v2022.12.

1 Like

Hi! In the snippet above, where do I enter my API key?? Thanks!

The snippet defines a configuration option for entering the API key. You should see the window to enter it after you install the extension. Thus:
CleanShot 2023-02-22 at 09.26.09@2x

I think a fixed prompt version of this may be very useful. Just as a proof of concept:

// #popclip
// name: OpenAI - Fixed Prompt
// icon: P
// language: javascript
// after: paste-result
// entitlements: [network]
// options:
// - {identifier: apikey, label: API Key, type: string,
//    description: 'Obtain API key from https://platform.openai.com/account/api-keys'}
// - {identifier: prompt, label: Prompt, type: string,
//    defaultValue: "Summarise the following in fewer words"}
const openai = require("axios").create({
  baseURL: 'https://api.openai.com/v1/',
  headers: { Authorization: `Bearer ${popclip.options.apikey}` }
});
const data = {
  model: 'text-davinci-003',
  max_tokens: 512,
  prompt: popclip.options.prompt + ":\n\n" + popclip.input.text
};
const response = await openai.post('completions', data);
return response.data.choices[0].text.trim();

Example (with the default prompt “Summarise the following in fewer words”):

CleanShot 2023-02-22 at 12.56.12

I used this same concept to make a German Sentence Case extension.

2 Likes

Hey @nick, Not sure what I’m doing wrong. For me it spins a bit but nothing happens. The API seems be called as indicated by OpenAI (key has been used). Any places I might check?

1 Like

You could enable extension debug output by pasting the following command in Terminal:

defaults write com.pilotmoon.popclip EnableExtensionDebug -bool YES

then Quit and restart PopClip.

(note, substitute com.pilotmoon.popclip-setapp if using Setapp edition)

Then open Console app and set the following filters process: PopClip, category: Extension

Now set Console to “Start” & “Now” you should see the API calls going in and the responses. You can also add debug using print(), e.g. such as print("varname:", varname); in the code if that helps.

Thanks @nick, that helped. Turns out my paid ChatGPT account didn’t cover API calls; I needed to add that separately. Now it seems to work.

1 Like

Ahh! Good to know. I have the paid ChatGPT too and wasn’t sure whether that linked up with the API service. So they are separate.

Looks like the API comes with 3 months free credit then you have to pay on a per usage model at $0.02 per 1000 tokens (1 token = about half a word).

1 Like

Interesting! I’m still getting used to ChatGPT and to think of new possibilities, it’s such an amazing tool. It would be nice to have a more versatile plugin where you can predefine multiple prompts, like “Summarize” or “Translate to Dutch”, essentially any prompt that someone can come up with. Just floating there idea out here… :wink:

1 Like

This is great. Thanks for putting the extension together @nick! I’ve been using the shortcut that’s been floating around but super handy to have the direct code (davinci-003) in popclip.

1 Like

@nick whelp it appears openai literally just released an api to chatgpt which is big news - time to update the script!

1 Like

Ooh. Here are the docs. A quick first attempt using the simplest possible approach:

// #popclip
// name: GPT-3.5
// icon: iconify:logos:openai-icon
// language: javascript
// after: paste-result
// entitlements: [network]
// options: [{
//   identifier: apikey, label: API Key, type: string,
//   description: 'Obtain API key from https://platform.openai.com/account/api-keys'
// }] 
const openai = require("axios").create({
  baseURL: 'https://api.openai.com/v1/',
  headers: { Authorization: `Bearer ${popclip.options.apikey}` }
});
const params = {
  model: 'gpt-3.5-turbo',
  messages: [{ "role": "user", "content": popclip.input.text }]
};
const { data }  = await openai.post('chat/completions', params);
return popclip.input.text + data.choices[0].message.content;

It uses the newly released gpt-3.5-turbo model, but it only works as a “one shot” question i.e. it doesn’t remember what the previous chat was. I need to look a bit more closely to see how to do that.

1 Like

OK, here is a snippet for the “real thing” ChatGPT, that you can actually chat with.

Update, 3 Mar 2023: A pre-packaged version of this extension is now available.

To use it, you’ll need to sign up for an OpenAI platform account, and get your own API key from https://platform.openai.com/account/api-keys .

// #popclip extension for ChatGPT
// name: ChatGPT
// icon: iconify:simple-icons:openai
// language: javascript
// module: true
// entitlements: [network]
// options: [{
//   identifier: apikey, label: API Key, type: string,
//   description: 'Obtain API key from https://platform.openai.com/account/api-keys'
// }]
const messages = []; // history of previous messages
async function chat (input, options) {
  const openai = require("axios").create({
    baseURL: "https://api.openai.com/v1",
    headers: { Authorization: `Bearer ${options.apikey}` },
  });
  messages.push({ "role": "user", "content": input.text });
  const { data } = await openai.post("/chat/completions", {
    model: "gpt-3.5-turbo", messages
  });
  messages.push(data.choices[0].message);
  return input.text.trimEnd() + "\n\n" + messages.at(-1).content.trim();
};
exports.actions = [{
  title: "ChatGPT: Chat",
  after: "paste-result",
  code: chat,
}, {
  title: "ChatGPT: Reset",
  icon: "iconify:game-icons:broom",
  requirements: [],
  after: "show-status",
  code: () => messages.length = 0 // clear the message history
}];

(The above block is an extension snippet – select the text then click “Install Extension” in PopClip.)

How to install it:
CleanShot 2023-02-02 at 09.57.52

Note there are two actions, Chat and Reset.

Chat (main icon): Type your message in any text field, select it so PopClip appears and choose the Chat action. After ChatGPT responds, type your response and repeat.

Reset (broom icon): click it whenever you need to start a new chat and forget the previous responses.

CleanShot 2023-03-01 at 21.08.55

I had to break out the module syntax (which I still haven’t properly documented) for this one because the extension itself has to remember the past messages in the chat and provide the whole thing to the API each time. But it’s really a very straightforward API to use.

3 Likes

Brilliant!

1 Like

2 posts were split to a new topic: “XmlHTTPRequest is not allowed here”