Skip to content

Commit 8844d73

Browse files
committed
Merged origin/main into feat/navbar-options
2 parents 15f5562 + ee1a47e commit 8844d73

Some content is hidden

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

66 files changed

+9086
-422
lines changed

.github/workflows/pytest.yaml

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

155155
playwright-examples:
156156
if: github.event_name != 'release'
157-
runs-on: ubuntu-20.04
157+
runs-on: ubuntu-latest
158158
strategy:
159159
matrix:
160160
python-version: ["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
@@ -103,6 +103,11 @@ quartodoc:
103103
contents:
104104
- ui.Chat
105105
- ui.chat_ui
106+
- title: Streaming markdown
107+
desc: Stream markdown content into the UI
108+
contents:
109+
- ui.MarkdownStream
110+
- ui.output_markdown_stream
106111
- title: Custom UI
107112
desc: Lower-level UI functions for creating custom HTML/CSS/JS
108113
contents:
@@ -229,19 +234,21 @@ quartodoc:
229234
path: Session
230235
summary:
231236
name: "Session"
232-
desc: ""
237+
desc: "Tools for managing user sessions and accessing session-related information."
233238
flatten: true
234239
contents:
235240
- session.get_current_session
236241
- session.require_active_session
237242
- session.session_context
238243
- reactive.get_current_context
244+
- session.ClientData
239245
- session.Session.send_custom_message
240246
- session.Session.send_input_message
241247
- session.Session.on_flush
242248
- session.Session.on_flushed
243249
- session.Session.on_ended
244250
- session.Session.dynamic_route
251+
- session.Session.close
245252
- input_handler.input_handlers
246253
- kind: page
247254
path: Renderer
@@ -359,4 +366,3 @@ quartodoc:
359366
contents:
360367
- name: experimental.ui.card_image
361368
dynamic: false
362-

docs/_quartodoc-express.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ quartodoc:
8282
desc: Build a chatbot interface
8383
contents:
8484
- express.ui.Chat
85+
- title: Streaming markdown
86+
desc: Stream markdown content into the UI
87+
contents:
88+
- express.ui.MarkdownStream
8589
- title: Reactive programming
8690
desc: Create reactive functions and dependencies.
8791
contents:
@@ -165,6 +169,14 @@ quartodoc:
165169
- express.ui.panel_conditional
166170
- express.ui.insert_ui
167171
- express.ui.remove_ui
172+
- title: User Session
173+
desc: Tools for managing user sessions and accessing session-related information.
174+
contents:
175+
- session.Session
176+
- title: Client Data
177+
desc: Access (client-side) information about the user session (e.g., URL, output info, etc).
178+
contents:
179+
- session.ClientData
168180
- title: UI as HTML
169181
desc: Tools for creating HTML/CSS/JS
170182
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)