Publishable Stuff

Rasmus Bååth's Blog


Call ChatGPT (or really any other API) from R

2023-03-03

It’s March 2023 and right now ChatGPT, the amazing AI chatbot tool from OpenAI, is all the rage. But when OpenAI released their public web API for ChatGPT on the 1st of March you might have been a bit disappointed. If you’re an R user, that is. Because, when scrolling through the release announcement you find that there is a python package to use this new API, but no R package.

I’m here to say: Don’t be disappointed! As long as there is a web API for a service then it’s going to be easy to use this service from R, no specialized package needed. So here’s an example of how to use the new (as of March 2023) ChatGPT API from R. But know that when the next AI API hotness comes out (likely April 2023, or so) then it’s going to be easy to interface with that from R, as well.

Calling the ChatGPT web API from R

To use the ChatGPT API in any way you first need to sign up and get an API key: The “password” you need to access the web API. It could look something like "sk-5xWWxmbnJvbWU4-M212Z2g5dzlu-MzhucmI5Yj-l4c2RkdmZ26". Of course, that’s not my real API key because that’s something you should keep secret!

With an API key at hand you now look up the documentation and learn that this is how you would send a request to the API from the terminal:

curl https://api.openai.com/v1/chat/completions \
 -H "Authorization: Bearer $OPENAI_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "model": "gpt-3.5-turbo",
 "messages": [{"role": "user", "content": "What is a banana?"}] 
 }'

But how do we send a request to the API using R? What we can do is to “replicate” this call using httr: a popular R package to send HTTP requests. Here’s how this request would be made using httr (with the curl lines as comments above the corresponding httr code)

library(httr)
api_key <- "sk-5xWW-replace-with-your-own-api-key-RkdmZ26"
response <- POST(
  # curl https://api.openai.com/v1/chat/completions 
  url = "https://api.openai.com/v1/chat/completions", 
  # -H "Authorization: Bearer $OPENAI_API_KEY"
  add_headers(Authorization = paste("Bearer", api_key)),
  # -H "Content-Type: application/json"
  content_type_json(),
  # -d '{
  #   "model": "gpt-3.5-turbo",
  #   "messages": [{"role": "user", "content": "What is a banana?"}] 
  # }'
  encode = "json",
  body = list(
    model = "gpt-3.5-turbo",
    messages = list(list(role = "user", content = "What is a banana?"))
  )
)

Even if you don’t know how curl and httr work you should be able to roughly see what’s going on here. The response now contains the metadata and the content of the response from ChatGPT which you access like so:

content(response)
$id
[1] "chatcmpl-6q4RKjGkL8YLsEZNgeG1GA0Mb6mus"

$object
[1] "chat.completion"

$created
[1] 1677868142

$model
[1] "gpt-3.5-turbo-0301"

$usage
$usage$prompt_tokens
[1] 14

$usage$completion_tokens
[1] 122

$usage$total_tokens
[1] 136

$choices
$choices[[1]]
$choices[[1]]$message
$choices[[1]]$message$role
[1] "assistant"

$choices[[1]]$message$content
[1] "\n\nA banana is a type of fruit that is usually elongated and
curved, with a soft, sweet flesh inside a yellow or green skin.
Bananas are rich in vitamins, minerals, fiber, and antioxidants, and
are a popular food around the world. They can be eaten raw, cooked,
or baked in a variety of dishes. Bananas are also used to make
drinks, smoothies, and desserts such as banana bread, banana pudding,
and banana split."

$choices[[1]]$finish_reason
[1] "stop"

$choices[[1]]$index
[1] 0

Buried in this response is the actual answer which we can extract, clean up (ChatGPT seems to start every answer with a double linebreak, for some reason), and print out:

chatGPT_answer <- content(response)$choices[[1]]$message$content
chatGPT_answer <- stringr::str_trim(chatGPT_answer)
cat(chatGPT_answer)
A banana is a type of fruit that is usually elongated and curved, with a soft,
sweet flesh inside a yellow or green skin. Bananas are rich in vitamins,
minerals, fiber, and antioxidants, and are a popular food around the world.
They can be eaten raw, cooked, or baked in a variety of dishes. Bananas are
also used to make drinks, smoothies, and desserts such as banana bread,
banana pudding, and banana split.

And that’s it! Now you have the latest and greatest AI powers at your fingertips in R! There are many more things you can do with the ChatGPT API (setting up elaborate prompts, continuing earlier conversations, etc.) but all are possible through a variant of the httr::POST call above.

All wrapped up in a function

If all you want is to send simple one-off requests to ChatGPT here is all of the above wrapped up in a handy function:

# How to call the new (as of 2023-03-01) ChatGPT API from R
# Get your API key over here: https://platform.openai.com/
api_key <- "sk-5-your-actual-api-key-Fvau6" # Don't share this! 😅

library(httr)
library(stringr)

# Calls the ChatGPT API with the given prompt and returns the answer
ask_chatgpt <- function(prompt) {
  response <- POST(
    url = "https://api.openai.com/v1/chat/completions", 
    add_headers(Authorization = paste("Bearer", api_key)),
    content_type_json(),
    encode = "json",
    body = list(
      model = "gpt-3.5-turbo",
      messages = list(list(
        role = "user", 
        content = prompt
      ))
    )
  )
  str_trim(content(response)$choices[[1]]$message$content)
}

Here’s how you could use it:

answer <- ask_chatgpt("What function makes a histogram in R?")
cat(answer)
The function that makes a histogram in R is "hist()".

Or why not use ChatGPT when you need some color inspiration? 🧟

fungal_green <- ask_chatgpt(
  "Answer only with the color hex code for 'fungal zombie green'"
)
print(fungal_green)
hist(rnorm(100), col = fungal_green)
[1] "#8B956D"

Posted by Rasmus Bååth | 2023-03-03 | Tags: R