chainlit 1.1.202__py3-none-any.whl → 1.1.300__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 (60) hide show
  1. chainlit/__init__.py +22 -4
  2. chainlit/cli/__init__.py +53 -6
  3. chainlit/config.py +25 -18
  4. chainlit/context.py +9 -0
  5. chainlit/copilot/dist/index.js +443 -410
  6. chainlit/data/__init__.py +19 -5
  7. chainlit/data/dynamodb.py +586 -0
  8. chainlit/data/sql_alchemy.py +47 -28
  9. chainlit/discord/app.py +4 -2
  10. chainlit/element.py +36 -20
  11. chainlit/emitter.py +8 -7
  12. chainlit/frontend/dist/assets/{DailyMotion-53376209.js → DailyMotion-578b63e6.js} +1 -1
  13. chainlit/frontend/dist/assets/{Facebook-aee41f5b.js → Facebook-b825e5bb.js} +1 -1
  14. chainlit/frontend/dist/assets/{FilePlayer-b2cdb30f.js → FilePlayer-bcba3b4e.js} +1 -1
  15. chainlit/frontend/dist/assets/{Kaltura-51db0377.js → Kaltura-fc1c9497.js} +1 -1
  16. chainlit/frontend/dist/assets/{Mixcloud-cb900886.js → Mixcloud-4cfb2724.js} +1 -1
  17. chainlit/frontend/dist/assets/{Mux-79ac59e6.js → Mux-aa92055c.js} +1 -1
  18. chainlit/frontend/dist/assets/{Preview-cfe7584c.js → Preview-9f55905a.js} +1 -1
  19. chainlit/frontend/dist/assets/{SoundCloud-a985707c.js → SoundCloud-f991fe03.js} +1 -1
  20. chainlit/frontend/dist/assets/{Streamable-3d89aab5.js → Streamable-53128f49.js} +1 -1
  21. chainlit/frontend/dist/assets/{Twitch-bf016588.js → Twitch-fce8b9f5.js} +1 -1
  22. chainlit/frontend/dist/assets/{Vidyard-1891ecd7.js → Vidyard-e35c6102.js} +1 -1
  23. chainlit/frontend/dist/assets/{Vimeo-0645662c.js → Vimeo-fff35f8e.js} +1 -1
  24. chainlit/frontend/dist/assets/{Wistia-3b449fe2.js → Wistia-ec07dc64.js} +1 -1
  25. chainlit/frontend/dist/assets/{YouTube-5ea2381e.js → YouTube-ad068e2a.js} +1 -1
  26. chainlit/frontend/dist/assets/index-aaf974a9.css +1 -0
  27. chainlit/frontend/dist/assets/index-d40d41cc.js +727 -0
  28. chainlit/frontend/dist/assets/{react-plotly-2ff19c9f.js → react-plotly-b2c6442b.js} +1 -1
  29. chainlit/frontend/dist/index.html +2 -3
  30. chainlit/langchain/callbacks.py +4 -2
  31. chainlit/llama_index/callbacks.py +2 -2
  32. chainlit/message.py +30 -25
  33. chainlit/oauth_providers.py +118 -0
  34. chainlit/server.py +208 -83
  35. chainlit/slack/app.py +2 -3
  36. chainlit/socket.py +27 -23
  37. chainlit/step.py +44 -30
  38. chainlit/teams/__init__.py +6 -0
  39. chainlit/teams/app.py +332 -0
  40. chainlit/translations/en-US.json +2 -4
  41. chainlit/types.py +17 -17
  42. chainlit/user.py +9 -1
  43. chainlit/utils.py +47 -3
  44. {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/METADATA +22 -14
  45. chainlit-1.1.300.dist-info/RECORD +79 -0
  46. chainlit/cli/utils.py +0 -24
  47. chainlit/frontend/dist/assets/index-a0c5a67e.js +0 -698
  48. chainlit/frontend/dist/assets/index-d088547c.css +0 -1
  49. chainlit/playground/__init__.py +0 -2
  50. chainlit/playground/config.py +0 -36
  51. chainlit/playground/provider.py +0 -108
  52. chainlit/playground/providers/__init__.py +0 -11
  53. chainlit/playground/providers/anthropic.py +0 -118
  54. chainlit/playground/providers/huggingface.py +0 -75
  55. chainlit/playground/providers/langchain.py +0 -89
  56. chainlit/playground/providers/openai.py +0 -386
  57. chainlit/playground/providers/vertexai.py +0 -171
  58. chainlit-1.1.202.dist-info/RECORD +0 -86
  59. {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/WHEEL +0 -0
  60. {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/entry_points.txt +0 -0
chainlit/teams/app.py ADDED
@@ -0,0 +1,332 @@
1
+ import asyncio
2
+ import base64
3
+ import mimetypes
4
+ import os
5
+ import uuid
6
+ from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union
7
+
8
+ import filetype
9
+
10
+ if TYPE_CHECKING:
11
+ from botbuilder.core import TurnContext
12
+ from botbuilder.schema import Activity
13
+
14
+ import httpx
15
+ from botbuilder.core import (
16
+ BotFrameworkAdapter,
17
+ BotFrameworkAdapterSettings,
18
+ MessageFactory,
19
+ TurnContext,
20
+ )
21
+ from botbuilder.schema import (
22
+ ActionTypes,
23
+ Activity,
24
+ ActivityTypes,
25
+ Attachment,
26
+ CardAction,
27
+ ChannelAccount,
28
+ HeroCard,
29
+ )
30
+ from chainlit.config import config
31
+ from chainlit.context import ChainlitContext, HTTPSession, context_var
32
+ from chainlit.data import get_data_layer
33
+ from chainlit.element import Element, ElementDict
34
+ from chainlit.emitter import BaseChainlitEmitter
35
+ from chainlit.logger import logger
36
+ from chainlit.message import Message, StepDict
37
+ from chainlit.telemetry import trace
38
+ from chainlit.types import Feedback
39
+ from chainlit.user import PersistedUser, User
40
+ from chainlit.user_session import user_session
41
+
42
+
43
+ class TeamsEmitter(BaseChainlitEmitter):
44
+ def __init__(self, session: HTTPSession, turn_context: TurnContext, enabled=False):
45
+ super().__init__(session)
46
+ self.turn_context = turn_context
47
+ self.enabled = enabled
48
+
49
+ async def send_element(self, element_dict: ElementDict):
50
+ if not self.enabled or element_dict.get("display") != "inline":
51
+ return
52
+
53
+ persisted_file = self.session.files.get(element_dict.get("chainlitKey") or "")
54
+ attachment: Optional[Attachment] = None
55
+ mime: Optional[str] = None
56
+
57
+ element_name: str = element_dict.get("name", "Untitled")
58
+
59
+ if mime:
60
+ file_extension = mimetypes.guess_extension(mime)
61
+ if file_extension:
62
+ element_name += file_extension
63
+
64
+ if persisted_file:
65
+ mime = element_dict.get("mime")
66
+ with open(persisted_file["path"], "rb") as file:
67
+ dencoded_string = base64.b64encode(file.read()).decode()
68
+ content_url = f"data:{mime};base64,{dencoded_string}"
69
+ attachment = Attachment(
70
+ content_type=mime, content_url=content_url, name=element_name
71
+ )
72
+
73
+ elif url := element_dict.get("url"):
74
+ attachment = Attachment(
75
+ content_type=mime, content_url=url, name=element_name
76
+ )
77
+
78
+ if not attachment:
79
+ return
80
+
81
+ await self.turn_context.send_activity(Activity(attachments=[attachment]))
82
+
83
+ async def send_step(self, step_dict: StepDict):
84
+ if not self.enabled:
85
+ return
86
+
87
+ step_type = step_dict.get("type")
88
+ is_message = step_type in [
89
+ "user_message",
90
+ "assistant_message",
91
+ ]
92
+ is_chain_of_thought = bool(step_dict.get("parentId"))
93
+ is_empty_output = not step_dict.get("output")
94
+
95
+ if is_chain_of_thought or is_empty_output or not is_message:
96
+ return
97
+ else:
98
+ reply = MessageFactory.text(step_dict["output"])
99
+ enable_feedback = not step_dict.get("disableFeedback") and get_data_layer()
100
+ if enable_feedback:
101
+ like_button = CardAction(
102
+ type=ActionTypes.message_back,
103
+ title="👍",
104
+ text="like",
105
+ value={"feedback": "like", "step_id": step_dict["id"]},
106
+ )
107
+ dislike_button = CardAction(
108
+ type=ActionTypes.message_back,
109
+ title="👎",
110
+ text="dislike",
111
+ value={"feedback": "dislike", "step_id": step_dict["id"]},
112
+ )
113
+ card = HeroCard(buttons=[like_button, dislike_button])
114
+ attachment = Attachment(
115
+ content_type="application/vnd.microsoft.card.hero", content=card
116
+ )
117
+ reply.attachments = [attachment]
118
+
119
+ await self.turn_context.send_activity(reply)
120
+
121
+ async def update_step(self, step_dict: StepDict):
122
+ if not self.enabled:
123
+ return
124
+
125
+ await self.send_step(step_dict)
126
+
127
+
128
+ adapter_settings = BotFrameworkAdapterSettings(
129
+ app_id=os.environ.get("TEAMS_APP_ID"),
130
+ app_password=os.environ.get("TEAMS_APP_PASSWORD"),
131
+ )
132
+ adapter = BotFrameworkAdapter(adapter_settings)
133
+
134
+
135
+ @trace
136
+ def init_teams_context(
137
+ session: HTTPSession,
138
+ turn_context: TurnContext,
139
+ ) -> ChainlitContext:
140
+ emitter = TeamsEmitter(session=session, turn_context=turn_context)
141
+ context = ChainlitContext(session=session, emitter=emitter)
142
+ context_var.set(context)
143
+ user_session.set("teams_turn_context", turn_context)
144
+ return context
145
+
146
+
147
+ users_by_teams_id: Dict[str, Union[User, PersistedUser]] = {}
148
+
149
+ USER_PREFIX = "teams_"
150
+
151
+
152
+ async def get_user(teams_user: ChannelAccount):
153
+ if teams_user.id in users_by_teams_id:
154
+ return users_by_teams_id[teams_user.id]
155
+
156
+ metadata = {
157
+ "name": teams_user.name,
158
+ "id": teams_user.id,
159
+ }
160
+ user = User(identifier=USER_PREFIX + str(teams_user.name), metadata=metadata)
161
+
162
+ users_by_teams_id[teams_user.id] = user
163
+
164
+ if data_layer := get_data_layer():
165
+ try:
166
+ persisted_user = await data_layer.create_user(user)
167
+ if persisted_user:
168
+ users_by_teams_id[teams_user.id] = persisted_user
169
+ except Exception as e:
170
+ logger.error(f"Error creating user: {e}")
171
+
172
+ return users_by_teams_id[teams_user.id]
173
+
174
+
175
+ async def download_teams_file(url: str):
176
+ async with httpx.AsyncClient() as client:
177
+ response = await client.get(url)
178
+ if response.status_code == 200:
179
+ return response.content
180
+ else:
181
+ return None
182
+
183
+
184
+ async def download_teams_files(
185
+ session: HTTPSession, attachments: Optional[List[Attachment]] = None
186
+ ):
187
+ if not attachments:
188
+ return []
189
+
190
+ attachments = [
191
+ attachment for attachment in attachments if isinstance(attachment.content, dict)
192
+ ]
193
+ download_coros = [
194
+ download_teams_file(attachment.content.get("downloadUrl"))
195
+ for attachment in attachments
196
+ ]
197
+ file_bytes_list = await asyncio.gather(*download_coros)
198
+ file_refs = []
199
+ for idx, file_bytes in enumerate(file_bytes_list):
200
+ if file_bytes:
201
+ name = attachments[idx].name
202
+ mime_type = filetype.guess_mime(file_bytes) or "application/octet-stream"
203
+ file_ref = await session.persist_file(
204
+ name=name, mime=mime_type, content=file_bytes
205
+ )
206
+ file_refs.append(file_ref)
207
+
208
+ files_dicts = [
209
+ session.files[file["id"]] for file in file_refs if file["id"] in session.files
210
+ ]
211
+
212
+ file_elements = [Element.from_dict(file_dict) for file_dict in files_dicts]
213
+
214
+ return file_elements
215
+
216
+
217
+ def clean_content(activity: Activity):
218
+ return activity.text.strip()
219
+
220
+
221
+ async def process_teams_message(
222
+ turn_context: TurnContext,
223
+ thread_name: str,
224
+ ):
225
+ user = await get_user(turn_context.activity.from_property)
226
+
227
+ thread_id = str(
228
+ uuid.uuid5(uuid.NAMESPACE_DNS, str(turn_context.activity.conversation.id))
229
+ )
230
+
231
+ text = clean_content(turn_context.activity)
232
+ teams_files = turn_context.activity.attachments
233
+
234
+ session_id = str(uuid.uuid4())
235
+
236
+ session = HTTPSession(
237
+ id=session_id,
238
+ thread_id=thread_id,
239
+ user=user,
240
+ client_type="teams",
241
+ )
242
+
243
+ ctx = init_teams_context(
244
+ session=session,
245
+ turn_context=turn_context,
246
+ )
247
+
248
+ file_elements = await download_teams_files(session, teams_files)
249
+
250
+ msg = Message(
251
+ content=text,
252
+ elements=file_elements,
253
+ type="user_message",
254
+ author=user.metadata.get("name"),
255
+ )
256
+
257
+ await msg.send()
258
+
259
+ ctx.emitter.enabled = True
260
+
261
+ if on_chat_start := config.code.on_chat_start:
262
+ await on_chat_start()
263
+
264
+ if on_message := config.code.on_message:
265
+ await on_message(msg)
266
+
267
+ if on_chat_end := config.code.on_chat_end:
268
+ await on_chat_end()
269
+
270
+ if data_layer := get_data_layer():
271
+ if isinstance(user, PersistedUser):
272
+ try:
273
+ await data_layer.update_thread(
274
+ thread_id=thread_id,
275
+ name=thread_name,
276
+ metadata=ctx.session.to_persistable(),
277
+ user_id=user.id,
278
+ )
279
+ except Exception as e:
280
+ logger.error(f"Error updating thread: {e}")
281
+
282
+ ctx.session.delete()
283
+
284
+
285
+ async def handle_message(turn_context: TurnContext):
286
+ if turn_context.activity.type == ActivityTypes.message:
287
+ if (
288
+ turn_context.activity.text == "like"
289
+ or turn_context.activity.text == "dislike"
290
+ ):
291
+ feedback_value: Literal[0, 1] = (
292
+ 0 if turn_context.activity.text == "dislike" else 1
293
+ )
294
+ step_id = turn_context.activity.value.get("step_id")
295
+ if data_layer := get_data_layer():
296
+ await data_layer.upsert_feedback(
297
+ Feedback(forId=step_id, value=feedback_value)
298
+ )
299
+ updated_text = "👍" if turn_context.activity.text == "like" else "👎"
300
+ # Update the existing message to remove the buttons
301
+ updated_message = Activity(
302
+ type=ActivityTypes.message,
303
+ id=turn_context.activity.reply_to_id,
304
+ text=updated_text,
305
+ attachments=[],
306
+ )
307
+ await turn_context.update_activity(updated_message)
308
+ else:
309
+ # Send typing activity
310
+ typing_activity = Activity(
311
+ type=ActivityTypes.typing,
312
+ from_property=turn_context.activity.recipient,
313
+ recipient=turn_context.activity.from_property,
314
+ conversation=turn_context.activity.conversation,
315
+ )
316
+ await turn_context.send_activity(typing_activity)
317
+ thread_name = f"{turn_context.activity.from_property.name} Teams DM"
318
+ await process_teams_message(turn_context, thread_name)
319
+
320
+
321
+ async def on_turn(turn_context: TurnContext):
322
+ await handle_message(turn_context)
323
+
324
+
325
+ # Create the main bot class
326
+ class TeamsBot:
327
+ async def on_turn(self, turn_context: TurnContext):
328
+ await on_turn(turn_context)
329
+
330
+
331
+ # Create the bot instance
332
+ bot = TeamsBot()
@@ -20,7 +20,7 @@
20
20
  "TaskList": {
21
21
  "title": "🗒️ Task List",
22
22
  "loading": "Loading...",
23
- "error": "An error occured"
23
+ "error": "An error occurred"
24
24
  }
25
25
  },
26
26
  "attachments": {
@@ -41,9 +41,7 @@
41
41
  },
42
42
  "detailsButton": {
43
43
  "using": "Using",
44
- "running": "Running",
45
- "took_one": "Took {{count}} step",
46
- "took_other": "Took {{count}} steps"
44
+ "used": "Used"
47
45
  },
48
46
  "auth": {
49
47
  "authLogin": {
chainlit/types.py CHANGED
@@ -150,11 +150,16 @@ class FileDict(TypedDict):
150
150
  type: str
151
151
 
152
152
 
153
- class UIMessagePayload(TypedDict):
153
+ class MessagePayload(TypedDict):
154
154
  message: "StepDict"
155
155
  fileReferences: Optional[List[FileReference]]
156
156
 
157
157
 
158
+ class SystemMessagePayload(TypedDict):
159
+ content: str
160
+ metadata: Optional[Dict[str, Any]]
161
+
162
+
158
163
  class AudioChunkPayload(TypedDict):
159
164
  isStart: bool
160
165
  mimeType: str
@@ -193,21 +198,6 @@ class AskActionResponse(TypedDict):
193
198
  collapsed: bool
194
199
 
195
200
 
196
- class GenerationRequest(BaseModel):
197
- chatGeneration: Optional[ChatGeneration] = None
198
- completionGeneration: Optional[CompletionGeneration] = None
199
- userEnv: Dict[str, str]
200
-
201
- @property
202
- def generation(self):
203
- if self.chatGeneration:
204
- return self.chatGeneration
205
- return self.completionGeneration
206
-
207
- def is_chat(self):
208
- return self.chatGeneration is not None
209
-
210
-
211
201
  class DeleteThreadRequest(BaseModel):
212
202
  threadId: str
213
203
 
@@ -226,6 +216,15 @@ class Theme(str, Enum):
226
216
  dark = "dark"
227
217
 
228
218
 
219
+ @dataclass
220
+ class Starter(DataClassJsonMixin):
221
+ """Specification for a starter that can be chosen by the user at the thread start."""
222
+
223
+ label: str
224
+ message: str
225
+ icon: Optional[str] = None
226
+
227
+
229
228
  @dataclass
230
229
  class ChatProfile(DataClassJsonMixin):
231
230
  """Specification for a chat profile that can be chosen by the user at the thread start."""
@@ -234,6 +233,7 @@ class ChatProfile(DataClassJsonMixin):
234
233
  markdown_description: str
235
234
  icon: Optional[str] = None
236
235
  default: bool = False
236
+ starters: Optional[List[Starter]] = None
237
237
 
238
238
 
239
239
  FeedbackStrategy = Literal["BINARY"]
@@ -249,8 +249,8 @@ class FeedbackDict(TypedDict):
249
249
  @dataclass
250
250
  class Feedback:
251
251
  forId: str
252
- threadId: Optional[str]
253
252
  value: Literal[0, 1]
253
+ threadId: Optional[str] = None
254
254
  id: Optional[str] = None
255
255
  comment: Optional[str] = None
256
256
 
chainlit/user.py CHANGED
@@ -4,7 +4,15 @@ from dataclasses_json import DataClassJsonMixin
4
4
  from pydantic.dataclasses import Field, dataclass
5
5
 
6
6
  Provider = Literal[
7
- "credentials", "header", "github", "google", "azure-ad", "okta", "auth0", "descope"
7
+ "credentials",
8
+ "header",
9
+ "github",
10
+ "google",
11
+ "azure-ad",
12
+ "azure-ad-hybrid",
13
+ "okta",
14
+ "auth0",
15
+ "descope",
8
16
  ]
9
17
 
10
18
 
chainlit/utils.py CHANGED
@@ -1,12 +1,16 @@
1
1
  import functools
2
2
  import importlib
3
3
  import inspect
4
+ import os
4
5
  from asyncio import CancelledError
5
6
  from typing import Callable
6
7
 
8
+ import click
9
+ from chainlit.auth import ensure_jwt_secret
7
10
  from chainlit.context import context
8
11
  from chainlit.logger import logger
9
12
  from chainlit.message import ErrorMessage
13
+ from fastapi import FastAPI
10
14
  from packaging import version
11
15
 
12
16
 
@@ -44,9 +48,10 @@ def wrap_user_function(user_function: Callable, with_task=False) -> Callable:
44
48
  pass
45
49
  except Exception as e:
46
50
  logger.exception(e)
47
- await ErrorMessage(
48
- content=str(e) or e.__class__.__name__, author="Error"
49
- ).send()
51
+ if with_task:
52
+ await ErrorMessage(
53
+ content=str(e) or e.__class__.__name__, author="Error"
54
+ ).send()
50
55
  finally:
51
56
  if with_task:
52
57
  await context.emitter.task_end()
@@ -86,3 +91,42 @@ def check_module_version(name, required_version):
86
91
  except ModuleNotFoundError:
87
92
  return False
88
93
  return version.parse(module.__version__) >= version.parse(required_version)
94
+
95
+
96
+ def check_file(target: str):
97
+ # Define accepted file extensions for Chainlit
98
+ ACCEPTED_FILE_EXTENSIONS = ("py", "py3")
99
+
100
+ _, extension = os.path.splitext(target)
101
+
102
+ # Check file extension
103
+ if extension[1:] not in ACCEPTED_FILE_EXTENSIONS:
104
+ if extension[1:] == "":
105
+ raise click.BadArgumentUsage(
106
+ "Chainlit requires raw Python (.py) files, but the provided file has no extension."
107
+ )
108
+ else:
109
+ raise click.BadArgumentUsage(
110
+ f"Chainlit requires raw Python (.py) files, not {extension}."
111
+ )
112
+
113
+ if not os.path.exists(target):
114
+ raise click.BadParameter(f"File does not exist: {target}")
115
+
116
+
117
+ def mount_chainlit(app: FastAPI, target: str, path="/chainlit"):
118
+ os.environ["CHAINLIT_ROOT_PATH"] = path
119
+ os.environ["CHAINLIT_SUBMOUNT"] = "true"
120
+ from chainlit.config import config, load_module
121
+ from chainlit.server import combined_asgi_app as chainlit_app
122
+
123
+ config.run.root_path = path
124
+
125
+ check_file(target)
126
+ # Load the module provided by the user
127
+ config.run.module_name = target
128
+ load_module(config.run.module_name)
129
+
130
+ ensure_jwt_secret()
131
+
132
+ app.mount("/", chainlit_app)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chainlit
3
- Version: 1.1.202
3
+ Version: 1.1.300
4
4
  Summary: Build Conversational AI.
5
5
  Home-page: https://github.com/Chainlit/chainlit
6
6
  License: Apache-2.0 license
@@ -18,17 +18,19 @@ Requires-Dist: asyncer (>=0.0.2,<0.0.3)
18
18
  Requires-Dist: click (>=8.1.3,<9.0.0)
19
19
  Requires-Dist: dataclasses_json (>=0.5.7,<0.6.0)
20
20
  Requires-Dist: fastapi (>=0.110.1,<0.111.0)
21
- Requires-Dist: fastapi-socketio (>=0.0.10,<0.0.11)
22
21
  Requires-Dist: filetype (>=1.2.0,<2.0.0)
23
22
  Requires-Dist: httpx (>=0.23.0)
24
23
  Requires-Dist: lazify (>=0.4.0,<0.5.0)
25
- Requires-Dist: literalai (==0.0.601)
24
+ Requires-Dist: literalai (==0.0.604)
26
25
  Requires-Dist: nest-asyncio (>=1.5.6,<2.0.0)
26
+ Requires-Dist: numpy (>=1.24.4,<2.0.0) ; python_version < "3.9"
27
+ Requires-Dist: numpy (>=1.26,<2.0) ; python_version >= "3.9"
27
28
  Requires-Dist: packaging (>=23.1,<24.0)
28
29
  Requires-Dist: pydantic (>=1,<3)
29
30
  Requires-Dist: pyjwt (>=2.8.0,<3.0.0)
30
31
  Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
31
32
  Requires-Dist: python-multipart (>=0.0.9,<0.0.10)
33
+ Requires-Dist: python-socketio (>=5.11.0,<6.0.0)
32
34
  Requires-Dist: starlette (>=0.37.2,<0.38.0)
33
35
  Requires-Dist: syncer (>=2.0.3,<3.0.0)
34
36
  Requires-Dist: tomli (>=2.0.1,<3.0.0)
@@ -42,13 +44,12 @@ Description-Content-Type: text/markdown
42
44
 
43
45
  [![](https://dcbadge.vercel.app/api/server/ZThrUxbAYw?style=flat)](https://discord.gg/k73SQ3FyUh)
44
46
  [![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)
47
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/chainlit)
48
+ [![GitHub Contributors](https://img.shields.io/github/contributors/chainlit/chainlit)](https://github.com/chainlit/chainlit/graphs/contributors)
45
49
  [![CI](https://github.com/Chainlit/chainlit/actions/workflows/ci.yaml/badge.svg)](https://github.com/Chainlit/chainlit/actions/workflows/ci.yaml)
46
50
 
47
51
  **Build production-ready Conversational AI applications in minutes, not weeks ⚡️**
48
52
 
49
- > [!NOTE]
50
- > You can ask Chainlit related questions to [Chainlit Help](https://help.chainlit.io/)! Also available on the Discord `@Chainlit Help`. Proudly built with Chainlit!
51
-
52
53
  Chainlit is an open-source async Python framework which allows developers to build scalable Conversational AI or agentic applications.
53
54
 
54
55
  - ✅ ChatGPT-like application
@@ -57,11 +58,15 @@ Chainlit is an open-source async Python framework which allows developers to bui
57
58
  - ✅ Custom frontend (build your own agentic experience)
58
59
  - ✅ API Endpoint
59
60
 
60
- Full documentation is available [here](https://docs.chainlit.io).
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!
61
62
 
62
- Contact us [here](https://forms.gle/BX3UNBLmTF75KgZVA) for **Enterprise Support** and to get early access to Literal AI, our product to evaluate and monitor LLM applications.
63
+ > [!NOTE]
64
+ > Contact us [here](https://forms.gle/BX3UNBLmTF75KgZVA) for **Enterprise Support**.
65
+ > 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.
63
66
 
64
- https://github.com/Chainlit/chainlit/assets/13104895/8882af90-fdfa-4b24-8200-1ee96c6c7490
67
+ <p align="center">
68
+ <img src="https://github.com/Chainlit/chainlit/assets/13104895/0c2cc7a9-766c-41d3-aae2-117a2d0eb8ed" width="80%" />
69
+ </p>
65
70
 
66
71
  ## Installation
67
72
 
@@ -84,8 +89,10 @@ Create a new file `demo.py` with the following code:
84
89
  import chainlit as cl
85
90
 
86
91
 
87
- @cl.step
88
- def tool():
92
+ @cl.step(type="tool")
93
+ async def tool():
94
+ # Fake tool
95
+ await cl.sleep(2)
89
96
  return "Response from the tool!"
90
97
 
91
98
 
@@ -102,11 +109,12 @@ async def main(message: cl.Message):
102
109
  None.
103
110
  """
104
111
 
112
+ final_answer = await cl.Message(content="").send()
113
+
105
114
  # Call the tool
106
- tool()
115
+ final_answer.content = await tool()
107
116
 
108
- # Send the final answer.
109
- await cl.Message(content="This is the final answer").send()
117
+ await final_answer.update()
110
118
  ```
111
119
 
112
120
  Now run it!
@@ -0,0 +1,79 @@
1
+ chainlit/__init__.py,sha256=g6MbN4Vuf8PbJTpTE2XNqVt-GklWQCk8g5_JZGbrB8M,11052
2
+ chainlit/__main__.py,sha256=7Vg3w3T3qDuz4KDu5lQhLH6lQ3cYdume7gHH7Z1V97U,87
3
+ chainlit/action.py,sha256=k-GsblVHI4DnDWFyF-RZgq3KfdfAFICFh2OBeU4w8N8,1410
4
+ chainlit/auth.py,sha256=lLHePwmwKzX0LiWqpTAtKTdSecrDLqCMSY9Yw4c-TD8,2681
5
+ chainlit/cache.py,sha256=Bv3dT4eHhE6Fq3c6Do0ZTpiyoXgXYewdxTgpYghEd9g,1361
6
+ chainlit/chat_settings.py,sha256=2ByenmwS8O6jQjDVJjhhbLrBPGA5aY2F7R3VvQQxXPk,877
7
+ chainlit/cli/__init__.py,sha256=iLyxU_9db-2n_MaSr6V0VNoQDxhwRIT10-OGlENlq7o,6163
8
+ chainlit/config.py,sha256=o2eF5q6O2xSYXAryW8xljuj98HH8u_AFWpTq6bHbrqM,16712
9
+ chainlit/context.py,sha256=wVtOHIAS9NufvnIW8e4VPHgD7W7pyrstEQGt29FtILc,3075
10
+ chainlit/copilot/dist/assets/logo_dark-2a3cf740.svg,sha256=Kjz3QMh-oh-ag4YatjU0YCPqGF7F8nHh8VUQoJIs01E,8887
11
+ chainlit/copilot/dist/assets/logo_light-b078e7bc.svg,sha256=sHjnvEq1rfqh3bcexJNYUY7WEDdTQZq3aKZYpi4w4ck,8889
12
+ chainlit/copilot/dist/index.js,sha256=nnRtMY1HcLmpOTmwk9ah8tLwgp8_dpDSUJb1voFRW7w,6752568
13
+ chainlit/data/__init__.py,sha256=cUT49s5AhIm5WDlESQEpahSl7k6nzlMAYSJgO_00kO0,17092
14
+ chainlit/data/acl.py,sha256=5EwZuKVcZediw77L661MohGce3JzGIaYmw6NutmMTw0,578
15
+ chainlit/data/dynamodb.py,sha256=u5L9xqp0FG6J2VuGqUjMiJmIddL5jXs4MUcoZb4mXsM,19420
16
+ chainlit/data/sql_alchemy.py,sha256=OFjNnNcswZOgYZfnc7sH2_lJQQDQF6olw2xW8-JMqsg,26805
17
+ chainlit/data/storage_clients.py,sha256=D9KY1XKDjZh2uuh01ECxeoEtjw-JlrCR-WCuOuePVQI,3007
18
+ chainlit/discord/__init__.py,sha256=kZ_AAMaCToqO-1FdeQ8_IHS2pqNT0QJ-yyd8bCMaHHs,198
19
+ chainlit/discord/app.py,sha256=KvBS-bL89tKzzz2-lqCQVaI2hb4qYTyhl_TzCdhMfHQ,10540
20
+ chainlit/element.py,sha256=sjOgHjDaTuQ-t663dmBT-iBOgSVTn3mTlbSGjE42LjE,10990
21
+ chainlit/emitter.py,sha256=BbZ0GwEY9DQu7cN2khgMqT7GzRK3dShPIJMRRwnGuag,13082
22
+ chainlit/frontend/dist/assets/DailyMotion-578b63e6.js,sha256=FljqIxuYhDmbN82fvg-_8c_mlTZPj_G_DefTX4TKuUk,2961
23
+ chainlit/frontend/dist/assets/Facebook-b825e5bb.js,sha256=SML0392XsEaiAX-umB3X4P1VxMmeyNGKSwNrf16504A,3216
24
+ chainlit/frontend/dist/assets/FilePlayer-bcba3b4e.js,sha256=YxE74TiGD3kSs4tUhlyV39d2axLSOZ7ogfzsZq1MQdo,9041
25
+ chainlit/frontend/dist/assets/Kaltura-fc1c9497.js,sha256=6GrAMBk1kETlbpFzcPMOOYkbjk_CUQem-nuiD2FimTw,2790
26
+ chainlit/frontend/dist/assets/Mixcloud-4cfb2724.js,sha256=DLVwQ7RLYm4dvfClyoSFDB6rjG7vCFv8hiNbSN-vNYY,2638
27
+ chainlit/frontend/dist/assets/Mux-aa92055c.js,sha256=unvszOgiIQfmZhFtEeIXJE5eiSr6w8Jx1sRpGZX4VlQ,5360
28
+ chainlit/frontend/dist/assets/Preview-9f55905a.js,sha256=RXuDNVigADyu5lGUk-y5QrhiPp1RHqcE5-RylFprdBo,3011
29
+ chainlit/frontend/dist/assets/SoundCloud-f991fe03.js,sha256=z8XVOBBfaskYyC-bRCsXb6qDFTH4mebmR5jsR5IiH44,2923
30
+ chainlit/frontend/dist/assets/Streamable-53128f49.js,sha256=7WZSefvfRi_qnIS9LTa3PFrs-pgr48YiXM1DXplb1LI,2935
31
+ chainlit/frontend/dist/assets/Twitch-fce8b9f5.js,sha256=H3rQ8YEW6AcejSWtvaVAcfjzQdYgdULPye5mTZ_nc_4,3083
32
+ chainlit/frontend/dist/assets/Vidyard-e35c6102.js,sha256=UW5ad17Jlo5U1BjQG6sFEHvAp8ic6en2Uvb-4DuVb04,2857
33
+ chainlit/frontend/dist/assets/Vimeo-fff35f8e.js,sha256=brWSILraomEKxRDGFR56wwZl81gvxvAvSVbGMCbHvB0,3627
34
+ chainlit/frontend/dist/assets/Wistia-ec07dc64.js,sha256=VU557IGXuda6KYDPVrohXQWDoyIX385ooBt2eIn6LZA,3514
35
+ chainlit/frontend/dist/assets/YouTube-ad068e2a.js,sha256=h-dP39j7ZP7AeqCrJLKlv_ZMD20GSc8nQeMJSaEiMLI,4448
36
+ chainlit/frontend/dist/assets/index-aaf974a9.css,sha256=qvl0qUmR5u0JcmJAfkzaZpN-0ZKdQjzqCSE9cnrQpZQ,2559
37
+ chainlit/frontend/dist/assets/index-d40d41cc.js,sha256=q548b7K04T5yFuuKXr3Z7_y24V5iM7ti_BNfLkRNgoQ,2753963
38
+ chainlit/frontend/dist/assets/logo_dark-2a3cf740.svg,sha256=Kjz3QMh-oh-ag4YatjU0YCPqGF7F8nHh8VUQoJIs01E,8887
39
+ chainlit/frontend/dist/assets/logo_light-b078e7bc.svg,sha256=sHjnvEq1rfqh3bcexJNYUY7WEDdTQZq3aKZYpi4w4ck,8889
40
+ chainlit/frontend/dist/assets/react-plotly-b2c6442b.js,sha256=zOhmPUI82UBQWmBpKFKuAQF_bQT-sXGbG3-kigjMQQ4,3739251
41
+ chainlit/frontend/dist/favicon.svg,sha256=0Cy8x28obT5eWW3nxZRhsEvu6_zMqrqbg0y6hT3D0Q0,6455
42
+ chainlit/frontend/dist/index.html,sha256=cIwIROqkmnFNLWkOz4N_7S91qPJA6r9SuYe4pNguwS8,965
43
+ chainlit/haystack/__init__.py,sha256=uZ77YiPy-qleSTi3dQCDO9HE6S6F6GpJWmh7jO4cxXA,217
44
+ chainlit/haystack/callbacks.py,sha256=tItLc6OmskPeDEJH2Qjtg7KgAgIy1TuYQYHTZm9cr3U,5209
45
+ chainlit/hello.py,sha256=LwENQWo5s5r8nNDn4iKSV77vX60Ky5r_qGjQhyi7qlY,416
46
+ chainlit/input_widget.py,sha256=KmOn1nPTBvnld3iIBHR0Vih0KsCxVnTbo2t_xBNANzo,4949
47
+ chainlit/langchain/__init__.py,sha256=zErMw0_3ufSGeF9ye7X0ZX3wDat4mTOx97T40ePDO2g,217
48
+ chainlit/langchain/callbacks.py,sha256=MHl_m6FYZmCzn0e2KOlZpd6ld0rSP1LzuCKs4Eh_N_8,20517
49
+ chainlit/langflow/__init__.py,sha256=wxhxdsl1yxdsRyNTgZticxFF_8VFtJJ4OdIy3tnEIyM,817
50
+ chainlit/llama_index/__init__.py,sha256=weRoIWCaRBGvA1LczCEfsqhWsltQSVlhtRnTovtdo8w,227
51
+ chainlit/llama_index/callbacks.py,sha256=THFmwotSF_ibqFuaQgxGvEjgKmmzoGJKNlVI75SI2ig,7267
52
+ chainlit/logger.py,sha256=wTwRSZsLfXwWy6U4351IgWAm4KCMThgxm9EZpjGUEr4,373
53
+ chainlit/markdown.py,sha256=VUpqW7MqgjiPIQYHU4funwqC4GmHZBu_TGZTjTI4B0k,2025
54
+ chainlit/message.py,sha256=aEw2VNZ0-4mAC3PSG-0j5ZjO1qZ9MaUFDnfiAXLM_q8,17997
55
+ chainlit/oauth_providers.py,sha256=MRqtsBLn1BQNjKduDNkf5M_IVpRTrAui6rECfewc3js,21774
56
+ chainlit/openai/__init__.py,sha256=DJP_ptclLUM5Zylr4RO1Vk0lCufo3yDqXyH5J9izYS8,1814
57
+ chainlit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
+ chainlit/secret.py,sha256=cQvIFGTQ7r2heC8EOGdgifSZZYqslh-qQxhUhKhD8vU,295
59
+ chainlit/server.py,sha256=H8Oj4rEqY9OulwbNoZzcTc53U0vuYXUPREhYUNKLqpM,28626
60
+ chainlit/session.py,sha256=SOX2zFct3apiSNcIzCDWgDRsUFgUG_6hewqWU8gfIZE,9694
61
+ chainlit/slack/__init__.py,sha256=Q41ztJHeVmpoXVgVqAcwGOufQp_bjf7dDT7eEXDdhPI,207
62
+ chainlit/slack/app.py,sha256=FgrlaupsCo-_1m8FiFcS5s-wFg_28bCjfKnawvlVbEM,11646
63
+ chainlit/socket.py,sha256=0xUoHRQXqhTb9IB9k7rMM7gYIoLQgZed6jV337KtL54,11824
64
+ chainlit/step.py,sha256=rLlK_dhZNKidK5Q7FtP_sNmlm-zUyjF4gHLPxl3PHA8,14213
65
+ chainlit/sync.py,sha256=G1n-7-3WgXsN8y1bJkEyws_YwmHZIyDZoZUwhprigag,1235
66
+ chainlit/teams/__init__.py,sha256=ZSEbsRJHT_mKfGn6yuzM5NX-xItleSDS0af7vt8Z1OA,217
67
+ chainlit/teams/app.py,sha256=i4uu5BizcPH_h824ZFBNbpqM0weCfpPt3zb8YpQ-5po,10378
68
+ chainlit/telemetry.py,sha256=Rk4dnZv0OnGOgV4kD-VHdhgl4i7i3ypqhSE_R-LZceM,3060
69
+ chainlit/translations/en-US.json,sha256=J46wpkc01XLnytWNLSziillMvfmwXsc-mIUeYDIy59M,7741
70
+ chainlit/translations.py,sha256=WG_r7HzxBYns-zk9tVvoGdoofv71okTZx8k1RlcoTIg,2034
71
+ chainlit/types.py,sha256=1W_IexztYW5ewOfxXtdL6qJHWYLWJ5qC9JG0iu6Rnv4,5329
72
+ chainlit/user.py,sha256=8PgRJvv59b7BKTNguObo68gyFoOGNJfVkT3WW-fvhAM,671
73
+ chainlit/user_session.py,sha256=G1amgs1_h2tVn4mtAXZmunm9nlBHQ_rCYvJQh3nsVwQ,1645
74
+ chainlit/utils.py,sha256=w3UIzvaQ72y5VrycFoWaqS_NocS40No7mzPWqkelzCE,3939
75
+ chainlit/version.py,sha256=iosXhlXclBwBqlADFKEilxAC2wWKbtuBKi87AmPi7s8,196
76
+ chainlit-1.1.300.dist-info/METADATA,sha256=uyhCBJZhUSS0H-4loW8u1UmAbJ7gI4D-PPH3i3UroOU,6315
77
+ chainlit-1.1.300.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
78
+ chainlit-1.1.300.dist-info/entry_points.txt,sha256=FrkqdjrFl8juSnvBndniyX7XuKojmUwO4ghRh-CFMQc,45
79
+ chainlit-1.1.300.dist-info/RECORD,,