chainlit 1.0.0rc2__py3-none-any.whl → 1.0.0rc3__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/__init__.py CHANGED
@@ -29,7 +29,7 @@ def queue_until_user_message():
29
29
  async def wrapper(self, *args, **kwargs):
30
30
  if (
31
31
  isinstance(context.session, WebsocketSession)
32
- and not context.session.has_user_message
32
+ and not context.session.has_first_interaction
33
33
  ):
34
34
  # Queue the method invocation waiting for the first user message
35
35
  queues = context.session.thread_queues
@@ -128,6 +128,7 @@ class ChainlitDataLayer:
128
128
  "chainlitKey": None,
129
129
  "display": metadata.get("display", "side"),
130
130
  "language": metadata.get("language"),
131
+ "page": metadata.get("page"),
131
132
  "size": metadata.get("size"),
132
133
  "type": metadata.get("type", "file"),
133
134
  "forId": attachment.step_id,
@@ -230,11 +231,15 @@ class ChainlitDataLayer:
230
231
  "language": element.language,
231
232
  "display": element.display,
232
233
  "type": element.type,
234
+ "page": getattr(element, "page", None),
233
235
  }
234
236
 
237
+ if not element.for_id:
238
+ return
239
+
235
240
  await self.client.api.create_attachment(
236
241
  thread_id=element.thread_id,
237
- step_id=element.for_id or "",
242
+ step_id=element.for_id,
238
243
  mime=element.mime,
239
244
  name=element.name,
240
245
  url=element.url,
chainlit/element.py CHANGED
@@ -37,6 +37,7 @@ class ElementDict(TypedDict):
37
37
  display: ElementDisplay
38
38
  size: Optional[ElementSize]
39
39
  language: Optional[str]
40
+ page: Optional[int]
40
41
  forId: Optional[str]
41
42
  mime: Optional[str]
42
43
 
@@ -46,7 +47,7 @@ class Element:
46
47
  # The type of the element. This will be used to determine how to display the element in the UI.
47
48
  type: ClassVar[ElementType]
48
49
  # Name of the element, this will be used to reference the element in the UI.
49
- name: str
50
+ name: str = ""
50
51
  # The ID of the element. This is set automatically when the element is sent to the UI.
51
52
  id: str = Field(default_factory=lambda: str(uuid.uuid4()))
52
53
  # The key of the element hosted on Chainlit.
@@ -91,6 +92,7 @@ class Element:
91
92
  "display": self.display,
92
93
  "objectKey": getattr(self, "object_key", None),
93
94
  "size": getattr(self, "size", None),
95
+ "page": getattr(self, "page", None),
94
96
  "language": getattr(self, "language", None),
95
97
  "forId": getattr(self, "for_id", None),
96
98
  "mime": getattr(self, "mime", None),
@@ -201,6 +203,7 @@ class Text(Element):
201
203
  class Pdf(Element):
202
204
  """Useful to send a pdf to the UI."""
203
205
 
206
+ page: Optional[int] = None
204
207
  type: ClassVar[ElementType] = "pdf"
205
208
 
206
209
 
chainlit/emitter.py CHANGED
@@ -64,8 +64,7 @@ class BaseChainlitEmitter:
64
64
  """Stub method to clear the prompt from the UI."""
65
65
  pass
66
66
 
67
- async def init_thread(self, step_dict: StepDict):
68
- """Signal the UI that a new thread (with a user message) exists"""
67
+ async def init_thread(self, interaction: str):
69
68
  pass
70
69
 
71
70
  async def process_user_message(self, payload: UIMessagePayload) -> Message:
@@ -167,7 +166,7 @@ class ChainlitEmitter(BaseChainlitEmitter):
167
166
 
168
167
  return self.emit("clear_ask", {})
169
168
 
170
- async def flush_thread_queues(self, name: str):
169
+ async def flush_thread_queues(self, interaction: str):
171
170
  if data_layer := get_data_layer():
172
171
  if isinstance(self.session.user, PersistedUser):
173
172
  user_id = self.session.user.id
@@ -176,14 +175,13 @@ class ChainlitEmitter(BaseChainlitEmitter):
176
175
  await data_layer.update_thread(
177
176
  thread_id=self.session.thread_id,
178
177
  user_id=user_id,
179
- metadata={"name": name},
178
+ metadata={"name": interaction},
180
179
  )
181
180
  await self.session.flush_method_queue()
182
181
 
183
- async def init_thread(self, step: StepDict):
184
- """Signal the UI that a new thread (with a user message) exists"""
185
- await self.flush_thread_queues(name=step["output"])
186
- await self.emit("init_thread", step)
182
+ async def init_thread(self, interaction: str):
183
+ await self.flush_thread_queues(interaction)
184
+ await self.emit("first_interaction", interaction)
187
185
 
188
186
  async def process_user_message(self, payload: UIMessagePayload):
189
187
  step_dict = payload["message"]
@@ -197,9 +195,9 @@ class ChainlitEmitter(BaseChainlitEmitter):
197
195
 
198
196
  asyncio.create_task(message._create())
199
197
 
200
- if not self.session.has_user_message:
201
- self.session.has_user_message = True
202
- asyncio.create_task(self.init_thread(message.to_dict()))
198
+ if not self.session.has_first_interaction:
199
+ self.session.has_first_interaction = True
200
+ asyncio.create_task(self.init_thread(message.content))
203
201
 
204
202
  if file_refs:
205
203
  files = [
@@ -239,11 +237,13 @@ class ChainlitEmitter(BaseChainlitEmitter):
239
237
  ] = None
240
238
 
241
239
  if user_res:
240
+ interaction = None
242
241
  if spec.type == "text":
243
242
  message_dict_res = cast(StepDict, user_res)
244
243
  await self.process_user_message(
245
244
  {"message": message_dict_res, "fileReferences": None}
246
245
  )
246
+ interaction = message_dict_res["output"]
247
247
  final_res = message_dict_res
248
248
  elif spec.type == "file":
249
249
  file_refs = cast(List[FileReference], user_res)
@@ -253,12 +253,7 @@ class ChainlitEmitter(BaseChainlitEmitter):
253
253
  if file["id"] in self.session.files
254
254
  ]
255
255
  final_res = files
256
- if not self.session.has_user_message:
257
- self.session.has_user_message = True
258
- await self.flush_thread_queues(
259
- name=",".join([file["name"] for file in files])
260
- )
261
-
256
+ interaction = ",".join([file["name"] for file in files])
262
257
  if get_data_layer():
263
258
  coros = [
264
259
  File(
@@ -274,6 +269,12 @@ class ChainlitEmitter(BaseChainlitEmitter):
274
269
  elif spec.type == "action":
275
270
  action_res = cast(AskActionResponse, user_res)
276
271
  final_res = action_res
272
+ interaction = action_res["value"]
273
+
274
+ if not self.session.has_first_interaction and interaction:
275
+ self.session.has_first_interaction = True
276
+ await self.init_thread(interaction=interaction)
277
+
277
278
  await self.clear_ask()
278
279
  return final_res
279
280
  except TimeoutError as e: