diff --git a/DESCRIPTION b/DESCRIPTION index ac8e7a2..06c760e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: gpttools Title: Extensions and Tools for gptstudio -Version: 0.0.8.9013 +Version: 0.0.8.9014 Authors@R: person("James", "Wade", , "github@jameshwade.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-9740-1905")) @@ -39,6 +39,7 @@ Imports: xml2, yaml Suggests: + AzureRMR, bsicons, bslib, covr, diff --git a/NEWS.md b/NEWS.md index c4c4c55..034ee23 100644 --- a/NEWS.md +++ b/NEWS.md @@ -24,6 +24,7 @@ * Added a new vignette for package scraping, making the scraping process clearer for other developers. * Added a vignette for chat with retrieval, offering a tutorial on how to leverage this new feature within the package. * Removed dedicated azure functions and azure embedding option due to the new focus on fully local options (in #ea30c57, #4259474). +* Azure OpenAI streaming added along with option to use api key and Azure token for auth ## Developmental changes diff --git a/R/stream-azure-openai.R b/R/stream-azure-openai.R new file mode 100755 index 0000000..e1467b1 --- /dev/null +++ b/R/stream-azure-openai.R @@ -0,0 +1,58 @@ +stream_chat_azure_openai <- function(prompt = NULL, + element_callback = create_handler("openai"), + shiny = FALSE, + use_token = Sys.getenv("AZURE_OPENAI_USE_TOKEN")) { + messages <- list( + list( + role = "user", + content = prompt + ) + ) + + body <- list( + stream = TRUE, + messages = messages + ) + + token <- retrieve_azure_token() + + response <- + httr2::request(Sys.getenv("AZURE_OPENAI_ENDPOINT")) |> + httr2::req_url_path_append("openai/deployments") |> + httr2::req_url_path_append(Sys.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")) |> + httr2::req_url_path_append(Sys.getenv("AZURE_OPENAI_TASK")) |> + httr2::req_url_query("api-version" = Sys.getenv("AZURE_OPENAI_API_VERSION")) |> + httr2::req_headers( + "api-key" = Sys.getenv("AZURE_OPENAI_KEY"), + "Content-Type" = "application/json" + ) + + if (use_token) { + response <- response |> httr2::req_auth_bearer_token(token = token) + } + + response <- + response |> + httr2::req_body_json(data = body) |> + httr2::req_retry(max_tries = 3) |> + httr2::req_error(is_error = function(resp) FALSE) |> + httr2::req_perform_stream( + callback = element_callback, + buffer_kb = 0.01 + ) + + invisible(response) +} + + +retrieve_azure_token <- function() { + rlang::check_installed("AzureRMR") + token <- AzureRMR::create_azure_login( + tenant = Sys.getenv("AZURE_OPENAI_TENANT_ID"), + app = Sys.getenv("AZURE_OPENAI_CLIENT_ID"), + password = Sys.getenv("AZURE_OPENAI_CLIENT_SECRET"), + host = "https://cognitiveservices.azure.com/", + scopes = ".default" + ) + invisible(token$token$credentials$access_token) +} diff --git a/R/stream-chat.R b/R/stream-chat.R index 85c8804..ef27091 100644 --- a/R/stream-chat.R +++ b/R/stream-chat.R @@ -33,6 +33,12 @@ stream_chat <- function(prompt, prompt = prompt, element_callback = create_handler("ollama", r, output_id, where) ) + }, + "azure_openai" = { + response <- stream_chat_azure_openai( + prompt = prompt, + element_callback = create_handler("azure_openai", r, output_id, where) + ) } ) } @@ -117,7 +123,11 @@ get_stream_pattern <- function(service) { "ollama" = { pattern <- '\\{"model":.*"done":false\\}' pluck <- "response" - } + }, + "azure_openai" = { + pattern <- '\\{"id":.*?\\}\\]\\}' + pluck <- c("choices", "delta", "content") + }, ) list(pattern = pattern, pluck = pluck) } diff --git a/inst/retriever/app.R b/inst/retriever/app.R index 0ee4593..6a29803 100644 --- a/inst/retriever/app.R +++ b/inst/retriever/app.R @@ -273,7 +273,7 @@ server <- function(input, output, session) { }) observe( - if (input$service %in% c("google", "huggingface", "azure_openai")) { + if (input$service %in% c("google", "huggingface")) { updateRadioButtons( session, "stream",