chainlit 2.7.0__py3-none-any.whl → 2.7.1__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 (85) hide show
  1. {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/METADATA +1 -1
  2. chainlit-2.7.1.dist-info/RECORD +4 -0
  3. chainlit/__init__.py +0 -207
  4. chainlit/__main__.py +0 -4
  5. chainlit/_utils.py +0 -8
  6. chainlit/action.py +0 -33
  7. chainlit/auth/__init__.py +0 -95
  8. chainlit/auth/cookie.py +0 -197
  9. chainlit/auth/jwt.py +0 -42
  10. chainlit/cache.py +0 -45
  11. chainlit/callbacks.py +0 -433
  12. chainlit/chat_context.py +0 -64
  13. chainlit/chat_settings.py +0 -34
  14. chainlit/cli/__init__.py +0 -235
  15. chainlit/config.py +0 -621
  16. chainlit/context.py +0 -112
  17. chainlit/data/__init__.py +0 -111
  18. chainlit/data/acl.py +0 -19
  19. chainlit/data/base.py +0 -107
  20. chainlit/data/chainlit_data_layer.py +0 -687
  21. chainlit/data/dynamodb.py +0 -616
  22. chainlit/data/literalai.py +0 -501
  23. chainlit/data/sql_alchemy.py +0 -741
  24. chainlit/data/storage_clients/__init__.py +0 -0
  25. chainlit/data/storage_clients/azure.py +0 -84
  26. chainlit/data/storage_clients/azure_blob.py +0 -94
  27. chainlit/data/storage_clients/base.py +0 -28
  28. chainlit/data/storage_clients/gcs.py +0 -101
  29. chainlit/data/storage_clients/s3.py +0 -88
  30. chainlit/data/utils.py +0 -29
  31. chainlit/discord/__init__.py +0 -6
  32. chainlit/discord/app.py +0 -364
  33. chainlit/element.py +0 -454
  34. chainlit/emitter.py +0 -450
  35. chainlit/hello.py +0 -12
  36. chainlit/input_widget.py +0 -182
  37. chainlit/langchain/__init__.py +0 -6
  38. chainlit/langchain/callbacks.py +0 -682
  39. chainlit/langflow/__init__.py +0 -25
  40. chainlit/llama_index/__init__.py +0 -6
  41. chainlit/llama_index/callbacks.py +0 -206
  42. chainlit/logger.py +0 -16
  43. chainlit/markdown.py +0 -57
  44. chainlit/mcp.py +0 -99
  45. chainlit/message.py +0 -619
  46. chainlit/mistralai/__init__.py +0 -50
  47. chainlit/oauth_providers.py +0 -835
  48. chainlit/openai/__init__.py +0 -53
  49. chainlit/py.typed +0 -0
  50. chainlit/secret.py +0 -9
  51. chainlit/semantic_kernel/__init__.py +0 -111
  52. chainlit/server.py +0 -1616
  53. chainlit/session.py +0 -304
  54. chainlit/sidebar.py +0 -55
  55. chainlit/slack/__init__.py +0 -6
  56. chainlit/slack/app.py +0 -427
  57. chainlit/socket.py +0 -381
  58. chainlit/step.py +0 -490
  59. chainlit/sync.py +0 -43
  60. chainlit/teams/__init__.py +0 -6
  61. chainlit/teams/app.py +0 -348
  62. chainlit/translations/bn.json +0 -214
  63. chainlit/translations/el-GR.json +0 -214
  64. chainlit/translations/en-US.json +0 -214
  65. chainlit/translations/fr-FR.json +0 -214
  66. chainlit/translations/gu.json +0 -214
  67. chainlit/translations/he-IL.json +0 -214
  68. chainlit/translations/hi.json +0 -214
  69. chainlit/translations/ja.json +0 -214
  70. chainlit/translations/kn.json +0 -214
  71. chainlit/translations/ml.json +0 -214
  72. chainlit/translations/mr.json +0 -214
  73. chainlit/translations/nl.json +0 -214
  74. chainlit/translations/ta.json +0 -214
  75. chainlit/translations/te.json +0 -214
  76. chainlit/translations/zh-CN.json +0 -214
  77. chainlit/translations.py +0 -60
  78. chainlit/types.py +0 -334
  79. chainlit/user.py +0 -43
  80. chainlit/user_session.py +0 -153
  81. chainlit/utils.py +0 -173
  82. chainlit/version.py +0 -8
  83. chainlit-2.7.0.dist-info/RECORD +0 -84
  84. {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/WHEEL +0 -0
  85. {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/entry_points.txt +0 -0
@@ -1,501 +0,0 @@
1
- import json
2
- from typing import Dict, List, Literal, Optional, Union, cast
3
-
4
- import aiofiles
5
- from httpx import HTTPStatusError, RequestError
6
- from literalai import (
7
- Attachment as LiteralAttachment,
8
- Score as LiteralScore,
9
- Step as LiteralStep,
10
- Thread as LiteralThread,
11
- )
12
- from literalai.observability.filter import threads_filters as LiteralThreadsFilters
13
- from literalai.observability.step import StepDict as LiteralStepDict
14
-
15
- from chainlit.data.base import BaseDataLayer
16
- from chainlit.data.utils import queue_until_user_message
17
- from chainlit.element import Audio, Element, ElementDict, File, Image, Pdf, Text, Video
18
- from chainlit.logger import logger
19
- from chainlit.step import (
20
- FeedbackDict,
21
- Step,
22
- StepDict,
23
- StepType,
24
- TrueStepType,
25
- check_add_step_in_cot,
26
- stub_step,
27
- )
28
- from chainlit.types import (
29
- Feedback,
30
- PageInfo,
31
- PaginatedResponse,
32
- Pagination,
33
- ThreadDict,
34
- ThreadFilter,
35
- )
36
- from chainlit.user import PersistedUser, User
37
-
38
-
39
- class LiteralToChainlitConverter:
40
- @classmethod
41
- def steptype_to_steptype(cls, step_type: Optional[StepType]) -> TrueStepType:
42
- return cast(TrueStepType, step_type or "undefined")
43
-
44
- @classmethod
45
- def score_to_feedbackdict(
46
- cls,
47
- score: Optional[LiteralScore],
48
- ) -> "Optional[FeedbackDict]":
49
- if not score:
50
- return None
51
- return {
52
- "id": score.id or "",
53
- "forId": score.step_id or "",
54
- "value": cast(Literal[0, 1], score.value),
55
- "comment": score.comment,
56
- }
57
-
58
- @classmethod
59
- def step_to_stepdict(cls, step: LiteralStep) -> "StepDict":
60
- metadata = step.metadata or {}
61
- input = (step.input or {}).get("content") or (
62
- json.dumps(step.input) if step.input and step.input != {} else ""
63
- )
64
- output = (step.output or {}).get("content") or (
65
- json.dumps(step.output) if step.output and step.output != {} else ""
66
- )
67
-
68
- user_feedback = (
69
- next(
70
- (
71
- s
72
- for s in step.scores
73
- if s.type == "HUMAN" and s.name == "user-feedback"
74
- ),
75
- None,
76
- )
77
- if step.scores
78
- else None
79
- )
80
-
81
- return {
82
- "createdAt": step.created_at,
83
- "id": step.id or "",
84
- "threadId": step.thread_id or "",
85
- "parentId": step.parent_id,
86
- "feedback": cls.score_to_feedbackdict(user_feedback),
87
- "start": step.start_time,
88
- "end": step.end_time,
89
- "type": step.type or "undefined",
90
- "name": step.name or "",
91
- "generation": step.generation.to_dict() if step.generation else None,
92
- "input": input,
93
- "output": output,
94
- "showInput": metadata.get("showInput", False),
95
- "language": metadata.get("language"),
96
- "isError": bool(step.error),
97
- "waitForAnswer": metadata.get("waitForAnswer", False),
98
- }
99
-
100
- @classmethod
101
- def attachment_to_elementdict(cls, attachment: LiteralAttachment) -> ElementDict:
102
- metadata = attachment.metadata or {}
103
- return {
104
- "chainlitKey": None,
105
- "display": metadata.get("display", "side"),
106
- "language": metadata.get("language"),
107
- "autoPlay": metadata.get("autoPlay", None),
108
- "playerConfig": metadata.get("playerConfig", None),
109
- "page": metadata.get("page"),
110
- "props": metadata.get("props"),
111
- "size": metadata.get("size"),
112
- "type": metadata.get("type", "file"),
113
- "forId": attachment.step_id,
114
- "id": attachment.id or "",
115
- "mime": attachment.mime,
116
- "name": attachment.name or "",
117
- "objectKey": attachment.object_key,
118
- "url": attachment.url,
119
- "threadId": attachment.thread_id,
120
- }
121
-
122
- @classmethod
123
- def attachment_to_element(
124
- cls, attachment: LiteralAttachment, thread_id: Optional[str] = None
125
- ) -> Element:
126
- metadata = attachment.metadata or {}
127
- element_type = metadata.get("type", "file")
128
-
129
- element_class = {
130
- "file": File,
131
- "image": Image,
132
- "audio": Audio,
133
- "video": Video,
134
- "text": Text,
135
- "pdf": Pdf,
136
- }.get(element_type, Element)
137
-
138
- assert thread_id or attachment.thread_id
139
-
140
- element = element_class(
141
- name=attachment.name or "",
142
- display=metadata.get("display", "side"),
143
- language=metadata.get("language"),
144
- size=metadata.get("size"),
145
- url=attachment.url,
146
- mime=attachment.mime,
147
- thread_id=thread_id or attachment.thread_id,
148
- )
149
- element.id = attachment.id or ""
150
- element.for_id = attachment.step_id
151
- element.object_key = attachment.object_key
152
- return element
153
-
154
- @classmethod
155
- def step_to_step(cls, step: LiteralStep) -> Step:
156
- chainlit_step = Step(
157
- name=step.name or "",
158
- type=cls.steptype_to_steptype(step.type),
159
- id=step.id,
160
- parent_id=step.parent_id,
161
- thread_id=step.thread_id or None,
162
- )
163
- chainlit_step.start = step.start_time
164
- chainlit_step.end = step.end_time
165
- chainlit_step.created_at = step.created_at
166
- chainlit_step.input = step.input.get("content", "") if step.input else ""
167
- chainlit_step.output = step.output.get("content", "") if step.output else ""
168
- chainlit_step.is_error = bool(step.error)
169
- chainlit_step.metadata = step.metadata or {}
170
- chainlit_step.tags = step.tags
171
- chainlit_step.generation = step.generation
172
-
173
- if step.attachments:
174
- chainlit_step.elements = [
175
- cls.attachment_to_element(attachment, chainlit_step.thread_id)
176
- for attachment in step.attachments
177
- ]
178
-
179
- return chainlit_step
180
-
181
- @classmethod
182
- def thread_to_threaddict(cls, thread: LiteralThread) -> ThreadDict:
183
- return {
184
- "id": thread.id,
185
- "createdAt": getattr(thread, "created_at", ""),
186
- "name": thread.name,
187
- "userId": thread.participant_id,
188
- "userIdentifier": thread.participant_identifier,
189
- "tags": thread.tags,
190
- "metadata": thread.metadata,
191
- "steps": [cls.step_to_stepdict(step) for step in thread.steps]
192
- if thread.steps
193
- else [],
194
- "elements": [
195
- cls.attachment_to_elementdict(attachment)
196
- for step in thread.steps
197
- for attachment in step.attachments
198
- ]
199
- if thread.steps
200
- else [],
201
- }
202
-
203
-
204
- class LiteralDataLayer(BaseDataLayer):
205
- def __init__(self, api_key: str, server: Optional[str]):
206
- from literalai import AsyncLiteralClient
207
-
208
- self.client = AsyncLiteralClient(api_key=api_key, url=server)
209
- logger.info("Chainlit data layer initialized")
210
-
211
- async def build_debug_url(self) -> str:
212
- try:
213
- project_id = await self.client.api.get_my_project_id()
214
- return f"{self.client.api.url}/projects/{project_id}/logs/threads/[thread_id]?currentStepId=[step_id]"
215
- except Exception as e:
216
- logger.error(f"Error building debug url: {e}")
217
- return ""
218
-
219
- async def get_user(self, identifier: str) -> Optional[PersistedUser]:
220
- user = await self.client.api.get_user(identifier=identifier)
221
- if not user:
222
- return None
223
- return PersistedUser(
224
- id=user.id or "",
225
- identifier=user.identifier or "",
226
- metadata=user.metadata,
227
- createdAt=user.created_at or "",
228
- )
229
-
230
- async def create_user(self, user: User) -> Optional[PersistedUser]:
231
- _user = await self.client.api.get_user(identifier=user.identifier)
232
- if not _user:
233
- _user = await self.client.api.create_user(
234
- identifier=user.identifier, metadata=user.metadata
235
- )
236
- elif _user.id:
237
- await self.client.api.update_user(id=_user.id, metadata=user.metadata)
238
- return PersistedUser(
239
- id=_user.id or "",
240
- identifier=_user.identifier or "",
241
- metadata=user.metadata,
242
- createdAt=_user.created_at or "",
243
- )
244
-
245
- async def delete_feedback(
246
- self,
247
- feedback_id: str,
248
- ):
249
- if feedback_id:
250
- await self.client.api.delete_score(
251
- id=feedback_id,
252
- )
253
- return True
254
- return False
255
-
256
- async def upsert_feedback(
257
- self,
258
- feedback: Feedback,
259
- ):
260
- if feedback.id:
261
- await self.client.api.update_score(
262
- id=feedback.id,
263
- update_params={
264
- "comment": feedback.comment,
265
- "value": feedback.value,
266
- },
267
- )
268
- return feedback.id
269
- else:
270
- created = await self.client.api.create_score(
271
- step_id=feedback.forId,
272
- value=feedback.value,
273
- comment=feedback.comment,
274
- name="user-feedback",
275
- type="HUMAN",
276
- )
277
- return created.id or ""
278
-
279
- async def safely_send_steps(self, steps):
280
- try:
281
- await self.client.api.send_steps(steps)
282
- except HTTPStatusError as e:
283
- logger.error(f"HTTP Request: error sending steps: {e.response.status_code}")
284
- except RequestError as e:
285
- logger.error(f"HTTP Request: error for {e.request.url!r}.")
286
-
287
- @queue_until_user_message()
288
- async def create_element(self, element: "Element"):
289
- metadata = {
290
- "size": element.size,
291
- "language": element.language,
292
- "display": element.display,
293
- "type": element.type,
294
- "page": getattr(element, "page", None),
295
- "props": getattr(element, "props", None),
296
- }
297
-
298
- if not element.for_id:
299
- return
300
-
301
- object_key = None
302
-
303
- if not element.url:
304
- if element.path:
305
- async with aiofiles.open(element.path, "rb") as f:
306
- content: Union[bytes, str] = await f.read()
307
- elif element.content:
308
- content = element.content
309
- else:
310
- raise ValueError("Either path or content must be provided")
311
- uploaded = await self.client.api.upload_file(
312
- content=content, mime=element.mime, thread_id=element.thread_id
313
- )
314
- object_key = uploaded["object_key"]
315
-
316
- await self.safely_send_steps(
317
- [
318
- {
319
- "id": element.for_id,
320
- "threadId": element.thread_id,
321
- "attachments": [
322
- {
323
- "id": element.id,
324
- "name": element.name,
325
- "metadata": metadata,
326
- "mime": element.mime,
327
- "url": element.url,
328
- "objectKey": object_key,
329
- }
330
- ],
331
- }
332
- ]
333
- )
334
-
335
- async def get_element(
336
- self, thread_id: str, element_id: str
337
- ) -> Optional["ElementDict"]:
338
- attachment = await self.client.api.get_attachment(id=element_id)
339
- if not attachment:
340
- return None
341
- return LiteralToChainlitConverter.attachment_to_elementdict(attachment)
342
-
343
- @queue_until_user_message()
344
- async def delete_element(self, element_id: str, thread_id: Optional[str] = None):
345
- await self.client.api.delete_attachment(id=element_id)
346
-
347
- @queue_until_user_message()
348
- async def create_step(self, step_dict: "StepDict"):
349
- metadata = dict(
350
- step_dict.get("metadata", {}),
351
- waitForAnswer=step_dict.get("waitForAnswer"),
352
- language=step_dict.get("language"),
353
- showInput=step_dict.get("showInput"),
354
- )
355
-
356
- step: LiteralStepDict = {
357
- "createdAt": step_dict.get("createdAt"),
358
- "startTime": step_dict.get("start"),
359
- "endTime": step_dict.get("end"),
360
- "generation": step_dict.get("generation"),
361
- "id": step_dict.get("id"),
362
- "parentId": step_dict.get("parentId"),
363
- "name": step_dict.get("name"),
364
- "threadId": step_dict.get("threadId"),
365
- "type": step_dict.get("type"),
366
- "tags": step_dict.get("tags"),
367
- "metadata": metadata,
368
- }
369
- if step_dict.get("input"):
370
- step["input"] = {"content": step_dict.get("input")}
371
- if step_dict.get("output"):
372
- step["output"] = {"content": step_dict.get("output")}
373
- if step_dict.get("isError"):
374
- step["error"] = step_dict.get("output")
375
-
376
- await self.safely_send_steps([step])
377
-
378
- @queue_until_user_message()
379
- async def update_step(self, step_dict: "StepDict"):
380
- await self.create_step(step_dict)
381
-
382
- @queue_until_user_message()
383
- async def delete_step(self, step_id: str):
384
- await self.client.api.delete_step(id=step_id)
385
-
386
- async def get_thread_author(self, thread_id: str) -> str:
387
- thread = await self.get_thread(thread_id)
388
- if not thread:
389
- return ""
390
- user_identifier = thread.get("userIdentifier")
391
- if not user_identifier:
392
- return ""
393
-
394
- return user_identifier
395
-
396
- async def delete_thread(self, thread_id: str):
397
- await self.client.api.delete_thread(id=thread_id)
398
-
399
- async def list_threads(
400
- self, pagination: "Pagination", filters: "ThreadFilter"
401
- ) -> "PaginatedResponse[ThreadDict]":
402
- if not filters.userId:
403
- raise ValueError("userId is required")
404
-
405
- literal_filters: LiteralThreadsFilters = [
406
- {
407
- "field": "participantId",
408
- "operator": "eq",
409
- "value": filters.userId,
410
- }
411
- ]
412
-
413
- if filters.search:
414
- literal_filters.append(
415
- {
416
- "field": "stepOutput",
417
- "operator": "ilike",
418
- "value": filters.search,
419
- "path": "content",
420
- }
421
- )
422
-
423
- if filters.feedback is not None:
424
- literal_filters.append(
425
- {
426
- "field": "scoreValue",
427
- "operator": "eq",
428
- "value": filters.feedback,
429
- "path": "user-feedback",
430
- }
431
- )
432
-
433
- literal_response = await self.client.api.list_threads(
434
- first=pagination.first,
435
- after=pagination.cursor,
436
- filters=literal_filters,
437
- order_by={"column": "createdAt", "direction": "DESC"},
438
- )
439
-
440
- chainlit_threads = [
441
- *map(LiteralToChainlitConverter.thread_to_threaddict, literal_response.data)
442
- ]
443
-
444
- return PaginatedResponse(
445
- pageInfo=PageInfo(
446
- hasNextPage=literal_response.page_info.has_next_page,
447
- startCursor=literal_response.page_info.start_cursor,
448
- endCursor=literal_response.page_info.end_cursor,
449
- ),
450
- data=chainlit_threads,
451
- )
452
-
453
- async def get_thread(self, thread_id: str) -> Optional[ThreadDict]:
454
- thread = await self.client.api.get_thread(id=thread_id)
455
- if not thread:
456
- return None
457
-
458
- elements: List[ElementDict] = []
459
- steps: List[StepDict] = []
460
- if thread.steps:
461
- for step in thread.steps:
462
- for attachment in step.attachments:
463
- elements.append(
464
- LiteralToChainlitConverter.attachment_to_elementdict(attachment)
465
- )
466
-
467
- chainlit_step = LiteralToChainlitConverter.step_to_step(step)
468
- if check_add_step_in_cot(chainlit_step):
469
- steps.append(
470
- LiteralToChainlitConverter.step_to_stepdict(step)
471
- ) # TODO: chainlit_step.to_dict()
472
- else:
473
- steps.append(stub_step(chainlit_step))
474
-
475
- return {
476
- "createdAt": thread.created_at or "",
477
- "id": thread.id,
478
- "name": thread.name or None,
479
- "steps": steps,
480
- "elements": elements,
481
- "metadata": thread.metadata,
482
- "userId": thread.participant_id,
483
- "userIdentifier": thread.participant_identifier,
484
- "tags": thread.tags,
485
- }
486
-
487
- async def update_thread(
488
- self,
489
- thread_id: str,
490
- name: Optional[str] = None,
491
- user_id: Optional[str] = None,
492
- metadata: Optional[Dict] = None,
493
- tags: Optional[List[str]] = None,
494
- ):
495
- await self.client.api.upsert_thread(
496
- id=thread_id,
497
- name=name,
498
- participant_id=user_id,
499
- metadata=metadata,
500
- tags=tags,
501
- )