chainlit 1.3.2__py3-none-any.whl → 2.0.0__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/__init__.py +58 -56
- chainlit/action.py +12 -10
- chainlit/{auth.py → auth/__init__.py} +24 -34
- chainlit/auth/cookie.py +123 -0
- chainlit/auth/jwt.py +37 -0
- chainlit/cache.py +4 -6
- chainlit/callbacks.py +65 -11
- chainlit/chat_context.py +2 -2
- chainlit/chat_settings.py +3 -1
- chainlit/cli/__init__.py +15 -2
- chainlit/config.py +46 -90
- chainlit/context.py +4 -3
- chainlit/copilot/dist/index.js +8608 -642
- chainlit/data/__init__.py +96 -8
- chainlit/data/acl.py +3 -2
- chainlit/data/base.py +1 -15
- chainlit/data/chainlit_data_layer.py +584 -0
- chainlit/data/dynamodb.py +7 -4
- chainlit/data/literalai.py +4 -6
- chainlit/data/sql_alchemy.py +9 -8
- chainlit/data/storage_clients/__init__.py +0 -0
- chainlit/data/{storage_clients.py → storage_clients/azure.py} +2 -33
- chainlit/data/storage_clients/azure_blob.py +80 -0
- chainlit/data/storage_clients/base.py +22 -0
- chainlit/data/storage_clients/gcs.py +78 -0
- chainlit/data/storage_clients/s3.py +49 -0
- chainlit/discord/__init__.py +4 -4
- chainlit/discord/app.py +2 -1
- chainlit/element.py +41 -9
- chainlit/emitter.py +37 -16
- chainlit/frontend/dist/assets/{DailyMotion-Bq4wFES6.js → DailyMotion-DgRzV5GZ.js} +1 -1
- chainlit/frontend/dist/assets/Dataframe-DVgwSMU2.js +22 -0
- chainlit/frontend/dist/assets/{Facebook-CHEgeJDe.js → Facebook-C0vx6HWv.js} +1 -1
- chainlit/frontend/dist/assets/{FilePlayer-BMFA6He5.js → FilePlayer-CdhzeHPP.js} +1 -1
- chainlit/frontend/dist/assets/{Kaltura-BS4Q0SKd.js → Kaltura-5iVmeUct.js} +1 -1
- chainlit/frontend/dist/assets/{Mixcloud-tLlgZy_i.js → Mixcloud-C2zi77Ex.js} +1 -1
- chainlit/frontend/dist/assets/{Mux-Bcz0qNhS.js → Mux-Vkebogdf.js} +1 -1
- chainlit/frontend/dist/assets/{Preview-RsJjlwJx.js → Preview-DwY_sEIl.js} +1 -1
- chainlit/frontend/dist/assets/{SoundCloud-B9UgR7Bk.js → SoundCloud-CREBXAWo.js} +1 -1
- chainlit/frontend/dist/assets/{Streamable-BOgIqbui.js → Streamable-B5Lu25uy.js} +1 -1
- chainlit/frontend/dist/assets/{Twitch-CBX_d6nV.js → Twitch-y9iKCcM1.js} +1 -1
- chainlit/frontend/dist/assets/{Vidyard-C5HPuozf.js → Vidyard-ClYvcuEu.js} +1 -1
- chainlit/frontend/dist/assets/{Vimeo-CHBmywi9.js → Vimeo-D6HvM2jt.js} +1 -1
- chainlit/frontend/dist/assets/Wistia-Cu4zZ2Ci.js +1 -0
- chainlit/frontend/dist/assets/{YouTube-CA7t0q0j.js → YouTube-D10tR6CJ.js} +1 -1
- chainlit/frontend/dist/assets/index-CI4qFOt5.js +8665 -0
- chainlit/frontend/dist/assets/index-CrrqM0nZ.css +1 -0
- chainlit/frontend/dist/assets/{react-plotly-Ba2Cl614.js → react-plotly-BpxUS-ab.js} +1 -1
- chainlit/frontend/dist/index.html +2 -2
- chainlit/haystack/callbacks.py +5 -4
- chainlit/input_widget.py +6 -4
- chainlit/langchain/callbacks.py +56 -47
- chainlit/langflow/__init__.py +1 -0
- chainlit/llama_index/callbacks.py +7 -7
- chainlit/message.py +8 -10
- chainlit/mistralai/__init__.py +3 -2
- chainlit/oauth_providers.py +70 -3
- chainlit/openai/__init__.py +3 -2
- chainlit/secret.py +1 -1
- chainlit/server.py +481 -182
- chainlit/session.py +7 -5
- chainlit/slack/__init__.py +3 -3
- chainlit/slack/app.py +3 -2
- chainlit/socket.py +89 -112
- chainlit/step.py +12 -12
- chainlit/sync.py +2 -1
- chainlit/teams/__init__.py +3 -3
- chainlit/teams/app.py +1 -0
- chainlit/translations/en-US.json +2 -1
- chainlit/translations/nl-NL.json +229 -0
- chainlit/types.py +24 -8
- chainlit/user.py +2 -1
- chainlit/utils.py +3 -2
- chainlit/version.py +3 -2
- {chainlit-1.3.2.dist-info → chainlit-2.0.0.dist-info}/METADATA +15 -35
- chainlit-2.0.0.dist-info/RECORD +106 -0
- chainlit/frontend/dist/assets/Wistia-1Gb23ljh.js +0 -1
- chainlit/frontend/dist/assets/index-CwmincdQ.css +0 -1
- chainlit/frontend/dist/assets/index-DnjoDoLU.js +0 -723
- chainlit-1.3.2.dist-info/RECORD +0 -96
- {chainlit-1.3.2.dist-info → chainlit-2.0.0.dist-info}/WHEEL +0 -0
- {chainlit-1.3.2.dist-info → chainlit-2.0.0.dist-info}/entry_points.txt +0 -0
chainlit/data/sql_alchemy.py
CHANGED
|
@@ -7,8 +7,13 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
|
|
7
7
|
|
|
8
8
|
import aiofiles
|
|
9
9
|
import aiohttp
|
|
10
|
+
from sqlalchemy import text
|
|
11
|
+
from sqlalchemy.exc import SQLAlchemyError
|
|
12
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine
|
|
13
|
+
from sqlalchemy.orm import sessionmaker
|
|
10
14
|
|
|
11
|
-
from chainlit.data.base import BaseDataLayer
|
|
15
|
+
from chainlit.data.base import BaseDataLayer
|
|
16
|
+
from chainlit.data.storage_clients.base import BaseStorageClient
|
|
12
17
|
from chainlit.data.utils import queue_until_user_message
|
|
13
18
|
from chainlit.element import ElementDict
|
|
14
19
|
from chainlit.logger import logger
|
|
@@ -23,10 +28,6 @@ from chainlit.types import (
|
|
|
23
28
|
ThreadFilter,
|
|
24
29
|
)
|
|
25
30
|
from chainlit.user import PersistedUser, User
|
|
26
|
-
from sqlalchemy import text
|
|
27
|
-
from sqlalchemy.exc import SQLAlchemyError
|
|
28
|
-
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine
|
|
29
|
-
from sqlalchemy.orm import sessionmaker
|
|
30
31
|
|
|
31
32
|
if TYPE_CHECKING:
|
|
32
33
|
from chainlit.element import Element, ElementDict
|
|
@@ -167,7 +168,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
167
168
|
async def create_user(self, user: User) -> Optional[PersistedUser]:
|
|
168
169
|
if self.show_logger:
|
|
169
170
|
logger.info(f"SQLAlchemy: create_user, user_identifier={user.identifier}")
|
|
170
|
-
existing_user: Optional[
|
|
171
|
+
existing_user: Optional[PersistedUser] = await self.get_user(user.identifier)
|
|
171
172
|
user_dict: Dict[str, Any] = {
|
|
172
173
|
"identifier": str(user.identifier),
|
|
173
174
|
"metadata": json.dumps(user.metadata) or {},
|
|
@@ -438,6 +439,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
438
439
|
url=element_dict.get("url"),
|
|
439
440
|
objectKey=element_dict.get("objectKey"),
|
|
440
441
|
name=element_dict["name"],
|
|
442
|
+
props=element_dict.get("props"),
|
|
441
443
|
display=element_dict["display"],
|
|
442
444
|
size=element_dict.get("size"),
|
|
443
445
|
language=element_dict.get("language"),
|
|
@@ -576,7 +578,6 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
576
578
|
s."generation" AS step_generation,
|
|
577
579
|
s."showInput" AS step_showinput,
|
|
578
580
|
s."language" AS step_language,
|
|
579
|
-
s."indent" AS step_indent,
|
|
580
581
|
f."value" AS feedback_value,
|
|
581
582
|
f."comment" AS feedback_comment,
|
|
582
583
|
f."id" AS feedback_id
|
|
@@ -664,7 +665,6 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
664
665
|
generation=step_feedback.get("step_generation"),
|
|
665
666
|
showInput=step_feedback.get("step_showinput"),
|
|
666
667
|
language=step_feedback.get("step_language"),
|
|
667
|
-
indent=step_feedback.get("step_indent"),
|
|
668
668
|
feedback=feedback,
|
|
669
669
|
)
|
|
670
670
|
# Append the step to the steps list of the corresponding ThreadDict
|
|
@@ -688,6 +688,7 @@ class SQLAlchemyDataLayer(BaseDataLayer):
|
|
|
688
688
|
autoPlay=element.get("element_autoPlay"),
|
|
689
689
|
playerConfig=element.get("element_playerconfig"),
|
|
690
690
|
page=element.get("element_page"),
|
|
691
|
+
props=element.get("element_props"),
|
|
691
692
|
forId=element.get("element_forid"),
|
|
692
693
|
mime=element.get("element_mime"),
|
|
693
694
|
)
|
|
File without changes
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
|
|
2
2
|
|
|
3
|
-
import boto3 # type: ignore
|
|
4
3
|
from azure.storage.filedatalake import (
|
|
5
4
|
ContentSettings,
|
|
6
5
|
DataLakeFileClient,
|
|
7
6
|
DataLakeServiceClient,
|
|
8
7
|
FileSystemClient,
|
|
9
8
|
)
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
from chainlit.data.storage_clients.base import BaseStorageClient
|
|
11
11
|
from chainlit.logger import logger
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
@@ -79,34 +79,3 @@ class AzureStorageClient(BaseStorageClient):
|
|
|
79
79
|
except Exception as e:
|
|
80
80
|
logger.warn(f"AzureStorageClient, upload_file error: {e}")
|
|
81
81
|
return {}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class S3StorageClient(BaseStorageClient):
|
|
85
|
-
"""
|
|
86
|
-
Class to enable Amazon S3 storage provider
|
|
87
|
-
"""
|
|
88
|
-
|
|
89
|
-
def __init__(self, bucket: str):
|
|
90
|
-
try:
|
|
91
|
-
self.bucket = bucket
|
|
92
|
-
self.client = boto3.client("s3")
|
|
93
|
-
logger.info("S3StorageClient initialized")
|
|
94
|
-
except Exception as e:
|
|
95
|
-
logger.warn(f"S3StorageClient initialization error: {e}")
|
|
96
|
-
|
|
97
|
-
async def upload_file(
|
|
98
|
-
self,
|
|
99
|
-
object_key: str,
|
|
100
|
-
data: Union[bytes, str],
|
|
101
|
-
mime: str = "application/octet-stream",
|
|
102
|
-
overwrite: bool = True,
|
|
103
|
-
) -> Dict[str, Any]:
|
|
104
|
-
try:
|
|
105
|
-
self.client.put_object(
|
|
106
|
-
Bucket=self.bucket, Key=object_key, Body=data, ContentType=mime
|
|
107
|
-
)
|
|
108
|
-
url = f"https://{self.bucket}.s3.amazonaws.com/{object_key}"
|
|
109
|
-
return {"object_key": object_key, "url": url}
|
|
110
|
-
except Exception as e:
|
|
111
|
-
logger.warn(f"S3StorageClient, upload_file error: {e}")
|
|
112
|
-
return {}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
from typing import Any, Dict, Union
|
|
3
|
+
|
|
4
|
+
from azure.storage.blob import BlobSasPermissions, ContentSettings, generate_blob_sas
|
|
5
|
+
from azure.storage.blob.aio import BlobServiceClient as AsyncBlobServiceClient
|
|
6
|
+
|
|
7
|
+
from chainlit.data.storage_clients.base import EXPIRY_TIME, BaseStorageClient
|
|
8
|
+
from chainlit.logger import logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AzureBlobStorageClient(BaseStorageClient):
|
|
12
|
+
def __init__(self, container_name: str, storage_account: str, storage_key: str):
|
|
13
|
+
self.container_name = container_name
|
|
14
|
+
self.storage_account = storage_account
|
|
15
|
+
self.storage_key = storage_key
|
|
16
|
+
connection_string = (
|
|
17
|
+
f"DefaultEndpointsProtocol=https;"
|
|
18
|
+
f"AccountName={storage_account};"
|
|
19
|
+
f"AccountKey={storage_key};"
|
|
20
|
+
f"EndpointSuffix=core.windows.net"
|
|
21
|
+
)
|
|
22
|
+
self.service_client = AsyncBlobServiceClient.from_connection_string(
|
|
23
|
+
connection_string
|
|
24
|
+
)
|
|
25
|
+
logger.info("AzureBlobStorageClient initialized")
|
|
26
|
+
|
|
27
|
+
async def get_read_url(self, object_key: str) -> str:
|
|
28
|
+
if not self.storage_key:
|
|
29
|
+
raise Exception("Not using Azure Storage")
|
|
30
|
+
|
|
31
|
+
sas_permissions = BlobSasPermissions(read=True)
|
|
32
|
+
start_time = datetime.now()
|
|
33
|
+
expiry_time = start_time + timedelta(seconds=EXPIRY_TIME)
|
|
34
|
+
|
|
35
|
+
sas_token = generate_blob_sas(
|
|
36
|
+
account_name=self.storage_account,
|
|
37
|
+
container_name=self.container_name,
|
|
38
|
+
blob_name=object_key,
|
|
39
|
+
account_key=self.storage_key,
|
|
40
|
+
permission=sas_permissions,
|
|
41
|
+
start=start_time,
|
|
42
|
+
expiry=expiry_time,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return f"https://{self.storage_account}.blob.core.windows.net/{self.container_name}/{object_key}?{sas_token}"
|
|
46
|
+
|
|
47
|
+
async def upload_file(
|
|
48
|
+
self,
|
|
49
|
+
object_key: str,
|
|
50
|
+
data: Union[bytes, str],
|
|
51
|
+
mime: str = "application/octet-stream",
|
|
52
|
+
overwrite: bool = True,
|
|
53
|
+
) -> Dict[str, Any]:
|
|
54
|
+
try:
|
|
55
|
+
container_client = self.service_client.get_container_client(
|
|
56
|
+
self.container_name
|
|
57
|
+
)
|
|
58
|
+
blob_client = container_client.get_blob_client(object_key)
|
|
59
|
+
|
|
60
|
+
if isinstance(data, str):
|
|
61
|
+
data = data.encode("utf-8")
|
|
62
|
+
|
|
63
|
+
content_settings = ContentSettings(content_type=mime)
|
|
64
|
+
|
|
65
|
+
await blob_client.upload_blob(
|
|
66
|
+
data, overwrite=overwrite, content_settings=content_settings
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
properties = await blob_client.get_blob_properties()
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
"path": object_key,
|
|
73
|
+
"size": properties.size,
|
|
74
|
+
"last_modified": properties.last_modified,
|
|
75
|
+
"etag": properties.etag,
|
|
76
|
+
"content_type": properties.content_settings.content_type,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
except Exception as e:
|
|
80
|
+
raise Exception(f"Failed to upload file to Azure Blob Storage: {e!s}")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict, Union
|
|
3
|
+
|
|
4
|
+
EXPIRY_TIME = 3600
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseStorageClient(ABC):
|
|
8
|
+
"""Base class for non-text data persistence like Azure Data Lake, S3, Google Storage, etc."""
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
async def upload_file(
|
|
12
|
+
self,
|
|
13
|
+
object_key: str,
|
|
14
|
+
data: Union[bytes, str],
|
|
15
|
+
mime: str = "application/octet-stream",
|
|
16
|
+
overwrite: bool = True,
|
|
17
|
+
) -> Dict[str, Any]:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
async def get_read_url(self, object_key: str) -> str:
|
|
22
|
+
pass
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from typing import Any, Dict, Union
|
|
3
|
+
|
|
4
|
+
from google.cloud import storage # type: ignore
|
|
5
|
+
from google.oauth2 import service_account
|
|
6
|
+
|
|
7
|
+
from chainlit import make_async
|
|
8
|
+
from chainlit.data.storage_clients.base import EXPIRY_TIME, BaseStorageClient
|
|
9
|
+
from chainlit.logger import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GCSStorageClient(BaseStorageClient):
|
|
13
|
+
def __init__(
|
|
14
|
+
self, project_id: str, client_email: str, private_key: str, bucket_name: str
|
|
15
|
+
):
|
|
16
|
+
private_key = base64.b64decode(private_key).decode("utf-8")
|
|
17
|
+
|
|
18
|
+
credentials = service_account.Credentials.from_service_account_info(
|
|
19
|
+
{
|
|
20
|
+
"type": "service_account",
|
|
21
|
+
"project_id": project_id,
|
|
22
|
+
"private_key": private_key,
|
|
23
|
+
"client_email": client_email,
|
|
24
|
+
"token_uri": "https://oauth2.googleapis.com/token",
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
self.client = storage.Client(project=project_id, credentials=credentials)
|
|
29
|
+
self.bucket_name = bucket_name
|
|
30
|
+
self.bucket = self.client.bucket(bucket_name)
|
|
31
|
+
logger.info("GCSStorageClient initialized")
|
|
32
|
+
|
|
33
|
+
def sync_get_read_url(self, object_key: str) -> str:
|
|
34
|
+
return self.bucket.blob(object_key).generate_signed_url(
|
|
35
|
+
version="v4", expiration=EXPIRY_TIME, method="GET"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
async def get_read_url(self, object_key: str) -> str:
|
|
39
|
+
return await make_async(self.sync_get_read_url)(object_key)
|
|
40
|
+
|
|
41
|
+
def sync_upload_file(
|
|
42
|
+
self,
|
|
43
|
+
object_key: str,
|
|
44
|
+
data: Union[bytes, str],
|
|
45
|
+
mime: str = "application/octet-stream",
|
|
46
|
+
overwrite: bool = True,
|
|
47
|
+
) -> Dict[str, Any]:
|
|
48
|
+
try:
|
|
49
|
+
blob = self.bucket.blob(object_key)
|
|
50
|
+
|
|
51
|
+
if not overwrite and blob.exists():
|
|
52
|
+
raise Exception(
|
|
53
|
+
f"File {object_key} already exists and overwrite is False"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if isinstance(data, str):
|
|
57
|
+
data = data.encode("utf-8")
|
|
58
|
+
|
|
59
|
+
blob.upload_from_string(data, content_type=mime)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
"object_key": object_key,
|
|
63
|
+
"url": f"gs://{self.bucket_name}/{object_key}",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
raise Exception(f"Failed to upload file to GCS: {e!s}")
|
|
68
|
+
|
|
69
|
+
async def upload_file(
|
|
70
|
+
self,
|
|
71
|
+
object_key: str,
|
|
72
|
+
data: Union[bytes, str],
|
|
73
|
+
mime: str = "application/octet-stream",
|
|
74
|
+
overwrite: bool = True,
|
|
75
|
+
) -> Dict[str, Any]:
|
|
76
|
+
return await make_async(self.sync_upload_file)(
|
|
77
|
+
object_key, data, mime, overwrite
|
|
78
|
+
)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Any, Dict, Union
|
|
2
|
+
|
|
3
|
+
import boto3 # type: ignore
|
|
4
|
+
|
|
5
|
+
from chainlit.data.storage_clients.base import EXPIRY_TIME, BaseStorageClient
|
|
6
|
+
from chainlit.logger import logger
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class S3StorageClient(BaseStorageClient):
|
|
10
|
+
"""
|
|
11
|
+
Class to enable Amazon S3 storage provider
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, bucket: str, **kwargs: Any):
|
|
15
|
+
try:
|
|
16
|
+
self.bucket = bucket
|
|
17
|
+
self.client = boto3.client("s3", **kwargs)
|
|
18
|
+
logger.info("S3StorageClient initialized")
|
|
19
|
+
except Exception as e:
|
|
20
|
+
logger.warn(f"S3StorageClient initialization error: {e}")
|
|
21
|
+
|
|
22
|
+
async def get_read_url(self, object_key: str) -> str:
|
|
23
|
+
try:
|
|
24
|
+
url = self.client.generate_presigned_url(
|
|
25
|
+
"get_object",
|
|
26
|
+
Params={"Bucket": self.bucket, "Key": object_key},
|
|
27
|
+
ExpiresIn=EXPIRY_TIME,
|
|
28
|
+
)
|
|
29
|
+
return url
|
|
30
|
+
except Exception as e:
|
|
31
|
+
logger.warn(f"S3StorageClient, get_read_url error: {e}")
|
|
32
|
+
return object_key
|
|
33
|
+
|
|
34
|
+
async def upload_file(
|
|
35
|
+
self,
|
|
36
|
+
object_key: str,
|
|
37
|
+
data: Union[bytes, str],
|
|
38
|
+
mime: str = "application/octet-stream",
|
|
39
|
+
overwrite: bool = True,
|
|
40
|
+
) -> Dict[str, Any]:
|
|
41
|
+
try:
|
|
42
|
+
self.client.put_object(
|
|
43
|
+
Bucket=self.bucket, Key=object_key, Body=data, ContentType=mime
|
|
44
|
+
)
|
|
45
|
+
url = f"https://{self.bucket}.s3.amazonaws.com/{object_key}"
|
|
46
|
+
return {"object_key": object_key, "url": url}
|
|
47
|
+
except Exception as e:
|
|
48
|
+
logger.warn(f"S3StorageClient, upload_file error: {e}")
|
|
49
|
+
return {}
|
chainlit/discord/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import importlib.util
|
|
2
|
+
|
|
3
|
+
if importlib.util.find_spec("discord") is None:
|
|
4
4
|
raise ValueError(
|
|
5
|
-
"The discord package is required to integrate Chainlit with a
|
|
5
|
+
"The discord package is required to integrate Chainlit with a Discord app. Run `pip install discord --upgrade`"
|
|
6
6
|
)
|
chainlit/discord/app.py
CHANGED
|
@@ -12,6 +12,8 @@ if TYPE_CHECKING:
|
|
|
12
12
|
import discord
|
|
13
13
|
import filetype
|
|
14
14
|
import httpx
|
|
15
|
+
from discord.ui import Button, View
|
|
16
|
+
|
|
15
17
|
from chainlit.config import config
|
|
16
18
|
from chainlit.context import ChainlitContext, HTTPSession, context, context_var
|
|
17
19
|
from chainlit.data import get_data_layer
|
|
@@ -23,7 +25,6 @@ from chainlit.telemetry import trace
|
|
|
23
25
|
from chainlit.types import Feedback
|
|
24
26
|
from chainlit.user import PersistedUser, User
|
|
25
27
|
from chainlit.user_session import user_session
|
|
26
|
-
from discord.ui import Button, View
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
class FeedbackView(View):
|
chainlit/element.py
CHANGED
|
@@ -16,13 +16,15 @@ from typing import (
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
import filetype
|
|
19
|
+
from pydantic import Field
|
|
20
|
+
from pydantic.dataclasses import dataclass
|
|
21
|
+
from syncer import asyncio
|
|
22
|
+
|
|
19
23
|
from chainlit.context import context
|
|
20
24
|
from chainlit.data import get_data_layer
|
|
21
25
|
from chainlit.logger import logger
|
|
22
26
|
from chainlit.telemetry import trace_event
|
|
23
27
|
from chainlit.types import FileDict
|
|
24
|
-
from pydantic.dataclasses import Field, dataclass
|
|
25
|
-
from syncer import asyncio
|
|
26
28
|
|
|
27
29
|
mime_types = {
|
|
28
30
|
"text": "text/plain",
|
|
@@ -31,7 +33,16 @@ mime_types = {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
ElementType = Literal[
|
|
34
|
-
"image",
|
|
36
|
+
"image",
|
|
37
|
+
"text",
|
|
38
|
+
"pdf",
|
|
39
|
+
"tasklist",
|
|
40
|
+
"audio",
|
|
41
|
+
"video",
|
|
42
|
+
"file",
|
|
43
|
+
"plotly",
|
|
44
|
+
"dataframe",
|
|
45
|
+
"custom",
|
|
35
46
|
]
|
|
36
47
|
ElementDisplay = Literal["inline", "side", "page"]
|
|
37
48
|
ElementSize = Literal["small", "medium", "large"]
|
|
@@ -49,6 +60,7 @@ class ElementDict(TypedDict):
|
|
|
49
60
|
size: Optional[ElementSize]
|
|
50
61
|
language: Optional[str]
|
|
51
62
|
page: Optional[int]
|
|
63
|
+
props: Optional[Dict]
|
|
52
64
|
autoPlay: Optional[bool]
|
|
53
65
|
playerConfig: Optional[dict]
|
|
54
66
|
forId: Optional[str]
|
|
@@ -106,6 +118,7 @@ class Element:
|
|
|
106
118
|
"display": self.display,
|
|
107
119
|
"objectKey": getattr(self, "object_key", None),
|
|
108
120
|
"size": getattr(self, "size", None),
|
|
121
|
+
"props": getattr(self, "props", None),
|
|
109
122
|
"page": getattr(self, "page", None),
|
|
110
123
|
"autoPlay": getattr(self, "auto_play", None),
|
|
111
124
|
"playerConfig": getattr(self, "player_config", None),
|
|
@@ -145,7 +158,7 @@ class Element:
|
|
|
145
158
|
try:
|
|
146
159
|
asyncio.create_task(data_layer.create_element(self))
|
|
147
160
|
except Exception as e:
|
|
148
|
-
logger.error(f"Failed to create element: {
|
|
161
|
+
logger.error(f"Failed to create element: {e!s}")
|
|
149
162
|
if not self.url and (not self.chainlit_key or self.updatable):
|
|
150
163
|
file_dict = await context.session.persist_file(
|
|
151
164
|
name=self.name,
|
|
@@ -343,8 +356,7 @@ class Plotly(Element):
|
|
|
343
356
|
content: str = ""
|
|
344
357
|
|
|
345
358
|
def __post_init__(self) -> None:
|
|
346
|
-
from plotly import graph_objects as go
|
|
347
|
-
from plotly import io as pio
|
|
359
|
+
from plotly import graph_objects as go, io as pio
|
|
348
360
|
|
|
349
361
|
if not isinstance(self.figure, go.Figure):
|
|
350
362
|
raise TypeError("figure must be a plotly.graph_objects.Figure")
|
|
@@ -359,14 +371,34 @@ class Plotly(Element):
|
|
|
359
371
|
|
|
360
372
|
|
|
361
373
|
@dataclass
|
|
362
|
-
class
|
|
363
|
-
"""Useful to send a
|
|
374
|
+
class Dataframe(Element):
|
|
375
|
+
"""Useful to send a pandas DataFrame to the UI."""
|
|
376
|
+
|
|
377
|
+
type: ClassVar[ElementType] = "dataframe"
|
|
378
|
+
size: ElementSize = "large"
|
|
379
|
+
data: Any = None # The type is Any because it is checked in __post_init__.
|
|
380
|
+
|
|
381
|
+
def __post_init__(self) -> None:
|
|
382
|
+
"""Ensures the data is a pandas DataFrame and converts it to JSON."""
|
|
383
|
+
from pandas import DataFrame
|
|
384
|
+
|
|
385
|
+
if not isinstance(self.data, DataFrame):
|
|
386
|
+
raise TypeError("data must be a pandas.DataFrame")
|
|
364
387
|
|
|
365
|
-
|
|
388
|
+
self.content = self.data.to_json(orient="split", date_format="iso")
|
|
389
|
+
super().__post_init__()
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
@dataclass
|
|
393
|
+
class CustomElement(Element):
|
|
394
|
+
"""Useful to send a custom element to the UI."""
|
|
395
|
+
|
|
396
|
+
type: ClassVar[ElementType] = "custom"
|
|
366
397
|
mime: str = "application/json"
|
|
367
398
|
props: Dict = Field(default_factory=dict)
|
|
368
399
|
|
|
369
400
|
def __post_init__(self) -> None:
|
|
370
401
|
self.content = json.dumps(self.props)
|
|
402
|
+
self.updatable = True
|
|
371
403
|
|
|
372
404
|
super().__post_init__()
|
chainlit/emitter.py
CHANGED
|
@@ -2,6 +2,9 @@ import asyncio
|
|
|
2
2
|
import uuid
|
|
3
3
|
from typing import Any, Dict, List, Literal, Optional, Union, cast
|
|
4
4
|
|
|
5
|
+
from literalai.helper import utc_now
|
|
6
|
+
from socketio.exceptions import TimeoutError
|
|
7
|
+
|
|
5
8
|
from chainlit.chat_context import chat_context
|
|
6
9
|
from chainlit.config import config
|
|
7
10
|
from chainlit.data import get_data_layer
|
|
@@ -16,11 +19,10 @@ from chainlit.types import (
|
|
|
16
19
|
FileDict,
|
|
17
20
|
FileReference,
|
|
18
21
|
MessagePayload,
|
|
22
|
+
OutputAudioChunk,
|
|
19
23
|
ThreadDict,
|
|
20
24
|
)
|
|
21
25
|
from chainlit.user import PersistedUser
|
|
22
|
-
from literalai.helper import utc_now
|
|
23
|
-
from socketio.exceptions import TimeoutError
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
class BaseChainlitEmitter:
|
|
@@ -52,6 +54,18 @@ class BaseChainlitEmitter:
|
|
|
52
54
|
"""Stub method to send an element to the UI."""
|
|
53
55
|
pass
|
|
54
56
|
|
|
57
|
+
async def update_audio_connection(self, state: Literal["on", "off"]):
|
|
58
|
+
"""Audio connection signaling."""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
async def send_audio_chunk(self, chunk: OutputAudioChunk):
|
|
62
|
+
"""Stub method to send an audio chunk to the UI."""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
async def send_audio_interrupt(self):
|
|
66
|
+
"""Stub method to interrupt the current audio response."""
|
|
67
|
+
pass
|
|
68
|
+
|
|
55
69
|
async def send_step(self, step_dict: StepDict):
|
|
56
70
|
"""Stub method to send a message to the UI."""
|
|
57
71
|
pass
|
|
@@ -114,10 +128,8 @@ class BaseChainlitEmitter:
|
|
|
114
128
|
"""Stub method to set chat settings."""
|
|
115
129
|
pass
|
|
116
130
|
|
|
117
|
-
async def
|
|
118
|
-
|
|
119
|
-
):
|
|
120
|
-
"""Send an action response to the UI."""
|
|
131
|
+
async def send_window_message(self, data: Any):
|
|
132
|
+
"""Stub method to send custom data to the host window."""
|
|
121
133
|
pass
|
|
122
134
|
|
|
123
135
|
|
|
@@ -157,6 +169,18 @@ class ChainlitEmitter(BaseChainlitEmitter):
|
|
|
157
169
|
"""Send a thread to the UI to resume it"""
|
|
158
170
|
return self.emit("resume_thread", thread_dict)
|
|
159
171
|
|
|
172
|
+
async def update_audio_connection(self, state: Literal["on", "off"]):
|
|
173
|
+
"""Audio connection signaling."""
|
|
174
|
+
await self.emit("audio_connection", state)
|
|
175
|
+
|
|
176
|
+
async def send_audio_chunk(self, chunk: OutputAudioChunk):
|
|
177
|
+
"""Send an audio chunk to the UI."""
|
|
178
|
+
await self.emit("audio_chunk", chunk)
|
|
179
|
+
|
|
180
|
+
async def send_audio_interrupt(self):
|
|
181
|
+
"""Method to interrupt the current audio response."""
|
|
182
|
+
await self.emit("audio_interrupt", {})
|
|
183
|
+
|
|
160
184
|
async def send_element(self, element_dict: ElementDict):
|
|
161
185
|
"""Stub method to send an element to the UI."""
|
|
162
186
|
await self.emit("element", element_dict)
|
|
@@ -258,9 +282,9 @@ class ChainlitEmitter(BaseChainlitEmitter):
|
|
|
258
282
|
# End the task temporarily so that the User can answer the prompt
|
|
259
283
|
await self.task_end()
|
|
260
284
|
|
|
261
|
-
final_res: Optional[
|
|
262
|
-
|
|
263
|
-
|
|
285
|
+
final_res: Optional[Union[StepDict, AskActionResponse, List[FileDict]]] = (
|
|
286
|
+
None
|
|
287
|
+
)
|
|
264
288
|
|
|
265
289
|
if user_res:
|
|
266
290
|
interaction: Union[str, None] = None
|
|
@@ -295,7 +319,7 @@ class ChainlitEmitter(BaseChainlitEmitter):
|
|
|
295
319
|
elif spec.type == "action":
|
|
296
320
|
action_res = cast(AskActionResponse, user_res)
|
|
297
321
|
final_res = action_res
|
|
298
|
-
interaction = action_res["
|
|
322
|
+
interaction = action_res["name"]
|
|
299
323
|
|
|
300
324
|
if not self.session.has_first_interaction and interaction:
|
|
301
325
|
self.session.has_first_interaction = True
|
|
@@ -361,9 +385,6 @@ class ChainlitEmitter(BaseChainlitEmitter):
|
|
|
361
385
|
def set_chat_settings(self, settings: Dict[str, Any]):
|
|
362
386
|
self.session.chat_settings = settings
|
|
363
387
|
|
|
364
|
-
def
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
return self.emit(
|
|
368
|
-
"action_response", {"id": id, "status": status, "response": response}
|
|
369
|
-
)
|
|
388
|
+
def send_window_message(self, data: Any):
|
|
389
|
+
"""Send custom data to the host window."""
|
|
390
|
+
return self.emit("window_message", data)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{n as P,r as v,o as D,q as O}from"./index-CI4qFOt5.js";function b(t,e){for(var r=0;r<e.length;r++){const o=e[r];if(typeof o!="string"&&!Array.isArray(o)){for(const a in o)if(a!=="default"&&!(a in t)){const i=Object.getOwnPropertyDescriptor(o,a);i&&Object.defineProperty(t,a,i.get?i:{enumerable:!0,get:()=>o[a]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var M=Object.create,s=Object.defineProperty,w=Object.getOwnPropertyDescriptor,S=Object.getOwnPropertyNames,j=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty,E=(t,e,r)=>e in t?s(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,A=(t,e)=>{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},h=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of S(e))!T.call(t,a)&&a!==r&&s(t,a,{get:()=>e[a],enumerable:!(o=w(e,a))||o.enumerable});return t},L=(t,e,r)=>(r=t!=null?M(j(t)):{},h(!t||!t.__esModule?s(r,"default",{value:t,enumerable:!0}):r,t)),C=t=>h(s({},"__esModule",{value:!0}),t),n=(t,e,r)=>(E(t,typeof e!="symbol"?e+"":e,r),r),d={};A(d,{default:()=>p});var _=C(d),c=L(v),l=D,f=O;const N="https://api.dmcdn.net/all.js",x="DM",K="dmAsyncInit";class p extends c.Component{constructor(){super(...arguments),n(this,"callPlayer",l.callPlayer),n(this,"onDurationChange",()=>{const e=this.getDuration();this.props.onDuration(e)}),n(this,"mute",()=>{this.callPlayer("setMuted",!0)}),n(this,"unmute",()=>{this.callPlayer("setMuted",!1)}),n(this,"ref",e=>{this.container=e})}componentDidMount(){this.props.onMount&&this.props.onMount(this)}load(e){const{controls:r,config:o,onError:a,playing:i}=this.props,[,y]=e.match(f.MATCH_URL_DAILYMOTION);if(this.player){this.player.load(y,{start:(0,l.parseStartTime)(e),autoplay:i});return}(0,l.getSDK)(N,x,K,u=>u.player).then(u=>{if(!this.container)return;const g=u.player;this.player=new g(this.container,{width:"100%",height:"100%",video:y,params:{controls:r,autoplay:this.props.playing,mute:this.props.muted,start:(0,l.parseStartTime)(e),origin:window.location.origin,...o.params},events:{apiready:this.props.onReady,seeked:()=>this.props.onSeek(this.player.currentTime),video_end:this.props.onEnded,durationchange:this.onDurationChange,pause:this.props.onPause,playing:this.props.onPlay,waiting:this.props.onBuffer,error:m=>a(m)}})},a)}play(){this.callPlayer("play")}pause(){this.callPlayer("pause")}stop(){}seekTo(e,r=!0){this.callPlayer("seek",e),r||this.pause()}setVolume(e){this.callPlayer("setVolume",e)}getDuration(){return this.player.duration||null}getCurrentTime(){return this.player.currentTime}getSecondsLoaded(){return this.player.bufferedTime}render(){const{display:e}=this.props,r={width:"100%",height:"100%",display:e};return c.default.createElement("div",{style:r},c.default.createElement("div",{ref:this.ref}))}}n(p,"displayName","DailyMotion");n(p,"canPlay",f.canPlay.dailymotion);n(p,"loopOnEnded",!0);const R=P(_),I=b({__proto__:null,default:R},[_]);export{I as D};
|