From 819358b32fb4119bb6cba214733b319187d9242a Mon Sep 17 00:00:00 2001 From: Adi Sarid Date: Thu, 24 Oct 2024 00:04:38 +0300 Subject: [PATCH 1/4] Update streaming-async.Rmd Added shiny app example for chat_async usage --- vignettes/streaming-async.Rmd | 72 ++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/vignettes/streaming-async.Rmd b/vignettes/streaming-async.Rmd index 540c8d69..e26ab98b 100644 --- a/vignettes/streaming-async.Rmd +++ b/vignettes/streaming-async.Rmd @@ -61,7 +61,77 @@ chat$chat_async("How's your day going?") %...>% print() #> I'm just a computer program, so I don't have feelings, but I'm here to help you with any questions you have. ``` -TODO: Shiny example +#### Shiny example + +The following shiny app uses `chat_async` to query the OpenAI API. The server function shows a loading element (spinner) while it is waiting for the API to return the answer. Then the recent response is displayed. +The `%...>%` operator from the `promises` package is used to push the asynchronous chat response and render it, once it is ready. It also hides the loading element. + +``` +library(shiny) +library(bslib) +library(elmer) +library(promises) +library(future) +library(shinyjs) + +# Initialize chat +chat <- chat_openai( + system_prompt = "You like chatting about star trek, mostly TNG and onwards (not TOS). Answers should be concise and star trek inspired." +) + +# The user interface is simple +ui <- page_sidebar( + title = "Interactive chat with async", + sidebar = sidebar( + title = "Controls", + useShinyjs(), + textInput("user_query", "Enter query:"), + actionButton("ask_chat", label = "Ask the chat") + ), + card( + card_header("The chat's response"), + hidden( + div("I'm thinking...", + div(class = "spinner-border text-primary", role = "status", + span(class = "sr-only")), + id = "loading")), + uiOutput("chat_response") + ) +) + +server <- function(input, output) { + + # Once the user requests chat gpt output: + observeEvent(input$ask_chat, { + + # Do something to show you're thinking + showElement("loading") + + # Call the chat_async function + result_async <- chat$chat_async("Answer this question:", + input$user_query) + + # Using the promises notation, this will run once the chat result comes through + result_async %...>% { + # Update the modal once the result is available + hideElement("loading") # results are in - hide the "loading". + output$chat_response <- renderUI({ + markdown(.) # The `.` is the chat result, markdown is just used to turn content into html. + }) + } %...!% { + # Error handling + output$chat_response <- renderUI({ + p("Something went wrong... :(") + }) + } + }) +} + +# Run the app +shinyApp(ui = ui, server = server) +``` + +TODO: Extend example to stream_async, simplify example. ### Asynchronous streaming From 2dd2d4712f41a352268202fed1707385cc766cf4 Mon Sep 17 00:00:00 2001 From: Adi Sarid Date: Thu, 24 Oct 2024 00:10:24 +0300 Subject: [PATCH 2/4] Update streaming-async.Rmd Removed redundant use of `future` library call --- vignettes/streaming-async.Rmd | 1 - 1 file changed, 1 deletion(-) diff --git a/vignettes/streaming-async.Rmd b/vignettes/streaming-async.Rmd index e26ab98b..e6d97fa2 100644 --- a/vignettes/streaming-async.Rmd +++ b/vignettes/streaming-async.Rmd @@ -71,7 +71,6 @@ library(shiny) library(bslib) library(elmer) library(promises) -library(future) library(shinyjs) # Initialize chat From cac344386a53f5f9fcf37e2a107e856714cf828f Mon Sep 17 00:00:00 2001 From: Adi Sarid Date: Fri, 25 Oct 2024 10:00:36 +0300 Subject: [PATCH 3/4] Update streaming-async.Rmd Incorporated changes suggested by @jcheng5 moved chat init to within server function and using the `input_task_button` instead of previous shinyjs. --- vignettes/streaming-async.Rmd | 49 +++++++---------------------------- 1 file changed, 9 insertions(+), 40 deletions(-) diff --git a/vignettes/streaming-async.Rmd b/vignettes/streaming-async.Rmd index e6d97fa2..a09f652f 100644 --- a/vignettes/streaming-async.Rmd +++ b/vignettes/streaming-async.Rmd @@ -71,62 +71,31 @@ library(shiny) library(bslib) library(elmer) library(promises) -library(shinyjs) -# Initialize chat -chat <- chat_openai( - system_prompt = "You like chatting about star trek, mostly TNG and onwards (not TOS). Answers should be concise and star trek inspired." -) - -# The user interface is simple ui <- page_sidebar( title = "Interactive chat with async", sidebar = sidebar( title = "Controls", - useShinyjs(), textInput("user_query", "Enter query:"), - actionButton("ask_chat", label = "Ask the chat") + input_task_button("ask_chat", label = "Ask the chat") ), card( card_header("The chat's response"), - hidden( - div("I'm thinking...", - div(class = "spinner-border text-primary", role = "status", - span(class = "sr-only")), - id = "loading")), uiOutput("chat_response") ) ) server <- function(input, output) { - - # Once the user requests chat gpt output: - observeEvent(input$ask_chat, { - - # Do something to show you're thinking - showElement("loading") - - # Call the chat_async function - result_async <- chat$chat_async("Answer this question:", - input$user_query) - - # Using the promises notation, this will run once the chat result comes through - result_async %...>% { - # Update the modal once the result is available - hideElement("loading") # results are in - hide the "loading". - output$chat_response <- renderUI({ - markdown(.) # The `.` is the chat result, markdown is just used to turn content into html. - }) - } %...!% { - # Error handling - output$chat_response <- renderUI({ - p("Something went wrong... :(") - }) - } - }) + output$chat_response <- renderUI({ + # Start the chat fresh each time, as the UI is not a multi-turn conversation + chat <- chat_openai( + system_prompt = "You like chatting about star trek, mostly TNG and onwards (not TOS). Answers should be concise and star trek inspired." + ) + # Asynchronously get the (Markdown) results and render to HTML + chat$chat_async("Answer this question:", input$user_query) %...>% markdown() + }) |> bindEvent(input$ask_chat) } -# Run the app shinyApp(ui = ui, server = server) ``` From c352a045a722e97dc5b37792b231558d7f4bd05b Mon Sep 17 00:00:00 2001 From: Adi Sarid Date: Fri, 7 Feb 2025 14:53:30 +0200 Subject: [PATCH 4/4] Updated package name to `ellmer` --- vignettes/streaming-async.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/streaming-async.Rmd b/vignettes/streaming-async.Rmd index a09f652f..921f6c79 100644 --- a/vignettes/streaming-async.Rmd +++ b/vignettes/streaming-async.Rmd @@ -69,7 +69,7 @@ The `%...>%` operator from the `promises` package is used to push the asynchrono ``` library(shiny) library(bslib) -library(elmer) +library(ellmer) library(promises) ui <- page_sidebar(