chainlit 0.1.103__tar.gz → 0.2.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.

Files changed (36) hide show
  1. {chainlit-0.1.103 → chainlit-0.2.1}/PKG-INFO +2 -2
  2. {chainlit-0.1.103 → chainlit-0.2.1}/README.md +1 -1
  3. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/__init__.py +47 -80
  4. chainlit-0.2.1/chainlit/action.py +29 -0
  5. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/client.py +16 -9
  6. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/config.py +5 -3
  7. chainlit-0.2.1/chainlit/element.py +122 -0
  8. chainlit-0.1.103/chainlit/frontend/dist/assets/index-2dad8c58.js → chainlit-0.2.1/chainlit/frontend/dist/assets/index-03f89089.js +120 -119
  9. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/frontend/dist/index.html +1 -1
  10. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/lc/utils.py +1 -2
  11. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/sdk.py +14 -85
  12. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/server.py +8 -6
  13. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/types.py +0 -6
  14. {chainlit-0.1.103 → chainlit-0.2.1}/pyproject.toml +1 -1
  15. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/__main__.py +0 -0
  16. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/cli/__init__.py +0 -0
  17. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/cli/auth.py +0 -0
  18. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/cli/deploy.py +0 -0
  19. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/cli/utils.py +0 -0
  20. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/frontend/dist/assets/index-bdffdaa0.css +0 -0
  21. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/frontend/dist/assets/logo_dark-bc7401f6.svg +0 -0
  22. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/frontend/dist/assets/logo_light-f19fc2ea.svg +0 -0
  23. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/frontend/dist/favicon.svg +0 -0
  24. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/hello.py +0 -0
  25. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/lc/__init__.py +0 -0
  26. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/lc/chainlit_handler.py +0 -0
  27. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/lc/monkey.py +0 -0
  28. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/lc/new_monkey.py +0 -0
  29. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/lc/old_monkey.py +0 -0
  30. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/logger.py +0 -0
  31. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/markdown.py +0 -0
  32. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/session.py +0 -0
  33. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/telemetry.py +0 -0
  34. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/user_session.py +0 -0
  35. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/version.py +0 -0
  36. {chainlit-0.1.103 → chainlit-0.2.1}/chainlit/watch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chainlit
3
- Version: 0.1.103
3
+ Version: 0.2.1
4
4
  Summary: A faster way to build chatbot UIs.
5
5
  Home-page: https://github.com/Chainlit/chainlit
6
6
  License: Apache-2.0 license
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  **A faster way to build chatbot UIs.**
39
39
 
40
- Chainlit lets you create chatbot UIs on top of any Python code in minutes. It’s all Python, open-source, and free!
40
+ Chainlit lets you create chatbot UIs on top of any Python code in minutes. It’s all Python, open-source, and free! Some of the key features include intermediary steps visualisation, element management & display (images, text, carousel, etc.) as well as cloud deployment.
41
41
 
42
42
  [![](https://dcbadge.vercel.app/api/server/ZThrUxbAYw?style=flat)](https://discord.gg/ZThrUxbAYw)
43
43
  [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/chainlit_io.svg?style=social&label=Follow%20%40chainlit_io)](https://twitter.com/chainlit_io)
@@ -2,7 +2,7 @@
2
2
 
3
3
  **A faster way to build chatbot UIs.**
4
4
 
5
- Chainlit lets you create chatbot UIs on top of any Python code in minutes. It’s all Python, open-source, and free!
5
+ Chainlit lets you create chatbot UIs on top of any Python code in minutes. It’s all Python, open-source, and free! Some of the key features include intermediary steps visualisation, element management & display (images, text, carousel, etc.) as well as cloud deployment.
6
6
 
7
7
  [![](https://dcbadge.vercel.app/api/server/ZThrUxbAYw?style=flat)](https://discord.gg/ZThrUxbAYw)
8
8
  [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/chainlit_io.svg?style=social&label=Follow%20%40chainlit_io)](https://twitter.com/chainlit_io)
@@ -8,21 +8,21 @@ from chainlit.lc import monkey
8
8
  monkey.patch()
9
9
 
10
10
  from chainlit.sdk import get_sdk
11
- from chainlit.user_session import user_session
12
11
  from chainlit.config import config
13
12
  from chainlit.types import (
14
- ElementDisplay,
15
13
  LLMSettings,
16
14
  AskSpec,
17
15
  AskFileSpec,
18
16
  AskFileResponse,
19
17
  AskResponse,
20
- Action,
21
18
  )
22
19
  from chainlit.telemetry import trace
23
20
  from chainlit.version import __version__
24
21
  from chainlit.logger import logger
25
22
  from chainlit.server import socketio
23
+ from chainlit.action import Action
24
+ from chainlit.element import LocalImage, RemoteImage, Text
25
+ from chainlit.user_session import user_session
26
26
  from typing import Callable, Any, List, Union
27
27
  from dotenv import load_dotenv
28
28
  import inspect
@@ -73,55 +73,6 @@ def wrap_user_function(user_function: Callable, with_task=False) -> Callable:
73
73
  return wrapper
74
74
 
75
75
 
76
- @trace
77
- def send_text(text: str, name: str, display: ElementDisplay = "side"):
78
- """
79
- Send a text element to the chatbot UI.
80
- If a project ID is configured, the element will be uploaded to the cloud storage.
81
-
82
- Args:
83
- text (str): The content of the text element.
84
- name (str): The name of the text element to be displayed in the UI.
85
- display (ElementDisplay, optional): Determines how the element should be displayed in the UI.
86
- Choices are "side" (default) or "inline" or "page".
87
- """
88
- sdk = get_sdk()
89
- if sdk:
90
- sdk.send_text(text, name, display)
91
-
92
-
93
- @trace
94
- def send_local_image(path: str, name: str, display: ElementDisplay = "side"):
95
- """
96
- Send a local image to the chatbot UI.
97
- If a project ID is configured, the image will be uploaded to the cloud storage.
98
-
99
- Args:
100
- path (str): The local file path of the image.
101
- name (str): The name of the image to be displayed in the UI.
102
- display (ElementDisplay, optional): Determines how the image should be displayed in the UI.
103
- Choices are "side" (default) or "inline" or "page".
104
- """
105
- sdk = get_sdk()
106
- if sdk:
107
- sdk.send_local_image(path, name, display)
108
-
109
-
110
- @trace
111
- def send_image(url: str, name: str, display: ElementDisplay = "side"):
112
- """
113
- Send an image to the chatbot UI.
114
- Args:
115
- url (str): The URL of the image.
116
- name (str): The name of the image to be displayed in the UI.
117
- display (ElementDisplay, optional): Determines how the image should be displayed in the UI.
118
- Choices are "side" (default) or "inline" or "page".
119
- """
120
- sdk = get_sdk()
121
- if sdk:
122
- sdk.send_image(url, name, display)
123
-
124
-
125
76
  @trace
126
77
  def send_message(
127
78
  content: str,
@@ -131,6 +82,8 @@ def send_message(
131
82
  indent=0,
132
83
  llm_settings: LLMSettings = None,
133
84
  end_stream=False,
85
+ actions: List[Action] = [],
86
+ elements: List[Union[LocalImage, RemoteImage, Text]] = [],
134
87
  ):
135
88
  """
136
89
  Send a message to the chatbot UI.
@@ -144,10 +97,13 @@ def send_message(
144
97
  indent (int, optional): If positive, the message will be nested in the UI.
145
98
  llm_settings (LLMSettings, optional): Settings of the LLM used to generate the prompt. This is useful for debug purposes in the prompt playground.
146
99
  end_stream (bool, optional): Pass True if this message was streamed.
100
+
101
+ Returns:
102
+ str: The message ID.
147
103
  """
148
104
  sdk = get_sdk()
149
105
  if sdk:
150
- sdk.send_message(
106
+ msg_id = sdk.send_message(
151
107
  author=author,
152
108
  content=content,
153
109
  prompt=prompt,
@@ -157,6 +113,12 @@ def send_message(
157
113
  end_stream=end_stream,
158
114
  )
159
115
 
116
+ for action in actions:
117
+ action.send(for_id=msg_id)
118
+
119
+ for element in elements:
120
+ element.send(for_id=msg_id)
121
+
160
122
 
161
123
  @trace
162
124
  def send_error_message(content: str, author=config.chatbot_name, indent=0):
@@ -237,20 +199,6 @@ def ask_for_file(
237
199
  return None
238
200
 
239
201
 
240
- @trace
241
- def send_action(name: str, trigger: str, description=""):
242
- """
243
- Send an action to the chatbot UI.
244
- Args:
245
- name (str): The name of the action to send.
246
- trigger (str): The text that should trigger the action when clicked.
247
- description (str, optional): The description of the action. Defaults to "".
248
- """
249
- sdk = get_sdk()
250
- if sdk:
251
- sdk.send_action(name=name, trigger=trigger, description=description)
252
-
253
-
254
202
  @trace
255
203
  def start_stream(
256
204
  author=config.chatbot_name,
@@ -301,7 +249,6 @@ def langchain_factory(func: Callable) -> Callable:
301
249
  Returns:
302
250
  Callable[[], Any]: The decorated factory function.
303
251
  """
304
- from chainlit.config import config
305
252
 
306
253
  config.lc_factory = wrap_user_function(func, with_task=True)
307
254
  return func
@@ -311,7 +258,8 @@ def langchain_factory(func: Callable) -> Callable:
311
258
  def langchain_postprocess(func: Callable[[Any], str]) -> Callable:
312
259
  """
313
260
  Useful to post process the response a LangChain object instantiated with @langchain_factory.
314
- The decorated function takes the raw output of the LangChain object and return a string as the final response.
261
+ The decorated function takes the raw output of the LangChain object as input.
262
+ The response will NOT be automatically sent to the UI, you need to call send_message.
315
263
 
316
264
  Args:
317
265
  func (Callable[[Any], str]): The post-processing function to apply after generating a response. Takes the response as parameter.
@@ -319,7 +267,6 @@ def langchain_postprocess(func: Callable[[Any], str]) -> Callable:
319
267
  Returns:
320
268
  Callable[[Any], str]: The decorated post-processing function.
321
269
  """
322
- from chainlit.config import config
323
270
 
324
271
  config.lc_postprocess = wrap_user_function(func)
325
272
  return func
@@ -337,7 +284,6 @@ def on_message(func: Callable) -> Callable:
337
284
  Returns:
338
285
  Callable[[str], Any]: The decorated on_message function.
339
286
  """
340
- from chainlit.config import config
341
287
 
342
288
  config.on_message = wrap_user_function(func)
343
289
  return func
@@ -348,14 +294,14 @@ def langchain_run(func: Callable[[Any, str], str]) -> Callable:
348
294
  """
349
295
  Useful to override the default behavior of the LangChain object instantiated with @langchain_factory.
350
296
  Use when your agent run method has custom parameters.
351
- This function should return a string as the final response.
297
+ Takes the LangChain agent and the user input as parameters.
298
+ The response will NOT be automatically sent to the UI, you need to call send_message.
352
299
  Args:
353
300
  func (Callable[[Any, str], str]): The function to be called when a new message is received. Takes the agent and user input as parameters and returns the output string.
354
301
 
355
302
  Returns:
356
303
  Callable[[Any, str], Any]: The decorated function.
357
304
  """
358
- from chainlit.config import config
359
305
 
360
306
  config.lc_run = wrap_user_function(func)
361
307
  return func
@@ -371,7 +317,6 @@ def langchain_rename(func: Callable[[str], str]) -> Callable[[str], str]:
371
317
  Returns:
372
318
  Callable[[Any, str], Any]: The decorated function.
373
319
  """
374
- from chainlit.config import config
375
320
 
376
321
  config.lc_rename = wrap_user_function(func)
377
322
  return func
@@ -388,7 +333,6 @@ def on_chat_start(func: Callable) -> Callable:
388
333
  Returns:
389
334
  Callable[], Any]: The decorated hook.
390
335
  """
391
- from chainlit.config import config
392
336
 
393
337
  config.on_chat_start = wrap_user_function(func, with_task=True)
394
338
  return func
@@ -405,20 +349,20 @@ def on_stop(func: Callable) -> Callable:
405
349
  Returns:
406
350
  Callable[[], Any]: The decorated stop hook.
407
351
  """
408
- from chainlit.config import config
409
352
 
410
353
  config.on_stop = wrap_user_function(func)
411
354
  return func
412
355
 
413
356
 
414
- def action(name: str) -> Callable:
357
+ def action_callback(name: str) -> Callable:
415
358
  """
416
- Callback to call when an action is triggered in the UI.
359
+ Callback to call when an action is clicked in the UI.
360
+
361
+ Args:
362
+ func (Callable[[Action], Any]): The action callback to exexute. First parameter is the action.
417
363
  """
418
364
 
419
365
  def decorator(func: Callable[[Action], Any]):
420
- from chainlit.config import config
421
-
422
366
  config.action_callbacks[name] = wrap_user_function(func, with_task=True)
423
367
  return func
424
368
 
@@ -432,3 +376,26 @@ def sleep(duration: int):
432
376
  duration (int): The duration in seconds.
433
377
  """
434
378
  return socketio.sleep(duration)
379
+
380
+
381
+ __all__ = [
382
+ "user_session",
383
+ "Action",
384
+ "LocalImage",
385
+ "RemoteImage",
386
+ "Text",
387
+ "send_message",
388
+ "send_error_message",
389
+ "ask_for_input",
390
+ "ask_for_file",
391
+ "start_stream",
392
+ "send_token",
393
+ "langchain_factory",
394
+ "langchain_postprocess",
395
+ "langchain_run",
396
+ "langchain_rename",
397
+ "on_chat_start",
398
+ "on_stop",
399
+ "action",
400
+ "sleep",
401
+ ]
@@ -0,0 +1,29 @@
1
+ from pydantic.dataclasses import dataclass
2
+ from dataclasses_json import dataclass_json
3
+ from chainlit.sdk import get_emit
4
+ from chainlit.telemetry import trace_event
5
+
6
+
7
+ @dataclass_json
8
+ @dataclass
9
+ class Action:
10
+ name: str
11
+ value: str
12
+ description: str = ""
13
+ forId: str = None
14
+
15
+ def __post_init__(self) -> None:
16
+ trace_event(f"init {self.__class__.__name__}")
17
+
18
+ def send(self, for_id: str):
19
+ emit = get_emit()
20
+ if emit:
21
+ trace_event(f"send {self.__class__.__name__}")
22
+ self.forId = for_id
23
+ emit("action", self.to_dict())
24
+
25
+ def remove(self):
26
+ emit = get_emit()
27
+ if emit:
28
+ trace_event(f"remove {self.__class__.__name__}")
29
+ emit("remove_action", self.to_dict())
@@ -20,13 +20,18 @@ class BaseClient(ABC):
20
20
  pass
21
21
 
22
22
  @abstractmethod
23
- def upload_element(self, ext: str, content: bytes) -> int:
23
+ def upload_element(self, content: bytes) -> int:
24
24
  pass
25
25
 
26
26
  @abstractmethod
27
27
  def create_element(
28
- self, conversation_id: str, type: ElementType, url: str, name: str, display: str
29
- ) -> int:
28
+ self,
29
+ type: ElementType,
30
+ url: str,
31
+ name: str,
32
+ display: str,
33
+ for_id: str = None,
34
+ ) -> Dict[str, Any]:
30
35
  pass
31
36
 
32
37
 
@@ -95,18 +100,19 @@ class CloudClient(BaseClient):
95
100
  return int(res["data"]["createMessage"]["id"])
96
101
 
97
102
  def create_element(
98
- self, type: ElementType, url: str, name: str, display: str
103
+ self, type: ElementType, url: str, name: str, display: str, for_id: str = None
99
104
  ) -> Dict[str, Any]:
100
105
  c_id = self.get_conversation_id()
101
106
 
102
107
  mutation = """
103
- mutation ($conversationId: ID!, $type: String!, $url: String!, $name: String!, $display: String!) {
104
- createElement(conversationId: $conversationId, type: $type, url: $url, name: $name, display: $display) {
108
+ mutation ($conversationId: ID!, $type: String!, $url: String!, $name: String!, $display: String!, $forId: String) {
109
+ createElement(conversationId: $conversationId, type: $type, url: $url, name: $name, display: $display, forId: $forId) {
105
110
  id,
106
111
  type,
107
112
  url,
108
113
  name,
109
- display
114
+ display,
115
+ forId
110
116
  }
111
117
  }
112
118
  """
@@ -116,12 +122,13 @@ class CloudClient(BaseClient):
116
122
  "url": url,
117
123
  "name": name,
118
124
  "display": display,
125
+ "forId": for_id,
119
126
  }
120
127
  res = self.mutation(mutation, variables)
121
128
  return res["data"]["createElement"]
122
129
 
123
- def upload_element(self, ext: str, content: bytes) -> str:
124
- id = f"{uuid.uuid4()}{ext}"
130
+ def upload_element(self, content: bytes) -> str:
131
+ id = f"{uuid.uuid4()}"
125
132
  url = f"{self.url}/api/upload/file"
126
133
  body = {"projectId": self.project_id, "fileName": id}
127
134
 
@@ -1,12 +1,14 @@
1
1
  import os
2
2
  import sys
3
- from typing import Optional, Literal, Any, Callable, List, Dict
3
+ from typing import Optional, Literal, Any, Callable, List, Dict, TYPE_CHECKING
4
4
  import tomli
5
- from chainlit.types import Action
6
5
  from pydantic.dataclasses import dataclass
7
6
  from importlib import machinery
8
7
  from chainlit.logger import logger
9
8
 
9
+ if TYPE_CHECKING:
10
+ from chainlit.action import Action
11
+
10
12
 
11
13
  # Get the directory the script is running from
12
14
  root = os.getcwd()
@@ -71,7 +73,7 @@ class ChainlitConfig:
71
73
  # Path to the local langchain cache database
72
74
  lc_cache_path: str
73
75
  # Developer defined callbacks for each action. Key is the action name, value is the callback function.
74
- action_callbacks: Dict[str, Callable[[Action], Any]]
76
+ action_callbacks: Dict[str, Callable[["Action"], Any]]
75
77
  # Directory where the Chainlit project is located
76
78
  root = root
77
79
  # Link to your github repo. This will add a github button in the UI's header.
@@ -0,0 +1,122 @@
1
+ from pydantic.dataclasses import dataclass
2
+ from dataclasses_json import dataclass_json
3
+ from typing import Dict
4
+ from abc import ABC, abstractmethod
5
+ from chainlit.sdk import get_sdk, BaseClient
6
+ from chainlit.telemetry import trace_event
7
+ from chainlit.types import ElementType, ElementDisplay
8
+
9
+
10
+ @dataclass_json
11
+ @dataclass
12
+ class Element(ABC):
13
+ name: str
14
+ type: ElementType
15
+ display: ElementDisplay = "side"
16
+ forId: str = None
17
+
18
+ def __post_init__(self) -> None:
19
+ trace_event(f"init {self.__class__.__name__}")
20
+
21
+ @abstractmethod
22
+ def persist(self, client: BaseClient, for_id: str = None) -> Dict:
23
+ pass
24
+
25
+ def before_emit(self, element: Dict) -> Dict:
26
+ return element
27
+
28
+ def send(self, for_id: str = None):
29
+ sdk = get_sdk()
30
+
31
+ # Cloud is enabled, upload the element to S3
32
+ if sdk.client:
33
+ element = self.persist(sdk.client, for_id)
34
+ else:
35
+ element = self.to_dict()
36
+ if for_id:
37
+ element["forId"] = for_id
38
+
39
+ if sdk.emit and element:
40
+ trace_event(f"send {self.__class__.__name__}")
41
+ element = self.before_emit(element)
42
+ sdk.emit("element", element)
43
+
44
+
45
+ @dataclass
46
+ class LocalElementBase:
47
+ content: bytes
48
+
49
+
50
+ @dataclass
51
+ class LocalElement(Element, LocalElementBase):
52
+ def persist(self, client: BaseClient, for_id: str = None):
53
+ url = client.upload_element(content=self.content)
54
+ if url:
55
+ element = client.create_element(
56
+ name=self.name,
57
+ url=url,
58
+ type=self.type,
59
+ display=self.display,
60
+ for_id=for_id,
61
+ )
62
+ return element
63
+
64
+
65
+ @dataclass
66
+ class RemoteElementBase:
67
+ url: str
68
+
69
+
70
+ @dataclass
71
+ class RemoteElement(Element, RemoteElementBase):
72
+ def persist(self, client: BaseClient, for_id: str = None):
73
+ element = client.create_element(
74
+ name=self.name,
75
+ url=self.url,
76
+ type=self.type,
77
+ display=self.display,
78
+ for_id=for_id,
79
+ )
80
+ return element
81
+
82
+
83
+ class LocalImage(LocalElement):
84
+ def __init__(
85
+ self,
86
+ name: str,
87
+ display: ElementDisplay = "side",
88
+ path: str = None,
89
+ content: bytes = None,
90
+ ):
91
+ if path:
92
+ with open(path, "rb") as f:
93
+ self.content = f.read()
94
+ elif content:
95
+ self.content = content
96
+ else:
97
+ raise ValueError("Must provide either path or content")
98
+
99
+ self.name = name
100
+ self.display = display
101
+ self.type = "image"
102
+
103
+
104
+ class RemoteImage(RemoteElement):
105
+ def __init__(self, name: str, url: str, display: ElementDisplay = "side"):
106
+ self.name = name
107
+ self.display = display
108
+ self.type = "image"
109
+ self.url = url
110
+
111
+
112
+ class Text(LocalElement):
113
+ def __init__(self, name: str, text: str, display: ElementDisplay = "side"):
114
+ self.name = name
115
+ self.display = display
116
+ self.type = "text"
117
+ self.content = bytes(text, "utf-8")
118
+
119
+ def before_emit(self, text_element):
120
+ if "content" in text_element and isinstance(text_element["content"], bytes):
121
+ text_element["content"] = text_element["content"].decode("utf-8")
122
+ return text_element