shinychat 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {shinychat-0.2.0 → shinychat-0.2.2}/PKG-INFO +1 -1
  2. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/__version.py +2 -2
  3. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_chat.py +15 -28
  4. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_chat_normalize.py +4 -0
  5. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_chat_types.py +8 -4
  6. {shinychat-0.2.0 → shinychat-0.2.2}/.gitignore +0 -0
  7. {shinychat-0.2.0 → shinychat-0.2.2}/LICENSE +0 -0
  8. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/README.md +0 -0
  9. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/__init__.py +0 -0
  10. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_chat_bookmark.py +0 -0
  11. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_chat_normalize_chatlas.py +0 -0
  12. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_chat_provider_types.py +0 -0
  13. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_chat_tokenizer.py +0 -0
  14. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_html_deps_py_shiny.py +0 -0
  15. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_markdown_stream.py +0 -0
  16. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_typing_extensions.py +0 -0
  17. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/_utils.py +0 -0
  18. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/express/__init__.py +0 -0
  19. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/playwright/__init__.py +0 -0
  20. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/playwright/_chat.py +0 -0
  21. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/py.typed +0 -0
  22. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/types/__init__.py +0 -0
  23. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/GIT_VERSION +0 -0
  24. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/chat/chat.css +0 -0
  25. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/chat/chat.css.map +0 -0
  26. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/chat/chat.js +0 -0
  27. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/chat/chat.js.map +0 -0
  28. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/markdown-stream/markdown-stream.css +0 -0
  29. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/markdown-stream/markdown-stream.css.map +0 -0
  30. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/markdown-stream/markdown-stream.js +0 -0
  31. {shinychat-0.2.0 → shinychat-0.2.2}/pkg-py/src/shinychat/www/markdown-stream/markdown-stream.js.map +0 -0
  32. {shinychat-0.2.0 → shinychat-0.2.2}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shinychat
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: An AI Chat interface for Shiny apps.
5
5
  Project-URL: Homepage, https://posit-dev.github.io/shinychat/
6
6
  Project-URL: Documentation, https://posit-dev.github.io/shinychat/py/
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.0'
32
- __version_tuple__ = version_tuple = (0, 2, 0)
31
+ __version__ = version = '0.2.2'
32
+ __version_tuple__ = version_tuple = (0, 2, 2)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -22,7 +22,7 @@ from weakref import WeakValueDictionary
22
22
 
23
23
  from htmltools import (
24
24
  HTML,
25
- RenderedHTML,
25
+ HTMLDependency,
26
26
  Tag,
27
27
  TagAttrValue,
28
28
  TagChild,
@@ -595,6 +595,7 @@ class Chat:
595
595
  * A dictionary with `content` and `role` keys. The `content` key can contain
596
596
  content as described above, and the `role` key can be "assistant" or
597
597
  "user".
598
+ * More generally, any type registered with :func:`shinychat.message_content`.
598
599
 
599
600
  **NOTE:** content may include specially formatted **input suggestion** links
600
601
  (see note below).
@@ -829,6 +830,7 @@ class Chat:
829
830
  * A dictionary with `content` and `role` keys. The `content` key can contain
830
831
  content as described above, and the `role` key can be "assistant" or
831
832
  "user".
833
+ * More generally, any type registered with :func:`shinychat.message_content_chunk`.
832
834
 
833
835
  **NOTE:** content may include specially formatted **input suggestion** links
834
836
  (see note below).
@@ -1588,7 +1590,9 @@ class ChatExpress(Chat):
1588
1590
  def ui(
1589
1591
  self,
1590
1592
  *,
1591
- messages: Optional[Sequence[TagChild | ChatMessageDict]] = None,
1593
+ messages: Optional[
1594
+ Iterable[str | TagChild | ChatMessageDict | ChatMessage | Any]
1595
+ ] = None,
1592
1596
  placeholder: str = "Enter a message...",
1593
1597
  width: CssUnit = "min(680px, 100%)",
1594
1598
  height: CssUnit = "auto",
@@ -1690,12 +1694,14 @@ class ChatExpress(Chat):
1690
1694
  def chat_ui(
1691
1695
  id: str,
1692
1696
  *,
1693
- messages: Optional[Sequence[TagChild | ChatMessageDict]] = None,
1697
+ messages: Optional[
1698
+ Iterable[str | TagChild | ChatMessageDict | ChatMessage | Any]
1699
+ ] = None,
1694
1700
  placeholder: str = "Enter a message...",
1695
1701
  width: CssUnit = "min(680px, 100%)",
1696
1702
  height: CssUnit = "auto",
1697
1703
  fill: bool = True,
1698
- icon_assistant: HTML | Tag | TagList | None = None,
1704
+ icon_assistant: Optional[HTML | Tag | TagList] = None,
1699
1705
  **kwargs: TagAttrValue,
1700
1706
  ) -> Tag:
1701
1707
  """
@@ -1722,6 +1728,7 @@ def chat_ui(
1722
1728
  interpreted as markdown as long as they're not inside HTML.
1723
1729
  * A dictionary with `content` and `role` keys. The `content` key can contain a
1724
1730
  content as described above, and the `role` key can be "assistant" or "user".
1731
+ * More generally, any type registered with :func:`shinychat.message_content`.
1725
1732
 
1726
1733
  **NOTE:** content may include specially formatted **input suggestion** links
1727
1734
  (see :method:`~shiny.ui.Chat.append_message` for more info).
@@ -1755,34 +1762,14 @@ def chat_ui(
1755
1762
  if messages is None:
1756
1763
  messages = []
1757
1764
  for x in messages:
1758
- role = "assistant"
1759
- content: TagChild = None
1760
- if not isinstance(x, dict):
1761
- content = x
1762
- else:
1763
- if "content" not in x:
1764
- raise ValueError(
1765
- "Each message dictionary must have a 'content' key."
1766
- )
1767
-
1768
- content = x["content"]
1769
- if "role" in x:
1770
- role = x["role"]
1771
-
1772
- # `content` is most likely a string, so avoid overhead in that case
1773
- # (it's also important that we *don't escape HTML* here).
1774
- if isinstance(content, str):
1775
- ui: RenderedHTML = {"html": content, "dependencies": []}
1776
- else:
1777
- ui = TagList(content).render()
1778
-
1765
+ msg = message_content(x)
1779
1766
  message_tags.append(
1780
1767
  Tag(
1781
1768
  "shiny-chat-message",
1782
- ui["dependencies"],
1783
- content=ui["html"],
1769
+ *[HTMLDependency(**d) for d in msg.html_deps],
1770
+ content=msg.content,
1784
1771
  icon=icon_attr,
1785
- data_role=role,
1772
+ data_role=msg.role,
1786
1773
  )
1787
1774
  )
1788
1775
 
@@ -44,6 +44,8 @@ def message_content(message):
44
44
  """
45
45
  if isinstance(message, (str, HTML)) or message is None:
46
46
  return ChatMessage(content=message)
47
+ if isinstance(message, ChatMessage):
48
+ return message
47
49
  if isinstance(message, dict):
48
50
  if "content" not in message:
49
51
  raise ValueError("Message dictionary must have a 'content' key")
@@ -90,6 +92,8 @@ def message_content_chunk(chunk):
90
92
  """
91
93
  if isinstance(chunk, (str, HTML)) or chunk is None:
92
94
  return ChatMessage(content=chunk)
95
+ if isinstance(chunk, ChatMessage):
96
+ return chunk
93
97
  if isinstance(chunk, dict):
94
98
  if "content" not in chunk:
95
99
  raise ValueError("Chunk dictionary must have a 'content' key")
@@ -4,7 +4,7 @@ from dataclasses import dataclass
4
4
  from typing import Literal, TypedDict
5
5
 
6
6
  from htmltools import HTML, Tag, TagChild, Tagifiable, TagList
7
- from shiny.session import require_active_session
7
+ from shiny.session import get_current_session
8
8
 
9
9
  from ._typing_extensions import NotRequired
10
10
 
@@ -32,10 +32,14 @@ class ChatMessage:
32
32
  # markdown), so only process it if it's not a string.
33
33
  deps = []
34
34
  if not isinstance(content, str):
35
- session = require_active_session(None)
36
- res = session._process_ui(content)
35
+ session = get_current_session()
36
+ if session and not session.is_stub_session():
37
+ res = session._process_ui(content)
38
+ deps = res["deps"]
39
+ else:
40
+ res = TagList(content).render()
41
+ deps = [d.as_dict() for d in res["dependencies"]]
37
42
  content = res["html"]
38
- deps = res["deps"]
39
43
 
40
44
  if is_html:
41
45
  # Code blocks with `{=html}` infostrings are rendered as-is by a
File without changes
File without changes
File without changes
File without changes