chainlit 1.1.403rc0__py3-none-any.whl → 1.2.0__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 (53) hide show
  1. chainlit/__init__.py +53 -305
  2. chainlit/_utils.py +8 -0
  3. chainlit/callbacks.py +308 -0
  4. chainlit/config.py +60 -33
  5. chainlit/copilot/dist/index.js +510 -629
  6. chainlit/data/__init__.py +6 -512
  7. chainlit/data/base.py +121 -0
  8. chainlit/data/dynamodb.py +2 -5
  9. chainlit/data/literalai.py +395 -0
  10. chainlit/data/sql_alchemy.py +10 -9
  11. chainlit/data/storage_clients.py +69 -15
  12. chainlit/data/utils.py +29 -0
  13. chainlit/element.py +3 -7
  14. chainlit/frontend/dist/assets/{DailyMotion-dd3d0f11.js → DailyMotion-05f4fe48.js} +1 -1
  15. chainlit/frontend/dist/assets/{Facebook-53a09094.js → Facebook-f25411d1.js} +1 -1
  16. chainlit/frontend/dist/assets/{FilePlayer-7fd97f72.js → FilePlayer-40ff3414.js} +1 -1
  17. chainlit/frontend/dist/assets/{Kaltura-127ca0f7.js → Kaltura-6cbf3897.js} +1 -1
  18. chainlit/frontend/dist/assets/{Mixcloud-14459c9d.js → Mixcloud-34e7c912.js} +1 -1
  19. chainlit/frontend/dist/assets/{Mux-913f2511.js → Mux-8aaff6ac.js} +1 -1
  20. chainlit/frontend/dist/assets/{Preview-cb48c96c.js → Preview-2d3bf558.js} +1 -1
  21. chainlit/frontend/dist/assets/{SoundCloud-f416790b.js → SoundCloud-b835f90f.js} +1 -1
  22. chainlit/frontend/dist/assets/{Streamable-304738e0.js → Streamable-1293e4f3.js} +1 -1
  23. chainlit/frontend/dist/assets/{Twitch-0fdf7e43.js → Twitch-c69660cd.js} +1 -1
  24. chainlit/frontend/dist/assets/{Vidyard-0fb7aefe.js → Vidyard-43bda599.js} +1 -1
  25. chainlit/frontend/dist/assets/{Vimeo-10a415ff.js → Vimeo-54150039.js} +1 -1
  26. chainlit/frontend/dist/assets/{Wistia-7239a75e.js → Wistia-aa3c721b.js} +1 -1
  27. chainlit/frontend/dist/assets/{YouTube-f2b37e5e.js → YouTube-dd0f3cc2.js} +1 -1
  28. chainlit/frontend/dist/assets/index-cf48bedd.js +729 -0
  29. chainlit/frontend/dist/assets/react-plotly-f52a41eb.js +3484 -0
  30. chainlit/frontend/dist/index.html +1 -1
  31. chainlit/langchain/callbacks.py +6 -1
  32. chainlit/llama_index/callbacks.py +21 -5
  33. chainlit/markdown.py +15 -9
  34. chainlit/message.py +0 -1
  35. chainlit/server.py +90 -36
  36. chainlit/session.py +4 -1
  37. chainlit/translations/bn.json +231 -0
  38. chainlit/translations/gu.json +231 -0
  39. chainlit/translations/he-IL.json +231 -0
  40. chainlit/translations/hi.json +231 -0
  41. chainlit/translations/kn.json +231 -0
  42. chainlit/translations/ml.json +231 -0
  43. chainlit/translations/mr.json +231 -0
  44. chainlit/translations/ta.json +231 -0
  45. chainlit/translations/te.json +231 -0
  46. chainlit/utils.py +1 -1
  47. {chainlit-1.1.403rc0.dist-info → chainlit-1.2.0.dist-info}/METADATA +5 -6
  48. chainlit-1.2.0.dist-info/RECORD +96 -0
  49. chainlit/frontend/dist/assets/index-b8952cd9.js +0 -730
  50. chainlit/frontend/dist/assets/react-plotly-cae83415.js +0 -3602
  51. chainlit-1.1.403rc0.dist-info/RECORD +0 -82
  52. {chainlit-1.1.403rc0.dist-info → chainlit-1.2.0.dist-info}/WHEEL +0 -0
  53. {chainlit-1.1.403rc0.dist-info → chainlit-1.2.0.dist-info}/entry_points.txt +0 -0
chainlit/callbacks.py ADDED
@@ -0,0 +1,308 @@
1
+ import inspect
2
+ from typing import Any, Awaitable, Callable, Dict, List, Optional
3
+
4
+ from chainlit.action import Action
5
+ from chainlit.config import config
6
+ from chainlit.message import Message
7
+ from chainlit.oauth_providers import get_configured_oauth_providers
8
+ from chainlit.step import Step, step
9
+ from chainlit.telemetry import trace
10
+ from chainlit.types import ChatProfile, Starter, ThreadDict
11
+ from chainlit.user import User
12
+ from chainlit.utils import wrap_user_function
13
+ from fastapi import Request, Response
14
+ from starlette.datastructures import Headers
15
+
16
+
17
+ @trace
18
+ def password_auth_callback(
19
+ func: Callable[[str, str], Awaitable[Optional[User]]]
20
+ ) -> Callable:
21
+ """
22
+ Framework agnostic decorator to authenticate the user.
23
+
24
+ Args:
25
+ func (Callable[[str, str], Awaitable[Optional[User]]]): The authentication callback to execute. Takes the email and password as parameters.
26
+
27
+ Example:
28
+ @cl.password_auth_callback
29
+ async def password_auth_callback(username: str, password: str) -> Optional[User]:
30
+
31
+ Returns:
32
+ Callable[[str, str], Awaitable[Optional[User]]]: The decorated authentication callback.
33
+ """
34
+
35
+ config.code.password_auth_callback = wrap_user_function(func)
36
+ return func
37
+
38
+
39
+ @trace
40
+ def header_auth_callback(
41
+ func: Callable[[Headers], Awaitable[Optional[User]]]
42
+ ) -> Callable:
43
+ """
44
+ Framework agnostic decorator to authenticate the user via a header
45
+
46
+ Args:
47
+ func (Callable[[Headers], Awaitable[Optional[User]]]): The authentication callback to execute.
48
+
49
+ Example:
50
+ @cl.header_auth_callback
51
+ async def header_auth_callback(headers: Headers) -> Optional[User]:
52
+
53
+ Returns:
54
+ Callable[[Headers], Awaitable[Optional[User]]]: The decorated authentication callback.
55
+ """
56
+
57
+ config.code.header_auth_callback = wrap_user_function(func)
58
+ return func
59
+
60
+
61
+ @trace
62
+ def oauth_callback(
63
+ func: Callable[
64
+ [str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]
65
+ ],
66
+ ) -> Callable:
67
+ """
68
+ Framework agnostic decorator to authenticate the user via oauth
69
+
70
+ Args:
71
+ func (Callable[[str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]]): The authentication callback to execute.
72
+
73
+ Example:
74
+ @cl.oauth_callback
75
+ async def oauth_callback(provider_id: str, token: str, raw_user_data: Dict[str, str], default_app_user: User, id_token: Optional[str]) -> Optional[User]:
76
+
77
+ Returns:
78
+ Callable[[str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]]: The decorated authentication callback.
79
+ """
80
+
81
+ if len(get_configured_oauth_providers()) == 0:
82
+ raise ValueError(
83
+ "You must set the environment variable for at least one oauth provider to use oauth authentication."
84
+ )
85
+
86
+ config.code.oauth_callback = wrap_user_function(func)
87
+ return func
88
+
89
+
90
+ @trace
91
+ def on_logout(func: Callable[[Request, Response], Any]) -> Callable:
92
+ """
93
+ Function called when the user logs out.
94
+ Takes the FastAPI request and response as parameters.
95
+ """
96
+
97
+ config.code.on_logout = wrap_user_function(func)
98
+ return func
99
+
100
+
101
+ @trace
102
+ def on_message(func: Callable) -> Callable:
103
+ """
104
+ Framework agnostic decorator to react to messages coming from the UI.
105
+ The decorated function is called every time a new message is received.
106
+
107
+ Args:
108
+ func (Callable[[Message], Any]): The function to be called when a new message is received. Takes a cl.Message.
109
+
110
+ Returns:
111
+ Callable[[str], Any]: The decorated on_message function.
112
+ """
113
+
114
+ async def with_parent_id(message: Message):
115
+ async with Step(name="on_message", type="run", parent_id=message.id) as s:
116
+ s.input = message.content
117
+ if len(inspect.signature(func).parameters) > 0:
118
+ await func(message)
119
+ else:
120
+ await func()
121
+
122
+ config.code.on_message = wrap_user_function(with_parent_id)
123
+ return func
124
+
125
+
126
+ @trace
127
+ def on_chat_start(func: Callable) -> Callable:
128
+ """
129
+ Hook to react to the user websocket connection event.
130
+
131
+ Args:
132
+ func (Callable[], Any]): The connection hook to execute.
133
+
134
+ Returns:
135
+ Callable[], Any]: The decorated hook.
136
+ """
137
+
138
+ config.code.on_chat_start = wrap_user_function(
139
+ step(func, name="on_chat_start", type="run"), with_task=True
140
+ )
141
+ return func
142
+
143
+
144
+ @trace
145
+ def on_chat_resume(func: Callable[[ThreadDict], Any]) -> Callable:
146
+ """
147
+ Hook to react to resume websocket connection event.
148
+
149
+ Args:
150
+ func (Callable[], Any]): The connection hook to execute.
151
+
152
+ Returns:
153
+ Callable[], Any]: The decorated hook.
154
+ """
155
+
156
+ config.code.on_chat_resume = wrap_user_function(func, with_task=True)
157
+ return func
158
+
159
+
160
+ @trace
161
+ def set_chat_profiles(
162
+ func: Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]],
163
+ ) -> Callable:
164
+ """
165
+ Programmatic declaration of the available chat profiles (can depend on the User from the session if authentication is setup).
166
+
167
+ Args:
168
+ func (Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]): The function declaring the chat profiles.
169
+
170
+ Returns:
171
+ Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]: The decorated function.
172
+ """
173
+
174
+ config.code.set_chat_profiles = wrap_user_function(func)
175
+ return func
176
+
177
+
178
+ @trace
179
+ def set_starters(
180
+ func: Callable[[Optional["User"]], Awaitable[List["Starter"]]]
181
+ ) -> Callable:
182
+ """
183
+ Programmatic declaration of the available starter (can depend on the User from the session if authentication is setup).
184
+
185
+ Args:
186
+ func (Callable[[Optional["User"]], Awaitable[List["Starter"]]]): The function declaring the starters.
187
+
188
+ Returns:
189
+ Callable[[Optional["User"]], Awaitable[List["Starter"]]]: The decorated function.
190
+ """
191
+
192
+ config.code.set_starters = wrap_user_function(func)
193
+ return func
194
+
195
+
196
+ @trace
197
+ def on_chat_end(func: Callable) -> Callable:
198
+ """
199
+ Hook to react to the user websocket disconnect event.
200
+
201
+ Args:
202
+ func (Callable[], Any]): The disconnect hook to execute.
203
+
204
+ Returns:
205
+ Callable[], Any]: The decorated hook.
206
+ """
207
+
208
+ config.code.on_chat_end = wrap_user_function(func, with_task=True)
209
+ return func
210
+
211
+
212
+ @trace
213
+ def on_audio_chunk(func: Callable) -> Callable:
214
+ """
215
+ Hook to react to the audio chunks being sent.
216
+
217
+ Args:
218
+ chunk (AudioChunk): The audio chunk being sent.
219
+
220
+ Returns:
221
+ Callable[], Any]: The decorated hook.
222
+ """
223
+
224
+ config.code.on_audio_chunk = wrap_user_function(func, with_task=False)
225
+ return func
226
+
227
+
228
+ @trace
229
+ def on_audio_end(func: Callable) -> Callable:
230
+ """
231
+ Hook to react to the audio stream ending. This is called after the last audio chunk is sent.
232
+
233
+ Args:
234
+ elements ([List[Element]): The files that were uploaded before starting the audio stream (if any).
235
+
236
+ Returns:
237
+ Callable[], Any]: The decorated hook.
238
+ """
239
+
240
+ config.code.on_audio_end = wrap_user_function(
241
+ step(func, name="on_audio_end", type="run"), with_task=True
242
+ )
243
+ return func
244
+
245
+
246
+ @trace
247
+ def author_rename(
248
+ func: Callable[[str], Awaitable[str]]
249
+ ) -> Callable[[str], Awaitable[str]]:
250
+ """
251
+ Useful to rename the author of message to display more friendly author names in the UI.
252
+ Args:
253
+ func (Callable[[str], Awaitable[str]]): The function to be called to rename an author. Takes the original author name as parameter.
254
+
255
+ Returns:
256
+ Callable[[Any, str], Awaitable[Any]]: The decorated function.
257
+ """
258
+
259
+ config.code.author_rename = wrap_user_function(func)
260
+ return func
261
+
262
+
263
+ @trace
264
+ def on_stop(func: Callable) -> Callable:
265
+ """
266
+ Hook to react to the user stopping a thread.
267
+
268
+ Args:
269
+ func (Callable[[], Any]): The stop hook to execute.
270
+
271
+ Returns:
272
+ Callable[[], Any]: The decorated stop hook.
273
+ """
274
+
275
+ config.code.on_stop = wrap_user_function(func)
276
+ return func
277
+
278
+
279
+ def action_callback(name: str) -> Callable:
280
+ """
281
+ Callback to call when an action is clicked in the UI.
282
+
283
+ Args:
284
+ func (Callable[[Action], Any]): The action callback to execute. First parameter is the action.
285
+ """
286
+
287
+ def decorator(func: Callable[[Action], Any]):
288
+ config.code.action_callbacks[name] = wrap_user_function(func, with_task=True)
289
+ return func
290
+
291
+ return decorator
292
+
293
+
294
+ def on_settings_update(
295
+ func: Callable[[Dict[str, Any]], Any],
296
+ ) -> Callable[[Dict[str, Any]], Any]:
297
+ """
298
+ Hook to react to the user changing any settings.
299
+
300
+ Args:
301
+ func (Callable[], Any]): The hook to execute after settings were changed.
302
+
303
+ Returns:
304
+ Callable[], Any]: The decorated hook.
305
+ """
306
+
307
+ config.code.on_settings_update = wrap_user_function(func, with_task=True)
308
+ return func
chainlit/config.py CHANGED
@@ -4,7 +4,17 @@ import site
4
4
  import sys
5
5
  from importlib import util
6
6
  from pathlib import Path
7
- from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Union
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Any,
10
+ Awaitable,
11
+ Callable,
12
+ Dict,
13
+ List,
14
+ Literal,
15
+ Optional,
16
+ Union,
17
+ )
8
18
 
9
19
  import tomli
10
20
  from chainlit.logger import logger
@@ -14,6 +24,8 @@ from dataclasses_json import DataClassJsonMixin
14
24
  from pydantic.dataclasses import Field, dataclass
15
25
  from starlette.datastructures import Headers
16
26
 
27
+ from ._utils import is_path_inside
28
+
17
29
  if TYPE_CHECKING:
18
30
  from chainlit.action import Action
19
31
  from chainlit.element import ElementBased
@@ -29,7 +41,7 @@ TRANSLATIONS_DIR = os.path.join(BACKEND_ROOT, "translations")
29
41
 
30
42
 
31
43
  # Get the directory the script is running from
32
- APP_ROOT = os.getcwd()
44
+ APP_ROOT = os.getenv("CHAINLIT_APP_ROOT", os.getcwd())
33
45
 
34
46
  # Create the directory to store the uploaded files
35
47
  FILES_DIRECTORY = Path(APP_ROOT) / ".files"
@@ -70,6 +82,9 @@ latex = false
70
82
  # Automatically tag threads with the current chat profile (if a chat profile is used)
71
83
  auto_tag_thread = true
72
84
 
85
+ # Allow users to edit their own messages
86
+ edit_message = true
87
+
73
88
  # Authorize users to spontaneously upload files with messages
74
89
  [features.spontaneous_file_upload]
75
90
  enabled = true
@@ -91,8 +106,6 @@ auto_tag_thread = true
91
106
  # Sample rate of the audio
92
107
  sample_rate = 44100
93
108
 
94
- edit_message = true
95
-
96
109
  [UI]
97
110
  # Name of the assistant.
98
111
  name = "Assistant"
@@ -163,7 +176,7 @@ generated_by = "{__version__}"
163
176
  """
164
177
 
165
178
 
166
- DEFAULT_HOST = "0.0.0.0"
179
+ DEFAULT_HOST = "127.0.0.1"
167
180
  DEFAULT_PORT = 8000
168
181
  DEFAULT_ROOT_PATH = ""
169
182
 
@@ -269,10 +282,14 @@ class CodeSettings:
269
282
  # Module object loaded from the module_name
270
283
  module: Any = None
271
284
  # Bunch of callbacks defined by the developer
272
- password_auth_callback: Optional[Callable[[str, str], Optional["User"]]] = None
273
- header_auth_callback: Optional[Callable[[Headers], Optional["User"]]] = None
285
+ password_auth_callback: Optional[
286
+ Callable[[str, str], Awaitable[Optional["User"]]]
287
+ ] = None
288
+ header_auth_callback: Optional[
289
+ Callable[[Headers], Awaitable[Optional["User"]]]
290
+ ] = None
274
291
  oauth_callback: Optional[
275
- Callable[[str, str, Dict[str, str], "User"], Optional["User"]]
292
+ Callable[[str, str, Dict[str, str], "User"], Awaitable[Optional["User"]]]
276
293
  ] = None
277
294
  on_logout: Optional[Callable[["Request", "Response"], Any]] = None
278
295
  on_stop: Optional[Callable[[], Any]] = None
@@ -283,12 +300,14 @@ class CodeSettings:
283
300
  on_audio_chunk: Optional[Callable[["AudioChunk"], Any]] = None
284
301
  on_audio_end: Optional[Callable[[List["ElementBased"]], Any]] = None
285
302
 
286
- author_rename: Optional[Callable[[str], str]] = None
303
+ author_rename: Optional[Callable[[str], Awaitable[str]]] = None
287
304
  on_settings_update: Optional[Callable[[Dict[str, Any]], Any]] = None
288
- set_chat_profiles: Optional[Callable[[Optional["User"]], List["ChatProfile"]]] = (
289
- None
290
- )
291
- set_starters: Optional[Callable[[Optional["User"]], List["Starter"]]] = None
305
+ set_chat_profiles: Optional[
306
+ Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]
307
+ ] = None
308
+ set_starters: Optional[
309
+ Callable[[Optional["User"]], Awaitable[List["Starter"]]]
310
+ ] = None
292
311
 
293
312
 
294
313
  @dataclass()
@@ -326,33 +345,41 @@ class ChainlitConfig:
326
345
  # fallback to root language (ex: `de` when `de-DE` is not found)
327
346
  parent_language = language.split("-")[0]
328
347
 
329
- translation_lib_file_path = os.path.join(
330
- config_translation_dir, f"{language}.json"
331
- )
332
- translation_lib_parent_language_file_path = os.path.join(
333
- config_translation_dir, f"{parent_language}.json"
334
- )
335
- default_translation_lib_file_path = os.path.join(
336
- config_translation_dir, f"{default_language}.json"
337
- )
348
+ translation_dir = Path(config_translation_dir)
338
349
 
339
- if os.path.exists(translation_lib_file_path):
340
- with open(translation_lib_file_path, "r", encoding="utf-8") as f:
341
- translation = json.load(f)
342
- elif os.path.exists(translation_lib_parent_language_file_path):
350
+ translation_lib_file_path = translation_dir / f"{language}.json"
351
+ translation_lib_parent_language_file_path = (
352
+ translation_dir / f"{parent_language}.json"
353
+ )
354
+ default_translation_lib_file_path = translation_dir / f"{default_language}.json"
355
+
356
+ if (
357
+ is_path_inside(translation_lib_file_path, translation_dir)
358
+ and translation_lib_file_path.is_file()
359
+ ):
360
+ translation = json.loads(
361
+ translation_lib_file_path.read_text(encoding="utf-8")
362
+ )
363
+ elif (
364
+ is_path_inside(translation_lib_parent_language_file_path, translation_dir)
365
+ and translation_lib_parent_language_file_path.is_file()
366
+ ):
343
367
  logger.warning(
344
368
  f"Translation file for {language} not found. Using parent translation {parent_language}."
345
369
  )
346
- with open(
347
- translation_lib_parent_language_file_path, "r", encoding="utf-8"
348
- ) as f:
349
- translation = json.load(f)
350
- elif os.path.exists(default_translation_lib_file_path):
370
+ translation = json.loads(
371
+ translation_lib_parent_language_file_path.read_text(encoding="utf-8")
372
+ )
373
+ elif (
374
+ is_path_inside(default_translation_lib_file_path, translation_dir)
375
+ and default_translation_lib_file_path.is_file()
376
+ ):
351
377
  logger.warning(
352
378
  f"Translation file for {language} not found. Using default translation {default_language}."
353
379
  )
354
- with open(default_translation_lib_file_path, "r", encoding="utf-8") as f:
355
- translation = json.load(f)
380
+ translation = json.loads(
381
+ default_translation_lib_file_path.read_text(encoding="utf-8")
382
+ )
356
383
 
357
384
  return translation
358
385