chainlit 1.1.404__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of chainlit might be problematic. Click here for more details.

Files changed (52) hide show
  1. chainlit/__init__.py +53 -305
  2. chainlit/_utils.py +8 -0
  3. chainlit/callbacks.py +308 -0
  4. chainlit/config.py +55 -29
  5. chainlit/copilot/dist/index.js +510 -629
  6. chainlit/data/__init__.py +6 -521
  7. chainlit/data/base.py +121 -0
  8. chainlit/data/dynamodb.py +2 -5
  9. chainlit/data/literalai.py +395 -0
  10. chainlit/data/sql_alchemy.py +10 -9
  11. chainlit/data/storage_clients.py +69 -15
  12. chainlit/data/utils.py +29 -0
  13. chainlit/frontend/dist/assets/{DailyMotion-e665b444.js → DailyMotion-05f4fe48.js} +1 -1
  14. chainlit/frontend/dist/assets/{Facebook-5207db92.js → Facebook-f25411d1.js} +1 -1
  15. chainlit/frontend/dist/assets/{FilePlayer-86937d6e.js → FilePlayer-40ff3414.js} +1 -1
  16. chainlit/frontend/dist/assets/{Kaltura-c96622c1.js → Kaltura-6cbf3897.js} +1 -1
  17. chainlit/frontend/dist/assets/{Mixcloud-57ae3e32.js → Mixcloud-34e7c912.js} +1 -1
  18. chainlit/frontend/dist/assets/{Mux-20373920.js → Mux-8aaff6ac.js} +1 -1
  19. chainlit/frontend/dist/assets/{Preview-c68c0613.js → Preview-2d3bf558.js} +1 -1
  20. chainlit/frontend/dist/assets/{SoundCloud-8a9e3eae.js → SoundCloud-b835f90f.js} +1 -1
  21. chainlit/frontend/dist/assets/{Streamable-1ed099af.js → Streamable-1293e4f3.js} +1 -1
  22. chainlit/frontend/dist/assets/{Twitch-6820039f.js → Twitch-c69660cd.js} +1 -1
  23. chainlit/frontend/dist/assets/{Vidyard-d39ab91d.js → Vidyard-43bda599.js} +1 -1
  24. chainlit/frontend/dist/assets/{Vimeo-017cd9a7.js → Vimeo-54150039.js} +1 -1
  25. chainlit/frontend/dist/assets/{Wistia-a509d9f2.js → Wistia-aa3c721b.js} +1 -1
  26. chainlit/frontend/dist/assets/{YouTube-42dfd82f.js → YouTube-dd0f3cc2.js} +1 -1
  27. chainlit/frontend/dist/assets/index-cf48bedd.js +729 -0
  28. chainlit/frontend/dist/assets/react-plotly-f52a41eb.js +3484 -0
  29. chainlit/frontend/dist/index.html +1 -1
  30. chainlit/langchain/callbacks.py +6 -1
  31. chainlit/llama_index/callbacks.py +20 -4
  32. chainlit/markdown.py +15 -9
  33. chainlit/message.py +0 -1
  34. chainlit/server.py +90 -36
  35. chainlit/session.py +4 -1
  36. chainlit/translations/bn.json +231 -0
  37. chainlit/translations/gu.json +231 -0
  38. chainlit/translations/he-IL.json +231 -0
  39. chainlit/translations/hi.json +231 -0
  40. chainlit/translations/kn.json +231 -0
  41. chainlit/translations/ml.json +231 -0
  42. chainlit/translations/mr.json +231 -0
  43. chainlit/translations/ta.json +231 -0
  44. chainlit/translations/te.json +231 -0
  45. chainlit/utils.py +1 -1
  46. {chainlit-1.1.404.dist-info → chainlit-1.2.0.dist-info}/METADATA +3 -3
  47. chainlit-1.2.0.dist-info/RECORD +96 -0
  48. chainlit/frontend/dist/assets/index-30df9b2b.js +0 -730
  49. chainlit/frontend/dist/assets/react-plotly-5bb34118.js +0 -3602
  50. chainlit-1.1.404.dist-info/RECORD +0 -82
  51. {chainlit-1.1.404.dist-info → chainlit-1.2.0.dist-info}/WHEEL +0 -0
  52. {chainlit-1.1.404.dist-info → chainlit-1.2.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,395 @@
1
+ import json
2
+ from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union, cast
3
+
4
+ import aiofiles
5
+ from chainlit.data.base import BaseDataLayer
6
+ from chainlit.data.utils import queue_until_user_message
7
+ from chainlit.logger import logger
8
+ from chainlit.types import (
9
+ Feedback,
10
+ PageInfo,
11
+ PaginatedResponse,
12
+ Pagination,
13
+ ThreadDict,
14
+ ThreadFilter,
15
+ )
16
+ from chainlit.user import PersistedUser, User
17
+ from httpx import HTTPStatusError, RequestError
18
+ from literalai import Attachment
19
+ from literalai import Score as LiteralScore
20
+ from literalai import Step as LiteralStep
21
+ from literalai.filter import threads_filters as LiteralThreadsFilters
22
+ from literalai.step import StepDict as LiteralStepDict
23
+
24
+ if TYPE_CHECKING:
25
+ from chainlit.element import Element, ElementDict
26
+ from chainlit.step import FeedbackDict, StepDict
27
+
28
+
29
+ _data_layer: Optional[BaseDataLayer] = None
30
+
31
+
32
+ class LiteralDataLayer(BaseDataLayer):
33
+ def __init__(self, api_key: str, server: Optional[str]):
34
+ from literalai import AsyncLiteralClient
35
+
36
+ self.client = AsyncLiteralClient(api_key=api_key, url=server)
37
+ logger.info("Chainlit data layer initialized")
38
+
39
+ def attachment_to_element_dict(self, attachment: Attachment) -> "ElementDict":
40
+ metadata = attachment.metadata or {}
41
+ return {
42
+ "chainlitKey": None,
43
+ "display": metadata.get("display", "side"),
44
+ "language": metadata.get("language"),
45
+ "autoPlay": metadata.get("autoPlay", None),
46
+ "playerConfig": metadata.get("playerConfig", None),
47
+ "page": metadata.get("page"),
48
+ "size": metadata.get("size"),
49
+ "type": metadata.get("type", "file"),
50
+ "forId": attachment.step_id,
51
+ "id": attachment.id or "",
52
+ "mime": attachment.mime,
53
+ "name": attachment.name or "",
54
+ "objectKey": attachment.object_key,
55
+ "url": attachment.url,
56
+ "threadId": attachment.thread_id,
57
+ }
58
+
59
+ def score_to_feedback_dict(
60
+ self, score: Optional[LiteralScore]
61
+ ) -> "Optional[FeedbackDict]":
62
+ if not score:
63
+ return None
64
+ return {
65
+ "id": score.id or "",
66
+ "forId": score.step_id or "",
67
+ "value": cast(Literal[0, 1], score.value),
68
+ "comment": score.comment,
69
+ }
70
+
71
+ def step_to_step_dict(self, step: LiteralStep) -> "StepDict":
72
+ metadata = step.metadata or {}
73
+ input = (step.input or {}).get("content") or (
74
+ json.dumps(step.input) if step.input and step.input != {} else ""
75
+ )
76
+ output = (step.output or {}).get("content") or (
77
+ json.dumps(step.output) if step.output and step.output != {} else ""
78
+ )
79
+
80
+ user_feedback = (
81
+ next(
82
+ (
83
+ s
84
+ for s in step.scores
85
+ if s.type == "HUMAN" and s.name == "user-feedback"
86
+ ),
87
+ None,
88
+ )
89
+ if step.scores
90
+ else None
91
+ )
92
+
93
+ return {
94
+ "createdAt": step.created_at,
95
+ "id": step.id or "",
96
+ "threadId": step.thread_id or "",
97
+ "parentId": step.parent_id,
98
+ "feedback": self.score_to_feedback_dict(user_feedback),
99
+ "start": step.start_time,
100
+ "end": step.end_time,
101
+ "type": step.type or "undefined",
102
+ "name": step.name or "",
103
+ "generation": step.generation.to_dict() if step.generation else None,
104
+ "input": input,
105
+ "output": output,
106
+ "showInput": metadata.get("showInput", False),
107
+ "indent": metadata.get("indent"),
108
+ "language": metadata.get("language"),
109
+ "isError": bool(step.error),
110
+ "waitForAnswer": metadata.get("waitForAnswer", False),
111
+ }
112
+
113
+ async def build_debug_url(self) -> str:
114
+ try:
115
+ project_id = await self.client.api.get_my_project_id()
116
+ return f"{self.client.api.url}/projects/{project_id}/logs/threads/[thread_id]?currentStepId=[step_id]"
117
+ except Exception as e:
118
+ logger.error(f"Error building debug url: {e}")
119
+ return ""
120
+
121
+ async def get_user(self, identifier: str) -> Optional[PersistedUser]:
122
+ user = await self.client.api.get_user(identifier=identifier)
123
+ if not user:
124
+ return None
125
+ return PersistedUser(
126
+ id=user.id or "",
127
+ identifier=user.identifier or "",
128
+ metadata=user.metadata,
129
+ createdAt=user.created_at or "",
130
+ )
131
+
132
+ async def create_user(self, user: User) -> Optional[PersistedUser]:
133
+ _user = await self.client.api.get_user(identifier=user.identifier)
134
+ if not _user:
135
+ _user = await self.client.api.create_user(
136
+ identifier=user.identifier, metadata=user.metadata
137
+ )
138
+ elif _user.id:
139
+ await self.client.api.update_user(id=_user.id, metadata=user.metadata)
140
+ return PersistedUser(
141
+ id=_user.id or "",
142
+ identifier=_user.identifier or "",
143
+ metadata=user.metadata,
144
+ createdAt=_user.created_at or "",
145
+ )
146
+
147
+ async def delete_feedback(
148
+ self,
149
+ feedback_id: str,
150
+ ):
151
+ if feedback_id:
152
+ await self.client.api.delete_score(
153
+ id=feedback_id,
154
+ )
155
+ return True
156
+ return False
157
+
158
+ async def upsert_feedback(
159
+ self,
160
+ feedback: Feedback,
161
+ ):
162
+ if feedback.id:
163
+ await self.client.api.update_score(
164
+ id=feedback.id,
165
+ update_params={
166
+ "comment": feedback.comment,
167
+ "value": feedback.value,
168
+ },
169
+ )
170
+ return feedback.id
171
+ else:
172
+ created = await self.client.api.create_score(
173
+ step_id=feedback.forId,
174
+ value=feedback.value,
175
+ comment=feedback.comment,
176
+ name="user-feedback",
177
+ type="HUMAN",
178
+ )
179
+ return created.id or ""
180
+
181
+ async def safely_send_steps(self, steps):
182
+ try:
183
+ await self.client.api.send_steps(steps)
184
+ except HTTPStatusError as e:
185
+ logger.error(f"HTTP Request: error sending steps: {e.response.status_code}")
186
+ except RequestError as e:
187
+ logger.error(f"HTTP Request: error for {e.request.url!r}.")
188
+
189
+ @queue_until_user_message()
190
+ async def create_element(self, element: "Element"):
191
+ metadata = {
192
+ "size": element.size,
193
+ "language": element.language,
194
+ "display": element.display,
195
+ "type": element.type,
196
+ "page": getattr(element, "page", None),
197
+ }
198
+
199
+ if not element.for_id:
200
+ return
201
+
202
+ object_key = None
203
+
204
+ if not element.url:
205
+ if element.path:
206
+ async with aiofiles.open(element.path, "rb") as f:
207
+ content: Union[bytes, str] = await f.read()
208
+ elif element.content:
209
+ content = element.content
210
+ else:
211
+ raise ValueError("Either path or content must be provided")
212
+ uploaded = await self.client.api.upload_file(
213
+ content=content, mime=element.mime, thread_id=element.thread_id
214
+ )
215
+ object_key = uploaded["object_key"]
216
+
217
+ await self.safely_send_steps(
218
+ [
219
+ {
220
+ "id": element.for_id,
221
+ "threadId": element.thread_id,
222
+ "attachments": [
223
+ {
224
+ "id": element.id,
225
+ "name": element.name,
226
+ "metadata": metadata,
227
+ "mime": element.mime,
228
+ "url": element.url,
229
+ "objectKey": object_key,
230
+ }
231
+ ],
232
+ }
233
+ ]
234
+ )
235
+
236
+ async def get_element(
237
+ self, thread_id: str, element_id: str
238
+ ) -> Optional["ElementDict"]:
239
+ attachment = await self.client.api.get_attachment(id=element_id)
240
+ if not attachment:
241
+ return None
242
+ return self.attachment_to_element_dict(attachment)
243
+
244
+ @queue_until_user_message()
245
+ async def delete_element(self, element_id: str, thread_id: Optional[str] = None):
246
+ await self.client.api.delete_attachment(id=element_id)
247
+
248
+ @queue_until_user_message()
249
+ async def create_step(self, step_dict: "StepDict"):
250
+ metadata = dict(
251
+ step_dict.get("metadata", {}),
252
+ **{
253
+ "waitForAnswer": step_dict.get("waitForAnswer"),
254
+ "language": step_dict.get("language"),
255
+ "showInput": step_dict.get("showInput"),
256
+ },
257
+ )
258
+
259
+ step: LiteralStepDict = {
260
+ "createdAt": step_dict.get("createdAt"),
261
+ "startTime": step_dict.get("start"),
262
+ "endTime": step_dict.get("end"),
263
+ "generation": step_dict.get("generation"),
264
+ "id": step_dict.get("id"),
265
+ "parentId": step_dict.get("parentId"),
266
+ "name": step_dict.get("name"),
267
+ "threadId": step_dict.get("threadId"),
268
+ "type": step_dict.get("type"),
269
+ "tags": step_dict.get("tags"),
270
+ "metadata": metadata,
271
+ }
272
+ if step_dict.get("input"):
273
+ step["input"] = {"content": step_dict.get("input")}
274
+ if step_dict.get("output"):
275
+ step["output"] = {"content": step_dict.get("output")}
276
+ if step_dict.get("isError"):
277
+ step["error"] = step_dict.get("output")
278
+
279
+ await self.safely_send_steps([step])
280
+
281
+ @queue_until_user_message()
282
+ async def update_step(self, step_dict: "StepDict"):
283
+ await self.create_step(step_dict)
284
+
285
+ @queue_until_user_message()
286
+ async def delete_step(self, step_id: str):
287
+ await self.client.api.delete_step(id=step_id)
288
+
289
+ async def get_thread_author(self, thread_id: str) -> str:
290
+ thread = await self.get_thread(thread_id)
291
+ if not thread:
292
+ return ""
293
+ user_identifier = thread.get("userIdentifier")
294
+ if not user_identifier:
295
+ return ""
296
+
297
+ return user_identifier
298
+
299
+ async def delete_thread(self, thread_id: str):
300
+ await self.client.api.delete_thread(id=thread_id)
301
+
302
+ async def list_threads(
303
+ self, pagination: "Pagination", filters: "ThreadFilter"
304
+ ) -> "PaginatedResponse[ThreadDict]":
305
+ if not filters.userId:
306
+ raise ValueError("userId is required")
307
+
308
+ literal_filters: LiteralThreadsFilters = [
309
+ {
310
+ "field": "participantId",
311
+ "operator": "eq",
312
+ "value": filters.userId,
313
+ }
314
+ ]
315
+
316
+ if filters.search:
317
+ literal_filters.append(
318
+ {
319
+ "field": "stepOutput",
320
+ "operator": "ilike",
321
+ "value": filters.search,
322
+ "path": "content",
323
+ }
324
+ )
325
+
326
+ if filters.feedback is not None:
327
+ literal_filters.append(
328
+ {
329
+ "field": "scoreValue",
330
+ "operator": "eq",
331
+ "value": filters.feedback,
332
+ "path": "user-feedback",
333
+ }
334
+ )
335
+
336
+ literal_response = await self.client.api.list_threads(
337
+ first=pagination.first,
338
+ after=pagination.cursor,
339
+ filters=literal_filters,
340
+ order_by={"column": "createdAt", "direction": "DESC"},
341
+ )
342
+ return PaginatedResponse(
343
+ pageInfo=PageInfo(
344
+ hasNextPage=literal_response.pageInfo.hasNextPage,
345
+ startCursor=literal_response.pageInfo.startCursor,
346
+ endCursor=literal_response.pageInfo.endCursor,
347
+ ),
348
+ data=literal_response.data,
349
+ )
350
+
351
+ async def get_thread(self, thread_id: str) -> "Optional[ThreadDict]":
352
+ from chainlit.step import check_add_step_in_cot, stub_step
353
+
354
+ thread = await self.client.api.get_thread(id=thread_id)
355
+ if not thread:
356
+ return None
357
+ elements = [] # List[ElementDict]
358
+ steps = [] # List[StepDict]
359
+ if thread.steps:
360
+ for step in thread.steps:
361
+ for attachment in step.attachments:
362
+ elements.append(self.attachment_to_element_dict(attachment))
363
+
364
+ if check_add_step_in_cot(step):
365
+ steps.append(self.step_to_step_dict(step))
366
+ else:
367
+ steps.append(stub_step(step))
368
+
369
+ return {
370
+ "createdAt": thread.created_at or "",
371
+ "id": thread.id,
372
+ "name": thread.name or None,
373
+ "steps": steps,
374
+ "elements": elements,
375
+ "metadata": thread.metadata,
376
+ "userId": thread.participant_id,
377
+ "userIdentifier": thread.participant_identifier,
378
+ "tags": thread.tags,
379
+ }
380
+
381
+ async def update_thread(
382
+ self,
383
+ thread_id: str,
384
+ name: Optional[str] = None,
385
+ user_id: Optional[str] = None,
386
+ metadata: Optional[Dict] = None,
387
+ tags: Optional[List[str]] = None,
388
+ ):
389
+ await self.client.api.upsert_thread(
390
+ id=thread_id,
391
+ name=name,
392
+ participant_id=user_id,
393
+ metadata=metadata,
394
+ tags=tags,
395
+ )
@@ -8,7 +8,8 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
8
8
  import aiofiles
9
9
  import aiohttp
10
10
  from chainlit.context import context
11
- from chainlit.data import BaseDataLayer, BaseStorageClient, queue_until_user_message
11
+ from chainlit.data.base import BaseDataLayer, BaseStorageClient
12
+ from chainlit.data.utils import queue_until_user_message
12
13
  from chainlit.element import ElementDict
13
14
  from chainlit.logger import logger
14
15
  from chainlit.step import StepDict
@@ -54,7 +55,9 @@ class SQLAlchemyDataLayer(BaseDataLayer):
54
55
  self.engine: AsyncEngine = create_async_engine(
55
56
  self._conninfo, connect_args=ssl_args
56
57
  )
57
- self.async_session = sessionmaker(bind=self.engine, expire_on_commit=False, class_=AsyncSession) # type: ignore
58
+ self.async_session = sessionmaker(
59
+ bind=self.engine, expire_on_commit=False, class_=AsyncSession
60
+ ) # type: ignore
58
61
  if storage_provider:
59
62
  self.storage_provider: Optional[BaseStorageClient] = storage_provider
60
63
  if self.show_logger:
@@ -378,7 +381,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
378
381
  raise ValueError("No authenticated user in context")
379
382
  if not self.storage_provider:
380
383
  logger.warn(
381
- f"SQLAlchemy: create_element error. No blob_storage_client is configured!"
384
+ "SQLAlchemy: create_element error. No blob_storage_client is configured!"
382
385
  )
383
386
  return
384
387
  if not element.for_id:
@@ -440,15 +443,12 @@ class SQLAlchemyDataLayer(BaseDataLayer):
440
443
  parameters = {"id": element_id}
441
444
  await self.execute_sql(query=query, parameters=parameters)
442
445
 
443
- async def delete_user_session(self, id: str) -> bool:
444
- return False # Not sure why documentation wants this
445
-
446
446
  async def get_all_user_threads(
447
447
  self, user_id: Optional[str] = None, thread_id: Optional[str] = None
448
448
  ) -> Optional[List[ThreadDict]]:
449
449
  """Fetch all user threads up to self.user_thread_limit, or one thread by id if thread_id is provided."""
450
450
  if self.show_logger:
451
- logger.info(f"SQLAlchemy: get_all_user_threads")
451
+ logger.info("SQLAlchemy: get_all_user_threads")
452
452
  user_threads_query = """
453
453
  SELECT
454
454
  "id" AS thread_id,
@@ -504,7 +504,8 @@ class SQLAlchemyDataLayer(BaseDataLayer):
504
504
  s."language" AS step_language,
505
505
  s."indent" AS step_indent,
506
506
  f."value" AS feedback_value,
507
- f."comment" AS feedback_comment
507
+ f."comment" AS feedback_comment,
508
+ f."id" AS feedback_id
508
509
  FROM steps s LEFT JOIN feedbacks f ON s."id" = f."forId"
509
510
  WHERE s."threadId" IN {thread_ids}
510
511
  ORDER BY s."createdAt" ASC
@@ -578,7 +579,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
578
579
  tags=step_feedback.get("step_tags"),
579
580
  input=(
580
581
  step_feedback.get("step_input", "")
581
- if step_feedback["step_showinput"] == "true"
582
+ if step_feedback.get("step_showinput") not in [None, "false"]
582
583
  else None
583
584
  ),
584
585
  output=step_feedback.get("step_output", ""),
@@ -1,11 +1,22 @@
1
- from chainlit.data import BaseStorageClient
1
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Union
2
+
3
+ import boto3 # type: ignore
4
+ from azure.storage.filedatalake import (
5
+ ContentSettings,
6
+ DataLakeFileClient,
7
+ DataLakeServiceClient,
8
+ FileSystemClient,
9
+ )
10
+ from chainlit.data.base import BaseStorageClient
2
11
  from chainlit.logger import logger
3
- from typing import TYPE_CHECKING, Optional, Dict, Union, Any
4
- from azure.storage.filedatalake import DataLakeServiceClient, FileSystemClient, DataLakeFileClient, ContentSettings
5
- import boto3 # type: ignore
6
12
 
7
13
  if TYPE_CHECKING:
8
- from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential
14
+ from azure.core.credentials import (
15
+ AzureNamedKeyCredential,
16
+ AzureSasCredential,
17
+ TokenCredential,
18
+ )
19
+
9
20
 
10
21
  class AzureStorageClient(BaseStorageClient):
11
22
  """
@@ -16,30 +27,65 @@ class AzureStorageClient(BaseStorageClient):
16
27
  credential: Access credential (AzureKeyCredential)
17
28
  sas_token: Optionally include SAS token to append to urls
18
29
  """
19
- def __init__(self, account_url: str, container: str, credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]], sas_token: Optional[str] = None):
30
+
31
+ def __init__(
32
+ self,
33
+ account_url: str,
34
+ container: str,
35
+ credential: Optional[
36
+ Union[
37
+ str,
38
+ Dict[str, str],
39
+ "AzureNamedKeyCredential",
40
+ "AzureSasCredential",
41
+ "TokenCredential",
42
+ ]
43
+ ],
44
+ sas_token: Optional[str] = None,
45
+ ):
20
46
  try:
21
- self.data_lake_client = DataLakeServiceClient(account_url=account_url, credential=credential)
22
- self.container_client: FileSystemClient = self.data_lake_client.get_file_system_client(file_system=container)
47
+ self.data_lake_client = DataLakeServiceClient(
48
+ account_url=account_url, credential=credential
49
+ )
50
+ self.container_client: FileSystemClient = (
51
+ self.data_lake_client.get_file_system_client(file_system=container)
52
+ )
23
53
  self.sas_token = sas_token
24
54
  logger.info("AzureStorageClient initialized")
25
55
  except Exception as e:
26
56
  logger.warn(f"AzureStorageClient initialization error: {e}")
27
-
28
- async def upload_file(self, object_key: str, data: Union[bytes, str], mime: str = 'application/octet-stream', overwrite: bool = True) -> Dict[str, Any]:
57
+
58
+ async def upload_file(
59
+ self,
60
+ object_key: str,
61
+ data: Union[bytes, str],
62
+ mime: str = "application/octet-stream",
63
+ overwrite: bool = True,
64
+ ) -> Dict[str, Any]:
29
65
  try:
30
- file_client: DataLakeFileClient = self.container_client.get_file_client(object_key)
66
+ file_client: DataLakeFileClient = self.container_client.get_file_client(
67
+ object_key
68
+ )
31
69
  content_settings = ContentSettings(content_type=mime)
32
- file_client.upload_data(data, overwrite=overwrite, content_settings=content_settings)
33
- url = f"{file_client.url}{self.sas_token}" if self.sas_token else file_client.url
70
+ file_client.upload_data(
71
+ data, overwrite=overwrite, content_settings=content_settings
72
+ )
73
+ url = (
74
+ f"{file_client.url}{self.sas_token}"
75
+ if self.sas_token
76
+ else file_client.url
77
+ )
34
78
  return {"object_key": object_key, "url": url}
35
79
  except Exception as e:
36
80
  logger.warn(f"AzureStorageClient, upload_file error: {e}")
37
81
  return {}
38
82
 
83
+
39
84
  class S3StorageClient(BaseStorageClient):
40
85
  """
41
86
  Class to enable Amazon S3 storage provider
42
87
  """
88
+
43
89
  def __init__(self, bucket: str):
44
90
  try:
45
91
  self.bucket = bucket
@@ -48,9 +94,17 @@ class S3StorageClient(BaseStorageClient):
48
94
  except Exception as e:
49
95
  logger.warn(f"S3StorageClient initialization error: {e}")
50
96
 
51
- async def upload_file(self, object_key: str, data: Union[bytes, str], mime: str = 'application/octet-stream', overwrite: bool = True) -> Dict[str, Any]:
97
+ async def upload_file(
98
+ self,
99
+ object_key: str,
100
+ data: Union[bytes, str],
101
+ mime: str = "application/octet-stream",
102
+ overwrite: bool = True,
103
+ ) -> Dict[str, Any]:
52
104
  try:
53
- self.client.put_object(Bucket=self.bucket, Key=object_key, Body=data, ContentType=mime)
105
+ self.client.put_object(
106
+ Bucket=self.bucket, Key=object_key, Body=data, ContentType=mime
107
+ )
54
108
  url = f"https://{self.bucket}.s3.amazonaws.com/{object_key}"
55
109
  return {"object_key": object_key, "url": url}
56
110
  except Exception as e:
chainlit/data/utils.py ADDED
@@ -0,0 +1,29 @@
1
+ import functools
2
+ from collections import deque
3
+
4
+ from chainlit.context import context
5
+ from chainlit.session import WebsocketSession
6
+
7
+
8
+ def queue_until_user_message():
9
+ def decorator(method):
10
+ @functools.wraps(method)
11
+ async def wrapper(self, *args, **kwargs):
12
+ if (
13
+ isinstance(context.session, WebsocketSession)
14
+ and not context.session.has_first_interaction
15
+ ):
16
+ # Queue the method invocation waiting for the first user message
17
+ queues = context.session.thread_queues
18
+ method_name = method.__name__
19
+ if method_name not in queues:
20
+ queues[method_name] = deque()
21
+ queues[method_name].append((method, self, args, kwargs))
22
+
23
+ else:
24
+ # Otherwise, Execute the method immediately
25
+ return await method(self, *args, **kwargs)
26
+
27
+ return wrapper
28
+
29
+ return decorator
@@ -1 +1 @@
1
- import{g as P,r as v,u as D,a as O}from"./index-30df9b2b.js";function b(t,e){for(var r=0;r<e.length;r++){const o=e[r];if(typeof o!="string"&&!Array.isArray(o)){for(const a in o)if(a!=="default"&&!(a in t)){const i=Object.getOwnPropertyDescriptor(o,a);i&&Object.defineProperty(t,a,i.get?i:{enumerable:!0,get:()=>o[a]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var M=Object.create,s=Object.defineProperty,w=Object.getOwnPropertyDescriptor,S=Object.getOwnPropertyNames,j=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty,E=(t,e,r)=>e in t?s(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,A=(t,e)=>{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},h=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of S(e))!T.call(t,a)&&a!==r&&s(t,a,{get:()=>e[a],enumerable:!(o=w(e,a))||o.enumerable});return t},L=(t,e,r)=>(r=t!=null?M(j(t)):{},h(e||!t||!t.__esModule?s(r,"default",{value:t,enumerable:!0}):r,t)),C=t=>h(s({},"__esModule",{value:!0}),t),n=(t,e,r)=>(E(t,typeof e!="symbol"?e+"":e,r),r),d={};A(d,{default:()=>p});var _=C(d),c=L(v),l=D,f=O;const x="https://api.dmcdn.net/all.js",N="DM",K="dmAsyncInit";class p extends c.Component{constructor(){super(...arguments),n(this,"callPlayer",l.callPlayer),n(this,"onDurationChange",()=>{const e=this.getDuration();this.props.onDuration(e)}),n(this,"mute",()=>{this.callPlayer("setMuted",!0)}),n(this,"unmute",()=>{this.callPlayer("setMuted",!1)}),n(this,"ref",e=>{this.container=e})}componentDidMount(){this.props.onMount&&this.props.onMount(this)}load(e){const{controls:r,config:o,onError:a,playing:i}=this.props,[,y]=e.match(f.MATCH_URL_DAILYMOTION);if(this.player){this.player.load(y,{start:(0,l.parseStartTime)(e),autoplay:i});return}(0,l.getSDK)(x,N,K,u=>u.player).then(u=>{if(!this.container)return;const g=u.player;this.player=new g(this.container,{width:"100%",height:"100%",video:y,params:{controls:r,autoplay:this.props.playing,mute:this.props.muted,start:(0,l.parseStartTime)(e),origin:window.location.origin,...o.params},events:{apiready:this.props.onReady,seeked:()=>this.props.onSeek(this.player.currentTime),video_end:this.props.onEnded,durationchange:this.onDurationChange,pause:this.props.onPause,playing:this.props.onPlay,waiting:this.props.onBuffer,error:m=>a(m)}})},a)}play(){this.callPlayer("play")}pause(){this.callPlayer("pause")}stop(){}seekTo(e,r=!0){this.callPlayer("seek",e),r||this.pause()}setVolume(e){this.callPlayer("setVolume",e)}getDuration(){return this.player.duration||null}getCurrentTime(){return this.player.currentTime}getSecondsLoaded(){return this.player.bufferedTime}render(){const{display:e}=this.props,r={width:"100%",height:"100%",display:e};return c.default.createElement("div",{style:r},c.default.createElement("div",{ref:this.ref}))}}n(p,"displayName","DailyMotion");n(p,"canPlay",f.canPlay.dailymotion);n(p,"loopOnEnded",!0);const R=P(_),I=b({__proto__:null,default:R},[_]);export{I as D};
1
+ import{g as P,r as v,u as D,a as O}from"./index-cf48bedd.js";function b(t,e){for(var r=0;r<e.length;r++){const o=e[r];if(typeof o!="string"&&!Array.isArray(o)){for(const a in o)if(a!=="default"&&!(a in t)){const i=Object.getOwnPropertyDescriptor(o,a);i&&Object.defineProperty(t,a,i.get?i:{enumerable:!0,get:()=>o[a]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var M=Object.create,s=Object.defineProperty,w=Object.getOwnPropertyDescriptor,S=Object.getOwnPropertyNames,j=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty,E=(t,e,r)=>e in t?s(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,A=(t,e)=>{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},h=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of S(e))!T.call(t,a)&&a!==r&&s(t,a,{get:()=>e[a],enumerable:!(o=w(e,a))||o.enumerable});return t},L=(t,e,r)=>(r=t!=null?M(j(t)):{},h(e||!t||!t.__esModule?s(r,"default",{value:t,enumerable:!0}):r,t)),C=t=>h(s({},"__esModule",{value:!0}),t),n=(t,e,r)=>(E(t,typeof e!="symbol"?e+"":e,r),r),d={};A(d,{default:()=>p});var _=C(d),c=L(v),l=D,f=O;const x="https://api.dmcdn.net/all.js",N="DM",K="dmAsyncInit";class p extends c.Component{constructor(){super(...arguments),n(this,"callPlayer",l.callPlayer),n(this,"onDurationChange",()=>{const e=this.getDuration();this.props.onDuration(e)}),n(this,"mute",()=>{this.callPlayer("setMuted",!0)}),n(this,"unmute",()=>{this.callPlayer("setMuted",!1)}),n(this,"ref",e=>{this.container=e})}componentDidMount(){this.props.onMount&&this.props.onMount(this)}load(e){const{controls:r,config:o,onError:a,playing:i}=this.props,[,y]=e.match(f.MATCH_URL_DAILYMOTION);if(this.player){this.player.load(y,{start:(0,l.parseStartTime)(e),autoplay:i});return}(0,l.getSDK)(x,N,K,u=>u.player).then(u=>{if(!this.container)return;const g=u.player;this.player=new g(this.container,{width:"100%",height:"100%",video:y,params:{controls:r,autoplay:this.props.playing,mute:this.props.muted,start:(0,l.parseStartTime)(e),origin:window.location.origin,...o.params},events:{apiready:this.props.onReady,seeked:()=>this.props.onSeek(this.player.currentTime),video_end:this.props.onEnded,durationchange:this.onDurationChange,pause:this.props.onPause,playing:this.props.onPlay,waiting:this.props.onBuffer,error:m=>a(m)}})},a)}play(){this.callPlayer("play")}pause(){this.callPlayer("pause")}stop(){}seekTo(e,r=!0){this.callPlayer("seek",e),r||this.pause()}setVolume(e){this.callPlayer("setVolume",e)}getDuration(){return this.player.duration||null}getCurrentTime(){return this.player.currentTime}getSecondsLoaded(){return this.player.bufferedTime}render(){const{display:e}=this.props,r={width:"100%",height:"100%",display:e};return c.default.createElement("div",{style:r},c.default.createElement("div",{ref:this.ref}))}}n(p,"displayName","DailyMotion");n(p,"canPlay",f.canPlay.dailymotion);n(p,"loopOnEnded",!0);const R=P(_),I=b({__proto__:null,default:R},[_]);export{I as D};
@@ -1 +1 @@
1
- import{g as _,r as g,u as P,a as m}from"./index-30df9b2b.js";function v(t,e){for(var r=0;r<e.length;r++){const a=e[r];if(typeof a!="string"&&!Array.isArray(a)){for(const s in a)if(s!=="default"&&!(s in t)){const p=Object.getOwnPropertyDescriptor(a,s);p&&Object.defineProperty(t,s,p.get?p:{enumerable:!0,get:()=>a[s]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var O=Object.create,i=Object.defineProperty,D=Object.getOwnPropertyDescriptor,E=Object.getOwnPropertyNames,S=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty,I=(t,e,r)=>e in t?i(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,k=(t,e)=>{for(var r in e)i(t,r,{get:e[r],enumerable:!0})},h=(t,e,r,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of E(e))!j.call(t,s)&&s!==r&&i(t,s,{get:()=>e[s],enumerable:!(a=D(e,s))||a.enumerable});return t},w=(t,e,r)=>(r=t!=null?O(S(t)):{},h(e||!t||!t.__esModule?i(r,"default",{value:t,enumerable:!0}):r,t)),F=t=>h(i({},"__esModule",{value:!0}),t),o=(t,e,r)=>(I(t,typeof e!="symbol"?e+"":e,r),r),b={};k(b,{default:()=>l});var d=F(b),u=w(g),n=P,x=m;const c="https://connect.facebook.net/en_US/sdk.js",y="FB",f="fbAsyncInit",L="facebook-player-";class l extends u.Component{constructor(){super(...arguments),o(this,"callPlayer",n.callPlayer),o(this,"playerID",this.props.config.playerId||`${L}${(0,n.randomString)()}`),o(this,"mute",()=>{this.callPlayer("mute")}),o(this,"unmute",()=>{this.callPlayer("unmute")})}componentDidMount(){this.props.onMount&&this.props.onMount(this)}load(e,r){if(r){(0,n.getSDK)(c,y,f).then(a=>a.XFBML.parse());return}(0,n.getSDK)(c,y,f).then(a=>{a.init({appId:this.props.config.appId,xfbml:!0,version:this.props.config.version}),a.Event.subscribe("xfbml.render",s=>{this.props.onLoaded()}),a.Event.subscribe("xfbml.ready",s=>{s.type==="video"&&s.id===this.playerID&&(this.player=s.instance,this.player.subscribe("startedPlaying",this.props.onPlay),this.player.subscribe("paused",this.props.onPause),this.player.subscribe("finishedPlaying",this.props.onEnded),this.player.subscribe("startedBuffering",this.props.onBuffer),this.player.subscribe("finishedBuffering",this.props.onBufferEnd),this.player.subscribe("error",this.props.onError),this.props.muted?this.callPlayer("mute"):this.callPlayer("unmute"),this.props.onReady(),document.getElementById(this.playerID).querySelector("iframe").style.visibility="visible")})})}play(){this.callPlayer("play")}pause(){this.callPlayer("pause")}stop(){}seekTo(e,r=!0){this.callPlayer("seek",e),r||this.pause()}setVolume(e){this.callPlayer("setVolume",e)}getDuration(){return this.callPlayer("getDuration")}getCurrentTime(){return this.callPlayer("getCurrentPosition")}getSecondsLoaded(){return null}render(){const{attributes:e}=this.props.config,r={width:"100%",height:"100%"};return u.default.createElement("div",{style:r,id:this.playerID,className:"fb-video","data-href":this.props.url,"data-autoplay":this.props.playing?"true":"false","data-allowfullscreen":"true","data-controls":this.props.controls?"true":"false",...e})}}o(l,"displayName","Facebook");o(l,"canPlay",x.canPlay.facebook);o(l,"loopOnEnded",!0);const M=_(d),B=v({__proto__:null,default:M},[d]);export{B as F};
1
+ import{g as _,r as g,u as P,a as m}from"./index-cf48bedd.js";function v(t,e){for(var r=0;r<e.length;r++){const a=e[r];if(typeof a!="string"&&!Array.isArray(a)){for(const s in a)if(s!=="default"&&!(s in t)){const p=Object.getOwnPropertyDescriptor(a,s);p&&Object.defineProperty(t,s,p.get?p:{enumerable:!0,get:()=>a[s]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var O=Object.create,i=Object.defineProperty,D=Object.getOwnPropertyDescriptor,E=Object.getOwnPropertyNames,S=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty,I=(t,e,r)=>e in t?i(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,k=(t,e)=>{for(var r in e)i(t,r,{get:e[r],enumerable:!0})},h=(t,e,r,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of E(e))!j.call(t,s)&&s!==r&&i(t,s,{get:()=>e[s],enumerable:!(a=D(e,s))||a.enumerable});return t},w=(t,e,r)=>(r=t!=null?O(S(t)):{},h(e||!t||!t.__esModule?i(r,"default",{value:t,enumerable:!0}):r,t)),F=t=>h(i({},"__esModule",{value:!0}),t),o=(t,e,r)=>(I(t,typeof e!="symbol"?e+"":e,r),r),b={};k(b,{default:()=>l});var d=F(b),u=w(g),n=P,x=m;const c="https://connect.facebook.net/en_US/sdk.js",y="FB",f="fbAsyncInit",L="facebook-player-";class l extends u.Component{constructor(){super(...arguments),o(this,"callPlayer",n.callPlayer),o(this,"playerID",this.props.config.playerId||`${L}${(0,n.randomString)()}`),o(this,"mute",()=>{this.callPlayer("mute")}),o(this,"unmute",()=>{this.callPlayer("unmute")})}componentDidMount(){this.props.onMount&&this.props.onMount(this)}load(e,r){if(r){(0,n.getSDK)(c,y,f).then(a=>a.XFBML.parse());return}(0,n.getSDK)(c,y,f).then(a=>{a.init({appId:this.props.config.appId,xfbml:!0,version:this.props.config.version}),a.Event.subscribe("xfbml.render",s=>{this.props.onLoaded()}),a.Event.subscribe("xfbml.ready",s=>{s.type==="video"&&s.id===this.playerID&&(this.player=s.instance,this.player.subscribe("startedPlaying",this.props.onPlay),this.player.subscribe("paused",this.props.onPause),this.player.subscribe("finishedPlaying",this.props.onEnded),this.player.subscribe("startedBuffering",this.props.onBuffer),this.player.subscribe("finishedBuffering",this.props.onBufferEnd),this.player.subscribe("error",this.props.onError),this.props.muted?this.callPlayer("mute"):this.callPlayer("unmute"),this.props.onReady(),document.getElementById(this.playerID).querySelector("iframe").style.visibility="visible")})})}play(){this.callPlayer("play")}pause(){this.callPlayer("pause")}stop(){}seekTo(e,r=!0){this.callPlayer("seek",e),r||this.pause()}setVolume(e){this.callPlayer("setVolume",e)}getDuration(){return this.callPlayer("getDuration")}getCurrentTime(){return this.callPlayer("getCurrentPosition")}getSecondsLoaded(){return null}render(){const{attributes:e}=this.props.config,r={width:"100%",height:"100%"};return u.default.createElement("div",{style:r,id:this.playerID,className:"fb-video","data-href":this.props.url,"data-autoplay":this.props.playing?"true":"false","data-allowfullscreen":"true","data-controls":this.props.controls?"true":"false",...e})}}o(l,"displayName","Facebook");o(l,"canPlay",x.canPlay.facebook);o(l,"loopOnEnded",!0);const M=_(d),B=v({__proto__:null,default:M},[d]);export{B as F};