chainlit 1.1.404__py3-none-any.whl → 1.2.0rc0__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 (63) hide show
  1. chainlit/__init__.py +63 -305
  2. chainlit/_utils.py +8 -0
  3. chainlit/assistant.py +16 -0
  4. chainlit/assistant_settings.py +35 -0
  5. chainlit/callbacks.py +340 -0
  6. chainlit/cli/__init__.py +1 -1
  7. chainlit/config.py +58 -28
  8. chainlit/copilot/dist/index.js +512 -631
  9. chainlit/data/__init__.py +6 -521
  10. chainlit/data/base.py +121 -0
  11. chainlit/data/dynamodb.py +5 -8
  12. chainlit/data/literalai.py +395 -0
  13. chainlit/data/sql_alchemy.py +11 -9
  14. chainlit/data/storage_clients.py +69 -15
  15. chainlit/data/utils.py +29 -0
  16. chainlit/element.py +1 -1
  17. chainlit/emitter.py +7 -0
  18. chainlit/frontend/dist/assets/{DailyMotion-e665b444.js → DailyMotion-aa368b7e.js} +1 -1
  19. chainlit/frontend/dist/assets/{Facebook-5207db92.js → Facebook-0335db46.js} +1 -1
  20. chainlit/frontend/dist/assets/{FilePlayer-86937d6e.js → FilePlayer-8d04256c.js} +1 -1
  21. chainlit/frontend/dist/assets/{Kaltura-c96622c1.js → Kaltura-67c9dd31.js} +1 -1
  22. chainlit/frontend/dist/assets/{Mixcloud-57ae3e32.js → Mixcloud-6bbaccf5.js} +1 -1
  23. chainlit/frontend/dist/assets/{Mux-20373920.js → Mux-c2bcb757.js} +1 -1
  24. chainlit/frontend/dist/assets/{Preview-c68c0613.js → Preview-210f3955.js} +1 -1
  25. chainlit/frontend/dist/assets/{SoundCloud-8a9e3eae.js → SoundCloud-a0276b84.js} +1 -1
  26. chainlit/frontend/dist/assets/{Streamable-1ed099af.js → Streamable-a007323d.js} +1 -1
  27. chainlit/frontend/dist/assets/{Twitch-6820039f.js → Twitch-e6a88aa3.js} +1 -1
  28. chainlit/frontend/dist/assets/{Vidyard-d39ab91d.js → Vidyard-dfb88a35.js} +1 -1
  29. chainlit/frontend/dist/assets/{Vimeo-017cd9a7.js → Vimeo-3baa13d9.js} +1 -1
  30. chainlit/frontend/dist/assets/{Wistia-a509d9f2.js → Wistia-e52f7bef.js} +1 -1
  31. chainlit/frontend/dist/assets/{YouTube-42dfd82f.js → YouTube-1715f22b.js} +1 -1
  32. chainlit/frontend/dist/assets/index-bfdd8585.js +729 -0
  33. chainlit/frontend/dist/assets/react-plotly-55648373.js +3484 -0
  34. chainlit/frontend/dist/index.html +1 -1
  35. chainlit/input_widget.py +22 -0
  36. chainlit/langchain/callbacks.py +6 -1
  37. chainlit/llama_index/callbacks.py +20 -4
  38. chainlit/markdown.py +15 -9
  39. chainlit/message.py +0 -1
  40. chainlit/server.py +113 -37
  41. chainlit/session.py +27 -4
  42. chainlit/socket.py +50 -1
  43. chainlit/translations/bn.json +231 -0
  44. chainlit/translations/en-US.json +6 -0
  45. chainlit/translations/fr-FR.json +236 -0
  46. chainlit/translations/gu.json +231 -0
  47. chainlit/translations/he-IL.json +231 -0
  48. chainlit/translations/hi.json +231 -0
  49. chainlit/translations/kn.json +231 -0
  50. chainlit/translations/ml.json +231 -0
  51. chainlit/translations/mr.json +231 -0
  52. chainlit/translations/ta.json +231 -0
  53. chainlit/translations/te.json +231 -0
  54. chainlit/types.py +1 -1
  55. chainlit/user_session.py +4 -0
  56. chainlit/utils.py +1 -1
  57. {chainlit-1.1.404.dist-info → chainlit-1.2.0rc0.dist-info}/METADATA +10 -10
  58. chainlit-1.2.0rc0.dist-info/RECORD +99 -0
  59. chainlit/frontend/dist/assets/index-30df9b2b.js +0 -730
  60. chainlit/frontend/dist/assets/react-plotly-5bb34118.js +0 -3602
  61. chainlit-1.1.404.dist-info/RECORD +0 -82
  62. {chainlit-1.1.404.dist-info → chainlit-1.2.0rc0.dist-info}/WHEEL +0 -0
  63. {chainlit-1.1.404.dist-info → chainlit-1.2.0rc0.dist-info}/entry_points.txt +0 -0
chainlit/callbacks.py ADDED
@@ -0,0 +1,340 @@
1
+ import functools
2
+ import inspect
3
+ from typing import Any, Awaitable, Callable, Dict, List, Optional
4
+
5
+ from chainlit.action import Action
6
+ from chainlit.assistant import Assistant
7
+ from chainlit.assistant_settings import AssistantSettings
8
+ from chainlit.config import config
9
+ from chainlit.message import Message
10
+ from chainlit.oauth_providers import get_configured_oauth_providers
11
+ from chainlit.step import Step, step
12
+ from chainlit.telemetry import trace
13
+ from chainlit.types import ChatProfile, Starter, ThreadDict
14
+ from chainlit.user import User
15
+ from chainlit.utils import wrap_user_function
16
+ from fastapi import Request, Response
17
+ from starlette.datastructures import Headers
18
+
19
+
20
+ def experimental(func):
21
+ @functools.wraps(func)
22
+ def wrapper(*args, **kwargs):
23
+ print(f"\033[1;33mexperimental feature: {func.__name__}\033[0m")
24
+ return func(*args, **kwargs)
25
+
26
+ return wrapper
27
+
28
+
29
+ @trace
30
+ def password_auth_callback(
31
+ func: Callable[[str, str], Awaitable[Optional[User]]]
32
+ ) -> Callable:
33
+ """
34
+ Framework agnostic decorator to authenticate the user.
35
+
36
+ Args:
37
+ func (Callable[[str, str], Awaitable[Optional[User]]]): The authentication callback to execute. Takes the email and password as parameters.
38
+
39
+ Example:
40
+ @cl.password_auth_callback
41
+ async def password_auth_callback(username: str, password: str) -> Optional[User]:
42
+
43
+ Returns:
44
+ Callable[[str, str], Awaitable[Optional[User]]]: The decorated authentication callback.
45
+ """
46
+
47
+ config.code.password_auth_callback = wrap_user_function(func)
48
+ return func
49
+
50
+
51
+ @trace
52
+ def header_auth_callback(
53
+ func: Callable[[Headers], Awaitable[Optional[User]]]
54
+ ) -> Callable:
55
+ """
56
+ Framework agnostic decorator to authenticate the user via a header
57
+
58
+ Args:
59
+ func (Callable[[Headers], Awaitable[Optional[User]]]): The authentication callback to execute.
60
+
61
+ Example:
62
+ @cl.header_auth_callback
63
+ async def header_auth_callback(headers: Headers) -> Optional[User]:
64
+
65
+ Returns:
66
+ Callable[[Headers], Awaitable[Optional[User]]]: The decorated authentication callback.
67
+ """
68
+
69
+ config.code.header_auth_callback = wrap_user_function(func)
70
+ return func
71
+
72
+
73
+ @trace
74
+ def oauth_callback(
75
+ func: Callable[
76
+ [str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]
77
+ ],
78
+ ) -> Callable:
79
+ """
80
+ Framework agnostic decorator to authenticate the user via oauth
81
+
82
+ Args:
83
+ func (Callable[[str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]]): The authentication callback to execute.
84
+
85
+ Example:
86
+ @cl.oauth_callback
87
+ 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]:
88
+
89
+ Returns:
90
+ Callable[[str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]]: The decorated authentication callback.
91
+ """
92
+
93
+ if len(get_configured_oauth_providers()) == 0:
94
+ raise ValueError(
95
+ "You must set the environment variable for at least one oauth provider to use oauth authentication."
96
+ )
97
+
98
+ config.code.oauth_callback = wrap_user_function(func)
99
+ return func
100
+
101
+
102
+ @trace
103
+ def on_logout(func: Callable[[Request, Response], Any]) -> Callable:
104
+ """
105
+ Function called when the user logs out.
106
+ Takes the FastAPI request and response as parameters.
107
+ """
108
+
109
+ config.code.on_logout = wrap_user_function(func)
110
+ return func
111
+
112
+
113
+ @trace
114
+ def on_message(func: Callable) -> Callable:
115
+ """
116
+ Framework agnostic decorator to react to messages coming from the UI.
117
+ The decorated function is called every time a new message is received.
118
+
119
+ Args:
120
+ func (Callable[[Message], Any]): The function to be called when a new message is received. Takes a cl.Message.
121
+
122
+ Returns:
123
+ Callable[[str], Any]: The decorated on_message function.
124
+ """
125
+
126
+ async def with_parent_id(message: Message):
127
+ async with Step(name="on_message", type="run", parent_id=message.id) as s:
128
+ s.input = message.content
129
+ if len(inspect.signature(func).parameters) > 0:
130
+ await func(message)
131
+ else:
132
+ await func()
133
+
134
+ config.code.on_message = wrap_user_function(with_parent_id)
135
+ return func
136
+
137
+
138
+ @trace
139
+ def on_chat_start(func: Callable) -> Callable:
140
+ """
141
+ Hook to react to the user websocket connection event.
142
+
143
+ Args:
144
+ func (Callable[], Any]): The connection hook to execute.
145
+
146
+ Returns:
147
+ Callable[], Any]: The decorated hook.
148
+ """
149
+
150
+ config.code.on_chat_start = wrap_user_function(
151
+ step(func, name="on_chat_start", type="run"), with_task=True
152
+ )
153
+ return func
154
+
155
+
156
+ @trace
157
+ def on_chat_resume(func: Callable[[ThreadDict], Any]) -> Callable:
158
+ """
159
+ Hook to react to resume websocket connection event.
160
+
161
+ Args:
162
+ func (Callable[], Any]): The connection hook to execute.
163
+
164
+ Returns:
165
+ Callable[], Any]: The decorated hook.
166
+ """
167
+
168
+ config.code.on_chat_resume = wrap_user_function(func, with_task=True)
169
+ return func
170
+
171
+
172
+ @trace
173
+ def set_chat_profiles(
174
+ func: Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]],
175
+ ) -> Callable:
176
+ """
177
+ Programmatic declaration of the available chat profiles (can depend on the User from the session if authentication is setup).
178
+
179
+ Args:
180
+ func (Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]): The function declaring the chat profiles.
181
+
182
+ Returns:
183
+ Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]: The decorated function.
184
+ """
185
+
186
+ config.code.set_chat_profiles = wrap_user_function(func)
187
+ return func
188
+
189
+
190
+ @trace
191
+ def set_starters(
192
+ func: Callable[[Optional["User"]], Awaitable[List["Starter"]]]
193
+ ) -> Callable:
194
+ """
195
+ Programmatic declaration of the available starter (can depend on the User from the session if authentication is setup).
196
+
197
+ Args:
198
+ func (Callable[[Optional["User"]], Awaitable[List["Starter"]]]): The function declaring the starters.
199
+
200
+ Returns:
201
+ Callable[[Optional["User"]], Awaitable[List["Starter"]]]: The decorated function.
202
+ """
203
+
204
+ config.code.set_starters = wrap_user_function(func)
205
+ return func
206
+
207
+
208
+ @trace
209
+ def on_chat_end(func: Callable) -> Callable:
210
+ """
211
+ Hook to react to the user websocket disconnect event.
212
+
213
+ Args:
214
+ func (Callable[], Any]): The disconnect hook to execute.
215
+
216
+ Returns:
217
+ Callable[], Any]: The decorated hook.
218
+ """
219
+
220
+ config.code.on_chat_end = wrap_user_function(func, with_task=True)
221
+ return func
222
+
223
+
224
+ @trace
225
+ def on_audio_chunk(func: Callable) -> Callable:
226
+ """
227
+ Hook to react to the audio chunks being sent.
228
+
229
+ Args:
230
+ chunk (AudioChunk): The audio chunk being sent.
231
+
232
+ Returns:
233
+ Callable[], Any]: The decorated hook.
234
+ """
235
+
236
+ config.code.on_audio_chunk = wrap_user_function(func, with_task=False)
237
+ return func
238
+
239
+
240
+ @trace
241
+ def on_audio_end(func: Callable) -> Callable:
242
+ """
243
+ Hook to react to the audio stream ending. This is called after the last audio chunk is sent.
244
+
245
+ Args:
246
+ elements ([List[Element]): The files that were uploaded before starting the audio stream (if any).
247
+
248
+ Returns:
249
+ Callable[], Any]: The decorated hook.
250
+ """
251
+
252
+ config.code.on_audio_end = wrap_user_function(
253
+ step(func, name="on_audio_end", type="run"), with_task=True
254
+ )
255
+ return func
256
+
257
+
258
+ @trace
259
+ def author_rename(
260
+ func: Callable[[str], Awaitable[str]]
261
+ ) -> Callable[[str], Awaitable[str]]:
262
+ """
263
+ Useful to rename the author of message to display more friendly author names in the UI.
264
+ Args:
265
+ func (Callable[[str], Awaitable[str]]): The function to be called to rename an author. Takes the original author name as parameter.
266
+
267
+ Returns:
268
+ Callable[[Any, str], Awaitable[Any]]: The decorated function.
269
+ """
270
+
271
+ config.code.author_rename = wrap_user_function(func)
272
+ return func
273
+
274
+
275
+ @trace
276
+ def on_stop(func: Callable) -> Callable:
277
+ """
278
+ Hook to react to the user stopping a thread.
279
+
280
+ Args:
281
+ func (Callable[[], Any]): The stop hook to execute.
282
+
283
+ Returns:
284
+ Callable[[], Any]: The decorated stop hook.
285
+ """
286
+
287
+ config.code.on_stop = wrap_user_function(func)
288
+ return func
289
+
290
+
291
+ def action_callback(name: str) -> Callable:
292
+ """
293
+ Callback to call when an action is clicked in the UI.
294
+
295
+ Args:
296
+ func (Callable[[Action], Any]): The action callback to execute. First parameter is the action.
297
+ """
298
+
299
+ def decorator(func: Callable[[Action], Any]):
300
+ config.code.action_callbacks[name] = wrap_user_function(func, with_task=True)
301
+ return func
302
+
303
+ return decorator
304
+
305
+
306
+ def on_settings_update(
307
+ func: Callable[[Dict[str, Any]], Any],
308
+ ) -> Callable[[Dict[str, Any]], Any]:
309
+ """
310
+ Hook to react to the user changing any settings.
311
+
312
+ Args:
313
+ func (Callable[], Any]): The hook to execute after settings were changed.
314
+
315
+ Returns:
316
+ Callable[], Any]: The decorated hook.
317
+ """
318
+
319
+ config.code.on_settings_update = wrap_user_function(func, with_task=True)
320
+ return func
321
+
322
+
323
+ # Experimental
324
+ @trace
325
+ @experimental
326
+ def on_create_assistant(
327
+ func: Callable[[Optional[User], AssistantSettings], Any]
328
+ ) -> Callable[[Optional[User], AssistantSettings], Any]:
329
+ config.code.on_create_assistant = wrap_user_function(func)
330
+ return func
331
+
332
+
333
+ # Experimental
334
+ @trace
335
+ @experimental
336
+ def on_list_assistants(
337
+ func: Callable[[Optional[User]], List[Assistant]]
338
+ ) -> Callable[[Optional[User]], List[Assistant]]:
339
+ config.code.on_list_assistants = wrap_user_function(func)
340
+ return func
chainlit/cli/__init__.py CHANGED
@@ -183,7 +183,7 @@ def chainlit_run(
183
183
  no_cache = True
184
184
  # This is required to have OpenAI LLM providers available for the CI run
185
185
  os.environ["OPENAI_API_KEY"] = "sk-FAKE-OPENAI-API-KEY"
186
- # This is required for authenticationt tests
186
+ # This is required for authentication tests
187
187
  os.environ["CHAINLIT_AUTH_SECRET"] = "SUPER_SECRET"
188
188
  else:
189
189
  trace_event("chainlit run")
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,15 +24,17 @@ 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
31
+ from chainlit.assistant import Assistant
19
32
  from chainlit.element import ElementBased
20
33
  from chainlit.message import Message
21
34
  from chainlit.types import AudioChunk, ChatProfile, Starter, ThreadDict
22
35
  from chainlit.user import User
23
36
  from fastapi import Request, Response
24
37
 
25
-
26
38
  BACKEND_ROOT = os.path.dirname(__file__)
27
39
  PACKAGE_ROOT = os.path.dirname(os.path.dirname(BACKEND_ROOT))
28
40
  TRANSLATIONS_DIR = os.path.join(BACKEND_ROOT, "translations")
@@ -270,10 +282,14 @@ class CodeSettings:
270
282
  # Module object loaded from the module_name
271
283
  module: Any = None
272
284
  # Bunch of callbacks defined by the developer
273
- password_auth_callback: Optional[Callable[[str, str], Optional["User"]]] = None
274
- 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[Callable[[Headers], Awaitable[Optional["User"]]]] = (
289
+ None
290
+ )
275
291
  oauth_callback: Optional[
276
- Callable[[str, str, Dict[str, str], "User"], Optional["User"]]
292
+ Callable[[str, str, Dict[str, str], "User"], Awaitable[Optional["User"]]]
277
293
  ] = None
278
294
  on_logout: Optional[Callable[["Request", "Response"], Any]] = None
279
295
  on_stop: Optional[Callable[[], Any]] = None
@@ -284,12 +300,18 @@ class CodeSettings:
284
300
  on_audio_chunk: Optional[Callable[["AudioChunk"], Any]] = None
285
301
  on_audio_end: Optional[Callable[[List["ElementBased"]], Any]] = None
286
302
 
287
- author_rename: Optional[Callable[[str], str]] = None
303
+ author_rename: Optional[Callable[[str], Awaitable[str]]] = None
288
304
  on_settings_update: Optional[Callable[[Dict[str, Any]], Any]] = None
289
- set_chat_profiles: Optional[Callable[[Optional["User"]], List["ChatProfile"]]] = (
305
+ set_chat_profiles: Optional[
306
+ Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]
307
+ ] = None
308
+ set_starters: Optional[Callable[[Optional["User"]], Awaitable[List["Starter"]]]] = (
290
309
  None
291
310
  )
292
- set_starters: Optional[Callable[[Optional["User"]], List["Starter"]]] = None
311
+
312
+ # assistant-related callback function
313
+ on_create_assistant: Optional[Callable[[Optional["User"], Any], Any]] = None
314
+ on_list_assistants: Optional[Callable[[Optional["User"]], List["Assistant"]]] = None
293
315
 
294
316
 
295
317
  @dataclass()
@@ -327,33 +349,41 @@ class ChainlitConfig:
327
349
  # fallback to root language (ex: `de` when `de-DE` is not found)
328
350
  parent_language = language.split("-")[0]
329
351
 
330
- translation_lib_file_path = os.path.join(
331
- config_translation_dir, f"{language}.json"
332
- )
333
- translation_lib_parent_language_file_path = os.path.join(
334
- config_translation_dir, f"{parent_language}.json"
335
- )
336
- default_translation_lib_file_path = os.path.join(
337
- config_translation_dir, f"{default_language}.json"
338
- )
352
+ translation_dir = Path(config_translation_dir)
339
353
 
340
- if os.path.exists(translation_lib_file_path):
341
- with open(translation_lib_file_path, "r", encoding="utf-8") as f:
342
- translation = json.load(f)
343
- elif os.path.exists(translation_lib_parent_language_file_path):
354
+ translation_lib_file_path = translation_dir / f"{language}.json"
355
+ translation_lib_parent_language_file_path = (
356
+ translation_dir / f"{parent_language}.json"
357
+ )
358
+ default_translation_lib_file_path = translation_dir / f"{default_language}.json"
359
+
360
+ if (
361
+ is_path_inside(translation_lib_file_path, translation_dir)
362
+ and translation_lib_file_path.is_file()
363
+ ):
364
+ translation = json.loads(
365
+ translation_lib_file_path.read_text(encoding="utf-8")
366
+ )
367
+ elif (
368
+ is_path_inside(translation_lib_parent_language_file_path, translation_dir)
369
+ and translation_lib_parent_language_file_path.is_file()
370
+ ):
344
371
  logger.warning(
345
372
  f"Translation file for {language} not found. Using parent translation {parent_language}."
346
373
  )
347
- with open(
348
- translation_lib_parent_language_file_path, "r", encoding="utf-8"
349
- ) as f:
350
- translation = json.load(f)
351
- elif os.path.exists(default_translation_lib_file_path):
374
+ translation = json.loads(
375
+ translation_lib_parent_language_file_path.read_text(encoding="utf-8")
376
+ )
377
+ elif (
378
+ is_path_inside(default_translation_lib_file_path, translation_dir)
379
+ and default_translation_lib_file_path.is_file()
380
+ ):
352
381
  logger.warning(
353
382
  f"Translation file for {language} not found. Using default translation {default_language}."
354
383
  )
355
- with open(default_translation_lib_file_path, "r", encoding="utf-8") as f:
356
- translation = json.load(f)
384
+ translation = json.loads(
385
+ default_translation_lib_file_path.read_text(encoding="utf-8")
386
+ )
357
387
 
358
388
  return translation
359
389