chainlit 2.0rc0__tar.gz → 2.0.1__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.
Potentially problematic release.
This version of chainlit might be problematic. Click here for more details.
- {chainlit-2.0rc0 → chainlit-2.0.1}/PKG-INFO +3 -34
- {chainlit-2.0rc0 → chainlit-2.0.1}/README.md +1 -31
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/__init__.py +49 -54
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/action.py +12 -10
- chainlit-2.0rc0/chainlit/auth.py → chainlit-2.0.1/chainlit/auth/__init__.py +20 -34
- chainlit-2.0.1/chainlit/auth/cookie.py +123 -0
- chainlit-2.0.1/chainlit/auth/jwt.py +37 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/callbacks.py +29 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/chat_context.py +2 -2
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/chat_settings.py +3 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/cli/__init__.py +14 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/config.py +21 -59
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/context.py +3 -2
- chainlit-2.0.1/chainlit/copilot/dist/index.js +12200 -0
- chainlit-2.0.1/chainlit/data/__init__.py +113 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/acl.py +3 -2
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/base.py +1 -1
- chainlit-2.0.1/chainlit/data/chainlit_data_layer.py +584 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/dynamodb.py +5 -3
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/literalai.py +4 -6
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/sql_alchemy.py +8 -7
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/azure.py +1 -0
- chainlit-2.0.1/chainlit/data/storage_clients/azure_blob.py +80 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/base.py +6 -0
- chainlit-2.0.1/chainlit/data/storage_clients/gcs.py +78 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/s3.py +16 -3
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/discord/app.py +2 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/element.py +13 -9
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/emitter.py +17 -21
- chainlit-2.0rc0/chainlit/frontend/dist/assets/DailyMotion-CleI-8Dh.js → chainlit-2.0.1/chainlit/frontend/dist/assets/DailyMotion-B8XgmoRm.js +1 -1
- chainlit-2.0.1/chainlit/frontend/dist/assets/Dataframe-VU4lXMbv.js +22 -0
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Facebook-C4PuTowX.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Facebook-fVIMi9h_.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/FilePlayer-D49YToZz.js → chainlit-2.0.1/chainlit/frontend/dist/assets/FilePlayer-DlXvvaZa.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Kaltura-BkZcQEIs.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Kaltura-C48Ui_4V.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Mixcloud-DzvBFYsm.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Mixcloud-Dmjz7RrS.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Mux-UXPyWWYv.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Mux-Bqaa3ZzG.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Preview-0YXzpiVm.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Preview-B2d1Ugq4.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/SoundCloud-CS54COex.js → chainlit-2.0.1/chainlit/frontend/dist/assets/SoundCloud-BGuk87T3.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Streamable-DYYShO6Q.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Streamable-DOe4rXrG.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Twitch-DG7403Hm.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Twitch-TA7I2UEi.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Vidyard-C5JbOHIQ.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Vidyard-B5F6Dk_y.js +1 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Vimeo-dFLZbhqH.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Vimeo-DP_Y98tQ.js +1 -1
- chainlit-2.0.1/chainlit/frontend/dist/assets/Wistia-DB26BTg8.js +1 -0
- chainlit-2.0rc0/chainlit/frontend/dist/assets/YouTube-Dct4gpfH.js → chainlit-2.0.1/chainlit/frontend/dist/assets/YouTube-CMwwf2TN.js +1 -1
- chainlit-2.0.1/chainlit/frontend/dist/assets/index-88S3ZtD5.css +1 -0
- chainlit-2.0.1/chainlit/frontend/dist/assets/index-D7lZEN9m.js +8665 -0
- chainlit-2.0rc0/chainlit/frontend/dist/assets/react-plotly-CFHBSMgg.js → chainlit-2.0.1/chainlit/frontend/dist/assets/react-plotly-28_xImPF.js +1 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/index.html +2 -2
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/haystack/callbacks.py +5 -4
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/input_widget.py +6 -4
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/langchain/callbacks.py +56 -47
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/langflow/__init__.py +1 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/llama_index/callbacks.py +7 -7
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/message.py +6 -7
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/mistralai/__init__.py +3 -2
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/oauth_providers.py +70 -3
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/openai/__init__.py +3 -2
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/secret.py +1 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/server.py +483 -199
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/session.py +7 -5
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/slack/app.py +3 -2
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/socket.py +79 -106
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/step.py +11 -11
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/sync.py +2 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/teams/app.py +1 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/en-US.json +1 -1
- chainlit-2.0.1/chainlit/translations/nl-NL.json +229 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/types.py +20 -4
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/user.py +2 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/utils.py +3 -2
- {chainlit-2.0rc0 → chainlit-2.0.1}/pyproject.toml +10 -9
- chainlit-2.0rc0/chainlit/copilot/dist/index.js +0 -4900
- chainlit-2.0rc0/chainlit/data/__init__.py +0 -32
- chainlit-2.0rc0/chainlit/frontend/dist/assets/Wistia-143Q9V9c.js +0 -1
- chainlit-2.0rc0/chainlit/frontend/dist/assets/index-2yAiK0R5.js +0 -1091
- chainlit-2.0rc0/chainlit/frontend/dist/assets/index-CwmincdQ.css +0 -1
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/__main__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/_utils.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/cache.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/copilot/dist/assets/logo_dark-IkGJ_IwC.svg +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/copilot/dist/assets/logo_light-Bb_IPh6r.svg +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/__init__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/utils.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/discord/__init__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/assets/logo_dark-IkGJ_IwC.svg +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/assets/logo_light-Bb_IPh6r.svg +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/favicon.svg +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/haystack/__init__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/hello.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/langchain/__init__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/llama_index/__init__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/logger.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/markdown.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/py.typed +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/slack/__init__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/teams/__init__.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/telemetry.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/bn.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/gu.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/he-IL.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/hi.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/kn.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/ml.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/mr.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/ta.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/te.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/zh-CN.json +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/user_session.py +0 -0
- {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: chainlit
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: Build Conversational AI.
|
|
5
5
|
Home-page: https://chainlit.io/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -30,12 +30,11 @@ Requires-Dist: httpx (>=0.23.0)
|
|
|
30
30
|
Requires-Dist: lazify (>=0.4.0,<0.5.0)
|
|
31
31
|
Requires-Dist: literalai (==0.0.623)
|
|
32
32
|
Requires-Dist: nest-asyncio (>=1.6.0,<2.0.0)
|
|
33
|
-
Requires-Dist: numpy (>=1.26,<2.0)
|
|
34
33
|
Requires-Dist: packaging (>=23.1,<24.0)
|
|
35
34
|
Requires-Dist: pydantic (>=1,<3)
|
|
36
35
|
Requires-Dist: pyjwt (>=2.8.0,<3.0.0)
|
|
37
36
|
Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
|
|
38
|
-
Requires-Dist: python-multipart (>=0.0.
|
|
37
|
+
Requires-Dist: python-multipart (>=0.0.18,<0.0.19)
|
|
39
38
|
Requires-Dist: python-socketio (>=5.11.0,<6.0.0)
|
|
40
39
|
Requires-Dist: starlette (>=0.41.2,<0.42.0)
|
|
41
40
|
Requires-Dist: syncer (>=2.0.3,<3.0.0)
|
|
@@ -59,22 +58,10 @@ Description-Content-Type: text/markdown
|
|
|
59
58
|
|
|
60
59
|
Chainlit is an open-source async Python framework which allows developers to build scalable Conversational AI or agentic applications.
|
|
61
60
|
|
|
62
|
-
- ✅ ChatGPT-like application
|
|
63
|
-
- ✅ Embedded Chatbot & Software Copilot
|
|
64
|
-
- ✅ Slack & Discord
|
|
65
|
-
- ✅ Custom frontend (build your own agentic experience)
|
|
66
|
-
- ✅ API Endpoint
|
|
67
|
-
|
|
68
61
|
Full documentation is available [here](https://docs.chainlit.io). You can ask Chainlit related questions to [Chainlit Help](https://help.chainlit.io/), an app built using Chainlit!
|
|
69
62
|
|
|
70
|
-
|
|
71
|
-
> Check out [Literal AI](https://literalai.com), our product to monitor and evaluate LLM applications! It works with any Python or TypeScript applications and [seamlessly](https://docs.chainlit.io/data-persistence/overview) with Chainlit by adding a `LITERAL_API_KEY` in your project.
|
|
72
|
-
>
|
|
73
|
-
> Chainlit is developed and maintained by the Literal AI team, which is currently focused on expanding the capabilities of Literal AI. While we continue to support and maintain Chainlit, we are also committed to enabling the community to contribute, particularly in areas like integrations and data layers.
|
|
63
|
+
https://github.com/user-attachments/assets/b3738aba-55c0-42fa-ac00-6efd1ee0d148
|
|
74
64
|
|
|
75
|
-
<p align="center">
|
|
76
|
-
<img src="https://github.com/Chainlit/chainlit/assets/13104895/0c2cc7a9-766c-41d3-aae2-117a2d0eb8ed" alt="Chainlit user interface" width="80%"></img>
|
|
77
|
-
</p>
|
|
78
65
|
|
|
79
66
|
## Installation
|
|
80
67
|
|
|
@@ -142,24 +129,6 @@ chainlit run demo.py -w
|
|
|
142
129
|
|
|
143
130
|
<img src="/images/quick-start.png" alt="Quick Start"></img>
|
|
144
131
|
|
|
145
|
-
## 🎉 Key Features and Integrations
|
|
146
|
-
|
|
147
|
-
Full documentation is available [here](https://docs.chainlit.io). Key features:
|
|
148
|
-
|
|
149
|
-
- [💬 Multi Modal chats](https://docs.chainlit.io/advanced-features/multi-modal)
|
|
150
|
-
- [💭 Chain of Thought visualization](https://docs.chainlit.io/concepts/step)
|
|
151
|
-
- [💾 Data persistence + human feedback](https://docs.chainlit.io/data-persistence/overview)
|
|
152
|
-
- [🐛 Debug Mode](https://docs.chainlit.io/data-persistence/enterprise#debug-mode)
|
|
153
|
-
- [👤 Authentication](https://docs.chainlit.io/authentication/overview)
|
|
154
|
-
|
|
155
|
-
Chainlit is compatible with all Python programs and libraries. That being said, it comes with integrations for:
|
|
156
|
-
|
|
157
|
-
- [LangChain](https://docs.chainlit.io/integrations/langchain)
|
|
158
|
-
- [Llama Index](https://docs.chainlit.io/integrations/llama-index)
|
|
159
|
-
- [Autogen](https://github.com/Chainlit/cookbook/tree/main/pyautogen)
|
|
160
|
-
- [OpenAI Assistant](https://github.com/Chainlit/cookbook/tree/main/openai-assistant)
|
|
161
|
-
- [Haystack](https://docs.chainlit.io/integrations/haystack)
|
|
162
|
-
|
|
163
132
|
## 📚 More Examples - Cookbook
|
|
164
133
|
|
|
165
134
|
You can find various examples of Chainlit apps [here](https://github.com/Chainlit/cookbook) that leverage tools and services such as OpenAI, Anthropiс, LangChain, LlamaIndex, ChromaDB, Pinecone and more.
|
|
@@ -10,22 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
Chainlit is an open-source async Python framework which allows developers to build scalable Conversational AI or agentic applications.
|
|
12
12
|
|
|
13
|
-
- ✅ ChatGPT-like application
|
|
14
|
-
- ✅ Embedded Chatbot & Software Copilot
|
|
15
|
-
- ✅ Slack & Discord
|
|
16
|
-
- ✅ Custom frontend (build your own agentic experience)
|
|
17
|
-
- ✅ API Endpoint
|
|
18
|
-
|
|
19
13
|
Full documentation is available [here](https://docs.chainlit.io). You can ask Chainlit related questions to [Chainlit Help](https://help.chainlit.io/), an app built using Chainlit!
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
> Check out [Literal AI](https://literalai.com), our product to monitor and evaluate LLM applications! It works with any Python or TypeScript applications and [seamlessly](https://docs.chainlit.io/data-persistence/overview) with Chainlit by adding a `LITERAL_API_KEY` in your project.
|
|
23
|
-
>
|
|
24
|
-
> Chainlit is developed and maintained by the Literal AI team, which is currently focused on expanding the capabilities of Literal AI. While we continue to support and maintain Chainlit, we are also committed to enabling the community to contribute, particularly in areas like integrations and data layers.
|
|
15
|
+
https://github.com/user-attachments/assets/b3738aba-55c0-42fa-ac00-6efd1ee0d148
|
|
25
16
|
|
|
26
|
-
<p align="center">
|
|
27
|
-
<img src="https://github.com/Chainlit/chainlit/assets/13104895/0c2cc7a9-766c-41d3-aae2-117a2d0eb8ed" alt="Chainlit user interface" width="80%"></img>
|
|
28
|
-
</p>
|
|
29
17
|
|
|
30
18
|
## Installation
|
|
31
19
|
|
|
@@ -93,24 +81,6 @@ chainlit run demo.py -w
|
|
|
93
81
|
|
|
94
82
|
<img src="/images/quick-start.png" alt="Quick Start"></img>
|
|
95
83
|
|
|
96
|
-
## 🎉 Key Features and Integrations
|
|
97
|
-
|
|
98
|
-
Full documentation is available [here](https://docs.chainlit.io). Key features:
|
|
99
|
-
|
|
100
|
-
- [💬 Multi Modal chats](https://docs.chainlit.io/advanced-features/multi-modal)
|
|
101
|
-
- [💭 Chain of Thought visualization](https://docs.chainlit.io/concepts/step)
|
|
102
|
-
- [💾 Data persistence + human feedback](https://docs.chainlit.io/data-persistence/overview)
|
|
103
|
-
- [🐛 Debug Mode](https://docs.chainlit.io/data-persistence/enterprise#debug-mode)
|
|
104
|
-
- [👤 Authentication](https://docs.chainlit.io/authentication/overview)
|
|
105
|
-
|
|
106
|
-
Chainlit is compatible with all Python programs and libraries. That being said, it comes with integrations for:
|
|
107
|
-
|
|
108
|
-
- [LangChain](https://docs.chainlit.io/integrations/langchain)
|
|
109
|
-
- [Llama Index](https://docs.chainlit.io/integrations/llama-index)
|
|
110
|
-
- [Autogen](https://github.com/Chainlit/cookbook/tree/main/pyautogen)
|
|
111
|
-
- [OpenAI Assistant](https://github.com/Chainlit/cookbook/tree/main/openai-assistant)
|
|
112
|
-
- [Haystack](https://docs.chainlit.io/integrations/haystack)
|
|
113
|
-
|
|
114
84
|
## 📚 More Examples - Cookbook
|
|
115
85
|
|
|
116
86
|
You can find various examples of Chainlit apps [here](https://github.com/Chainlit/cookbook) that leverage tools and services such as OpenAI, Anthropiс, LangChain, LlamaIndex, ChromaDB, Pinecone and more.
|
|
@@ -25,7 +25,7 @@ from chainlit.chat_settings import ChatSettings
|
|
|
25
25
|
from chainlit.context import context
|
|
26
26
|
from chainlit.element import (
|
|
27
27
|
Audio,
|
|
28
|
-
|
|
28
|
+
CustomElement,
|
|
29
29
|
Dataframe,
|
|
30
30
|
File,
|
|
31
31
|
Image,
|
|
@@ -69,7 +69,9 @@ from .callbacks import (
|
|
|
69
69
|
on_message,
|
|
70
70
|
on_settings_update,
|
|
71
71
|
on_stop,
|
|
72
|
+
on_window_message,
|
|
72
73
|
password_auth_callback,
|
|
74
|
+
send_window_message,
|
|
73
75
|
set_chat_profiles,
|
|
74
76
|
set_starters,
|
|
75
77
|
)
|
|
@@ -115,80 +117,73 @@ __getattr__ = make_module_getattr(
|
|
|
115
117
|
)
|
|
116
118
|
|
|
117
119
|
__all__ = [
|
|
118
|
-
"
|
|
120
|
+
"Action",
|
|
121
|
+
"AskActionMessage",
|
|
122
|
+
"AskFileMessage",
|
|
123
|
+
"AskUserMessage",
|
|
124
|
+
"AsyncLangchainCallbackHandler",
|
|
125
|
+
"Audio",
|
|
126
|
+
"ChatGeneration",
|
|
119
127
|
"ChatProfile",
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"chat_context",
|
|
128
|
+
"ChatSettings",
|
|
129
|
+
"CompletionGeneration",
|
|
123
130
|
"CopilotFunction",
|
|
131
|
+
"CustomElement",
|
|
132
|
+
"Dataframe",
|
|
133
|
+
"ErrorMessage",
|
|
134
|
+
"File",
|
|
135
|
+
"GenerationMessage",
|
|
136
|
+
"HaystackAgentCallbackHandler",
|
|
137
|
+
"Image",
|
|
124
138
|
"InputAudioChunk",
|
|
139
|
+
"LangchainCallbackHandler",
|
|
140
|
+
"LlamaIndexCallbackHandler",
|
|
141
|
+
"Message",
|
|
125
142
|
"OutputAudioChunk",
|
|
126
|
-
"Action",
|
|
127
|
-
"User",
|
|
128
|
-
"PersistedUser",
|
|
129
|
-
"Audio",
|
|
130
143
|
"Pdf",
|
|
144
|
+
"PersistedUser",
|
|
131
145
|
"Plotly",
|
|
132
|
-
"Image",
|
|
133
|
-
"Text",
|
|
134
|
-
"Component",
|
|
135
146
|
"Pyplot",
|
|
136
|
-
"
|
|
147
|
+
"Starter",
|
|
148
|
+
"Step",
|
|
137
149
|
"Task",
|
|
138
150
|
"TaskList",
|
|
139
151
|
"TaskStatus",
|
|
152
|
+
"Text",
|
|
153
|
+
"User",
|
|
140
154
|
"Video",
|
|
141
|
-
"
|
|
142
|
-
"input_widget",
|
|
143
|
-
"Message",
|
|
144
|
-
"ErrorMessage",
|
|
145
|
-
"AskUserMessage",
|
|
146
|
-
"AskActionMessage",
|
|
147
|
-
"AskFileMessage",
|
|
148
|
-
"Step",
|
|
149
|
-
"step",
|
|
150
|
-
"ChatGeneration",
|
|
151
|
-
"CompletionGeneration",
|
|
152
|
-
"GenerationMessage",
|
|
153
|
-
"on_logout",
|
|
154
|
-
"on_chat_start",
|
|
155
|
-
"on_chat_end",
|
|
156
|
-
"on_chat_resume",
|
|
157
|
-
"on_stop",
|
|
155
|
+
"__version__",
|
|
158
156
|
"action_callback",
|
|
159
157
|
"author_rename",
|
|
160
|
-
"on_settings_update",
|
|
161
|
-
"password_auth_callback",
|
|
162
|
-
"header_auth_callback",
|
|
163
|
-
"sleep",
|
|
164
|
-
"run_sync",
|
|
165
|
-
"make_async",
|
|
166
158
|
"cache",
|
|
159
|
+
"chat_context",
|
|
167
160
|
"context",
|
|
168
|
-
"
|
|
169
|
-
"AsyncLangchainCallbackHandler",
|
|
170
|
-
"LlamaIndexCallbackHandler",
|
|
171
|
-
"HaystackAgentCallbackHandler",
|
|
172
|
-
"instrument_openai",
|
|
173
|
-
"instrument_mistralai",
|
|
174
|
-
"password_auth_callback",
|
|
161
|
+
"data_layer",
|
|
175
162
|
"header_auth_callback",
|
|
163
|
+
"input_widget",
|
|
164
|
+
"instrument_mistralai",
|
|
165
|
+
"instrument_openai",
|
|
166
|
+
"make_async",
|
|
176
167
|
"oauth_callback",
|
|
168
|
+
"on_audio_chunk",
|
|
169
|
+
"on_audio_end",
|
|
170
|
+
"on_audio_start",
|
|
171
|
+
"on_chat_end",
|
|
172
|
+
"on_chat_resume",
|
|
173
|
+
"on_chat_start",
|
|
177
174
|
"on_logout",
|
|
178
175
|
"on_message",
|
|
179
|
-
"
|
|
180
|
-
"
|
|
176
|
+
"on_settings_update",
|
|
177
|
+
"on_stop",
|
|
178
|
+
"on_window_message",
|
|
179
|
+
"password_auth_callback",
|
|
180
|
+
"run_sync",
|
|
181
|
+
"send_window_message",
|
|
181
182
|
"set_chat_profiles",
|
|
182
183
|
"set_starters",
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
"on_audio_end",
|
|
187
|
-
"author_rename",
|
|
188
|
-
"on_stop",
|
|
189
|
-
"action_callback",
|
|
190
|
-
"on_settings_update",
|
|
191
|
-
"data_layer",
|
|
184
|
+
"sleep",
|
|
185
|
+
"step",
|
|
186
|
+
"user_session",
|
|
192
187
|
]
|
|
193
188
|
|
|
194
189
|
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Dict, Optional
|
|
3
|
+
|
|
4
|
+
from dataclasses_json import DataClassJsonMixin
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
from pydantic.dataclasses import dataclass
|
|
3
7
|
|
|
4
8
|
from chainlit.context import context
|
|
5
9
|
from chainlit.telemetry import trace_event
|
|
6
|
-
from dataclasses_json import DataClassJsonMixin
|
|
7
|
-
from pydantic.dataclasses import Field, dataclass
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
@dataclass
|
|
11
13
|
class Action(DataClassJsonMixin):
|
|
12
14
|
# Name of the action, this should be used in the action_callback
|
|
13
15
|
name: str
|
|
14
|
-
# The
|
|
15
|
-
|
|
16
|
-
# The label of the action. This is what the user will see.
|
|
16
|
+
# The parameters to call this action with.
|
|
17
|
+
payload: Dict
|
|
18
|
+
# The label of the action. This is what the user will see.
|
|
17
19
|
label: str = ""
|
|
18
|
-
# The
|
|
19
|
-
|
|
20
|
+
# The tooltip of the action button. This is what the user will see when they hover the action.
|
|
21
|
+
tooltip: str = ""
|
|
22
|
+
# The lucid icon name for this action.
|
|
23
|
+
icon: Optional[str] = None
|
|
20
24
|
# This should not be set manually, only used internally.
|
|
21
25
|
forId: Optional[str] = None
|
|
22
26
|
# The ID of the action
|
|
23
27
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
24
|
-
# Show the action in a drawer menu
|
|
25
|
-
collapsed: bool = False
|
|
26
28
|
|
|
27
29
|
def __post_init__(self) -> None:
|
|
28
30
|
trace_event(f"init {self.__class__.__name__}")
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from typing import Any, Dict
|
|
4
2
|
|
|
5
|
-
import
|
|
3
|
+
from fastapi import Depends, HTTPException
|
|
4
|
+
|
|
6
5
|
from chainlit.config import config
|
|
7
6
|
from chainlit.data import get_data_layer
|
|
7
|
+
from chainlit.logger import logger
|
|
8
8
|
from chainlit.oauth_providers import get_configured_oauth_providers
|
|
9
|
-
from chainlit.user import User
|
|
10
|
-
from fastapi import Depends, HTTPException
|
|
11
|
-
from fastapi.security import OAuth2PasswordBearer
|
|
12
|
-
|
|
13
|
-
reuseable_oauth = OAuth2PasswordBearer(tokenUrl="/login", auto_error=False)
|
|
14
9
|
|
|
10
|
+
from .cookie import OAuth2PasswordBearerWithCookie
|
|
11
|
+
from .jwt import create_jwt, decode_jwt, get_jwt_secret
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
return os.environ.get("CHAINLIT_AUTH_SECRET")
|
|
13
|
+
reuseable_oauth = OAuth2PasswordBearerWithCookie(tokenUrl="/login", auto_error=False)
|
|
18
14
|
|
|
19
15
|
|
|
20
16
|
def ensure_jwt_secret():
|
|
@@ -45,49 +41,36 @@ def get_configuration():
|
|
|
45
41
|
"oauthProviders": (
|
|
46
42
|
get_configured_oauth_providers() if is_oauth_enabled() else []
|
|
47
43
|
),
|
|
44
|
+
"default_theme": config.ui.default_theme,
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
|
|
51
|
-
def create_jwt(data: User) -> str:
|
|
52
|
-
to_encode: Dict[str, Any] = data.to_dict()
|
|
53
|
-
to_encode.update(
|
|
54
|
-
{
|
|
55
|
-
"exp": datetime.utcnow() + timedelta(
|
|
56
|
-
seconds=config.project.user_session_timeout
|
|
57
|
-
),
|
|
58
|
-
}
|
|
59
|
-
)
|
|
60
|
-
encoded_jwt = jwt.encode(to_encode, get_jwt_secret(), algorithm="HS256")
|
|
61
|
-
return encoded_jwt
|
|
62
|
-
|
|
63
|
-
|
|
64
48
|
async def authenticate_user(token: str = Depends(reuseable_oauth)):
|
|
65
49
|
try:
|
|
66
|
-
|
|
67
|
-
token,
|
|
68
|
-
get_jwt_secret(),
|
|
69
|
-
algorithms=["HS256"],
|
|
70
|
-
options={"verify_signature": True},
|
|
71
|
-
)
|
|
72
|
-
del dict["exp"]
|
|
73
|
-
user = User(**dict)
|
|
50
|
+
user = decode_jwt(token)
|
|
74
51
|
except Exception as e:
|
|
75
52
|
raise HTTPException(
|
|
76
53
|
status_code=401, detail="Invalid authentication token"
|
|
77
54
|
) from e
|
|
55
|
+
|
|
78
56
|
if data_layer := get_data_layer():
|
|
57
|
+
# Get or create persistent user if we've a data layer available.
|
|
79
58
|
try:
|
|
80
59
|
persisted_user = await data_layer.get_user(user.identifier)
|
|
81
60
|
if persisted_user is None:
|
|
82
61
|
persisted_user = await data_layer.create_user(user)
|
|
83
|
-
|
|
62
|
+
assert persisted_user
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.exception("Unable to get persisted_user from data layer: %s", e)
|
|
84
65
|
return user
|
|
85
66
|
|
|
86
67
|
if user and user.display_name:
|
|
68
|
+
# Copy ephemeral display_name from authenticated user to persistent user.
|
|
87
69
|
persisted_user.display_name = user.display_name
|
|
70
|
+
|
|
88
71
|
return persisted_user
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
|
|
73
|
+
return user
|
|
91
74
|
|
|
92
75
|
|
|
93
76
|
async def get_current_user(token: str = Depends(reuseable_oauth)):
|
|
@@ -95,3 +78,6 @@ async def get_current_user(token: str = Depends(reuseable_oauth)):
|
|
|
95
78
|
return None
|
|
96
79
|
|
|
97
80
|
return await authenticate_user(token)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
__all__ = ["create_jwt", "get_configuration", "get_current_user"]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Literal, Optional, cast
|
|
3
|
+
|
|
4
|
+
from fastapi import Request, Response
|
|
5
|
+
from fastapi.exceptions import HTTPException
|
|
6
|
+
from fastapi.security.base import SecurityBase
|
|
7
|
+
from fastapi.security.utils import get_authorization_scheme_param
|
|
8
|
+
from starlette.status import HTTP_401_UNAUTHORIZED
|
|
9
|
+
|
|
10
|
+
""" Module level cookie settings. """
|
|
11
|
+
_cookie_samesite = cast(
|
|
12
|
+
Literal["lax", "strict", "none"],
|
|
13
|
+
os.environ.get("CHAINLIT_COOKIE_SAMESITE", "lax"),
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
assert (
|
|
17
|
+
_cookie_samesite
|
|
18
|
+
in [
|
|
19
|
+
"lax",
|
|
20
|
+
"strict",
|
|
21
|
+
"none",
|
|
22
|
+
]
|
|
23
|
+
), "Invalid value for CHAINLIT_COOKIE_SAMESITE. Must be one of 'lax', 'strict' or 'none'."
|
|
24
|
+
_cookie_secure = _cookie_samesite == "none"
|
|
25
|
+
|
|
26
|
+
_auth_cookie_lifetime = 60 * 60 # 1 hour
|
|
27
|
+
_state_cookie_lifetime = 3 * 60 # 3m
|
|
28
|
+
_auth_cookie_name = "access_token"
|
|
29
|
+
_state_cookie_name = "oauth_state"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class OAuth2PasswordBearerWithCookie(SecurityBase):
|
|
33
|
+
"""
|
|
34
|
+
OAuth2 password flow with cookie support with fallback to bearer token.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
tokenUrl: str,
|
|
40
|
+
scheme_name: Optional[str] = None,
|
|
41
|
+
auto_error: bool = True,
|
|
42
|
+
):
|
|
43
|
+
self.tokenUrl = tokenUrl
|
|
44
|
+
self.scheme_name = scheme_name or self.__class__.__name__
|
|
45
|
+
self.auto_error = auto_error
|
|
46
|
+
|
|
47
|
+
async def __call__(self, request: Request) -> Optional[str]:
|
|
48
|
+
# First try to get the token from the cookie
|
|
49
|
+
token = request.cookies.get(_auth_cookie_name)
|
|
50
|
+
|
|
51
|
+
# If no cookie, try the Authorization header as fallback
|
|
52
|
+
if not token:
|
|
53
|
+
# TODO: Only bother to check if cookie auth is explicitly disabled.
|
|
54
|
+
authorization = request.headers.get("Authorization")
|
|
55
|
+
if authorization:
|
|
56
|
+
scheme, token = get_authorization_scheme_param(authorization)
|
|
57
|
+
if scheme.lower() != "bearer":
|
|
58
|
+
if self.auto_error:
|
|
59
|
+
raise HTTPException(
|
|
60
|
+
status_code=HTTP_401_UNAUTHORIZED,
|
|
61
|
+
detail="Invalid authentication credentials",
|
|
62
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
return None
|
|
66
|
+
else:
|
|
67
|
+
if self.auto_error:
|
|
68
|
+
raise HTTPException(
|
|
69
|
+
status_code=HTTP_401_UNAUTHORIZED,
|
|
70
|
+
detail="Not authenticated",
|
|
71
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
return token
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def set_auth_cookie(response: Response, token: str):
|
|
80
|
+
"""
|
|
81
|
+
Helper function to set the authentication cookie with secure parameters
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
response.set_cookie(
|
|
85
|
+
key=_auth_cookie_name,
|
|
86
|
+
value=token,
|
|
87
|
+
httponly=True,
|
|
88
|
+
secure=_cookie_secure,
|
|
89
|
+
samesite=_cookie_samesite,
|
|
90
|
+
max_age=_auth_cookie_lifetime,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def clear_auth_cookie(response: Response):
|
|
95
|
+
"""
|
|
96
|
+
Helper function to clear the authentication cookie
|
|
97
|
+
"""
|
|
98
|
+
response.delete_cookie(key=_auth_cookie_name, path="/")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def set_oauth_state_cookie(response: Response, token: str):
|
|
102
|
+
response.set_cookie(
|
|
103
|
+
_state_cookie_name,
|
|
104
|
+
token,
|
|
105
|
+
httponly=True,
|
|
106
|
+
samesite=_cookie_samesite,
|
|
107
|
+
secure=_cookie_secure,
|
|
108
|
+
max_age=_state_cookie_lifetime,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def validate_oauth_state_cookie(request: Request, state: str):
|
|
113
|
+
"""Check the state from the oauth provider against the browser cookie."""
|
|
114
|
+
|
|
115
|
+
oauth_state = request.cookies.get(_state_cookie_name)
|
|
116
|
+
|
|
117
|
+
if oauth_state != state:
|
|
118
|
+
raise Exception("oauth state does not correspond")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def clear_oauth_state_cookie(response: Response):
|
|
122
|
+
"""Oauth complete, delete state token."""
|
|
123
|
+
response.delete_cookie(_state_cookie_name) # Do we set path here?
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import os
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import jwt as pyjwt
|
|
6
|
+
|
|
7
|
+
from chainlit.config import config
|
|
8
|
+
from chainlit.user import User
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_jwt_secret() -> Optional[str]:
|
|
12
|
+
return os.environ.get("CHAINLIT_AUTH_SECRET")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_jwt(data: User) -> str:
|
|
16
|
+
to_encode: Dict[str, Any] = data.to_dict()
|
|
17
|
+
to_encode.update(
|
|
18
|
+
{
|
|
19
|
+
"exp": datetime.datetime.utcnow()
|
|
20
|
+
+ datetime.timedelta(seconds=config.project.user_session_timeout),
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
secret = get_jwt_secret()
|
|
24
|
+
assert secret
|
|
25
|
+
encoded_jwt = pyjwt.encode(to_encode, secret, algorithm="HS256")
|
|
26
|
+
return encoded_jwt
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def decode_jwt(token: str) -> User:
|
|
30
|
+
dict = pyjwt.decode(
|
|
31
|
+
token,
|
|
32
|
+
get_jwt_secret(),
|
|
33
|
+
algorithms=["HS256"],
|
|
34
|
+
options={"verify_signature": True},
|
|
35
|
+
)
|
|
36
|
+
del dict["exp"]
|
|
37
|
+
return User(**dict)
|
|
@@ -6,6 +6,7 @@ from starlette.datastructures import Headers
|
|
|
6
6
|
|
|
7
7
|
from chainlit.action import Action
|
|
8
8
|
from chainlit.config import config
|
|
9
|
+
from chainlit.context import context
|
|
9
10
|
from chainlit.data.base import BaseDataLayer
|
|
10
11
|
from chainlit.message import Message
|
|
11
12
|
from chainlit.oauth_providers import get_configured_oauth_providers
|
|
@@ -125,6 +126,33 @@ def on_message(func: Callable) -> Callable:
|
|
|
125
126
|
return func
|
|
126
127
|
|
|
127
128
|
|
|
129
|
+
@trace
|
|
130
|
+
async def send_window_message(data: Any):
|
|
131
|
+
"""
|
|
132
|
+
Send custom data to the host window via a window.postMessage event.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
data (Any): The data to send with the event.
|
|
136
|
+
"""
|
|
137
|
+
await context.emitter.send_window_message(data)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@trace
|
|
141
|
+
def on_window_message(func: Callable[[str], Any]) -> Callable:
|
|
142
|
+
"""
|
|
143
|
+
Hook to react to javascript postMessage events coming from the UI.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
func (Callable[[str], Any]): The function to be called when a window message is received.
|
|
147
|
+
Takes the message content as a string parameter.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Callable[[str], Any]: The decorated on_window_message function.
|
|
151
|
+
"""
|
|
152
|
+
config.code.on_window_message = wrap_user_function(func)
|
|
153
|
+
return func
|
|
154
|
+
|
|
155
|
+
|
|
128
156
|
@trace
|
|
129
157
|
def on_chat_start(func: Callable) -> Callable:
|
|
130
158
|
"""
|
|
@@ -297,7 +325,7 @@ def action_callback(name: str) -> Callable:
|
|
|
297
325
|
"""
|
|
298
326
|
|
|
299
327
|
def decorator(func: Callable[[Action], Any]):
|
|
300
|
-
config.code.action_callbacks[name] = wrap_user_function(func, with_task=
|
|
328
|
+
config.code.action_callbacks[name] = wrap_user_function(func, with_task=False)
|
|
301
329
|
return func
|
|
302
330
|
|
|
303
331
|
return decorator
|
|
@@ -25,10 +25,10 @@ class ChatContext:
|
|
|
25
25
|
|
|
26
26
|
if context.session.id not in chat_contexts:
|
|
27
27
|
chat_contexts[context.session.id] = []
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
if message not in chat_contexts[context.session.id]:
|
|
30
30
|
chat_contexts[context.session.id].append(message)
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
return message
|
|
33
33
|
|
|
34
34
|
def remove(self, message: "Message") -> bool:
|
|
@@ -9,6 +9,7 @@ import uvicorn
|
|
|
9
9
|
nest_asyncio.apply()
|
|
10
10
|
|
|
11
11
|
# ruff: noqa: E402
|
|
12
|
+
from chainlit.auth import ensure_jwt_secret
|
|
12
13
|
from chainlit.cache import init_lc_cache
|
|
13
14
|
from chainlit.config import (
|
|
14
15
|
BACKEND_ROOT,
|
|
@@ -24,7 +25,18 @@ from chainlit.logger import logger
|
|
|
24
25
|
from chainlit.markdown import init_markdown
|
|
25
26
|
from chainlit.secret import random_secret
|
|
26
27
|
from chainlit.telemetry import trace_event
|
|
27
|
-
from chainlit.utils import check_file
|
|
28
|
+
from chainlit.utils import check_file
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def assert_app():
|
|
32
|
+
if (
|
|
33
|
+
not config.code.on_chat_start
|
|
34
|
+
and not config.code.on_message
|
|
35
|
+
and not config.code.on_audio_chunk
|
|
36
|
+
):
|
|
37
|
+
raise Exception(
|
|
38
|
+
"You need to configure at least one of on_chat_start, on_message or on_audio_chunk callback"
|
|
39
|
+
)
|
|
28
40
|
|
|
29
41
|
|
|
30
42
|
# Create the main command group for Chainlit CLI
|
|
@@ -66,6 +78,7 @@ def run_chainlit(target: str):
|
|
|
66
78
|
load_module(config.run.module_name)
|
|
67
79
|
|
|
68
80
|
ensure_jwt_secret()
|
|
81
|
+
assert_app()
|
|
69
82
|
|
|
70
83
|
# Create the chainlit.md file if it doesn't exist
|
|
71
84
|
init_markdown(config.root)
|