Skip to content

Commit a781305

Browse files
authored
Add ui.MarkdownStream (#1782)
1 parent 184a9eb commit a781305

File tree

30 files changed

+1228
-304
lines changed

30 files changed

+1228
-304
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### New features
1111

12+
* Added a new `ui.MarkdownStream()` component for performantly streaming in chunks of markdown/html strings into the UI. This component is primarily useful for text-based generative AI where responses are received incrementally. (#1782)
13+
1214
* Added a new `.add_sass_layer_file()` method to `ui.Theme` that supports reading a Sass file with layer boundary comments, e.g. `/*-- scss:defaults --*/`. This format [is supported by Quarto](https://quarto.org/docs/output-formats/html-themes-more.html#bootstrap-bootswatch-layering) and makes it easier to store Sass rules and declarations that need to be woven into Shiny's Sass Bootstrap files. (#1790)
1315

1416
* The `ui.Chat()` component's `.on_user_submit()` decorator method now passes the user input to the decorated function. This makes it a bit more obvious how to access the user input inside the decorated function. See the new templates (mentioned below) for examples. (#1801)

docs/_quartodoc-core.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ quartodoc:
102102
contents:
103103
- ui.Chat
104104
- ui.chat_ui
105+
- title: Streaming markdown
106+
desc: Stream markdown content into the UI
107+
contents:
108+
- ui.MarkdownStream
109+
- ui.output_markdown_stream
105110
- title: Custom UI
106111
desc: Lower-level UI functions for creating custom HTML/CSS/JS
107112
contents:
@@ -358,4 +363,3 @@ quartodoc:
358363
contents:
359364
- name: experimental.ui.card_image
360365
dynamic: false
361-

docs/_quartodoc-express.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ quartodoc:
8181
desc: Build a chatbot interface
8282
contents:
8383
- express.ui.Chat
84+
- title: Streaming markdown
85+
desc: Stream markdown content into the UI
86+
contents:
87+
- express.ui.MarkdownStream
8488
- title: Reactive programming
8589
desc: Create reactive functions and dependencies.
8690
contents:

js/build.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,20 @@ const opts: Array<BuildOptions> = [
7474
plugins: [sassPlugin({ type: "css", sourceMap: false })],
7575
metafile: true,
7676
},
77+
{
78+
entryPoints: {
79+
"markdown-stream/markdown-stream": "markdown-stream/markdown-stream.ts",
80+
},
81+
minify: true,
82+
sourcemap: true,
83+
},
84+
{
85+
entryPoints: {
86+
"markdown-stream/markdown-stream": "markdown-stream/markdown-stream.scss",
87+
},
88+
plugins: [sassPlugin({ type: "css", sourceMap: false })],
89+
metafile: true,
90+
},
7791
{
7892
entryPoints: {
7993
"chat/chat": "chat/chat.ts",

js/chat/_utils.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

js/chat/chat.scss

Lines changed: 1 addition & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
@use "highlight_styles" as highlight_styles;
2-
31
shiny-chat-container {
42
--shiny-chat-border: var(--bs-border-width, 1px) solid var(--bs-border-color, #e9ecef);
53
--shiny-chat-user-message-bg: RGBA(var(--bs-primary-rgb, 0, 123, 194), 0.06);
@@ -39,7 +37,7 @@ shiny-chat-message {
3937
}
4038
}
4139
/* Vertically center the 2nd column (message content) */
42-
.message-content {
40+
shiny-markdown-stream {
4341
align-self: center;
4442
}
4543
}
@@ -101,53 +99,3 @@ shiny-chat-input {
10199
.shiny-busy:has(shiny-chat-input[disabled])::after {
102100
display: none;
103101
}
104-
105-
/* Code highlighting (for both light and dark mode) */
106-
@include highlight_styles.atom_one_light;
107-
[data-bs-theme="dark"] {
108-
@include highlight_styles.atom_one_dark;
109-
}
110-
111-
/*
112-
Styling for the code-copy button (inspired by Quarto's code-copy feature)
113-
*/
114-
pre:has(.code-copy-button) {
115-
position: relative;
116-
}
117-
118-
.code-copy-button {
119-
position: absolute;
120-
top: 0;
121-
right: 0;
122-
border: 0;
123-
margin-top: 5px;
124-
margin-right: 5px;
125-
background-color: transparent;
126-
127-
> .bi {
128-
display: flex;
129-
gap: 0.25em;
130-
131-
&::after {
132-
content: "";
133-
display: block;
134-
height: 1rem;
135-
width: 1rem;
136-
mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/><path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/></svg>');
137-
background-color: var(--bs-body-color, #222);
138-
}
139-
}
140-
}
141-
142-
.code-copy-button-checked {
143-
> .bi::before {
144-
content: "Copied!";
145-
font-size: 0.75em;
146-
vertical-align: 0.25em;
147-
}
148-
149-
> .bi::after {
150-
mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>');
151-
background-color: var(--bs-success, #198754);
152-
}
153-
}

0 commit comments

Comments
 (0)