@@ -38,18 +38,18 @@ chat_deps <- function() {
3838# ' @param ... Extra HTML attributes to include on the chat element
3939# ' @param messages A list of messages to prepopulate the chat with. Each
4040# ' message can be one of the following:
41- # '
42- # ' * A string, which is interpreted as markdown and rendered to HTML on
41+ # '
42+ # ' * A string, which is interpreted as markdown and rendered to HTML on
4343# ' the client.
44- # ' * To prevent interpreting as markdown, mark the string as
44+ # ' * To prevent interpreting as markdown, mark the string as
4545# ' [htmltools::HTML()].
4646# ' * A UI element.
47- # ' * This includes [htmltools::tagList()], which take UI elements
48- # ' (including strings) as children. In this case, strings are still
47+ # ' * This includes [htmltools::tagList()], which take UI elements
48+ # ' (including strings) as children. In this case, strings are still
4949# ' interpreted as markdown as long as they're not inside HTML.
50- # ' * A named list of `content` and `role`. The `content` can contain content
50+ # ' * A named list of `content` and `role`. The `content` can contain content
5151# ' as described above, and the `role` can be "assistant" or "user".
52- # '
52+ # '
5353# ' @param placeholder The placeholder text for the chat's user input field
5454# ' @param width The CSS width of the chat element
5555# ' @param height The CSS height of the chat element
@@ -85,14 +85,14 @@ chat_deps <- function() {
8585# '
8686# ' @export
8787chat_ui <- function (
88- id ,
89- ... ,
90- messages = NULL ,
91- placeholder = " Enter a message..." ,
92- width = " min(680px, 100%)" ,
93- height = " auto" ,
94- fill = TRUE ) {
95-
88+ id ,
89+ ... ,
90+ messages = NULL ,
91+ placeholder = " Enter a message..." ,
92+ width = " min(680px, 100%)" ,
93+ height = " auto" ,
94+ fill = TRUE
95+ ) {
9696 attrs <- rlang :: list2(... )
9797 if (! all(nzchar(rlang :: names2(attrs )))) {
9898 rlang :: abort(" All arguments in ... must be named." )
@@ -129,19 +129,25 @@ chat_ui <- function(
129129 )
130130 })
131131
132- res <- tag(" shiny-chat-container" , rlang :: list2(
133- id = id ,
134- style = css(
135- width = width ,
136- height = height
137- ),
138- placeholder = placeholder ,
139- fill = if (isTRUE(fill )) NA else NULL ,
140- ... ,
141- tag(" shiny-chat-messages" , message_tags ),
142- tag(" shiny-chat-input" , list (id = paste0(id , " _user_input" ), placeholder = placeholder )),
143- chat_deps()
144- ))
132+ res <- tag(
133+ " shiny-chat-container" ,
134+ rlang :: list2(
135+ id = id ,
136+ style = css(
137+ width = width ,
138+ height = height
139+ ),
140+ placeholder = placeholder ,
141+ fill = if (isTRUE(fill )) NA else NULL ,
142+ ... ,
143+ tag(" shiny-chat-messages" , message_tags ),
144+ tag(
145+ " shiny-chat-input" ,
146+ list (id = paste0(id , " _user_input" ), placeholder = placeholder )
147+ ),
148+ chat_deps()
149+ )
150+ )
145151
146152 if (isTRUE(fill )) {
147153 res <- bslib :: as_fill_carrier(res )
@@ -178,16 +184,16 @@ chat_ui <- function(
178184# ' @param id The ID of the chat element
179185# ' @param response The message or message stream to append to the chat element.
180186# ' The actual message content can one of the following:
181- # '
182- # ' * A string, which is interpreted as markdown and rendered to HTML on
187+ # '
188+ # ' * A string, which is interpreted as markdown and rendered to HTML on
183189# ' the client.
184- # ' * To prevent interpreting as markdown, mark the string as
190+ # ' * To prevent interpreting as markdown, mark the string as
185191# ' [htmltools::HTML()].
186192# ' * A UI element.
187- # ' * This includes [htmltools::tagList()], which take UI elements
188- # ' (including strings) as children. In this case, strings are still
193+ # ' * This includes [htmltools::tagList()], which take UI elements
194+ # ' (including strings) as children. In this case, strings are still
189195# ' interpreted as markdown as long as they're not inside HTML.
190- # '
196+ # '
191197# ' @param role The role of the message (either "assistant" or "user"). Defaults
192198# ' to "assistant".
193199# ' @param session The Shiny session object
@@ -236,10 +242,15 @@ chat_ui <- function(
236242# ' shinyApp(ui, server)
237243# '
238244# ' @export
239- chat_append <- function (id , response , role = c(" assistant" , " user" ), session = getDefaultReactiveDomain()) {
245+ chat_append <- function (
246+ id ,
247+ response ,
248+ role = c(" assistant" , " user" ),
249+ session = getDefaultReactiveDomain()
250+ ) {
240251 check_active_session(session )
241252 role <- match.arg(role )
242-
253+
243254 stream <- as_generator(response )
244255 chat_append_stream(id , stream , role = role , session = session )
245256}
@@ -313,7 +324,13 @@ chat_append <- function(id, response, role = c("assistant", "user"), session = g
313324# ' shinyApp(ui, server)
314325# '
315326# ' @export
316- chat_append_message <- function (id , msg , chunk = TRUE , operation = c(" append" , " replace" ), session = getDefaultReactiveDomain()) {
327+ chat_append_message <- function (
328+ id ,
329+ msg ,
330+ chunk = TRUE ,
331+ operation = c(" append" , " replace" ),
332+ session = getDefaultReactiveDomain()
333+ ) {
317334 check_active_session(session )
318335
319336 if (! is.list(msg )) {
@@ -341,7 +358,10 @@ chat_append_message <- function(id, msg, chunk = TRUE, operation = c("append", "
341358 }
342359
343360 content <- msg [[" content" ]]
344- is_html <- inherits(content , c(" shiny.tag" , " shiny.tag.list" , " html" , " htmlwidget" ))
361+ is_html <- inherits(
362+ content ,
363+ c(" shiny.tag" , " shiny.tag.list" , " html" , " htmlwidget" )
364+ )
345365 content_type <- if (is_html ) " html" else " markdown"
346366
347367 operation <- match.arg(operation )
@@ -369,24 +389,35 @@ chat_append_message <- function(id, msg, chunk = TRUE, operation = c("append", "
369389 operation = operation
370390 )
371391
372- session $ sendCustomMessage(" shinyChatMessage" , list (
373- id = resolve_id(id , session ),
374- handler = msg_type ,
375- obj = msg
376- ))
392+ session $ sendCustomMessage(
393+ " shinyChatMessage" ,
394+ list (
395+ id = resolve_id(id , session ),
396+ handler = msg_type ,
397+ obj = msg
398+ )
399+ )
377400
378401 invisible (NULL )
379402}
380403
381- chat_append_stream <- function (id , stream , role = " assistant" , session = getDefaultReactiveDomain()) {
404+ chat_append_stream <- function (
405+ id ,
406+ stream ,
407+ role = " assistant" ,
408+ session = getDefaultReactiveDomain()
409+ ) {
382410 result <- chat_append_stream_impl(id , stream , role , session )
383411 # Handle erroneous result...
384412 promises :: catch(result , function (reason ) {
385413 chat_append_message(
386414 id ,
387415 list (
388416 role = role ,
389- content = paste0(" \n\n **An error occurred:** " , conditionMessage(reason ))
417+ content = paste0(
418+ " \n\n **An error occurred:** " ,
419+ conditionMessage(reason )
420+ )
390421 ),
391422 chunk = " end" ,
392423 operation = " append" ,
@@ -404,19 +435,43 @@ chat_append_stream <- function(id, stream, role = "assistant", session = getDefa
404435utils ::: globalVariables(c(" generator_env" , " exits" , " yield" ))
405436
406437chat_append_stream_impl <- NULL
407- rlang :: on_load(chat_append_stream_impl <- coro :: async(function (id , stream , role = " assistant" , session = shiny :: getDefaultReactiveDomain()) {
408- chat_append_message(id , list (role = role , content = " " ), chunk = " start" , session = session )
409- for (msg in stream ) {
410- if (promises :: is.promising(msg )) {
411- msg <- await(msg )
412- }
413- if (coro :: is_exhausted(msg )) {
414- break
438+ rlang :: on_load(
439+ chat_append_stream_impl <- coro :: async(function (
440+ id ,
441+ stream ,
442+ role = " assistant" ,
443+ session = shiny :: getDefaultReactiveDomain()
444+ ) {
445+ chat_append_message(
446+ id ,
447+ list (role = role , content = " " ),
448+ chunk = " start" ,
449+ session = session
450+ )
451+ for (msg in stream ) {
452+ if (promises :: is.promising(msg )) {
453+ msg <- await(msg )
454+ }
455+ if (coro :: is_exhausted(msg )) {
456+ break
457+ }
458+ chat_append_message(
459+ id ,
460+ list (role = role , content = msg ),
461+ chunk = TRUE ,
462+ operation = " append" ,
463+ session = session
464+ )
415465 }
416- chat_append_message(id , list (role = role , content = msg ), chunk = TRUE , operation = " append" , session = session )
417- }
418- chat_append_message(id , list (role = role , content = " " ), chunk = " end" , operation = " append" , session = session )
419- }))
466+ chat_append_message(
467+ id ,
468+ list (role = role , content = " " ),
469+ chunk = " end" ,
470+ operation = " append" ,
471+ session = session
472+ )
473+ })
474+ )
420475
421476
422477# ' Clear all messages from a chat control
0 commit comments