-
Notifications
You must be signed in to change notification settings - Fork 3
Azure OpenAI OAuth - R Shiny chat app #202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
34871de
7983550
d293074
271f481
85bcecd
ed34cc6
85d2e4a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
source("renv/activate.R") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/.posit/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# R Shiny App using an Azure OpenAI OAuth Integration | ||
|
||
An R Shiny app that uses `ellmer` and `shinychat` to create an interactive chat interface that answers questions about the `palmerpenguins` dataset. The app demonstrates the OAuth credential handoff made possible by the Azure OpenAI OAuth integration which gives the shiny app access to Azure OpenAI resources. | ||
|
||
# Setup | ||
|
||
An Azure OpenAI OAuth Integration must be configured by the Posit Connect administrator using application specific fields from the Azure administrator. | ||
|
||
Alternatively, if testing this shiny app locally, the environment variable `AZURE_OPENAI_API_KEY` must be set. | ||
|
||
# Usage | ||
|
||
Deploy the app to Connect. | ||
|
||
**Note**: | ||
|
||
Only members of the "Connect" group have been assigned the proper data action role to use the Azure OpenAI `gpt-4o-mini` deployment that this app is set up to interact with. Because of this, the primary purpose of the app is to serve as a blueprint for what utilizing the Azure OpenAI OAuth integration might look like. | ||
|
||
To adapt this shiny app to a different azure endpoint and model deployment, the `deployment_id`, `api_version`, and `endpoint` arguments passed to `ellmer::chat_azure_openai()`, must be respecified. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
library(shiny) | ||
library(shinychat) | ||
library(ellmer) | ||
library(palmerpenguins) | ||
library(connectapi) | ||
library(bslib) | ||
|
||
data(penguins) | ||
|
||
setup_ui <- bslib::page_fluid( | ||
theme = bslib::bs_theme(bootswatch = "flatly"), | ||
bslib::layout_columns( | ||
col_widths = c(2, 8, 2), | ||
NULL, | ||
bslib::card( | ||
bslib::card_header("Azure OpenAI OAuth Setup Instructions"), | ||
bslib::card_body( | ||
tags$h4("Configuration Required"), | ||
tags$p("This application requires an Azure OpenAI OAuth integration to be properly configured."), | ||
tags$p("For more detailed instructions, please refer to the ", | ||
tags$a(href="https://docs.posit.co/connect/admin/integrations/oauth-integrations/azure-openai/", | ||
"Posit Connect Azure OpenAI OAuth integration documentation", | ||
target="_blank")) | ||
), | ||
width = "100%", | ||
class = "shadow" | ||
), | ||
NULL | ||
) | ||
) | ||
|
||
app_ui <- bslib::page_fluid( | ||
theme = bslib::bs_theme(bootswatch = "flatly"), | ||
bslib::layout_columns( | ||
col_widths = c(2, 8, 2), | ||
NULL, | ||
bslib::card( | ||
bslib::card_header("Palmer Penguins Chat Assistant"), | ||
shinychat::chat_ui("chat", height = "300px"), | ||
width = "100%", | ||
class = "shadow" | ||
), | ||
NULL | ||
) | ||
) | ||
|
||
screen_ui <- shiny::uiOutput("screen") | ||
|
||
|
||
server <- function(input, output, session) { | ||
|
||
# Get Connect OAuth credentials using connectapi | ||
get_oauth_credentials <- function() { | ||
|
||
if (Sys.getenv("POSIT_PRODUCT") == "CONNECT") { | ||
|
||
client <- connectapi::connect() | ||
|
||
user_session_token <- session$request$HTTP_POSIT_CONNECT_USER_SESSION_TOKEN | ||
oauth_response <- connectapi::get_oauth_credentials(client, user_session_token) | ||
credentials <- list(Authorization = paste("Bearer", oauth_response$access_token)) | ||
|
||
} else { | ||
|
||
# Local development mode | ||
api_key <- Sys.getenv("AZURE_OPENAI_API_KEY") | ||
if (api_key != "") { | ||
credentials <- list("api-key" = api_key) | ||
} else { | ||
credentials <- NULL | ||
} | ||
|
||
} | ||
|
||
credentials | ||
|
||
} | ||
|
||
OAUTH_INTEGRATION_ENABLED <- TRUE | ||
user_session_token <- session$request$HTTP_POSIT_CONNECT_USER_SESSION_TOKEN | ||
|
||
if (!is.null(user_session_token)) { | ||
# Capture any messages that might contain the error code | ||
msg <- capture.output( | ||
try(connectapi::connect(token = user_session_token)), | ||
type = "message" | ||
) | ||
|
||
if (any(grepl("212", msg))) { | ||
OAUTH_INTEGRATION_ENABLED <- FALSE | ||
} | ||
} | ||
|
||
|
||
output$screen <- shiny::renderUI({ | ||
if (OAUTH_INTEGRATION_ENABLED) { | ||
app_ui | ||
} else { | ||
setup_ui | ||
} | ||
}) | ||
|
||
# Create Azure OpenAI chat function | ||
penguin_chat <- function() { | ||
|
||
credentials <- get_oauth_credentials() | ||
|
||
# Create a custom chat function for Azure OpenAI | ||
azure_chat <- ellmer::chat_azure_openai( | ||
deployment_id = "gpt-4o-mini", | ||
api_version = "2024-12-01-preview", | ||
endpoint = "https://8ul4l3wq0g.openai.azure.com", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on @mconflitti-pbc's question this also seems specific to the Posit organization, and not something we can add to the Gallery generally for others to use since you cannot change Gallery content prior to publishing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I totally agree with @mconflitti-pbc and your concerns on this. I was doing this work to fulfill a ticket (https://github.com/posit-dev/connect/issues/31840), but I agree that there probably needs to be a larger discussion about whether it's suited to be a gallery app (@zackverham @christierney). The non-generic api endpoint along with all of the particular data action roles that need to be assigned by an azure administrator make it feel out of place. |
||
credentials = credentials, | ||
system_prompt = paste0( | ||
"You are a data assistant helping with the Palmer Penguins dataset. ", | ||
"The dataset contains measurements for Adelie, Chinstrap, and Gentoo penguins observed on islands in the Palmer Archipelago. ", | ||
"Answer questions about the dataset concisely and accurately. ", | ||
"The dataset structure is: \n", paste(capture.output(str(penguins)), collapse = "\n") | ||
) | ||
) | ||
} | ||
|
||
shiny::observeEvent(input$chat_user_input, { | ||
|
||
current_chat <- penguin_chat() | ||
|
||
stream <- current_chat$stream_async(input$chat_user_input) | ||
shinychat::chat_append("chat", stream) | ||
|
||
|
||
}) | ||
|
||
} | ||
|
||
shiny::shinyApp(screen_ui, server) |
Uh oh!
There was an error while loading. Please reload this page.