Skip to content

Commit 940e032

Browse files
authored
Merge branch 'main' into bump_versions
2 parents 6afc4a9 + ee1a47e commit 940e032

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+9065
-409
lines changed

.github/workflows/pytest.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ jobs:
152152

153153
playwright-examples:
154154
if: github.event_name != 'release'
155-
runs-on: ubuntu-20.04
155+
runs-on: ubuntu-latest
156156
strategy:
157157
matrix:
158158
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"]

.github/workflows/verify-js-built.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
run: |
4040
if [[ `git status --porcelain` ]]; then
4141
git diff
42-
echo "Uncommitted changes found. Please commit any changes that result from 'npm run build'."
42+
echo "Uncommitted changes found. Please commit any changes that result from 'npm ci && npm run build'."
4343
exit 1
4444
else
4545
echo "No uncommitted changes found."

CHANGELOG.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,40 @@ 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+
14+
* The `ui.Chat()` component now supports input suggestion links. This feature is useful for providing users with clickable suggestions that can be used to quickly input text into the chat. This can be done in 2 different ways (see #1845 for more details):
15+
* By adding a `.suggestion` CSS class to an HTML element (e.g., `<span class="suggestion">A suggestion</span>`)
16+
* Add a `data-suggestion` attribute to an HTML element, and set the value to the input suggestion text (e.g., `<span data-suggestion="Suggestion value">Suggestion link</span>`)
17+
* To auto-submit the suggestion when clicked by the user, include the `.submit` class or the `data-suggestion-submit="true"` attribute on the HTML element. Alternatively, use Cmd/Ctrl + click to auto-submit any suggestion or Alt/Opt + click to apply any suggestion to the chat input without submitting.
18+
1219
* 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)
1320

14-
* 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)
21+
* The `ui.Chat()` component gains the following:
22+
* The `.on_user_submit()` decorator method now passes the user input to the decorated function. This makes it a bit easier to access the user input. See the new templates (mentioned below) for examples. (#1801)
23+
* A new `get_latest_stream_result()` method was added for an easy way to access the final result of the stream when it completes. (#1846)
24+
* The `.append_message_stream()` method now returns the `reactive.extended_task` instance that it launches. (#1846)
1525

1626
* `shiny create` includes new and improved `ui.Chat()` template options. Most of these templates leverage the new [`{chatlas}` package](https://posit-dev.github.io/chatlas/), our opinionated approach to interfacing with various LLM. (#1806)
1727

28+
* Client data values (e.g., url info, output sizes/styles, etc.) can now be accessed in the server-side Python code via `session.clientdata`. For example, `session.clientdata.url_search()` reactively reads the URL search parameters. (#1832)
29+
30+
* Available `input` ids can now be listed via `dir(input)`. This also works on the new `session.clientdata` object. (#1832)
31+
32+
* The `ui.Chat()` component's `.update_user_input()` method gains `submit` and `focus` options that allow you to submit the input on behalf of the user and to choose whether the input receives focus after the update. (#1851)
33+
34+
* The assistant icons is now configurable via `ui.chat_ui()` (or the `ui.Chat.ui()` method in Shiny Express) or for individual messages in the `.append_message()` and `.append_message_stream()` methods of `ui.Chat()`. (#1853)
35+
1836
### Bug fixes
1937

2038
* `ui.Chat()` now correctly handles new `ollama.chat()` return value introduced in `ollama` v0.4. (#1787)
2139

40+
### Changes
41+
42+
* The Shiny Core component `shiny.ui.Chat()` no longer has a `.ui()` method. This method
43+
was never intended to be used in Shiny Core (in that case, use `shiny.ui.chat_ui()`) to create the UI element. Note that the `shiny.express.ui.Chat()`
44+
class still has a `.ui()` method. (#1840)
45+
2246
## [1.2.1] - 2024-11-14
2347

2448
### Bug fixes

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,15 @@ You can create and run your first application with `shiny create`, the CLI will
4747
* https://posit-dev.github.io/py-shiny/docs/api/express/
4848
* https://posit-dev.github.io/py-shiny/docs/api/core/
4949

50-
If you want to do development on Shiny for Python:
50+
If you are working from a fork you may not have the git tags from the original repo.
51+
Git tags are required for the install to succeed. To add tags to your own fork:
52+
53+
```sh
54+
git remote add upstream https://github.com/posit-dev/py-shiny.git
55+
git fetch --tags upstream
56+
```
57+
58+
Then install:
5159

5260
```sh
5361
pip install -e ".[dev,test]"

docs/_quartodoc-core.yml

Lines changed: 8 additions & 2 deletions
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:
@@ -228,19 +233,21 @@ quartodoc:
228233
path: Session
229234
summary:
230235
name: "Session"
231-
desc: ""
236+
desc: "Tools for managing user sessions and accessing session-related information."
232237
flatten: true
233238
contents:
234239
- session.get_current_session
235240
- session.require_active_session
236241
- session.session_context
237242
- reactive.get_current_context
243+
- session.ClientData
238244
- session.Session.send_custom_message
239245
- session.Session.send_input_message
240246
- session.Session.on_flush
241247
- session.Session.on_flushed
242248
- session.Session.on_ended
243249
- session.Session.dynamic_route
250+
- session.Session.close
244251
- input_handler.input_handlers
245252
- kind: page
246253
path: Renderer
@@ -358,4 +365,3 @@ quartodoc:
358365
contents:
359366
- name: experimental.ui.card_image
360367
dynamic: false
361-

docs/_quartodoc-express.yml

Lines changed: 12 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:
@@ -164,6 +168,14 @@ quartodoc:
164168
- express.ui.panel_conditional
165169
- express.ui.insert_ui
166170
- express.ui.remove_ui
171+
- title: User Session
172+
desc: Tools for managing user sessions and accessing session-related information.
173+
contents:
174+
- session.Session
175+
- title: Client Data
176+
desc: Access (client-side) information about the user session (e.g., URL, output info, etc).
177+
contents:
178+
- session.ClientData
167179
- title: UI as HTML
168180
desc: Tools for creating HTML/CSS/JS
169181
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: 78 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,66 @@
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);
4+
--_chat-container-padding: 0.25rem;
65

7-
display: flex;
8-
flex-direction: column;
6+
display: grid;
7+
grid-template-columns: 1fr;
8+
grid-template-rows: 1fr auto;
99
margin: 0 auto;
10-
gap: 1rem;
11-
overflow: auto;
12-
padding: 0.25rem;
10+
gap: 0;
11+
padding: var(--_chat-container-padding);
12+
padding-bottom: 0; // Bottom padding is on input element
1313

1414
p:last-child {
1515
margin-bottom: 0;
1616
}
17+
18+
.suggestion,
19+
[data-suggestion] {
20+
cursor: pointer;
21+
color: var(--bs-link-color, #007bc2);
22+
23+
text-decoration-color: var(--bs-link-color, #007bc2);
24+
text-decoration-line: underline;
25+
text-decoration-style: dotted;
26+
text-decoration-thickness: 2px;
27+
text-underline-offset: 2px;
28+
text-underline-offset: 4px;
29+
text-decoration-thickness: 2px;
30+
31+
padding: 2px;
32+
33+
&:hover {
34+
text-decoration-style: solid;
35+
}
36+
37+
&::after {
38+
content: "\2726"; // diamond/star
39+
display: inline-block;
40+
margin-inline-start: 0.15em;
41+
}
42+
43+
&.submit,
44+
&[data-suggestion-submit=""],
45+
&[data-suggestion-submit="true"] {
46+
&::after {
47+
content: "\21B5"; // return key symbol
48+
}
49+
}
50+
}
1751
}
1852

1953
shiny-chat-messages {
2054
display: flex;
2155
flex-direction: column;
2256
gap: 2rem;
57+
overflow: auto;
58+
margin-bottom: 1rem;
59+
60+
// Make space for the scroll bar
61+
--_scroll-margin: 1rem;
62+
padding-right: var(--_scroll-margin);
63+
margin-right: calc(-1 * var(--_scroll-margin));
2364
}
2465

2566
shiny-chat-message {
@@ -32,14 +73,32 @@ shiny-chat-message {
3273
.message-icon {
3374
border-radius: 50%;
3475
border: var(--shiny-chat-border);
76+
height: 2rem;
77+
width: 2rem;
78+
display: grid;
79+
place-items: center;
80+
overflow: clip;
81+
3582
> * {
36-
margin: 0.5rem;
37-
height: 20px;
38-
width: 20px;
83+
// images and avatars are full-bleed
84+
height: 100%;
85+
width: 100%;
86+
margin: 0 !important;
87+
object-fit: contain;
88+
}
89+
90+
> svg,
91+
> .icon,
92+
> .fa,
93+
> .bi {
94+
// icons and svgs need some padding within the circle
95+
max-height: 66%;
96+
max-width: 66%;
3997
}
4098
}
99+
41100
/* Vertically center the 2nd column (message content) */
42-
.message-content {
101+
shiny-markdown-stream {
43102
align-self: center;
44103
}
45104
}
@@ -62,10 +121,14 @@ shiny-chat-message {
62121
}
63122

64123
shiny-chat-input {
65-
margin-top: auto;
124+
--_input-padding-top: 0;
125+
--_input-padding-bottom: var(--_chat-container-padding, 0.25rem);
126+
127+
margin-top: calc(-1 * var(--_input-padding-top));
66128
position: sticky;
67-
background-color: var(--bs-body-bg, white);
68-
bottom: 0;
129+
bottom: calc(-1 * var(--_input-padding-bottom));
130+
padding-block: var(--_input-padding-top) var(--_input-padding-bottom);
131+
69132
textarea {
70133
--bs-border-radius: 26px;
71134
resize: none;
@@ -77,7 +140,7 @@ shiny-chat-input {
77140
}
78141
button {
79142
position: absolute;
80-
bottom: 7px;
143+
bottom: calc(6px + var(--_input-padding-bottom));
81144
right: 8px;
82145
background-color: transparent;
83146
color: var(--bs-primary, #007bc2);
@@ -101,53 +164,3 @@ shiny-chat-input {
101164
.shiny-busy:has(shiny-chat-input[disabled])::after {
102165
display: none;
103166
}
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)