Skip to content
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

Pathological streaming slowdown with promises 1.3.1 #16

Closed
jcheng5 opened this issue Nov 27, 2024 · 2 comments · Fixed by rstudio/promises#115 · May be fixed by rstudio/promises#116
Closed

Pathological streaming slowdown with promises 1.3.1 #16

jcheng5 opened this issue Nov 27, 2024 · 2 comments · Fixed by rstudio/promises#115 · May be fixed by rstudio/promises#116

Comments

@jcheng5
Copy link
Collaborator

jcheng5 commented Nov 27, 2024

With yesterday's {promises} 1.3.1 release, long streaming answers from elmer in shinychat have ground to an absolute halt. Using the example from the README:

app source
library(shiny)
library(shinychat)

ui <- bslib::page_fluid(
  chat_ui("chat")
)

server <- function(input, output, session) {
  chat <- elmer::chat_openai(system_prompt = "You're a trickster who answers in riddles")
  
  observeEvent(input$chat_user_input, {
    stream <- chat$stream_async(input$chat_user_input)
    chat_append("chat", stream)
  })
}

shinyApp(ui, server)
shinychat-1.mov

The slowness can be addressed by setting options(shiny.deepstacktrace=FALSE), but then you get a stack overflow:

shinychat-2.mov
@jcheng5
Copy link
Collaborator Author

jcheng5 commented Nov 27, 2024

The following test app is an excellent way to see the problem. The only thing it doesn't show is how many promise domains are in effect at the same time--I suspect by the time the slowdown is noticeable, each handler is executing with the burden of hundreds if not thousands of Shiny's call-stack-capturing promise domains being simultaneously active, due to rstudio/shiny#4155.

Run this and type "Tell me a story" as the user prompt.

library(shiny)
library(shinychat)
library(promises)

# options(shiny.deepstacktrace=FALSE)

instrument_async_stream <- function(stream) {
  (coro::async_generator(function() {
    for (i in await_each(stream)) {
      deepStackDepth <- length(shiny:::.globals$deepStack)
      callStackDepth <- length(sys.calls())
      message("deepStackDepth: ", deepStackDepth, ", callStackDepth: ", callStackDepth)
      yield(i)
    }
  }))()
}

ui <- bslib::page_fluid(
  chat_ui("chat")
)

server <- function(input, output, session) {
  chat <- elmer::chat_openai(
    model = "gpt-4o-mini",
    system_prompt = "You're a trickster who answers in riddles"
  )
  
  observeEvent(input$chat_user_input, {
    stream <- chat$stream_async(input$chat_user_input) |>
      instrument_async_stream()
    chat_append("chat", stream)
  })
}

shinyApp(ui, server)

@jcheng5
Copy link
Collaborator Author

jcheng5 commented Nov 27, 2024

Just cause the pingbacks are getting a little confusing, here are the underlying issues along with PRs for their fixes:

shiny

promises

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant