Skip to content

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

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions extensions/rshiny-chat-app/.Rprofile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source("renv/activate.R")
1 change: 1 addition & 0 deletions extensions/rshiny-chat-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.posit/
19 changes: 19 additions & 0 deletions extensions/rshiny-chat-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# R Shiny Chat App

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.
87 changes: 87 additions & 0 deletions extensions/rshiny-chat-app/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
library(shiny)
library(shinychat)
library(ellmer)
library(palmerpenguins)
library(connectapi)
library(ggplot2)
library(bslib)

data(penguins)

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
)
)

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

}

# 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",
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(ui, server)
1,862 changes: 1,862 additions & 0 deletions extensions/rshiny-chat-app/manifest.json

Large diffs are not rendered by default.

2,392 changes: 2,392 additions & 0 deletions extensions/rshiny-chat-app/renv.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions extensions/rshiny-chat-app/renv/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
library/
local/
cellar/
lock/
python/
sandbox/
staging/
Loading