diff --git a/DESCRIPTION b/DESCRIPTION index 8082193..30a1fd6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: chatgpt Type: Package Title: Interface to 'ChatGPT' from R -Version: 0.2.2 +Version: 0.2.3 Authors@R: c( person( given = "Juan Cruz", family = "Rodriguez", role = c("aut", "cre"), diff --git a/NAMESPACE b/NAMESPACE index 2727702..1b48be6 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,11 +10,13 @@ export(explain_code) export(find_issues_in_code) export(optimize_code) export(refactor_code) +export(reset_chat_session) importFrom(clipr,read_clip) importFrom(httr,POST) importFrom(httr,add_headers) importFrom(httr,content) importFrom(httr,content_type_json) +importFrom(httr,use_proxy) importFrom(jsonlite,toJSON) importFrom(miniUI,gadgetTitleBar) importFrom(miniUI,miniPage) @@ -25,6 +27,7 @@ importFrom(shiny,actionButton) importFrom(shiny,br) importFrom(shiny,icon) importFrom(shiny,observeEvent) +importFrom(shiny,onStop) importFrom(shiny,runGadget) importFrom(shiny,stopApp) importFrom(shiny,textAreaInput) diff --git a/R/addins.R b/R/addins.R index f78b9c3..4f2925f 100644 --- a/R/addins.R +++ b/R/addins.R @@ -36,7 +36,7 @@ run_addin <- function(addin_name) { } modifyRange(doc_range, out, doc_context$id) } else if (as.logical(Sys.getenv("OPENAI_VERBOSE", TRUE))) { - cat(paste0("\n*** ChatGPT output:\n\n", out, "\n")) + message(paste0("\n*** ChatGPT output:\n\n", out, "\n")) } else { warning("Please set one of `OPENAI_ADDIN_REPLACE=TRUE` or `OPENAI_VERBOSE=TRUE`") } @@ -58,11 +58,12 @@ run_addin_refactor_code <- function() run_addin("refactor_code") #' Opens an interactive chat session with ChatGPT #' #' @importFrom miniUI gadgetTitleBar miniPage -#' @importFrom shiny actionButton br icon observeEvent runGadget stopApp textAreaInput +#' @importFrom shiny actionButton br icon observeEvent onStop runGadget stopApp textAreaInput #' @importFrom shiny updateTextAreaInput wellPanel #' @importFrom utils getFromNamespace #' run_addin_ask_chatgpt <- function() { + reset_chat_session() ui <- miniPage(wellPanel( gadgetTitleBar("Ask ChatGPT", NULL), textAreaInput("question", "Question:", width = "100%", height = "150px"), @@ -74,11 +75,15 @@ run_addin_ask_chatgpt <- function() { observeEvent(input$ask_button, { chatgpt_reply <- ask_chatgpt(input$question) if (as.logical(Sys.getenv("OPENAI_VERBOSE", TRUE))) { - cat(paste0("\n*** ChatGPT output:\n\n", chatgpt_reply, "\n")) + message(paste0("\n*** ChatGPT output:\n\n", chatgpt_reply, "\n")) } updateTextAreaInput(session, "answer", value = chatgpt_reply) }) - observeEvent(input$done, stopApp()) + observeEvent(input$done, { + reset_chat_session() + stopApp() + }) + onStop(reset_chat_session) } runGadget(ui, server) } diff --git a/R/ask_chatgpt.R b/R/ask_chatgpt.R index f11ab05..7b7a7c7 100644 --- a/R/ask_chatgpt.R +++ b/R/ask_chatgpt.R @@ -1,5 +1,7 @@ #' Ask ChatGPT #' +#' Note: See also `reset_chat_session`. +#' #' @param question The question to ask ChatGPT. #' #' @examples @@ -12,5 +14,16 @@ #' @export #' ask_chatgpt <- function(question) { - parse_response(gpt_get_completions(question)) + # Get the existing chat session messages, and add the new message. + chat_session_messages <- append(get("chat_session_messages", envir = .state), list( + list(role = "user", content = question) + )) + # Send the query to ChatGPT. + chat_gpt_reply <- parse_response(gpt_get_completions(question, messages = chat_session_messages)) + chat_session_messages <- append(chat_session_messages, list( + list(role = "assistant", content = chat_gpt_reply) + )) + # Update the chat session messages with the new question and the reply. + assign("chat_session_messages", chat_session_messages, .state) + chat_gpt_reply } diff --git a/R/chatgpt-package.R b/R/chatgpt-package.R new file mode 100644 index 0000000..f316fd8 --- /dev/null +++ b/R/chatgpt-package.R @@ -0,0 +1,13 @@ +#' 'OpenAI's 'ChatGPT' coding assistant for 'RStudio'. A set +#' of functions and 'RStudio' addins that aim to help the R developer in tedious coding tasks. +#' +"_PACKAGE" + +.state <- new.env(parent = emptyenv()) + +# Empty chat session messages at startup. +assign( + "chat_session_messages", + list(list(role = "system", content = "You are a helpful assistant.")), + envir = .state +) diff --git a/R/create_unit_tests.R b/R/create_unit_tests.R index 1b6c0cd..4ef3f8e 100644 --- a/R/create_unit_tests.R +++ b/R/create_unit_tests.R @@ -19,7 +19,7 @@ create_unit_tests <- function(code = clipr::read_clip(allow_non_interactive = TRUE)) { code <- paste(gsub('"', "'", code), collapse = "\n") prompt <- paste0( - 'Using testthat 3e, version over 3.0.0, create a full testthat file, with test cases for the ', + "Using testthat 3e, version over 3.0.0, create a full testthat file, with test cases for the ", 'following R code: "', code, '"' ) parse_response(gpt_get_completions(prompt)) diff --git a/R/gpt_get_completions.R b/R/gpt_get_completions.R index 9b16c66..1e627f6 100644 --- a/R/gpt_get_completions.R +++ b/R/gpt_get_completions.R @@ -2,19 +2,19 @@ #' #' @param prompt The prompt to generate completions for. #' @param openai_api_key OpenAI's API key. +#' @param messages Available variable, to send the needed messages list to ChatGPT. #' -#' @importFrom httr add_headers content content_type_json POST +#' @importFrom httr add_headers content content_type_json POST use_proxy #' @importFrom jsonlite toJSON #' -gpt_get_completions <- function(prompt, openai_api_key = Sys.getenv("OPENAI_API_KEY")) { +gpt_get_completions <- function(prompt, openai_api_key = Sys.getenv("OPENAI_API_KEY"), + messages = NULL) { if (nchar(openai_api_key) == 0) { stop("`OPENAI_API_KEY` not provided.") } - # See https://platform.openai.com/docs/api-reference/chat - # and https://beta.openai.com/docs/api-reference/completions/create - model <- Sys.getenv("OPENAI_MODEL", "gpt-3.5-turbo") + # See https://platform.openai.com/docs/api-reference/chat . params <- list( - model = model, + model = Sys.getenv("OPENAI_MODEL", "gpt-3.5-turbo"), max_tokens = as.numeric(Sys.getenv("OPENAI_MAX_TOKENS", 256)), temperature = as.numeric(Sys.getenv("OPENAI_TEMPERATURE", 1)), top_p = as.numeric(Sys.getenv("OPENAI_TOP_P", 1)), @@ -22,13 +22,13 @@ gpt_get_completions <- function(prompt, openai_api_key = Sys.getenv("OPENAI_API_ presence_penalty = as.numeric(Sys.getenv("OPENAI_PRESENCE_PENALTY", 0)) ) if (as.logical(Sys.getenv("OPENAI_VERBOSE", TRUE))) { - cat(paste0("\n*** ChatGPT input:\n\n", prompt, "\n")) + message(paste0("\n*** ChatGPT input:\n\n", prompt, "\n")) } - if (grepl("gpt-3.5-turbo", model)) { - return_language <- Sys.getenv("OPENAI_RETURN_LANGUAGE") - if (nchar(return_language) > 0) { - return_language <- paste0("You return all your replies in ", return_language, ".") - } + return_language <- Sys.getenv("OPENAI_RETURN_LANGUAGE") + if (nchar(return_language) > 0) { + return_language <- paste0("You return all your replies in ", return_language, ".") + } + if (is.null(messages)) { messages <- list( list( role = "system", @@ -39,22 +39,49 @@ gpt_get_completions <- function(prompt, openai_api_key = Sys.getenv("OPENAI_API_ ), list(role = "user", content = prompt) ) + } else { + # If there are messages provided, then add the `return_language` if available. + messages[[which(sapply(messages, function(message) message$role == "system"))]]$content <- + paste( + messages[[which(sapply(messages, function(message) message$role == "system"))]]$content, + return_language + ) + } + # Get the proxy to use, if provided. + proxy <- NULL + if (nchar(Sys.getenv("OPENAI_PROXY")) > 0) { + proxy <- Sys.getenv("OPENAI_PROXY") + if (grepl("^(?:\\d{1,3}\\.){3}\\d{1,3}:\\d{2,5}$", proxy)) { + proxy <- use_proxy(gsub(":.*", "", proxy), as.numeric(gsub(".*:", "", proxy))) + } else { + stop("Invalid proxy provided in `OPENAI_PROXY`: ", proxy) + } + } + # Run the API query. + final_res <- list() + keep_querying <- TRUE + while (keep_querying) { post_res <- POST( "https://api.openai.com/v1/chat/completions", add_headers("Authorization" = paste("Bearer", openai_api_key)), content_type_json(), - body = toJSON(c(params, list(messages = messages)), auto_unbox = TRUE) + body = toJSON(c(params, list(messages = messages)), auto_unbox = TRUE), + proxy ) - } else { - post_res <- POST( - "https://api.openai.com/v1/completions", - add_headers("Authorization" = paste("Bearer", openai_api_key)), - content_type_json(), - body = toJSON(c(params, list(prompt = prompt)), auto_unbox = TRUE) + if (!post_res$status_code %in% 200:299) { + stop(content(post_res)) + } + post_res <- content(post_res) + final_res <- append(final_res, list(post_res)) + # In the case the finish_reason is the length of the message, then we need to keep querying. + keep_querying <- all(sapply(post_res$choices, function(x) x$finish_reason == "length")) + # And update the messages sent to ChatGPT, in order to continue the current session. + messages <- append( + append( + messages, list(list(role = "assistant", content = parse_response(list(post_res)))) + ), + list(list(role = "user", content = "continue")) ) } - if (!post_res$status_code %in% 200:299) { - stop(content(post_res)) - } - content(post_res) + final_res } diff --git a/R/parse_response.R b/R/parse_response.R index 38fb7da..c09890c 100644 --- a/R/parse_response.R +++ b/R/parse_response.R @@ -1,17 +1,14 @@ #' Parse OpenAI API Response #' #' Takes the raw response from the OpenAI API and extracts the text content from it. -#' This function is currently designed to differentiate between gpt-3.5-turbo and others. #' -#' @param raw_response The raw response object returned by the OpenAI API. +#' @param raw_responses The raw response object returned by the OpenAI API. #' #' @return Returns a character vector containing the text content of the response. #' -parse_response <- function(raw_response) { - # If the model is from the `gpt-3.5-turbo` family, it parses in a different way. - if (grepl("gpt-3.5-turbo", Sys.getenv("OPENAI_MODEL", "gpt-3.5-turbo"))) { - trimws(sapply(raw_response$choices, function(x) x$message$content)) - } else { - trimws(sapply(raw_response$choices, function(x) x$text)) - } +parse_response <- function(raw_responses) { + # Parse the message content of the list of raw_responses. Trim those message, and paste them. + paste(trimws(sapply(raw_responses, function(response) { + sapply(response$choices, function(x) x$message$content) + })), collapse = "") } diff --git a/R/reset_chat_session.R b/R/reset_chat_session.R new file mode 100644 index 0000000..45c1fae --- /dev/null +++ b/R/reset_chat_session.R @@ -0,0 +1,15 @@ +#' Reset Chat Session +#' +#' This function is intended to be used with `ask_chatgpt`. If we are using `ask_chatgpt` to chat with ChatGPT, and +#' we want to start a new conversation, we must call `reset_chat_session`. +#' +#' @param system_role ChatGPT's role as an AI assistant. +#' +#' @export +#' +reset_chat_session <- function(system_role = "You are a helpful assistant.") { + assign( + "chat_session_messages", list(list(role = "system", content = system_role)), + envir = .state + ) +} diff --git a/README.Rmd b/README.Rmd index f2bc8c6..10b8602 100644 --- a/README.Rmd +++ b/README.Rmd @@ -6,6 +6,7 @@ output: github_document ```{r, include = FALSE} library("chatgpt") +Sys.setenv("OPENAI_VERBOSE" = FALSE) knitr::opts_chunk$set( collapse = TRUE, comment = "#>", @@ -22,9 +23,16 @@ knitr::opts_chunk$set( ## Installation -You can install the development version of {chatgpt} from [GitHub](https://github.com/jcrodriguez1989/chatgpt) with: +Install the current released version of `{chatgpt}` from +[CRAN](https://cran.r-project.org/package=chatgpt): -``` r +```{r eval = FALSE} +install.packages("chatgpt") +``` + +Or install the development version from [GitHub](https://github.com/jcrodriguez1989/chatgpt) with: + +```{r eval = FALSE} # install.packages("remotes") remotes::install_github("jcrodriguez1989/chatgpt") ``` @@ -67,11 +75,22 @@ cat(paste( **Note:** When no code is selected, it will use the whole file's code. +## Common Errors + +#### You exceeded your current quota, please check your plan and billing details + +```r +Error in gpt_get_completions: + list(message = "You exceeded your current quota, please check your plan and billing details.", type = "insufficient_quota", param = NULL, code = NULL) +``` + +To fix this, you need to **provide a billing method** in OpenAI. More information can be found in this [article](https://help.openai.com/en/articles/6891831-error-code-429-you-exceeded-your-current-quota-please-check-your-plan-and-billing-details). + ## Code Examples ```{r, echo=FALSE, results='asis'} pkg_name <- "chatgpt" -exported_functions <- sort(getNamespaceExports(pkg_name)) +exported_functions <- setdiff(sort(getNamespaceExports(pkg_name)), "reset_chat_session") examples_usage <- sapply(exported_functions, function(exported_function) { function_example <- example(exported_function, pkg_name, character.only = TRUE, give.lines = TRUE) function_example <- function_example[grepl("^##D ", function_example)] @@ -109,6 +128,11 @@ Sys.setenv("OPENAI_RETURN_LANGUAGE" = "Español") cat(chatgpt::explain_code("for (i in 1:10) {\n print(i ** 2)\n}")) ``` +### Use ChatGPT behind a proxy + +In order to run ChatGPT queries behind a proxy, set the `OPENAI_PROXY` environment variable with a valid `IP:PORT` proxy. +E.g., `Sys.setenv("OPENAI_PROXY" = "81.94.255.13:8080")`. + ### ChatGPT Model Tweaks ChatGPT model parameters can be tweaked by using environment variables. diff --git a/README.md b/README.md index 8669255..dface83 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,14 @@ Meme by Programming Jokes I IT Humor & Memes ## Installation -You can install the development version of {chatgpt} from +Install the current released version of `{chatgpt}` from +[CRAN](https://cran.r-project.org/package=chatgpt): + +``` r +install.packages("chatgpt") +``` + +Or install the development version from [GitHub](https://github.com/jcrodriguez1989/chatgpt) with: ``` r @@ -66,33 +73,36 @@ coding. Current existing addins: **Note:** When no code is selected, it will use the whole file’s code. +## Common Errors + +#### You exceeded your current quota, please check your plan and billing details + +``` r +Error in gpt_get_completions: + list(message = "You exceeded your current quota, please check your plan and billing details.", type = "insufficient_quota", param = NULL, code = NULL) +``` + +To fix this, you need to **provide a billing method** in OpenAI. More +information can be found in this +[article](https://help.openai.com/en/articles/6891831-error-code-429-you-exceeded-your-current-quota-please-check-your-plan-and-billing-details). + ## Code Examples #### `ask_chatgpt` ``` r > cat(ask_chatgpt("What do you think about R language?")) - -*** ChatGPT input: - -What do you think about R language? -As an AI language model, I do not have personal opinions, but I can tell you some facts about R programming language. R is a widely-used open source programming language and software environment for statistical computing and graphics. It is a popular tool for data analysis, data visualization, and machine learning. R has a large and active community of users and developers who contribute to packages and libraries that extend its functionality. R is also known for its flexibility and versatility, making it a powerful tool for data scientists, statisticians, and researchers. +As an AI language model, I dont have personal opinions, but I can provide you factual information about R language. R is a popular programming language used for statistical computing, data analysis, and graphical visualization. It provides a wide range of tools for analyzing data, including linear and non-linear modeling, time-series analysis, and classification methods, among others. R is also an open-source language, which means it is freely available to use for everyone. Due to its extensive package ecosystem and user-friendly syntax, R is widely preferred by data analysts, statisticians, and researchers. ``` #### `comment_code` ``` r > cat(comment_code("for (i in 1:10) {\n print(i ** 2)\n}")) - -*** ChatGPT input: - -Add inline comments to the following R code: "for (i in 1:10) { - print(i ** 2) -}" - -# This is a for loop that iterates over the sequence 1 to 10 and assigns each value to the variable i. -for (i in 1:10) { - # This line prints the square of the current value of i. +# This is a for loop that initializes the variable i to 1 and iterates until it reaches 10 +for (i in 1:10) { +# The code block within the loop will execute once for each iteration +# This line prints the result of i raised to the power of 2 using the ** operator print(i ** 2) } ``` @@ -101,196 +111,182 @@ for (i in 1:10) { ``` r > cat(complete_code("# A function to square each element of a vector\nsquare_each <- function(")) - -*** ChatGPT input: - -Complete the following R code: "# A function to square each element of a vector -square_each <- function(" -square_each <- function(x) { - x_squared <- x^2 - return(x_squared) +square_each <- function(x){ + x_squared <- x^2 + return(x_squared) } -# This function takes a vector "x" as input, squares each element of the vector using the "^" operator, stores the squared values in a new vector "x_squared", and returns the new vector. +# Example usage +my_vector <- c(1, 2, 3, 4, 5) +square_each(my_vector) # Output: 1 4 9 16 25 ``` #### `create_unit_tests` ``` r > cat(create_unit_tests("squared_numbers <- function(numbers) {\n numbers ^ 2\n}")) +Sure, heres a full testthat file with test cases for the given R code: -*** ChatGPT input: - -Create a full testthat file, with test cases for the following R code: "squared_numbers <- function(numbers) { - numbers ^ 2 -}" -Here is a possible testthat file for the squared_numbers function: - -R +{r} library(testthat) -# Test the squared_numbers function -context("squared_numbers") +# Define the function +squared_numbers <- function(numbers) { + numbers ^ 2 +} -test_that("squared_numbers returns the square of each number", { - numbers <- 1:5 - expected <- c(1, 4, 9, 16, 25) - result <- squared_numbers(numbers) - expect_equal(result, expected) +# Test case for a vector of one number +test_that("squared_numbers works with one number", { + expect_equal(squared_numbers(2), 4) }) -test_that("squared_numbers handles zero correctly", { - numbers <- 0 - expected <- 0 - result <- squared_numbers(numbers) - expect_equal(result, expected) +# Test case for a vector of multiple numbers +test_that("squared_numbers works with multiple numbers", { + expect_equal(squared_numbers(c(2, 3, 4)), c(4, 9, 16)) }) -test_that("squared_numbers handles negative numbers correctly", { - numbers <- -3:-1 - expected <- c(9, 4, 1) - result <- squared_numbers(numbers) - expect_equal(result, expected) +# Test case for an empty vector +test_that("squared_numbers works with an empty vector", { + expect_error(squared_numbers(NULL)) + expect_warning(squared_numbers(NaN)) }) -test_that("squared_numbers handles non-numeric input correctly", { - numbers <- c(1, "a", NA, TRUE) - expect_error(squared_numbers(numbers)) +# Test case for a non-numeric vector +test_that("squared_numbers works with a non-numeric vector", { + expect_error(squared_numbers("test")) + expect_error(squared_numbers(TRUE)) }) -These tests cover a variety of scenarios, including positive, zero, and negative numbers, as well as non-numeric input. +In these test cases, were testing: +- whether the function works with a vector of one number +- whether the function works with a vector of multiple numbers +- whether the function gracefully handles an empty vector- whether the function gracefully handles a non-numeric vector + +For the first two test cases, were using expect_equal() to check that the functions output matches the expected output. For the next two test cases, were using expect_error() and expect_warning() to check that the function throws the expected errors and warnings. + +You can save this code as a file with a .R extension, for example squared_numbers_test.R, and then run the tests with the test_file() function from the testthat package: + +{r} +library(testthat) +test_file("squared_numbers_test.R") + + +This will output a summary of the test results, showing how many tests passed, skipped, and failed. ``` #### `create_variable_name` ``` r > cat(create_variable_name("sapply(1:10, function(i) i ** 2)")) +Here is an example of a good variable name for the result: -*** ChatGPT input: - -Give a good variable name to the result of the following R code: "sapply(1:10, function(i) i ** 2)" -One possible variable name for the result of this R code could be "squared_values", since the code calculates the squares of integers from 1 to 10. So you could assign the result to a variable using something like: -R squared_values <- sapply(1:10, function(i) i ** 2) - -Then you could use the variable "squared_values" later in your code to refer to the vector of squared values. + +The variable name squared_values indicates that the result of the code is a set of values that have been squared. ``` #### `document_code` ``` r > cat(document_code("square_numbers <- function(numbers) numbers ** 2")) +Id be happy to help! Heres an example of how you could document the "square_numbers" function using roxygen2 format: -*** ChatGPT input: - -Document, in roxygen2 format, this R function: "square_numbers <- function(numbers) numbers ** 2" -# Square a Vector of Numbers +{r} +# Square numbers # -# This function takes a vector of numbers as input and returns the vector of numbers squared. +# This function takes a vector of numbers and returns their squares. # # @param numbers A numeric vector to be squared -# @return A numeric vector of squared values of input numbers +# +# @return A numeric vector representing the squares of the input numbers +# # @examples # square_numbers(1:5) -# # returns: 1 4 9 16 25 +# # @export square_numbers <- function(numbers) { numbers ** 2 } + + +This includes a brief description of the function, an explanation of the input parameter, a description of the output, an example usage of the function, and the @export tag, which indicates that this function should be available to users of the package. ``` #### `explain_code` ``` r > cat(explain_code("for (i in 1:10) {\n print(i ** 2)\n}")) +This is a for loop that will run 10 times, with the value of i ranging from 1 to 10. -*** ChatGPT input: +During each iteration of the loop, the value of i is squared using the ** (exponentiation) operator, and the result is printed using the print() function. -Explain the following R code: "for (i in 1:10) { - print(i ** 2) -}" -This R code creates a loop that iterates from 1 to 10, with i taking on the values 1, 2, ..., 10. For each value of i, the code prints i squared using the print() function. +So, each time the loop runs, the output will be: -The ** operator is used to raise i to the power of 2 (i.e., i squared). +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 -So, the output of this code will be a sequence of numbers, each number squared: - -1, 4, 9, 16, 25, 36, 49, 64, 81, 100. +This loop can be used to generate the sequence of squares from 1 to 10. ``` #### `find_issues_in_code` ``` r > cat(find_issues_in_code("i <- 0\nwhile (i < 0) {\n i <- i - 1\n}")) - -*** ChatGPT input: - -Find issues or bugs in the following R code: "i <- 0 -while (i < 0) { - i <- i - 1 -}" -The issue with the given R code is that the condition in the while loop is not being satisfied as the initial value of "i" is zero and the condition is while "i" is less than zero. Therefore, the while loop will not execute at all. - -If the intention was to decrement the value of "i" until it reaches a negative value, then the initial value of "i" should be greater than zero, and the condition in the while loop should be changed accordingly. - -Corrected code: - -i <- 10 -while (i > 0) { - i <- i - 1 -} - - -This code will decrement the value of i by 1 in each iteration of the while loop until the value of i becomes 0. +The code creates an infinite loop since the condition inside the while loop (i < 0) is never met when the initial value of i is 0. To fix it, either initialize i with a negative value like i <- -1 or change the comparison operator inside the loop to >, e.g. while (i > 0) { i <- i - 1 }. ``` #### `optimize_code` ``` r > cat(optimize_code("i <- 10\nwhile (i > 0) {\n i <- i - 1\n print(i)\n}")) +The code can be optimized using a for loop which is a more efficient and concise loop for iterating over a sequence of values. Heres the optimized code: -*** ChatGPT input: - -Optimize the following R code: "i <- 10 -while (i > 0) { - i <- i - 1 - print(i) -}" -The code you provided counts down from 10 to 1 and prints each number. Heres an optimized version of the code that achieves the same outcome: - - +R for (i in 9:0) { print(i) } -This code uses a for loop instead of a while loop, which is a more concise and efficient way to iterate through a sequence of numbers. Instead of manually decrementing the value of i in each iteration, the for loop iterates through a pre-defined sequence (9:0) and assigns the value of i in each iteration automatically. +This code does the same thing as the original code, but its more efficient because it eliminates the need for the while loop and the extra variable assignment. The for loop directly iterates over the sequence from 9 to 0 and prints each value. ``` #### `refactor_code` ``` r > cat(refactor_code("i <- 10\nwhile (i > 0) {\n i <- i - 1\n print(i)\n}")) +Here is the refactored R code: -*** ChatGPT input: -Refactor the following R code, returning valid R code: "i <- 10 -while (i > 0) { - i <- i - 1 +i <- 10 + +for (i in 9:0) { print(i) -}" +} + + +This can also be done using a while loop: + i <- 10 + while (i > 0) { - print(i) + print(i - 1) i <- i - 1 } - -This code will print a sequence of integers from 10 down to 1. The updated code moves the print(i) statement before the decrement of i (i <- i - 1) to ensure that 10 gets printed first. Additionally, the placement of } has not been changed, because it is already in the correct position. + +Both versions will produce the same output as the original code. ``` ## Additional Parameters @@ -314,27 +310,38 @@ To change the language that ChatGPT responds in, the ``` r Sys.setenv("OPENAI_RETURN_LANGUAGE" = "Español") cat(chatgpt::explain_code("for (i in 1:10) {\n print(i ** 2)\n}")) +#> El código utiliza un bucle "for" para imprimir los cuadrados de los números del 1 al 10. #> -#> *** ChatGPT input: -#> -#> Explain the following R code: "for (i in 1:10) { -#> print(i ** 2) -#> }" -#> Este código de R utiliza la función "for" para imprimir los cuadrados de los números del 1 al 10. +#> La sintaxis "for (i in 1:10)" indica que el bucle se va a ejecutar 10 veces, y que la variable "i" va a tomar valores desde 1 hasta 10. #> -#> El "for" es un bucle que ejecuta un bloque de código un número específico de veces. En este caso, especifica que la variable "i" tomará valores del 1 al 10, uno a la vez. +#> Dentro del bucle, "print(i ** 2)" calcula el cuadrado del valor actual de "i" y lo imprime en la consola. El operador "**" se usa para elevar un número a una potencia. #> -#> La función "print" se utiliza para mostrar el resultado en la consola. Dentro del paréntesis, la expresión "i ** 2" eleva el valor actual de "i" al cuadrado. +#> Entonces, la salida del código será: #> -#> Entonces, durante cada iteración del bucle, imprimirá el número actual de "i", elevado al cuadrado. El resultado final será los siguientes números: 1, 4, 9, 16, 25, 36, 49, 64, 81 y 100. +#> [1] 1 +#> [1] 4 +#> [1] 9 +#> [1] 16 +#> [1] 25 +#> [1] 36 +#> [1] 49 +#> [1] 64 +#> [1] 81 +#> [1] 100 ``` +### Use ChatGPT behind a proxy + +In order to run ChatGPT queries behind a proxy, set the `OPENAI_PROXY` +environment variable with a valid `IP:PORT` proxy. E.g., +`Sys.setenv("OPENAI_PROXY" = "81.94.255.13:8080")`. + ### ChatGPT Model Tweaks ChatGPT model parameters can be tweaked by using environment variables. -The following environment variables can be set to tweak the -behavior, as documented in +The following environment variables can be set to tweak the behavior, as +documented in . - `OPENAI_MODEL`; defaults to `"gpt-3.5-turbo"` diff --git a/man/ask_chatgpt.Rd b/man/ask_chatgpt.Rd index 6f459ee..8ec7698 100644 --- a/man/ask_chatgpt.Rd +++ b/man/ask_chatgpt.Rd @@ -13,7 +13,7 @@ ask_chatgpt(question) A character value with the response generated by ChatGPT. } \description{ -Ask ChatGPT +Note: See also `reset_chat_session`. } \examples{ \dontrun{ diff --git a/man/chatgpt-package.Rd b/man/chatgpt-package.Rd new file mode 100644 index 0000000..fbf963e --- /dev/null +++ b/man/chatgpt-package.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/chatgpt-package.R +\docType{package} +\name{chatgpt-package} +\alias{chatgpt} +\alias{chatgpt-package} +\title{'OpenAI's 'ChatGPT' coding assistant for 'RStudio'. A set +of functions and 'RStudio' addins that aim to help the R developer in tedious coding tasks.} +\description{ +'OpenAI's 'ChatGPT' \url{https://chat.openai.com/} coding assistant for 'RStudio'. A set of functions and 'RStudio' addins that aim to help the R developer in tedious coding tasks. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/jcrodriguez1989/chatgpt} + \item Report bugs at \url{https://github.com/jcrodriguez1989/chatgpt/issues} +} + +} +\author{ +\strong{Maintainer}: Juan Cruz Rodriguez \email{jcrodriguez@unc.edu.ar} + +} diff --git a/man/gpt_get_completions.Rd b/man/gpt_get_completions.Rd index 22d77f2..e3ba82b 100644 --- a/man/gpt_get_completions.Rd +++ b/man/gpt_get_completions.Rd @@ -4,12 +4,18 @@ \alias{gpt_get_completions} \title{Get GPT Completions Endpoint} \usage{ -gpt_get_completions(prompt, openai_api_key = Sys.getenv("OPENAI_API_KEY")) +gpt_get_completions( + prompt, + openai_api_key = Sys.getenv("OPENAI_API_KEY"), + messages = NULL +) } \arguments{ \item{prompt}{The prompt to generate completions for.} \item{openai_api_key}{OpenAI's API key.} + +\item{messages}{Available variable, to send the needed messages list to ChatGPT.} } \description{ Get GPT Completions Endpoint diff --git a/man/parse_response.Rd b/man/parse_response.Rd index e73ab9a..644f2be 100644 --- a/man/parse_response.Rd +++ b/man/parse_response.Rd @@ -4,15 +4,14 @@ \alias{parse_response} \title{Parse OpenAI API Response} \usage{ -parse_response(raw_response) +parse_response(raw_responses) } \arguments{ -\item{raw_response}{The raw response object returned by the OpenAI API.} +\item{raw_responses}{The raw response object returned by the OpenAI API.} } \value{ Returns a character vector containing the text content of the response. } \description{ Takes the raw response from the OpenAI API and extracts the text content from it. -This function is currently designed to differentiate between gpt-3.5-turbo and others. } diff --git a/man/reset_chat_session.Rd b/man/reset_chat_session.Rd new file mode 100644 index 0000000..ea923e2 --- /dev/null +++ b/man/reset_chat_session.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/reset_chat_session.R +\name{reset_chat_session} +\alias{reset_chat_session} +\title{Reset Chat Session} +\usage{ +reset_chat_session(system_role = "You are a helpful assistant.") +} +\arguments{ +\item{system_role}{ChatGPT's role as an AI assistant.} +} +\description{ +This function is intended to be used with `ask_chatgpt`. If we are using `ask_chatgpt` to chat with ChatGPT, and +we want to start a new conversation, we must call `reset_chat_session`. +}