chainlit 1.1.0__py3-none-any.whl → 1.1.0rc0__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/config.py +2 -4
- chainlit/context.py +7 -19
- chainlit/copilot/dist/index.js +521 -639
- chainlit/data/acl.py +1 -4
- chainlit/data/sql_alchemy.py +21 -22
- chainlit/element.py +2 -5
- chainlit/emitter.py +2 -11
- chainlit/frontend/dist/assets/{index-0a52365d.js → index-032fca02.js} +120 -120
- chainlit/frontend/dist/assets/react-plotly-8c993614.js +3484 -0
- chainlit/frontend/dist/index.html +1 -1
- chainlit/server.py +4 -27
- chainlit/session.py +61 -72
- chainlit/socket.py +15 -21
- chainlit/step.py +1 -25
- chainlit/types.py +1 -2
- chainlit/user_session.py +2 -5
- {chainlit-1.1.0.dist-info → chainlit-1.1.0rc0.dist-info}/METADATA +3 -4
- {chainlit-1.1.0.dist-info → chainlit-1.1.0rc0.dist-info}/RECORD +20 -24
- chainlit/discord/__init__.py +0 -6
- chainlit/discord/app.py +0 -304
- chainlit/frontend/dist/assets/react-plotly-509d26a7.js +0 -3602
- chainlit/slack/__init__.py +0 -6
- chainlit/slack/app.py +0 -368
- {chainlit-1.1.0.dist-info → chainlit-1.1.0rc0.dist-info}/WHEEL +0 -0
- {chainlit-1.1.0.dist-info → chainlit-1.1.0rc0.dist-info}/entry_points.txt +0 -0
chainlit/data/acl.py
CHANGED
|
@@ -5,12 +5,9 @@ from fastapi import HTTPException
|
|
|
5
5
|
async def is_thread_author(username: str, thread_id: str):
|
|
6
6
|
data_layer = get_data_layer()
|
|
7
7
|
if not data_layer:
|
|
8
|
-
raise HTTPException(status_code=
|
|
8
|
+
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
9
9
|
|
|
10
10
|
thread_author = await data_layer.get_thread_author(thread_id)
|
|
11
|
-
|
|
12
|
-
if not thread_author:
|
|
13
|
-
raise HTTPException(status_code=404, detail="Thread not found")
|
|
14
11
|
|
|
15
12
|
if thread_author != username:
|
|
16
13
|
raise HTTPException(status_code=401, detail="Unauthorized")
|
chainlit/data/sql_alchemy.py
CHANGED
|
@@ -39,11 +39,9 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
39
39
|
ssl_require: bool = False,
|
|
40
40
|
storage_provider: Optional[BaseStorageClient] = None,
|
|
41
41
|
user_thread_limit: Optional[int] = 1000,
|
|
42
|
-
show_logger: Optional[bool] = False,
|
|
43
42
|
):
|
|
44
43
|
self._conninfo = conninfo
|
|
45
44
|
self.user_thread_limit = user_thread_limit
|
|
46
|
-
self.show_logger = show_logger
|
|
47
45
|
ssl_args = {}
|
|
48
46
|
if ssl_require:
|
|
49
47
|
# Create an SSL context to require an SSL connection
|
|
@@ -57,7 +55,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
57
55
|
self.async_session = sessionmaker(bind=self.engine, expire_on_commit=False, class_=AsyncSession) # type: ignore
|
|
58
56
|
if storage_provider:
|
|
59
57
|
self.storage_provider: Optional[BaseStorageClient] = storage_provider
|
|
60
|
-
|
|
58
|
+
logger.info("SQLAlchemyDataLayer storage client initialized")
|
|
61
59
|
else:
|
|
62
60
|
self.storage_provider = None
|
|
63
61
|
logger.warn(
|
|
@@ -104,7 +102,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
104
102
|
|
|
105
103
|
###### User ######
|
|
106
104
|
async def get_user(self, identifier: str) -> Optional[PersistedUser]:
|
|
107
|
-
|
|
105
|
+
logger.info(f"SQLAlchemy: get_user, identifier={identifier}")
|
|
108
106
|
query = "SELECT * FROM users WHERE identifier = :identifier"
|
|
109
107
|
parameters = {"identifier": identifier}
|
|
110
108
|
result = await self.execute_sql(query=query, parameters=parameters)
|
|
@@ -114,20 +112,20 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
114
112
|
return None
|
|
115
113
|
|
|
116
114
|
async def create_user(self, user: User) -> Optional[PersistedUser]:
|
|
117
|
-
|
|
115
|
+
logger.info(f"SQLAlchemy: create_user, user_identifier={user.identifier}")
|
|
118
116
|
existing_user: Optional["PersistedUser"] = await self.get_user(user.identifier)
|
|
119
117
|
user_dict: Dict[str, Any] = {
|
|
120
118
|
"identifier": str(user.identifier),
|
|
121
119
|
"metadata": json.dumps(user.metadata) or {},
|
|
122
120
|
}
|
|
123
121
|
if not existing_user: # create the user
|
|
124
|
-
|
|
122
|
+
logger.info("SQLAlchemy: create_user, creating the user")
|
|
125
123
|
user_dict["id"] = str(uuid.uuid4())
|
|
126
124
|
user_dict["createdAt"] = await self.get_current_timestamp()
|
|
127
125
|
query = """INSERT INTO users ("id", "identifier", "createdAt", "metadata") VALUES (:id, :identifier, :createdAt, :metadata)"""
|
|
128
126
|
await self.execute_sql(query=query, parameters=user_dict)
|
|
129
127
|
else: # update the user
|
|
130
|
-
|
|
128
|
+
logger.info("SQLAlchemy: update user metadata")
|
|
131
129
|
query = """UPDATE users SET "metadata" = :metadata WHERE "identifier" = :identifier"""
|
|
132
130
|
await self.execute_sql(
|
|
133
131
|
query=query, parameters=user_dict
|
|
@@ -136,18 +134,19 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
136
134
|
|
|
137
135
|
###### Threads ######
|
|
138
136
|
async def get_thread_author(self, thread_id: str) -> str:
|
|
139
|
-
|
|
137
|
+
logger.info(f"SQLAlchemy: get_thread_author, thread_id={thread_id}")
|
|
140
138
|
query = """SELECT "userIdentifier" FROM threads WHERE "id" = :id"""
|
|
141
139
|
parameters = {"id": thread_id}
|
|
142
140
|
result = await self.execute_sql(query=query, parameters=parameters)
|
|
143
141
|
if isinstance(result, list) and result[0]:
|
|
144
142
|
author_identifier = result[0].get("userIdentifier")
|
|
145
143
|
if author_identifier is not None:
|
|
144
|
+
print(f"Author found: {author_identifier}")
|
|
146
145
|
return author_identifier
|
|
147
146
|
raise ValueError(f"Author not found for thread_id {thread_id}")
|
|
148
147
|
|
|
149
148
|
async def get_thread(self, thread_id: str) -> Optional[ThreadDict]:
|
|
150
|
-
|
|
149
|
+
logger.info(f"SQLAlchemy: get_thread, thread_id={thread_id}")
|
|
151
150
|
user_threads: Optional[List[ThreadDict]] = await self.get_all_user_threads(
|
|
152
151
|
thread_id=thread_id
|
|
153
152
|
)
|
|
@@ -164,7 +163,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
164
163
|
metadata: Optional[Dict] = None,
|
|
165
164
|
tags: Optional[List[str]] = None,
|
|
166
165
|
):
|
|
167
|
-
|
|
166
|
+
logger.info(f"SQLAlchemy: update_thread, thread_id={thread_id}")
|
|
168
167
|
if context.session.user is not None:
|
|
169
168
|
user_identifier = context.session.user.identifier
|
|
170
169
|
else:
|
|
@@ -201,7 +200,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
201
200
|
await self.execute_sql(query=query, parameters=parameters)
|
|
202
201
|
|
|
203
202
|
async def delete_thread(self, thread_id: str):
|
|
204
|
-
|
|
203
|
+
logger.info(f"SQLAlchemy: delete_thread, thread_id={thread_id}")
|
|
205
204
|
# Delete feedbacks/elements/steps/thread
|
|
206
205
|
feedbacks_query = """DELETE FROM feedbacks WHERE "forId" IN (SELECT "id" FROM steps WHERE "threadId" = :id)"""
|
|
207
206
|
elements_query = """DELETE FROM elements WHERE "threadId" = :id"""
|
|
@@ -216,7 +215,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
216
215
|
async def list_threads(
|
|
217
216
|
self, pagination: Pagination, filters: ThreadFilter
|
|
218
217
|
) -> PaginatedResponse:
|
|
219
|
-
|
|
218
|
+
logger.info(
|
|
220
219
|
f"SQLAlchemy: list_threads, pagination={pagination}, filters={filters}"
|
|
221
220
|
)
|
|
222
221
|
if not filters.userId:
|
|
@@ -276,7 +275,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
276
275
|
###### Steps ######
|
|
277
276
|
@queue_until_user_message()
|
|
278
277
|
async def create_step(self, step_dict: "StepDict"):
|
|
279
|
-
|
|
278
|
+
logger.info(f"SQLAlchemy: create_step, step_id={step_dict.get('id')}")
|
|
280
279
|
if not getattr(context.session.user, "id", None):
|
|
281
280
|
raise ValueError("No authenticated user in context")
|
|
282
281
|
step_dict["showInput"] = (
|
|
@@ -306,12 +305,12 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
306
305
|
|
|
307
306
|
@queue_until_user_message()
|
|
308
307
|
async def update_step(self, step_dict: "StepDict"):
|
|
309
|
-
|
|
308
|
+
logger.info(f"SQLAlchemy: update_step, step_id={step_dict.get('id')}")
|
|
310
309
|
await self.create_step(step_dict)
|
|
311
310
|
|
|
312
311
|
@queue_until_user_message()
|
|
313
312
|
async def delete_step(self, step_id: str):
|
|
314
|
-
|
|
313
|
+
logger.info(f"SQLAlchemy: delete_step, step_id={step_id}")
|
|
315
314
|
# Delete feedbacks/elements/steps
|
|
316
315
|
feedbacks_query = """DELETE FROM feedbacks WHERE "forId" = :id"""
|
|
317
316
|
elements_query = """DELETE FROM elements WHERE "forId" = :id"""
|
|
@@ -323,7 +322,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
323
322
|
|
|
324
323
|
###### Feedback ######
|
|
325
324
|
async def upsert_feedback(self, feedback: Feedback) -> str:
|
|
326
|
-
|
|
325
|
+
logger.info(f"SQLAlchemy: upsert_feedback, feedback_id={feedback.id}")
|
|
327
326
|
feedback.id = feedback.id or str(uuid.uuid4())
|
|
328
327
|
feedback_dict = asdict(feedback)
|
|
329
328
|
parameters = {
|
|
@@ -345,7 +344,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
345
344
|
return feedback.id
|
|
346
345
|
|
|
347
346
|
async def delete_feedback(self, feedback_id: str) -> bool:
|
|
348
|
-
|
|
347
|
+
logger.info(f"SQLAlchemy: delete_feedback, feedback_id={feedback_id}")
|
|
349
348
|
query = """DELETE FROM feedbacks WHERE "id" = :feedback_id"""
|
|
350
349
|
parameters = {"feedback_id": feedback_id}
|
|
351
350
|
await self.execute_sql(query=query, parameters=parameters)
|
|
@@ -354,7 +353,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
354
353
|
###### Elements ######
|
|
355
354
|
@queue_until_user_message()
|
|
356
355
|
async def create_element(self, element: "Element"):
|
|
357
|
-
|
|
356
|
+
logger.info(f"SQLAlchemy: create_element, element_id = {element.id}")
|
|
358
357
|
if not getattr(context.session.user, "id", None):
|
|
359
358
|
raise ValueError("No authenticated user in context")
|
|
360
359
|
if isinstance(element, Avatar): # Skip creating elements of type avatar
|
|
@@ -417,7 +416,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
417
416
|
|
|
418
417
|
@queue_until_user_message()
|
|
419
418
|
async def delete_element(self, element_id: str):
|
|
420
|
-
|
|
419
|
+
logger.info(f"SQLAlchemy: delete_element, element_id={element_id}")
|
|
421
420
|
query = """DELETE FROM elements WHERE "id" = :id"""
|
|
422
421
|
parameters = {"id": element_id}
|
|
423
422
|
await self.execute_sql(query=query, parameters=parameters)
|
|
@@ -429,7 +428,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
429
428
|
self, user_id: Optional[str] = None, thread_id: Optional[str] = None
|
|
430
429
|
) -> Optional[List[ThreadDict]]:
|
|
431
430
|
"""Fetch all user threads up to self.user_thread_limit, or one thread by id if thread_id is provided."""
|
|
432
|
-
|
|
431
|
+
logger.info(f"SQLAlchemy: get_all_user_threads")
|
|
433
432
|
user_threads_query = """
|
|
434
433
|
SELECT
|
|
435
434
|
"id" AS thread_id,
|
|
@@ -563,8 +562,8 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
563
562
|
tags=step_feedback.get("step_tags"),
|
|
564
563
|
input=(
|
|
565
564
|
step_feedback.get("step_input", "")
|
|
566
|
-
if step_feedback["step_showinput"]
|
|
567
|
-
else
|
|
565
|
+
if step_feedback["step_showinput"]
|
|
566
|
+
else ""
|
|
568
567
|
),
|
|
569
568
|
output=step_feedback.get("step_output", ""),
|
|
570
569
|
createdAt=step_feedback.get("step_createdat"),
|
chainlit/element.py
CHANGED
|
@@ -5,7 +5,6 @@ from io import BytesIO
|
|
|
5
5
|
from typing import Any, ClassVar, List, Literal, Optional, TypedDict, TypeVar, Union
|
|
6
6
|
|
|
7
7
|
import filetype
|
|
8
|
-
import mimetypes
|
|
9
8
|
from chainlit.context import context
|
|
10
9
|
from chainlit.data import get_data_layer
|
|
11
10
|
from chainlit.logger import logger
|
|
@@ -166,16 +165,14 @@ class Element:
|
|
|
166
165
|
if self.type in mime_types
|
|
167
166
|
else filetype.guess_mime(self.path or self.content)
|
|
168
167
|
)
|
|
169
|
-
|
|
170
|
-
self.mime = mimetypes.guess_type(self.url)[0]
|
|
171
|
-
|
|
168
|
+
|
|
172
169
|
await self._create()
|
|
173
170
|
|
|
174
171
|
if not self.url and not self.chainlit_key:
|
|
175
172
|
raise ValueError("Must provide url or chainlit key to send element")
|
|
176
173
|
|
|
177
174
|
trace_event(f"send {self.__class__.__name__}")
|
|
178
|
-
await context.emitter.
|
|
175
|
+
await context.emitter.emit("element", self.to_dict())
|
|
179
176
|
|
|
180
177
|
|
|
181
178
|
ElementBased = TypeVar("ElementBased", bound=Element)
|
chainlit/emitter.py
CHANGED
|
@@ -4,10 +4,10 @@ from typing import Any, Dict, List, Literal, Optional, Union, cast
|
|
|
4
4
|
|
|
5
5
|
from chainlit.config import config
|
|
6
6
|
from chainlit.data import get_data_layer
|
|
7
|
-
from chainlit.element import Element,
|
|
7
|
+
from chainlit.element import Element, File
|
|
8
8
|
from chainlit.logger import logger
|
|
9
9
|
from chainlit.message import Message
|
|
10
|
-
from chainlit.session import BaseSession,
|
|
10
|
+
from chainlit.session import BaseSession, WebsocketSession
|
|
11
11
|
from chainlit.step import StepDict
|
|
12
12
|
from chainlit.types import (
|
|
13
13
|
AskActionResponse,
|
|
@@ -29,7 +29,6 @@ class BaseChainlitEmitter:
|
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
session: BaseSession
|
|
32
|
-
enabled: bool = True
|
|
33
32
|
|
|
34
33
|
def __init__(self, session: BaseSession) -> None:
|
|
35
34
|
"""Initialize with the user session."""
|
|
@@ -47,10 +46,6 @@ class BaseChainlitEmitter:
|
|
|
47
46
|
"""Stub method to resume a thread."""
|
|
48
47
|
pass
|
|
49
48
|
|
|
50
|
-
async def send_element(self, element_dict: ElementDict):
|
|
51
|
-
"""Stub method to send an element to the UI."""
|
|
52
|
-
pass
|
|
53
|
-
|
|
54
49
|
async def send_step(self, step_dict: StepDict):
|
|
55
50
|
"""Stub method to send a message to the UI."""
|
|
56
51
|
pass
|
|
@@ -156,10 +151,6 @@ class ChainlitEmitter(BaseChainlitEmitter):
|
|
|
156
151
|
"""Send a thread to the UI to resume it"""
|
|
157
152
|
return self.emit("resume_thread", thread_dict)
|
|
158
153
|
|
|
159
|
-
async def send_element(self, element_dict: ElementDict):
|
|
160
|
-
"""Stub method to send an element to the UI."""
|
|
161
|
-
await self.emit("element", element_dict)
|
|
162
|
-
|
|
163
154
|
def send_step(self, step_dict: StepDict):
|
|
164
155
|
"""Send a message to the UI."""
|
|
165
156
|
return self.emit("new_message", step_dict)
|