Skip to content

Commit 5253cb4

Browse files
authored
Merge branch 'main' into add-bookmarking-layouts
2 parents c59ca9c + 29a1c66 commit 5253cb4

File tree

83 files changed

+1405
-211
lines changed

Some content is hidden

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

83 files changed

+1405
-211
lines changed

CHANGELOG.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
* Both `ui.Chat()` and `ui.MarkdownStream()` now support arbirary Shiny UI elements inside of messages. This allows for gathering input from the user (e.g., `ui.input_select()`), displaying of rich output (e.g., `render.DataGrid()`), and more. (#1868)
1313

14+
* Added a new `.message_stream_context()` method to `ui.Chat()`. This context manager is a useful alternative to `.append_message_stream()` when you want to: (1) Nest a stream within another and/or
15+
(2) Overwrite/replace streaming content. (#1906)
16+
1417
### Changes
1518

1619
* Express mode's `app_opts()` requires all arguments to be keyword-only. If you are using positional arguments, you will need to update your code. (#1895)
1720

1821
* The `.get_latest_stream_result()` method on `ui.MarkdownStream()` was deprecated in favor of the new `.latest_stream` property. Call `.result()` on the property to get the latest result, `.status` to check the status, and `.cancel()` to cancel the stream.
1922

23+
* `MarkdownStream()` now has a default maximum width of `680px` for better readability. Also, similar to `Chat()`, it now also horizontally centers itself. (#1944)
24+
25+
* `ui.page_navbar()` and `ui.navset_bar()` now correctly apply `theme` and additional attributes from `navbar_options` created with `ui.navbar_options()`. (#1942)
26+
2027
### Bug fixes
2128

2229
* Fixed an issue where the `<main>` areas of `ui.page_sidebar()` and `ui.page_navbar()` (with a `sidebar`) were made to be a fillable containers even when `fillable=False`. (#1816)
2330

2431
* Fixed an issue where the `.update_user_input()` method on `ui.Chat()` isn't working in shinylive. (#1891)
2532

33+
* Fixed an issue where `width` and `height` on `MarkdownStream()` were not working as intended. (#1944)
34+
2635
* Fixed an issue with the `.click()` method on InputActionButton controllers in `shiny.playwright.controllers` where the method would not work as expected. (#1886)
2736

2837
## [1.3.0] - 2025-03-03
@@ -59,12 +68,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5968

6069
### Breaking changes
6170

62-
* The navbar-related style options of `ui.page_navbar()` and `ui.navset_bar()` have been consolidated into a single `navbar_options` argument that pairs with a new `ui.navbar_options()` helper. Using the direct `position`, `bg`, `inverse`, `collapsible`, and `underline` arguments will continue to work with a deprecation message.
71+
* The navbar-related style options of `ui.page_navbar()` and `ui.navset_bar()` have been consolidated into a single `navbar_options` argument that pairs with a new `ui.navbar_options()` helper. Using the direct `position`, `bg`, `inverse`, `collapsible`, and `underline` arguments will continue to work with a deprecation message. (#1822)
6372

6473
Related to this change, `ui.navset_bar()` now defaults to using `underline=True` so that it uses the same set of default `ui.navbar_options()` as the page variant. In `ui.navbar_options()`, `inverse` is replaced by `theme`, which takes values `"light"` (dark text on a **light** background), `"dark"` (light text on a **dark** background), or `"auto"` (follow page settings).
6574

66-
* The Shiny Core component `shiny.ui.Chat()` no longer has a `.ui()` method. This method
67-
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()` class still has a `.ui()` method. (#1840)
75+
* The Shiny Core component `shiny.ui.Chat()` no longer has a `.ui()` method. This method 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()` class still has a `.ui()` method. (#1840)
6876

6977
### Bug fixes
7078

js/chat/chat.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ shiny-chat-input {
145145

146146
margin-top: calc(-1 * var(--_input-padding-top));
147147
position: sticky;
148-
bottom: calc(-1 * var(--_input-padding-bottom));
148+
bottom: calc(-1 * var(--_input-padding-bottom) + 4px);
149+
// 4px: autoscroll adds 2px to height, this keeps input from wiggling when scrolling on top of chat
149150
padding-block: var(--_input-padding-top) var(--_input-padding-bottom);
150151

151152
textarea {

js/markdown-stream/markdown-stream.scss

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
@include highlight_styles.atom_one_dark;
77
}
88

9+
shiny-markdown-stream {
10+
display: block;
11+
}
12+
913
/*
1014
Styling for the code-copy button (inspired by Quarto's code-copy feature)
1115
*/
@@ -68,7 +72,8 @@ pre:has(.code-copy-button) {
6872
.markdown-stream-dot {
6973
// The stream dot is appended with each streaming chunk update, so the pulse animation
7074
// only shows up when streaming pauses but isn't complete.
71-
animation: markdown-stream-dot-pulse 2s infinite cubic-bezier(0.18, 0.89, 0.32, 1.28);
75+
animation: markdown-stream-dot-pulse 1.75s infinite cubic-bezier(0.18, 0.89, 0.32, 1.28);
76+
animation-delay: 250ms;
7277
display: inline-block;
7378
transform-origin: center;
7479
}

shiny/_main_create.py

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,6 @@ def apps(self) -> list[ShinyTemplate]:
223223
def packages(self) -> list[ShinyTemplate]:
224224
return self._templates("templates/package")
225225

226-
@property
227-
def chat_starters(self) -> list[ShinyTemplate]:
228-
return self._templates("templates/chat/starters")
229-
230226
@property
231227
def chat_llms(self) -> list[ShinyTemplate]:
232228
return self._templates("templates/chat/llms")
@@ -235,6 +231,14 @@ def chat_llms(self) -> list[ShinyTemplate]:
235231
def chat_enterprise(self) -> list[ShinyTemplate]:
236232
return self._templates("templates/chat/llm-enterprise")
237233

234+
@property
235+
def stream_llms(self) -> list[ShinyTemplate]:
236+
return self._templates("templates/markdown-stream/llms")
237+
238+
@property
239+
def stream_enterprise(self) -> list[ShinyTemplate]:
240+
return self._templates("templates/markdown-stream/llm-enterpise")
241+
238242

239243
shiny_internal_templates = ShinyInternalTemplates()
240244

@@ -261,15 +265,16 @@ def use_internal_template(
261265

262266
app_templates = shiny_internal_templates.apps
263267
pkg_templates = shiny_internal_templates.packages
264-
chat_templates = [
265-
*shiny_internal_templates.chat_starters,
268+
gen_ai_templates = [
266269
*shiny_internal_templates.chat_llms,
267270
*shiny_internal_templates.chat_enterprise,
271+
*shiny_internal_templates.stream_llms,
272+
*shiny_internal_templates.stream_enterprise,
268273
]
269274

270275
menu_choices = [
276+
Choice(title="Generative AI...", value="_gen-ai"),
271277
Choice(title="Custom JavaScript component...", value="_js-component"),
272-
Choice(title="Chat component templates...", value="_chat"),
273278
Choice(
274279
title="Choose from the Shiny Templates website", value="_external-gallery"
275280
),
@@ -279,7 +284,7 @@ def use_internal_template(
279284
question_state = question_choose_template(app_templates, *menu_choices)
280285

281286
template = template_by_name(
282-
[*app_templates, *pkg_templates, *chat_templates], question_state
287+
[*app_templates, *pkg_templates, *gen_ai_templates], question_state
283288
)
284289

285290
if template is not None:
@@ -302,8 +307,8 @@ def use_internal_template(
302307
sys.exit(0)
303308
elif question_state == "_js-component":
304309
use_internal_package_template(dest_dir=dest_dir, package_name=package_name)
305-
elif question_state == "_chat":
306-
use_internal_chat_ai_template(dest_dir=dest_dir, package_name=package_name)
310+
elif question_state == "_gen-ai":
311+
use_internal_gen_ai_template(dest_dir=dest_dir, package_name=package_name)
307312
else:
308313
valid_choices = [t.id for t in app_templates + pkg_templates]
309314
if question_state not in valid_choices:
@@ -345,18 +350,24 @@ def use_internal_package_template(
345350
package_template_questions(template, dest_dir=dest_dir, package_name=package_name)
346351

347352

348-
def use_internal_chat_ai_template(
353+
def use_internal_gen_ai_template(
349354
input: str | None = None,
350355
dest_dir: Optional[Path] = None,
351356
package_name: Optional[str] = None,
352357
):
353358
if input is None:
354359
input = questionary.select(
355-
"Which kind of chat template would you like?",
360+
"Which kind of Gen AI template would you like?",
356361
choices=[
357-
Choice(title="Chat starters...", value="_chat-starters"),
358-
Choice(title="LLM powered chat...", value="_chat-llms"),
359-
Choice(title="Enterprise LLM...", value="_chat-llm_enterprise"),
362+
Choice(title="Chat with LLM...", value="_chat-llms"),
363+
Choice(
364+
title="Chat with enterprise LLM...", value="_chat-llm_enterprise"
365+
),
366+
Choice(title="Stream markdown with LLM...", value="_stream-llms"),
367+
Choice(
368+
title="Stream markdown with enterprise LLM...",
369+
value="_stream-enterprise",
370+
),
360371
back_choice,
361372
cancel_choice,
362373
],
@@ -370,29 +381,34 @@ def use_internal_chat_ai_template(
370381
use_internal_template(dest_dir=dest_dir, package_name=package_name)
371382
return
372383

373-
use_internal_chat_ai_template(
384+
use_internal_gen_ai_template(
374385
input, dest_dir=dest_dir, package_name=package_name
375386
)
376387
return
377388

378-
if input == "_chat-starters":
379-
template_choices = shiny_internal_templates.chat_starters
380-
elif input == "_chat-llms":
389+
if input == "_chat-llms":
381390
template_choices = shiny_internal_templates.chat_llms
382-
else:
391+
elif input == "_chat-llm_enterprise":
383392
template_choices = shiny_internal_templates.chat_enterprise
393+
elif input == "_stream-llms":
394+
template_choices = shiny_internal_templates.stream_llms
395+
elif input == "_stream-enterprise":
396+
template_choices = shiny_internal_templates.stream_enterprise
397+
else:
398+
raise ValueError(f"Invalid Gen AI template choice: {input}")
384399

385400
choice = question_choose_template(template_choices, back_choice)
386401

387402
if choice == "back":
388-
use_internal_chat_ai_template(dest_dir=dest_dir, package_name=package_name)
403+
use_internal_gen_ai_template(dest_dir=dest_dir, package_name=package_name)
389404
return
390405

391406
template = template_by_name(
392407
[
393-
*shiny_internal_templates.chat_starters,
394408
*shiny_internal_templates.chat_llms,
395409
*shiny_internal_templates.chat_enterprise,
410+
*shiny_internal_templates.stream_llms,
411+
*shiny_internal_templates.stream_enterprise,
396412
],
397413
choice,
398414
)

shiny/templates/chat/starters/hello/app-core.py renamed to shiny/api-examples/Chat/app-core.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
# Create a welcome message
1010
welcome = """
1111
Hi! This is a simple Shiny `Chat` UI. Enter a message below and I will
12-
simply repeat it back to you. For more examples, see this
13-
[folder of examples](https://github.com/posit-dev/py-shiny/tree/main/shiny/templates/chat).
12+
simply repeat it back to you.
13+
14+
To learn more about chatbots and how to build them with Shiny, check out
15+
[the documentation](https://shiny.posit.co/py/docs/genai-chatbots.html).
1416
"""
1517

1618

shiny/templates/chat/starters/hello/app-express.py renamed to shiny/api-examples/Chat/app-express.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
# Create a welcome message
1111
welcome = """
1212
Hi! This is a simple Shiny `Chat` UI. Enter a message below and I will
13-
simply repeat it back to you. For more examples, see this
14-
[folder of examples](https://github.com/posit-dev/py-shiny/tree/main/shiny/templates/chat).
13+
simply repeat it back to you.
14+
15+
To learn more about chatbots and how to build them with Shiny, check out
16+
[the documentation](https://shiny.posit.co/py/docs/genai-chatbots.html).
1517
"""
1618

1719
# Create a chat instance

0 commit comments

Comments
 (0)