chainlit 1.1.0__py3-none-any.whl → 1.1.0rc1__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/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=400, detail="Data layer not initialized")
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")
@@ -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
- if self.show_logger: logger.info("SQLAlchemyDataLayer storage client initialized")
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
- if self.show_logger: logger.info(f"SQLAlchemy: get_user, identifier={identifier}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: create_user, user_identifier={user.identifier}")
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
- if self.show_logger: logger.info("SQLAlchemy: create_user, creating the user")
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
- if self.show_logger: logger.info("SQLAlchemy: update user metadata")
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
- if self.show_logger: logger.info(f"SQLAlchemy: get_thread_author, thread_id={thread_id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: get_thread, thread_id={thread_id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: update_thread, thread_id={thread_id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: delete_thread, thread_id={thread_id}")
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
- if self.show_logger: logger.info(
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
- if self.show_logger: logger.info(f"SQLAlchemy: create_step, step_id={step_dict.get('id')}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: update_step, step_id={step_dict.get('id')}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: delete_step, step_id={step_id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: upsert_feedback, feedback_id={feedback.id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: delete_feedback, feedback_id={feedback_id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: create_element, element_id = {element.id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: delete_element, element_id={element_id}")
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
- if self.show_logger: logger.info(f"SQLAlchemy: get_all_user_threads")
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"] == "true"
567
- else None
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
- if not self.mime and self.url:
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.send_element(self.to_dict())
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, ElementDict, File
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, HTTPSession, WebsocketSession
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)