chainlit 1.0.401__py3-none-any.whl → 2.0.4__py3-none-any.whl

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.

Files changed (113) hide show
  1. chainlit/__init__.py +98 -279
  2. chainlit/_utils.py +8 -0
  3. chainlit/action.py +12 -10
  4. chainlit/{auth.py → auth/__init__.py} +28 -36
  5. chainlit/auth/cookie.py +123 -0
  6. chainlit/auth/jwt.py +39 -0
  7. chainlit/cache.py +4 -6
  8. chainlit/callbacks.py +362 -0
  9. chainlit/chat_context.py +64 -0
  10. chainlit/chat_settings.py +3 -1
  11. chainlit/cli/__init__.py +77 -8
  12. chainlit/config.py +191 -102
  13. chainlit/context.py +42 -13
  14. chainlit/copilot/dist/index.js +8750 -903
  15. chainlit/data/__init__.py +101 -416
  16. chainlit/data/acl.py +6 -2
  17. chainlit/data/base.py +107 -0
  18. chainlit/data/chainlit_data_layer.py +614 -0
  19. chainlit/data/dynamodb.py +590 -0
  20. chainlit/data/literalai.py +500 -0
  21. chainlit/data/sql_alchemy.py +721 -0
  22. chainlit/data/storage_clients/__init__.py +0 -0
  23. chainlit/data/storage_clients/azure.py +81 -0
  24. chainlit/data/storage_clients/azure_blob.py +89 -0
  25. chainlit/data/storage_clients/base.py +26 -0
  26. chainlit/data/storage_clients/gcs.py +88 -0
  27. chainlit/data/storage_clients/s3.py +75 -0
  28. chainlit/data/utils.py +29 -0
  29. chainlit/discord/__init__.py +6 -0
  30. chainlit/discord/app.py +354 -0
  31. chainlit/element.py +91 -33
  32. chainlit/emitter.py +81 -29
  33. chainlit/frontend/dist/assets/DailyMotion-Ce9dQoqZ.js +1 -0
  34. chainlit/frontend/dist/assets/Dataframe-C1XonMcV.js +22 -0
  35. chainlit/frontend/dist/assets/Facebook-DVVt6lrr.js +1 -0
  36. chainlit/frontend/dist/assets/FilePlayer-c7stW4vz.js +1 -0
  37. chainlit/frontend/dist/assets/Kaltura-BmMmgorA.js +1 -0
  38. chainlit/frontend/dist/assets/Mixcloud-Cw8hDmiO.js +1 -0
  39. chainlit/frontend/dist/assets/Mux-DiRZfeUf.js +1 -0
  40. chainlit/frontend/dist/assets/Preview-6Jt2mRHx.js +1 -0
  41. chainlit/frontend/dist/assets/SoundCloud-DKwcT58_.js +1 -0
  42. chainlit/frontend/dist/assets/Streamable-BVdxrEeX.js +1 -0
  43. chainlit/frontend/dist/assets/Twitch-DFqZR7Gu.js +1 -0
  44. chainlit/frontend/dist/assets/Vidyard-0BQAAtVk.js +1 -0
  45. chainlit/frontend/dist/assets/Vimeo-CRFSH0Vu.js +1 -0
  46. chainlit/frontend/dist/assets/Wistia-CKrmdQaG.js +1 -0
  47. chainlit/frontend/dist/assets/YouTube-CQpL-rvU.js +1 -0
  48. chainlit/frontend/dist/assets/index-DQmLRKyv.css +1 -0
  49. chainlit/frontend/dist/assets/index-QdmxtIMQ.js +8665 -0
  50. chainlit/frontend/dist/assets/react-plotly-B9hvVpUG.js +3484 -0
  51. chainlit/frontend/dist/index.html +2 -4
  52. chainlit/haystack/callbacks.py +4 -7
  53. chainlit/input_widget.py +8 -4
  54. chainlit/langchain/callbacks.py +103 -68
  55. chainlit/langflow/__init__.py +1 -0
  56. chainlit/llama_index/callbacks.py +65 -40
  57. chainlit/markdown.py +22 -6
  58. chainlit/message.py +54 -56
  59. chainlit/mistralai/__init__.py +50 -0
  60. chainlit/oauth_providers.py +266 -8
  61. chainlit/openai/__init__.py +10 -18
  62. chainlit/secret.py +1 -1
  63. chainlit/server.py +789 -228
  64. chainlit/session.py +108 -90
  65. chainlit/slack/__init__.py +6 -0
  66. chainlit/slack/app.py +397 -0
  67. chainlit/socket.py +199 -116
  68. chainlit/step.py +141 -89
  69. chainlit/sync.py +2 -1
  70. chainlit/teams/__init__.py +6 -0
  71. chainlit/teams/app.py +338 -0
  72. chainlit/translations/bn.json +244 -0
  73. chainlit/translations/en-US.json +122 -8
  74. chainlit/translations/gu.json +244 -0
  75. chainlit/translations/he-IL.json +244 -0
  76. chainlit/translations/hi.json +244 -0
  77. chainlit/translations/ja.json +242 -0
  78. chainlit/translations/kn.json +244 -0
  79. chainlit/translations/ml.json +244 -0
  80. chainlit/translations/mr.json +244 -0
  81. chainlit/translations/nl-NL.json +242 -0
  82. chainlit/translations/ta.json +244 -0
  83. chainlit/translations/te.json +244 -0
  84. chainlit/translations/zh-CN.json +243 -0
  85. chainlit/translations.py +60 -0
  86. chainlit/types.py +133 -28
  87. chainlit/user.py +14 -3
  88. chainlit/user_session.py +6 -3
  89. chainlit/utils.py +52 -5
  90. chainlit/version.py +3 -2
  91. {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/METADATA +48 -50
  92. chainlit-2.0.4.dist-info/RECORD +107 -0
  93. chainlit/cli/utils.py +0 -24
  94. chainlit/frontend/dist/assets/index-9711593e.js +0 -723
  95. chainlit/frontend/dist/assets/index-d088547c.css +0 -1
  96. chainlit/frontend/dist/assets/react-plotly-d8762cc2.js +0 -3602
  97. chainlit/playground/__init__.py +0 -2
  98. chainlit/playground/config.py +0 -40
  99. chainlit/playground/provider.py +0 -108
  100. chainlit/playground/providers/__init__.py +0 -13
  101. chainlit/playground/providers/anthropic.py +0 -118
  102. chainlit/playground/providers/huggingface.py +0 -75
  103. chainlit/playground/providers/langchain.py +0 -89
  104. chainlit/playground/providers/openai.py +0 -408
  105. chainlit/playground/providers/vertexai.py +0 -171
  106. chainlit/translations/pt-BR.json +0 -155
  107. chainlit-1.0.401.dist-info/RECORD +0 -66
  108. /chainlit/copilot/dist/assets/{logo_dark-2a3cf740.svg → logo_dark-IkGJ_IwC.svg} +0 -0
  109. /chainlit/copilot/dist/assets/{logo_light-b078e7bc.svg → logo_light-Bb_IPh6r.svg} +0 -0
  110. /chainlit/frontend/dist/assets/{logo_dark-2a3cf740.svg → logo_dark-IkGJ_IwC.svg} +0 -0
  111. /chainlit/frontend/dist/assets/{logo_light-b078e7bc.svg → logo_light-Bb_IPh6r.svg} +0 -0
  112. {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/WHEEL +0 -0
  113. {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/entry_points.txt +0 -0
chainlit/session.py CHANGED
@@ -1,50 +1,51 @@
1
+ import asyncio
1
2
  import json
2
3
  import mimetypes
3
4
  import shutil
4
5
  import uuid
5
- from typing import (
6
- TYPE_CHECKING,
7
- Any,
8
- Callable,
9
- Deque,
10
- Dict,
11
- List,
12
- Literal,
13
- Optional,
14
- Union,
15
- )
6
+ from typing import TYPE_CHECKING, Any, Callable, Deque, Dict, Literal, Optional, Union
16
7
 
17
8
  import aiofiles
9
+
18
10
  from chainlit.logger import logger
11
+ from chainlit.types import FileReference
19
12
 
20
13
  if TYPE_CHECKING:
21
- from chainlit.message import Message
22
- from chainlit.step import Step
23
- from chainlit.types import FileDict, FileReference
14
+ from chainlit.types import FileDict
24
15
  from chainlit.user import PersistedUser, User
25
16
 
26
- ClientType = Literal["app", "copilot", "teams", "slack"]
17
+ ClientType = Literal["webapp", "copilot", "teams", "slack", "discord"]
27
18
 
28
19
 
29
20
  class JSONEncoderIgnoreNonSerializable(json.JSONEncoder):
30
- def default(self, obj):
21
+ def default(self, o):
31
22
  try:
32
- return super(JSONEncoderIgnoreNonSerializable, self).default(obj)
23
+ return super().default(o)
33
24
  except TypeError:
34
25
  return None
35
26
 
36
27
 
37
- def clean_metadata(metadata: Dict):
38
- return json.loads(
28
+ def clean_metadata(metadata: Dict, max_size: int = 1048576):
29
+ cleaned_metadata = json.loads(
39
30
  json.dumps(metadata, cls=JSONEncoderIgnoreNonSerializable, ensure_ascii=False)
40
31
  )
41
32
 
33
+ metadata_size = len(json.dumps(cleaned_metadata).encode("utf-8"))
34
+ if metadata_size > max_size:
35
+ # Redact the metadata if it exceeds the maximum size
36
+ cleaned_metadata = {
37
+ "message": f"Metadata size exceeds the limit of {max_size} bytes. Redacted."
38
+ }
39
+
40
+ return cleaned_metadata
41
+
42
42
 
43
43
  class BaseSession:
44
44
  """Base object."""
45
45
 
46
46
  thread_id_to_resume: Optional[str] = None
47
47
  client_type: ClientType
48
+ current_task: Optional[asyncio.Task] = None
48
49
 
49
50
  def __init__(
50
51
  self,
@@ -53,16 +54,18 @@ class BaseSession:
53
54
  client_type: ClientType,
54
55
  # Thread id
55
56
  thread_id: Optional[str],
56
- # Logged-in user informations
57
+ # Logged-in user information
57
58
  user: Optional[Union["User", "PersistedUser"]],
58
59
  # Logged-in user token
59
60
  token: Optional[str],
60
61
  # User specific environment variables. Empty if no user environment variables are required.
61
62
  user_env: Optional[Dict[str, str]],
62
- # Last message at the root of the chat
63
- root_message: Optional["Message"] = None,
64
63
  # Chat profile selected before the session was created
65
64
  chat_profile: Optional[str] = None,
65
+ # Origin of the request
66
+ http_referer: Optional[str] = None,
67
+ # Cookie
68
+ http_cookie: Optional[str] = None,
66
69
  ):
67
70
  if thread_id:
68
71
  self.thread_id_to_resume = thread_id
@@ -70,23 +73,73 @@ class BaseSession:
70
73
  self.user = user
71
74
  self.client_type = client_type
72
75
  self.token = token
73
- self.root_message = root_message
74
76
  self.has_first_interaction = False
75
77
  self.user_env = user_env or {}
76
78
  self.chat_profile = chat_profile
79
+ self.http_referer = http_referer
80
+ self.http_cookie = http_cookie
81
+
82
+ self.files: Dict[str, FileDict] = {}
77
83
 
78
84
  self.id = id
79
85
 
80
86
  self.chat_settings: Dict[str, Any] = {}
81
87
 
88
+ @property
89
+ def files_dir(self):
90
+ from chainlit.config import FILES_DIRECTORY
91
+
92
+ return FILES_DIRECTORY / self.id
93
+
82
94
  async def persist_file(
83
95
  self,
84
96
  name: str,
85
97
  mime: str,
86
98
  path: Optional[str] = None,
87
99
  content: Optional[Union[bytes, str]] = None,
88
- ):
89
- return None
100
+ ) -> FileReference:
101
+ if not path and not content:
102
+ raise ValueError(
103
+ "Either path or content must be provided to persist a file"
104
+ )
105
+
106
+ self.files_dir.mkdir(exist_ok=True)
107
+
108
+ file_id = str(uuid.uuid4())
109
+
110
+ file_path = self.files_dir / file_id
111
+
112
+ file_extension = mimetypes.guess_extension(mime)
113
+
114
+ if file_extension:
115
+ file_path = file_path.with_suffix(file_extension)
116
+
117
+ if path:
118
+ # Copy the file from the given path
119
+ async with (
120
+ aiofiles.open(path, "rb") as src,
121
+ aiofiles.open(file_path, "wb") as dst,
122
+ ):
123
+ await dst.write(await src.read())
124
+ elif content:
125
+ # Write the provided content to the file
126
+ async with aiofiles.open(file_path, "wb") as buffer:
127
+ if isinstance(content, str):
128
+ content = content.encode("utf-8")
129
+ await buffer.write(content)
130
+
131
+ # Get the file size
132
+ file_size = file_path.stat().st_size
133
+ # Store the file content in memory
134
+ self.files[file_id] = {
135
+ "id": file_id,
136
+ "path": file_path,
137
+ "name": name,
138
+ "type": mime,
139
+ "size": file_size,
140
+ }
141
+
142
+ return {"id": file_id}
90
143
 
91
144
  def to_persistable(self) -> Dict:
92
145
  from chainlit.user_session import user_sessions
@@ -94,6 +147,8 @@ class BaseSession:
94
147
  user_session = user_sessions.get(self.id) or {} # type: Dict
95
148
  user_session["chat_settings"] = self.chat_settings
96
149
  user_session["chat_profile"] = self.chat_profile
150
+ user_session["http_referer"] = self.http_referer
151
+ user_session["client_type"] = self.client_type
97
152
  metadata = clean_metadata(user_session)
98
153
  return metadata
99
154
 
@@ -108,14 +163,15 @@ class HTTPSession(BaseSession):
108
163
  client_type: ClientType,
109
164
  # Thread id
110
165
  thread_id: Optional[str] = None,
111
- # Logged-in user informations
166
+ # Logged-in user information
112
167
  user: Optional[Union["User", "PersistedUser"]] = None,
113
168
  # Logged-in user token
114
169
  token: Optional[str] = None,
115
170
  user_env: Optional[Dict[str, str]] = None,
116
- # Last message at the root of the chat
117
- root_message: Optional["Message"] = None,
118
- # User specific environment variables. Empty if no user environment variables are required.
171
+ # Origin of the request
172
+ http_referer: Optional[str] = None,
173
+ # Cookie
174
+ http_cookie: Optional[str] = None,
119
175
  ):
120
176
  super().__init__(
121
177
  id=id,
@@ -124,9 +180,18 @@ class HTTPSession(BaseSession):
124
180
  token=token,
125
181
  client_type=client_type,
126
182
  user_env=user_env,
127
- root_message=root_message,
183
+ http_referer=http_referer,
184
+ http_cookie=http_cookie,
128
185
  )
129
186
 
187
+ def delete(self):
188
+ """Delete the session."""
189
+ if self.files_dir.is_dir():
190
+ shutil.rmtree(self.files_dir)
191
+
192
+
193
+ ThreadQueue = Deque[tuple[Callable, object, tuple, Dict]]
194
+
130
195
 
131
196
  class WebsocketSession(BaseSession):
132
197
  """Internal web socket session object.
@@ -140,6 +205,8 @@ class WebsocketSession(BaseSession):
140
205
  socket id for convenience.
141
206
  """
142
207
 
208
+ to_clear: bool = False
209
+
143
210
  def __init__(
144
211
  self,
145
212
  # Id from the session cookie
@@ -155,14 +222,18 @@ class WebsocketSession(BaseSession):
155
222
  client_type: ClientType,
156
223
  # Thread id
157
224
  thread_id: Optional[str] = None,
158
- # Logged-in user informations
225
+ # Logged-in user information
159
226
  user: Optional[Union["User", "PersistedUser"]] = None,
160
227
  # Logged-in user token
161
228
  token: Optional[str] = None,
162
- # Last message at the root of the chat
163
- root_message: Optional["Message"] = None,
164
229
  # Chat profile selected before the session was created
165
230
  chat_profile: Optional[str] = None,
231
+ # Languages of the user's browser
232
+ languages: Optional[str] = None,
233
+ # Origin of the request
234
+ http_referer: Optional[str] = None,
235
+ # Cookie
236
+ http_cookie: Optional[str] = None,
166
237
  ):
167
238
  super().__init__(
168
239
  id=id,
@@ -171,76 +242,23 @@ class WebsocketSession(BaseSession):
171
242
  token=token,
172
243
  user_env=user_env,
173
244
  client_type=client_type,
174
- root_message=root_message,
175
245
  chat_profile=chat_profile,
246
+ http_referer=http_referer,
247
+ http_cookie=http_cookie,
176
248
  )
177
249
 
178
250
  self.socket_id = socket_id
179
251
  self.emit_call = emit_call
180
252
  self.emit = emit
181
253
 
182
- self.should_stop = False
183
254
  self.restored = False
184
255
 
185
- self.thread_queues = {} # type: Dict[str, Deque[Callable]]
186
- self.files = {} # type: Dict[str, "FileDict"]
256
+ self.thread_queues: Dict[str, ThreadQueue] = {}
187
257
 
188
258
  ws_sessions_id[self.id] = self
189
259
  ws_sessions_sid[socket_id] = self
190
260
 
191
- @property
192
- def files_dir(self):
193
- from chainlit.config import FILES_DIRECTORY
194
-
195
- return FILES_DIRECTORY / self.id
196
-
197
- async def persist_file(
198
- self,
199
- name: str,
200
- mime: str,
201
- path: Optional[str] = None,
202
- content: Optional[Union[bytes, str]] = None,
203
- ) -> "FileReference":
204
- if not path and not content:
205
- raise ValueError(
206
- "Either path or content must be provided to persist a file"
207
- )
208
-
209
- self.files_dir.mkdir(exist_ok=True)
210
-
211
- file_id = str(uuid.uuid4())
212
-
213
- file_path = self.files_dir / file_id
214
-
215
- file_extension = mimetypes.guess_extension(mime)
216
- if file_extension:
217
- file_path = file_path.with_suffix(file_extension)
218
-
219
- if path:
220
- # Copy the file from the given path
221
- async with aiofiles.open(path, "rb") as src, aiofiles.open(
222
- file_path, "wb"
223
- ) as dst:
224
- await dst.write(await src.read())
225
- elif content:
226
- # Write the provided content to the file
227
- async with aiofiles.open(file_path, "wb") as buffer:
228
- if isinstance(content, str):
229
- content = content.encode("utf-8")
230
- await buffer.write(content)
231
-
232
- # Get the file size
233
- file_size = file_path.stat().st_size
234
- # Store the file content in memory
235
- self.files[file_id] = {
236
- "id": file_id,
237
- "path": file_path,
238
- "name": name,
239
- "type": mime,
240
- "size": file_size,
241
- }
242
-
243
- return {"id": file_id}
261
+ self.languages = languages
244
262
 
245
263
  def restore(self, new_socket_id: str):
246
264
  """Associate a new socket id to the session."""
@@ -0,0 +1,6 @@
1
+ import importlib.util
2
+
3
+ if importlib.util.find_spec("slack_bolt") is None:
4
+ raise ValueError(
5
+ "The slack_bolt package is required to integrate Chainlit with a Slack app. Run `pip install slack_bolt --upgrade`"
6
+ )