chainlit 0.4.1__py3-none-any.whl → 0.4.2__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.

@@ -14,7 +14,7 @@
14
14
  <script>
15
15
  const global = globalThis;
16
16
  </script>
17
- <script type="module" crossorigin src="/assets/index-68c36c96.js"></script>
17
+ <script type="module" crossorigin src="/assets/index-fb1e167a.js"></script>
18
18
  <link rel="stylesheet" href="/assets/index-f93cc942.css">
19
19
  </head>
20
20
  <body>
chainlit/lc/agent.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from typing import Any
2
2
  from chainlit.lc.callbacks import ChainlitCallbackHandler, AsyncChainlitCallbackHandler
3
3
  from chainlit.sync import make_async
4
+ from chainlit.context import emitter_var
4
5
 
5
6
 
6
7
  async def run_langchain_agent(agent: Any, input_str: str, use_async: bool):
chainlit/lc/callbacks.py CHANGED
@@ -6,7 +6,8 @@ from langchain.schema import (
6
6
  BaseMessage,
7
7
  LLMResult,
8
8
  )
9
- from chainlit.emitter import get_emitter, ChainlitEmitter
9
+ from chainlit.emitter import ChainlitEmitter
10
+ from chainlit.context import get_emitter
10
11
  from chainlit.message import Message, ErrorMessage
11
12
  from chainlit.config import config
12
13
  from chainlit.types import LLMSettings
@@ -107,14 +108,10 @@ class ChainlitCallbackHandler(BaseChainlitCallbackHandler, BaseCallbackHandler):
107
108
  return
108
109
 
109
110
  if config.code.lc_rename:
110
- author = run_sync(
111
- config.code.lc_rename(author, __chainlit_emitter__=self.emitter)
112
- )
111
+ author = run_sync(config.code.lc_rename(author))
113
112
 
114
113
  self.pop_prompt()
115
114
 
116
- __chainlit_emitter__ = self.emitter
117
-
118
115
  streamed_message = Message(
119
116
  author=author,
120
117
  indent=indent,
@@ -135,11 +132,7 @@ class ChainlitCallbackHandler(BaseChainlitCallbackHandler, BaseCallbackHandler):
135
132
  return
136
133
 
137
134
  if config.code.lc_rename:
138
- author = run_sync(
139
- config.code.lc_rename(author, __chainlit_emitter__=self.emitter)
140
- )
141
-
142
- __chainlit_emitter__ = self.emitter
135
+ author = run_sync(config.code.lc_rename(author))
143
136
 
144
137
  if error:
145
138
  run_sync(ErrorMessage(author=author, content=message).send())
@@ -267,14 +260,10 @@ class AsyncChainlitCallbackHandler(BaseChainlitCallbackHandler, AsyncCallbackHan
267
260
  return
268
261
 
269
262
  if config.code.lc_rename:
270
- author = await config.code.lc_rename(
271
- author, __chainlit_emitter__=self.emitter
272
- )
263
+ author = await config.code.lc_rename(author)
273
264
 
274
265
  self.pop_prompt()
275
266
 
276
- __chainlit_emitter__ = self.emitter
277
-
278
267
  streamed_message = Message(
279
268
  author=author,
280
269
  indent=indent,
@@ -295,11 +284,7 @@ class AsyncChainlitCallbackHandler(BaseChainlitCallbackHandler, AsyncCallbackHan
295
284
  return
296
285
 
297
286
  if config.code.lc_rename:
298
- author = await config.code.lc_rename(
299
- author, __chainlit_emitter__=self.emitter
300
- )
301
-
302
- __chainlit_emitter__ = self.emitter
287
+ author = await config.code.lc_rename(author)
303
288
 
304
289
  if error:
305
290
  await ErrorMessage(author=author, content=message).send()
chainlit/logger.py CHANGED
@@ -1,12 +1,17 @@
1
1
  import logging
2
+ import sys
3
+
2
4
 
3
5
  logging.basicConfig(
4
- level=logging.INFO, format="%(asctime)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
6
+ level=logging.INFO,
7
+ stream=sys.stdout,
8
+ format="%(asctime)s - %(message)s",
9
+ datefmt="%Y-%m-%d %H:%M:%S",
5
10
  )
6
11
 
7
12
  logging.getLogger("socketio").setLevel(logging.ERROR)
8
13
  logging.getLogger("engineio").setLevel(logging.ERROR)
9
- logging.getLogger("geventwebsocket.handler").setLevel(logging.ERROR)
10
14
  logging.getLogger("numexpr").setLevel(logging.ERROR)
11
15
 
16
+
12
17
  logger = logging.getLogger("chainlit")
chainlit/message.py CHANGED
@@ -1,11 +1,11 @@
1
1
  from typing import List, Dict, Union
2
2
  from abc import ABC, abstractmethod
3
3
  import uuid
4
- import time
5
4
  import asyncio
5
+ from datetime import datetime, timezone
6
6
 
7
7
  from chainlit.telemetry import trace_event
8
- from chainlit.emitter import get_emitter
8
+ from chainlit.context import get_emitter
9
9
  from chainlit.config import config
10
10
  from chainlit.types import (
11
11
  LLMSettings,
@@ -16,11 +16,7 @@ from chainlit.types import (
16
16
  )
17
17
  from chainlit.element import Element
18
18
  from chainlit.action import Action
19
-
20
-
21
- def current_milli_time():
22
- """Get the current time in milliseconds."""
23
- return round(time.time() * 1000)
19
+ from chainlit.logger import logger
24
20
 
25
21
 
26
22
  class MessageBase(ABC):
@@ -28,14 +24,13 @@ class MessageBase(ABC):
28
24
  temp_id: str = None
29
25
  streaming = False
30
26
  created_at: int = None
27
+ fail_on_persist_error: bool = True
31
28
 
32
29
  def __post_init__(self) -> None:
33
30
  trace_event(f"init {self.__class__.__name__}")
34
31
  self.temp_id = uuid.uuid4().hex
35
- self.created_at = current_milli_time()
32
+ self.created_at = datetime.now(timezone.utc).isoformat()
36
33
  self.emitter = get_emitter()
37
- if not self.emitter:
38
- raise RuntimeError("Message should be instantiated in a Chainlit context")
39
34
 
40
35
  @abstractmethod
41
36
  def to_dict(self):
@@ -44,9 +39,14 @@ class MessageBase(ABC):
44
39
  async def _create(self):
45
40
  msg_dict = self.to_dict()
46
41
  if self.emitter.client and not self.id:
47
- self.id = await self.emitter.client.create_message(msg_dict)
48
- if self.id:
49
- msg_dict["id"] = self.id
42
+ try:
43
+ self.id = await self.emitter.client.create_message(msg_dict)
44
+ if self.id:
45
+ msg_dict["id"] = self.id
46
+ except Exception as e:
47
+ if self.fail_on_persist_error:
48
+ raise e
49
+ logger.error(f"Failed to persist message: {str(e)}")
50
50
 
51
51
  return msg_dict
52
52
 
@@ -77,8 +77,7 @@ class MessageBase(ABC):
77
77
  msg_dict = self.to_dict()
78
78
 
79
79
  if self.emitter.client and self.id:
80
- self.emitter.client.update_message(self.id, msg_dict)
81
- msg_dict["id"] = self.id
80
+ await self.emitter.client.update_message(self.id, msg_dict)
82
81
 
83
82
  await self.emitter.update_message(msg_dict)
84
83
 
@@ -171,7 +170,7 @@ class Message(MessageBase):
171
170
  super().__post_init__()
172
171
 
173
172
  def to_dict(self):
174
- return {
173
+ _dict = {
175
174
  "tempId": self.temp_id,
176
175
  "createdAt": self.created_at,
177
176
  "content": self.content,
@@ -182,6 +181,11 @@ class Message(MessageBase):
182
181
  "indent": self.indent,
183
182
  }
184
183
 
184
+ if self.id:
185
+ _dict["id"] = self.id
186
+
187
+ return _dict
188
+
185
189
  async def send(self):
186
190
  """
187
191
  Send the message to the UI and persist it in the cloud if a project ID is configured.
@@ -214,10 +218,12 @@ class ErrorMessage(MessageBase):
214
218
  content: str,
215
219
  author: str = config.ui.name,
216
220
  indent: int = 0,
221
+ fail_on_persist_error: bool = False,
217
222
  ):
218
223
  self.content = content
219
224
  self.author = author
220
225
  self.indent = indent
226
+ self.fail_on_persist_error = fail_on_persist_error
221
227
 
222
228
  super().__post_init__()
223
229
 
chainlit/server.py CHANGED
@@ -6,11 +6,13 @@ mimetypes.add_type("text/css", ".css")
6
6
  import os
7
7
  import json
8
8
  import webbrowser
9
+ from pathlib import Path
10
+
9
11
 
10
12
  from contextlib import asynccontextmanager
11
13
  from watchfiles import awatch
12
14
 
13
- from fastapi import FastAPI
15
+ from fastapi import FastAPI, Request
14
16
  from fastapi.responses import (
15
17
  HTMLResponse,
16
18
  JSONResponse,
@@ -21,17 +23,25 @@ from fastapi_socketio import SocketManager
21
23
  from starlette.middleware.cors import CORSMiddleware
22
24
  import asyncio
23
25
 
26
+ from chainlit.context import emitter_var, loop_var
24
27
  from chainlit.config import config, load_module, reload_config, DEFAULT_HOST
25
28
  from chainlit.session import Session, sessions
26
29
  from chainlit.user_session import user_sessions
27
- from chainlit.client import CloudClient
30
+ from chainlit.client.cloud import CloudClient
31
+ from chainlit.client.local import LocalClient
32
+ from chainlit.client.utils import get_client
28
33
  from chainlit.emitter import ChainlitEmitter
29
34
  from chainlit.markdown import get_markdown_str
30
35
  from chainlit.action import Action
31
36
  from chainlit.message import Message, ErrorMessage
32
37
  from chainlit.telemetry import trace_event
33
38
  from chainlit.logger import logger
34
- from chainlit.types import CompletionRequest
39
+ from chainlit.types import (
40
+ CompletionRequest,
41
+ UpdateFeedbackRequest,
42
+ GetConversationsRequest,
43
+ DeleteConversationRequest,
44
+ )
35
45
 
36
46
 
37
47
  @asynccontextmanager
@@ -39,18 +49,25 @@ async def lifespan(app: FastAPI):
39
49
  host = config.run.host
40
50
  port = config.run.port
41
51
 
42
- if not config.run.headless:
43
- if host == DEFAULT_HOST:
44
- url = f"http://localhost:{port}"
45
- else:
46
- url = f"http://{host}:{port}"
52
+ if host == DEFAULT_HOST:
53
+ url = f"http://localhost:{port}"
54
+ else:
55
+ url = f"http://{host}:{port}"
47
56
 
48
- logger.info(f"Your app is available at {url}")
57
+ logger.info(f"Your app is available at {url}")
49
58
 
59
+ if not config.run.headless:
50
60
  # Add a delay before opening the browser
51
61
  await asyncio.sleep(1)
52
62
  webbrowser.open(url)
53
63
 
64
+ if config.project.database == "local":
65
+ from prisma import Client, register
66
+
67
+ client = Client()
68
+ register(client)
69
+ await client.connect()
70
+
54
71
  watch_task = None
55
72
  stop_event = asyncio.Event()
56
73
 
@@ -92,6 +109,8 @@ async def lifespan(app: FastAPI):
92
109
  try:
93
110
  yield
94
111
  finally:
112
+ if config.project.database == "local":
113
+ await client.disconnect()
95
114
  if watch_task:
96
115
  try:
97
116
  stop_event.set()
@@ -206,6 +225,80 @@ async def project_settings():
206
225
  )
207
226
 
208
227
 
228
+ @app.put("/message/feedback")
229
+ async def update_feedback(request: Request, update: UpdateFeedbackRequest):
230
+ """Update the human feedback for a particular message."""
231
+
232
+ client = await get_client(request)
233
+ await client.set_human_feedback(
234
+ message_id=update.messageId, feedback=update.feedback
235
+ )
236
+ return JSONResponse(content={"success": True})
237
+
238
+
239
+ @app.get("/project/members")
240
+ async def get_project_members(request: Request):
241
+ """Get all the members of a project."""
242
+
243
+ client = await get_client(request)
244
+ res = await client.get_project_members()
245
+ return JSONResponse(content=res)
246
+
247
+
248
+ @app.get("/project/role")
249
+ async def get_member_role(request: Request):
250
+ """Get the role of a member."""
251
+
252
+ client = await get_client(request)
253
+ res = await client.get_member_role()
254
+ return PlainTextResponse(content=res)
255
+
256
+
257
+ @app.post("/project/conversations")
258
+ async def get_project_conversations(request: Request, payload: GetConversationsRequest):
259
+ """Get the conversations page by page."""
260
+
261
+ client = await get_client(request)
262
+ res = await client.get_conversations(payload.pagination, payload.filter)
263
+ return JSONResponse(content=res.to_dict())
264
+
265
+
266
+ @app.get("/project/conversation/{conversation_id}")
267
+ async def get_conversation(request: Request, conversation_id: str):
268
+ """Get a specific conversation."""
269
+
270
+ client = await get_client(request)
271
+ res = await client.get_conversation(int(conversation_id))
272
+ return JSONResponse(content=res)
273
+
274
+
275
+ @app.get("/project/conversation/{conversation_id}/element/{element_id}")
276
+ async def get_conversation(request: Request, conversation_id: str, element_id: str):
277
+ """Get a specific conversation."""
278
+
279
+ client = await get_client(request)
280
+ res = await client.get_element(int(conversation_id), int(element_id))
281
+ return JSONResponse(content=res)
282
+
283
+
284
+ @app.delete("/project/conversation")
285
+ async def delete_conversation(request: Request, payload: DeleteConversationRequest):
286
+ """Delete a conversation."""
287
+
288
+ client = await get_client(request)
289
+ await client.delete_conversation(conversation_id=payload.conversationId)
290
+ return JSONResponse(content={"success": True})
291
+
292
+
293
+ @app.get("/files/{filename:path}")
294
+ async def serve_file(filename: str):
295
+ file_path = Path(config.project.local_fs_path) / filename
296
+ if file_path.is_file():
297
+ return FileResponse(file_path)
298
+ else:
299
+ return {"error": "File not found"}
300
+
301
+
209
302
  @app.get("/{path:path}")
210
303
  async def serve(path: str):
211
304
  """Serve the UI."""
@@ -236,7 +329,7 @@ def need_session(id: str):
236
329
  async def connect(sid, environ):
237
330
  user_env = environ.get("HTTP_USER_ENV")
238
331
  authorization = environ.get("HTTP_AUTHORIZATION")
239
- cloud_client = None
332
+ client = None
240
333
 
241
334
  # Check authorization
242
335
  if not config.project.public and not authorization:
@@ -244,17 +337,22 @@ async def connect(sid, environ):
244
337
  trace_event("no_access_token")
245
338
  logger.error("Connection refused: No access token provided")
246
339
  return False
247
- elif authorization and config.project.id:
340
+ elif authorization and config.project.id and config.project.database == "cloud":
248
341
  # Create the cloud client
249
- cloud_client = CloudClient(
342
+ client = CloudClient(
250
343
  project_id=config.project.id,
251
- session_id=sid,
252
344
  access_token=authorization,
253
345
  )
254
- is_project_member = await cloud_client.is_project_member()
346
+ is_project_member = await client.is_project_member()
255
347
  if not is_project_member:
256
348
  logger.error("Connection refused: You are not a member of this project")
257
349
  return False
350
+ elif config.project.database == "local":
351
+ client = LocalClient()
352
+ elif config.project.database == "custom":
353
+ if not config.code.client_factory:
354
+ raise ValueError("Client factory not provided")
355
+ client = await config.code.client_factory()
258
356
 
259
357
  # Check user env
260
358
  if config.project.user_env:
@@ -293,9 +391,8 @@ async def connect(sid, environ):
293
391
  "id": sid,
294
392
  "emit": emit_fn,
295
393
  "ask_user": ask_user_fn,
296
- "client": cloud_client,
394
+ "client": client,
297
395
  "user_env": user_env,
298
- "running_sync": False,
299
396
  "should_stop": False,
300
397
  } # type: Session
301
398
 
@@ -308,15 +405,17 @@ async def connect(sid, environ):
308
405
  @socket.on("connection_successful")
309
406
  async def connection_successful(sid):
310
407
  session = need_session(sid)
311
- __chainlit_emitter__ = ChainlitEmitter(session)
408
+ emitter_var.set(ChainlitEmitter(session))
409
+ loop_var.set(asyncio.get_event_loop())
410
+
312
411
  if config.code.lc_factory:
313
412
  """Instantiate the langchain agent and store it in the session."""
314
- agent = await config.code.lc_factory(__chainlit_emitter__=__chainlit_emitter__)
413
+ agent = await config.code.lc_factory()
315
414
  session["agent"] = agent
316
415
 
317
416
  if config.code.on_chat_start:
318
417
  """Call the on_chat_start function provided by the developer."""
319
- await config.code.on_chat_start(__chainlit_emitter__=__chainlit_emitter__)
418
+ await config.code.on_chat_start()
320
419
 
321
420
 
322
421
  @socket.on("disconnect")
@@ -336,7 +435,8 @@ async def stop(sid):
336
435
  trace_event("stop_task")
337
436
  session = sessions[sid]
338
437
 
339
- __chainlit_emitter__ = ChainlitEmitter(session)
438
+ emitter_var.set(ChainlitEmitter(session))
439
+ loop_var.set(asyncio.get_event_loop())
340
440
 
341
441
  await Message(author="System", content="Task stopped by the user.").send()
342
442
 
@@ -350,8 +450,11 @@ async def process_message(session: Session, author: str, input_str: str):
350
450
  """Process a message from the user."""
351
451
 
352
452
  try:
353
- __chainlit_emitter__ = ChainlitEmitter(session)
354
- await __chainlit_emitter__.task_start()
453
+ emitter = ChainlitEmitter(session)
454
+ emitter_var.set(emitter)
455
+ loop_var.set(asyncio.get_event_loop())
456
+
457
+ await emitter.task_start()
355
458
 
356
459
  if session["client"]:
357
460
  # If cloud is enabled, persist the message
@@ -373,7 +476,6 @@ async def process_message(session: Session, author: str, input_str: str):
373
476
  await config.code.lc_run(
374
477
  langchain_agent,
375
478
  input_str,
376
- __chainlit_emitter__=__chainlit_emitter__,
377
479
  )
378
480
  return
379
481
  else:
@@ -384,9 +486,7 @@ async def process_message(session: Session, author: str, input_str: str):
384
486
 
385
487
  if config.code.lc_postprocess:
386
488
  # If the developer provided a custom postprocess function, use it
387
- await config.code.lc_postprocess(
388
- raw_res, __chainlit_emitter__=__chainlit_emitter__
389
- )
489
+ await config.code.lc_postprocess(raw_res)
390
490
  return
391
491
  elif output_key is not None:
392
492
  # Use the output key if provided
@@ -399,16 +499,16 @@ async def process_message(session: Session, author: str, input_str: str):
399
499
 
400
500
  elif config.code.on_message:
401
501
  # If no langchain agent is available, call the on_message function provided by the developer
402
- await config.code.on_message(
403
- input_str, __chainlit_emitter__=__chainlit_emitter__
404
- )
502
+ await config.code.on_message(input_str)
405
503
  except InterruptedError:
406
504
  pass
407
505
  except Exception as e:
408
506
  logger.exception(e)
409
- await ErrorMessage(author="Error", content=str(e)).send()
507
+ await ErrorMessage(
508
+ author="Error", content=str(e) or e.__class__.__name__
509
+ ).send()
410
510
  finally:
411
- await __chainlit_emitter__.task_end()
511
+ await emitter.task_end()
412
512
 
413
513
 
414
514
  @socket.on("ui_message")
@@ -423,11 +523,10 @@ async def message(sid, data):
423
523
  await process_message(session, author, input_str)
424
524
 
425
525
 
426
- async def process_action(session: Session, action: Action):
427
- __chainlit_emitter__ = ChainlitEmitter(session)
526
+ async def process_action(action: Action):
428
527
  callback = config.code.action_callbacks.get(action.name)
429
528
  if callback:
430
- await callback(action, __chainlit_emitter__=__chainlit_emitter__)
529
+ await callback(action)
431
530
  else:
432
531
  logger.warning("No callback found for action %s", action.name)
433
532
 
@@ -436,8 +535,9 @@ async def process_action(session: Session, action: Action):
436
535
  async def call_action(sid, action):
437
536
  """Handle an action call from the UI."""
438
537
  session = need_session(sid)
538
+ emitter_var.set(ChainlitEmitter(session))
539
+ loop_var.set(asyncio.get_event_loop())
439
540
 
440
- __chainlit_emitter__ = ChainlitEmitter(session)
441
541
  action = Action(**action)
442
542
 
443
- await process_action(session, action)
543
+ await process_action(action)
chainlit/session.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from typing import Dict, TypedDict, Optional, Callable, Any, Union
2
- from chainlit.client import BaseClient
2
+ from chainlit.client.base import BaseClient
3
3
  from chainlit.types import AskResponse
4
4
 
5
5
 
@@ -16,8 +16,6 @@ class Session(TypedDict):
16
16
  user_env: Dict[str, str]
17
17
  # Optional langchain agent
18
18
  agent: Any
19
- # If the session is currently running a sync task
20
- running_sync: bool
21
19
  # Whether the current task should be stopped
22
20
  should_stop: bool
23
21
  # Optional client to persist messages and files
chainlit/sync.py CHANGED
@@ -1,37 +1,25 @@
1
- from typing import Any, Callable
1
+ import sys
2
+ from typing import Any, TypeVar, Coroutine
3
+
4
+ if sys.version_info >= (3, 10):
5
+ from typing import ParamSpec
6
+ else:
7
+ from typing_extensions import ParamSpec
2
8
 
3
9
  import asyncio
4
- from syncer import sync
5
10
  from asyncer import asyncify
6
11
 
7
- from chainlit.emitter import get_emitter
8
-
9
-
10
- def make_async(function: Callable):
11
- emitter = get_emitter()
12
- if not emitter:
13
- raise RuntimeError(
14
- "Emitter not found, please call make_async in a Chainlit context."
15
- )
12
+ from chainlit.context import get_loop
16
13
 
17
- def wrapper(*args, **kwargs):
18
- emitter.session["running_sync"] = True
19
- __chainlit_emitter__ = emitter
20
- res = function(*args, **kwargs)
21
- emitter.session["running_sync"] = False
22
- return res
23
14
 
24
- return asyncify(wrapper, cancellable=True)
15
+ make_async = asyncify
25
16
 
17
+ T_Retval = TypeVar("T_Retval")
18
+ T_ParamSpec = ParamSpec("T_ParamSpec")
19
+ T = TypeVar("T")
26
20
 
27
- def run_sync(co: Any):
28
- try:
29
- loop = asyncio.get_event_loop()
30
- except RuntimeError as e:
31
- if "There is no current event loop" in str(e):
32
- loop = None
33
21
 
34
- if loop is None or not loop.is_running():
35
- loop = asyncio.new_event_loop()
36
- asyncio.set_event_loop(loop)
37
- return sync(co)
22
+ def run_sync(co: Coroutine[Any, Any, T_Retval]) -> T_Retval:
23
+ loop = get_loop()
24
+ result = asyncio.run_coroutine_threadsafe(co, loop=loop)
25
+ return result.result()
chainlit/types.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import List, TypedDict, Optional, Literal, Dict, Union
1
+ from typing import List, Any, TypedDict, Optional, Literal, Dict, Union
2
2
  from pydantic import BaseModel
3
3
  from pydantic.dataclasses import dataclass
4
4
  from dataclasses_json import dataclass_json
@@ -66,3 +66,28 @@ class CompletionRequest(BaseModel):
66
66
  prompt: str
67
67
  userEnv: Dict[str, str]
68
68
  settings: LLMSettings
69
+
70
+
71
+ class UpdateFeedbackRequest(BaseModel):
72
+ messageId: int
73
+ feedback: int
74
+
75
+
76
+ class DeleteConversationRequest(BaseModel):
77
+ conversationId: int
78
+
79
+
80
+ class Pagination(BaseModel):
81
+ first: int
82
+ cursor: Any
83
+
84
+
85
+ class ConversationFilter(BaseModel):
86
+ feedback: Optional[Literal[-1, 0, 1]]
87
+ authorEmail: Optional[str]
88
+ search: Optional[str]
89
+
90
+
91
+ class GetConversationsRequest(BaseModel):
92
+ pagination: Pagination
93
+ filter: ConversationFilter
chainlit/user_session.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from typing import Dict
2
- from chainlit.emitter import get_emitter
2
+ from chainlit.context import get_emitter
3
3
 
4
4
  user_sessions: Dict[str, Dict] = {}
5
5
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chainlit
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: A faster way to build chatbot UIs.
5
5
  Home-page: https://github.com/Chainlit/chainlit
6
6
  License: Apache-2.0 license
@@ -21,8 +21,8 @@ Requires-Dist: click (>=8.1.3,<9.0.0)
21
21
  Requires-Dist: dataclasses_json (>=0.5.7,<0.6.0)
22
22
  Requires-Dist: fastapi (>=0.96.0,<0.97.0)
23
23
  Requires-Dist: fastapi-socketio (>=0.0.10,<0.0.11)
24
- Requires-Dist: nest-asyncio (>=1.5.6,<2.0.0)
25
24
  Requires-Dist: openai (>=0.27.7,<0.28.0)
25
+ Requires-Dist: prisma (>=0.9.0,<0.10.0)
26
26
  Requires-Dist: pydantic (>=1.10.8,<2.0.0)
27
27
  Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
28
28
  Requires-Dist: python-graphql-client (>=0.4.3,<0.5.0)
@@ -92,7 +92,10 @@ $ chainlit run demo.py -w
92
92
 
93
93
  ### 🔗 With LangChain
94
94
 
95
- Checkout our plug and play [integration](https://docs.chainlit.io/langchain) with LangChain!
95
+ Check out our plug-and-play [integration](https://docs.chainlit.io/langchain) with LangChain!
96
+
97
+ ### 📚 More Examples - Cookbook
98
+ You can find various examples of Chainlit apps [here](https://github.com/Chainlit/cookbook) that leverage tools and services such as OpenAI, Anthropiс, LangChain, LlamaIndex, ChromaDB, Pinecone and more.
96
99
 
97
100
  ## 🛣 Roadmap
98
101
  - [ ] New UI elements (spreadsheet, video, carousel...)