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.
- chainlit/__init__.py +22 -4
- chainlit/cli/__init__.py +53 -6
- chainlit/config.py +25 -18
- chainlit/context.py +9 -0
- chainlit/copilot/dist/index.js +443 -410
- chainlit/data/__init__.py +19 -5
- chainlit/data/dynamodb.py +586 -0
- chainlit/data/sql_alchemy.py +47 -28
- chainlit/discord/app.py +4 -2
- chainlit/element.py +36 -20
- chainlit/emitter.py +8 -7
- chainlit/frontend/dist/assets/{DailyMotion-53376209.js → DailyMotion-578b63e6.js} +1 -1
- chainlit/frontend/dist/assets/{Facebook-aee41f5b.js → Facebook-b825e5bb.js} +1 -1
- chainlit/frontend/dist/assets/{FilePlayer-b2cdb30f.js → FilePlayer-bcba3b4e.js} +1 -1
- chainlit/frontend/dist/assets/{Kaltura-51db0377.js → Kaltura-fc1c9497.js} +1 -1
- chainlit/frontend/dist/assets/{Mixcloud-cb900886.js → Mixcloud-4cfb2724.js} +1 -1
- chainlit/frontend/dist/assets/{Mux-79ac59e6.js → Mux-aa92055c.js} +1 -1
- chainlit/frontend/dist/assets/{Preview-cfe7584c.js → Preview-9f55905a.js} +1 -1
- chainlit/frontend/dist/assets/{SoundCloud-a985707c.js → SoundCloud-f991fe03.js} +1 -1
- chainlit/frontend/dist/assets/{Streamable-3d89aab5.js → Streamable-53128f49.js} +1 -1
- chainlit/frontend/dist/assets/{Twitch-bf016588.js → Twitch-fce8b9f5.js} +1 -1
- chainlit/frontend/dist/assets/{Vidyard-1891ecd7.js → Vidyard-e35c6102.js} +1 -1
- chainlit/frontend/dist/assets/{Vimeo-0645662c.js → Vimeo-fff35f8e.js} +1 -1
- chainlit/frontend/dist/assets/{Wistia-3b449fe2.js → Wistia-ec07dc64.js} +1 -1
- chainlit/frontend/dist/assets/{YouTube-5ea2381e.js → YouTube-ad068e2a.js} +1 -1
- chainlit/frontend/dist/assets/index-aaf974a9.css +1 -0
- chainlit/frontend/dist/assets/index-d40d41cc.js +727 -0
- chainlit/frontend/dist/assets/{react-plotly-2ff19c9f.js → react-plotly-b2c6442b.js} +1 -1
- chainlit/frontend/dist/index.html +2 -3
- chainlit/langchain/callbacks.py +4 -2
- chainlit/llama_index/callbacks.py +2 -2
- chainlit/message.py +30 -25
- chainlit/oauth_providers.py +118 -0
- chainlit/server.py +208 -83
- chainlit/slack/app.py +2 -3
- chainlit/socket.py +27 -23
- chainlit/step.py +44 -30
- chainlit/teams/__init__.py +6 -0
- chainlit/teams/app.py +332 -0
- chainlit/translations/en-US.json +2 -4
- chainlit/types.py +17 -17
- chainlit/user.py +9 -1
- chainlit/utils.py +47 -3
- {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/METADATA +22 -14
- chainlit-1.1.300.dist-info/RECORD +79 -0
- chainlit/cli/utils.py +0 -24
- chainlit/frontend/dist/assets/index-a0c5a67e.js +0 -698
- chainlit/frontend/dist/assets/index-d088547c.css +0 -1
- chainlit/playground/__init__.py +0 -2
- chainlit/playground/config.py +0 -36
- chainlit/playground/provider.py +0 -108
- chainlit/playground/providers/__init__.py +0 -11
- chainlit/playground/providers/anthropic.py +0 -118
- chainlit/playground/providers/huggingface.py +0 -75
- chainlit/playground/providers/langchain.py +0 -89
- chainlit/playground/providers/openai.py +0 -386
- chainlit/playground/providers/vertexai.py +0 -171
- chainlit-1.1.202.dist-info/RECORD +0 -86
- {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/WHEEL +0 -0
- {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()
|
chainlit/translations/en-US.json
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"TaskList": {
|
|
21
21
|
"title": "🗒️ Task List",
|
|
22
22
|
"loading": "Loading...",
|
|
23
|
-
"error": "An error
|
|
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
|
-
"
|
|
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
|
|
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",
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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.
|
|
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.
|
|
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://discord.gg/k73SQ3FyUh)
|
|
44
46
|
[](https://twitter.com/chainlit_io)
|
|
47
|
+

|
|
48
|
+
[](https://github.com/chainlit/chainlit/graphs/contributors)
|
|
45
49
|
[](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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,,
|