chainlit 2.7.0__py3-none-any.whl → 2.7.1__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-2.7.0.dist-info → chainlit-2.7.1.dist-info}/METADATA +1 -1
- chainlit-2.7.1.dist-info/RECORD +4 -0
- chainlit/__init__.py +0 -207
- chainlit/__main__.py +0 -4
- chainlit/_utils.py +0 -8
- chainlit/action.py +0 -33
- chainlit/auth/__init__.py +0 -95
- chainlit/auth/cookie.py +0 -197
- chainlit/auth/jwt.py +0 -42
- chainlit/cache.py +0 -45
- chainlit/callbacks.py +0 -433
- chainlit/chat_context.py +0 -64
- chainlit/chat_settings.py +0 -34
- chainlit/cli/__init__.py +0 -235
- chainlit/config.py +0 -621
- chainlit/context.py +0 -112
- chainlit/data/__init__.py +0 -111
- chainlit/data/acl.py +0 -19
- chainlit/data/base.py +0 -107
- chainlit/data/chainlit_data_layer.py +0 -687
- chainlit/data/dynamodb.py +0 -616
- chainlit/data/literalai.py +0 -501
- chainlit/data/sql_alchemy.py +0 -741
- chainlit/data/storage_clients/__init__.py +0 -0
- chainlit/data/storage_clients/azure.py +0 -84
- chainlit/data/storage_clients/azure_blob.py +0 -94
- chainlit/data/storage_clients/base.py +0 -28
- chainlit/data/storage_clients/gcs.py +0 -101
- chainlit/data/storage_clients/s3.py +0 -88
- chainlit/data/utils.py +0 -29
- chainlit/discord/__init__.py +0 -6
- chainlit/discord/app.py +0 -364
- chainlit/element.py +0 -454
- chainlit/emitter.py +0 -450
- chainlit/hello.py +0 -12
- chainlit/input_widget.py +0 -182
- chainlit/langchain/__init__.py +0 -6
- chainlit/langchain/callbacks.py +0 -682
- chainlit/langflow/__init__.py +0 -25
- chainlit/llama_index/__init__.py +0 -6
- chainlit/llama_index/callbacks.py +0 -206
- chainlit/logger.py +0 -16
- chainlit/markdown.py +0 -57
- chainlit/mcp.py +0 -99
- chainlit/message.py +0 -619
- chainlit/mistralai/__init__.py +0 -50
- chainlit/oauth_providers.py +0 -835
- chainlit/openai/__init__.py +0 -53
- chainlit/py.typed +0 -0
- chainlit/secret.py +0 -9
- chainlit/semantic_kernel/__init__.py +0 -111
- chainlit/server.py +0 -1616
- chainlit/session.py +0 -304
- chainlit/sidebar.py +0 -55
- chainlit/slack/__init__.py +0 -6
- chainlit/slack/app.py +0 -427
- chainlit/socket.py +0 -381
- chainlit/step.py +0 -490
- chainlit/sync.py +0 -43
- chainlit/teams/__init__.py +0 -6
- chainlit/teams/app.py +0 -348
- chainlit/translations/bn.json +0 -214
- chainlit/translations/el-GR.json +0 -214
- chainlit/translations/en-US.json +0 -214
- chainlit/translations/fr-FR.json +0 -214
- chainlit/translations/gu.json +0 -214
- chainlit/translations/he-IL.json +0 -214
- chainlit/translations/hi.json +0 -214
- chainlit/translations/ja.json +0 -214
- chainlit/translations/kn.json +0 -214
- chainlit/translations/ml.json +0 -214
- chainlit/translations/mr.json +0 -214
- chainlit/translations/nl.json +0 -214
- chainlit/translations/ta.json +0 -214
- chainlit/translations/te.json +0 -214
- chainlit/translations/zh-CN.json +0 -214
- chainlit/translations.py +0 -60
- chainlit/types.py +0 -334
- chainlit/user.py +0 -43
- chainlit/user_session.py +0 -153
- chainlit/utils.py +0 -173
- chainlit/version.py +0 -8
- chainlit-2.7.0.dist-info/RECORD +0 -84
- {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/WHEEL +0 -0
- {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/entry_points.txt +0 -0
chainlit/discord/app.py
DELETED
|
@@ -1,364 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import mimetypes
|
|
3
|
-
import re
|
|
4
|
-
import uuid
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
from io import BytesIO
|
|
7
|
-
from typing import TYPE_CHECKING, Dict, List, Optional, Union
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from discord.abc import MessageableChannel
|
|
11
|
-
|
|
12
|
-
import discord
|
|
13
|
-
import filetype
|
|
14
|
-
import httpx
|
|
15
|
-
from discord.ui import Button, View
|
|
16
|
-
|
|
17
|
-
from chainlit.config import config
|
|
18
|
-
from chainlit.context import ChainlitContext, HTTPSession, context, context_var
|
|
19
|
-
from chainlit.data import get_data_layer
|
|
20
|
-
from chainlit.element import Element, ElementDict
|
|
21
|
-
from chainlit.emitter import BaseChainlitEmitter
|
|
22
|
-
from chainlit.logger import logger
|
|
23
|
-
from chainlit.message import Message, StepDict
|
|
24
|
-
from chainlit.types import Feedback
|
|
25
|
-
from chainlit.user import PersistedUser, User
|
|
26
|
-
from chainlit.user_session import user_session
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class FeedbackView(View):
|
|
30
|
-
def __init__(self, step_id: str):
|
|
31
|
-
super().__init__(timeout=None)
|
|
32
|
-
self.step_id = step_id
|
|
33
|
-
|
|
34
|
-
@discord.ui.button(label="👎")
|
|
35
|
-
async def thumbs_down(self, interaction: discord.Interaction, button: Button):
|
|
36
|
-
if data_layer := get_data_layer():
|
|
37
|
-
try:
|
|
38
|
-
feedback = Feedback(forId=self.step_id, value=0)
|
|
39
|
-
await data_layer.upsert_feedback(feedback)
|
|
40
|
-
except Exception as e:
|
|
41
|
-
logger.error(f"Error upserting feedback: {e}")
|
|
42
|
-
if interaction.message:
|
|
43
|
-
await interaction.message.edit(view=None)
|
|
44
|
-
await interaction.message.add_reaction("👎")
|
|
45
|
-
|
|
46
|
-
@discord.ui.button(label="👍")
|
|
47
|
-
async def thumbs_up(self, interaction: discord.Interaction, button: Button):
|
|
48
|
-
if data_layer := get_data_layer():
|
|
49
|
-
try:
|
|
50
|
-
feedback = Feedback(forId=self.step_id, value=1)
|
|
51
|
-
await data_layer.upsert_feedback(feedback)
|
|
52
|
-
except Exception as e:
|
|
53
|
-
logger.error(f"Error upserting feedback: {e}")
|
|
54
|
-
if interaction.message:
|
|
55
|
-
await interaction.message.edit(view=None)
|
|
56
|
-
await interaction.message.add_reaction("👍")
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class DiscordEmitter(BaseChainlitEmitter):
|
|
60
|
-
def __init__(self, session: HTTPSession, channel: "MessageableChannel"):
|
|
61
|
-
super().__init__(session)
|
|
62
|
-
self.channel = channel
|
|
63
|
-
|
|
64
|
-
async def send_element(self, element_dict: ElementDict):
|
|
65
|
-
if element_dict.get("display") != "inline":
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
persisted_file = self.session.files.get(element_dict.get("chainlitKey") or "")
|
|
69
|
-
file: Optional[Union[BytesIO, str]] = None
|
|
70
|
-
mime: Optional[str] = None
|
|
71
|
-
|
|
72
|
-
if persisted_file:
|
|
73
|
-
file = str(persisted_file["path"])
|
|
74
|
-
mime = element_dict.get("mime")
|
|
75
|
-
elif file_url := element_dict.get("url"):
|
|
76
|
-
async with httpx.AsyncClient() as client:
|
|
77
|
-
response = await client.get(file_url)
|
|
78
|
-
if response.status_code == 200:
|
|
79
|
-
file = BytesIO(response.content)
|
|
80
|
-
mime = filetype.guess_mime(file)
|
|
81
|
-
|
|
82
|
-
if not file:
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
element_name: str = element_dict.get("name", "Untitled")
|
|
86
|
-
|
|
87
|
-
if mime:
|
|
88
|
-
file_extension = mimetypes.guess_extension(mime)
|
|
89
|
-
if file_extension:
|
|
90
|
-
element_name += file_extension
|
|
91
|
-
|
|
92
|
-
file_obj = discord.File(file, filename=element_name)
|
|
93
|
-
await self.channel.send(file=file_obj)
|
|
94
|
-
|
|
95
|
-
async def send_step(self, step_dict: StepDict):
|
|
96
|
-
if not step_dict["type"] == "assistant_message":
|
|
97
|
-
return
|
|
98
|
-
|
|
99
|
-
step_type = step_dict.get("type")
|
|
100
|
-
is_message = step_type in [
|
|
101
|
-
"user_message",
|
|
102
|
-
"assistant_message",
|
|
103
|
-
]
|
|
104
|
-
is_empty_output = not step_dict.get("output")
|
|
105
|
-
|
|
106
|
-
if is_empty_output or not is_message:
|
|
107
|
-
return
|
|
108
|
-
else:
|
|
109
|
-
enable_feedback = get_data_layer()
|
|
110
|
-
message = await self.channel.send(step_dict["output"])
|
|
111
|
-
|
|
112
|
-
if enable_feedback:
|
|
113
|
-
current_run = context.current_run
|
|
114
|
-
scorable_id = current_run.id if current_run else step_dict.get("id")
|
|
115
|
-
if not scorable_id:
|
|
116
|
-
return
|
|
117
|
-
view = FeedbackView(scorable_id)
|
|
118
|
-
await message.edit(view=view)
|
|
119
|
-
|
|
120
|
-
async def update_step(self, step_dict: StepDict):
|
|
121
|
-
if not step_dict["type"] == "assistant_message":
|
|
122
|
-
return
|
|
123
|
-
|
|
124
|
-
await self.send_step(step_dict)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
intents = discord.Intents.default()
|
|
128
|
-
intents.message_content = True
|
|
129
|
-
|
|
130
|
-
client = discord.Client(intents=intents)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def init_discord_context(
|
|
134
|
-
session: HTTPSession,
|
|
135
|
-
channel: "MessageableChannel",
|
|
136
|
-
message: discord.Message,
|
|
137
|
-
) -> ChainlitContext:
|
|
138
|
-
emitter = DiscordEmitter(session=session, channel=channel)
|
|
139
|
-
context = ChainlitContext(session=session, emitter=emitter)
|
|
140
|
-
context_var.set(context)
|
|
141
|
-
user_session.set("discord_message", message)
|
|
142
|
-
user_session.set("discord_channel", channel)
|
|
143
|
-
return context
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
users_by_discord_id: Dict[int, Union[User, PersistedUser]] = {}
|
|
147
|
-
|
|
148
|
-
USER_PREFIX = "discord_"
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
async def get_user(discord_user: Union[discord.User, discord.Member]):
|
|
152
|
-
if discord_user.id in users_by_discord_id:
|
|
153
|
-
return users_by_discord_id[discord_user.id]
|
|
154
|
-
|
|
155
|
-
metadata = {
|
|
156
|
-
"name": discord_user.name,
|
|
157
|
-
"id": discord_user.id,
|
|
158
|
-
}
|
|
159
|
-
user = User(identifier=USER_PREFIX + str(discord_user.name), metadata=metadata)
|
|
160
|
-
|
|
161
|
-
users_by_discord_id[discord_user.id] = user
|
|
162
|
-
|
|
163
|
-
if data_layer := get_data_layer():
|
|
164
|
-
try:
|
|
165
|
-
persisted_user = await data_layer.create_user(user)
|
|
166
|
-
if persisted_user:
|
|
167
|
-
users_by_discord_id[discord_user.id] = persisted_user
|
|
168
|
-
except Exception as e:
|
|
169
|
-
logger.error(f"Error creating user: {e}")
|
|
170
|
-
|
|
171
|
-
return users_by_discord_id[discord_user.id]
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
async def download_discord_file(url: str):
|
|
175
|
-
async with httpx.AsyncClient() as client:
|
|
176
|
-
response = await client.get(url)
|
|
177
|
-
if response.status_code == 200:
|
|
178
|
-
return response.content
|
|
179
|
-
else:
|
|
180
|
-
return None
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
async def download_discord_files(
|
|
184
|
-
session: HTTPSession, attachments: List[discord.Attachment]
|
|
185
|
-
):
|
|
186
|
-
download_coros = [
|
|
187
|
-
download_discord_file(attachment.url) for attachment in attachments
|
|
188
|
-
]
|
|
189
|
-
file_bytes_list = await asyncio.gather(*download_coros)
|
|
190
|
-
file_refs = []
|
|
191
|
-
for idx, file_bytes in enumerate(file_bytes_list):
|
|
192
|
-
if file_bytes:
|
|
193
|
-
name = attachments[idx].filename
|
|
194
|
-
mime_type = attachments[idx].content_type or "application/octet-stream"
|
|
195
|
-
file_ref = await session.persist_file(
|
|
196
|
-
name=name, mime=mime_type, content=file_bytes
|
|
197
|
-
)
|
|
198
|
-
file_refs.append(file_ref)
|
|
199
|
-
|
|
200
|
-
files_dicts = [
|
|
201
|
-
session.files[file["id"]] for file in file_refs if file["id"] in session.files
|
|
202
|
-
]
|
|
203
|
-
|
|
204
|
-
elements = [
|
|
205
|
-
Element.from_dict(
|
|
206
|
-
{
|
|
207
|
-
"id": file["id"],
|
|
208
|
-
"name": file["name"],
|
|
209
|
-
"path": str(file["path"]),
|
|
210
|
-
"chainlitKey": file["id"],
|
|
211
|
-
"display": "inline",
|
|
212
|
-
"type": Element.infer_type_from_mime(file["type"]),
|
|
213
|
-
}
|
|
214
|
-
)
|
|
215
|
-
for file in files_dicts
|
|
216
|
-
]
|
|
217
|
-
|
|
218
|
-
return elements
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def clean_content(message: discord.Message):
|
|
222
|
-
if not client.user:
|
|
223
|
-
return message.content
|
|
224
|
-
|
|
225
|
-
# Regex to find mentions of the bot
|
|
226
|
-
bot_mention = f"<@!?{client.user.id}>"
|
|
227
|
-
# Replace the bot's mention with nothing
|
|
228
|
-
return re.sub(bot_mention, "", message.content).strip()
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
async def process_discord_message(
|
|
232
|
-
message: discord.Message,
|
|
233
|
-
thread_id: str,
|
|
234
|
-
thread_name: str,
|
|
235
|
-
channel: "MessageableChannel",
|
|
236
|
-
bind_thread_to_user=False,
|
|
237
|
-
):
|
|
238
|
-
user = await get_user(message.author)
|
|
239
|
-
|
|
240
|
-
text = clean_content(message)
|
|
241
|
-
discord_files = message.attachments
|
|
242
|
-
|
|
243
|
-
session_id = str(uuid.uuid4())
|
|
244
|
-
session = HTTPSession(
|
|
245
|
-
id=session_id,
|
|
246
|
-
thread_id=thread_id,
|
|
247
|
-
user=user,
|
|
248
|
-
client_type="discord",
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
ctx = init_discord_context(
|
|
252
|
-
session=session,
|
|
253
|
-
channel=channel,
|
|
254
|
-
message=message,
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
file_elements = await download_discord_files(session, discord_files)
|
|
258
|
-
|
|
259
|
-
if on_chat_start := config.code.on_chat_start:
|
|
260
|
-
await on_chat_start()
|
|
261
|
-
|
|
262
|
-
msg = Message(
|
|
263
|
-
content=text,
|
|
264
|
-
elements=file_elements,
|
|
265
|
-
type="user_message",
|
|
266
|
-
author=user.metadata.get("name"),
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
await msg.send()
|
|
270
|
-
|
|
271
|
-
if on_message := config.code.on_message:
|
|
272
|
-
async with channel.typing():
|
|
273
|
-
await on_message(msg)
|
|
274
|
-
|
|
275
|
-
if on_chat_end := config.code.on_chat_end:
|
|
276
|
-
await on_chat_end()
|
|
277
|
-
|
|
278
|
-
if data_layer := get_data_layer():
|
|
279
|
-
user_id = None
|
|
280
|
-
if isinstance(user, PersistedUser):
|
|
281
|
-
user_id = user.id if bind_thread_to_user else None
|
|
282
|
-
|
|
283
|
-
try:
|
|
284
|
-
await data_layer.update_thread(
|
|
285
|
-
thread_id=thread_id,
|
|
286
|
-
name=thread_name,
|
|
287
|
-
metadata=ctx.session.to_persistable(),
|
|
288
|
-
user_id=user_id,
|
|
289
|
-
)
|
|
290
|
-
except Exception as e:
|
|
291
|
-
logger.error(f"Error updating thread: {e}")
|
|
292
|
-
|
|
293
|
-
await ctx.session.delete()
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
@client.event
|
|
297
|
-
async def on_ready():
|
|
298
|
-
logger.info(f"Logged in as {client.user}")
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
@client.event
|
|
302
|
-
async def on_message(message: discord.Message):
|
|
303
|
-
if not client.user or message.author == client.user:
|
|
304
|
-
return
|
|
305
|
-
|
|
306
|
-
is_dm = isinstance(message.channel, discord.DMChannel)
|
|
307
|
-
if not client.user.mentioned_in(message) and not is_dm:
|
|
308
|
-
return
|
|
309
|
-
|
|
310
|
-
thread_name: str = ""
|
|
311
|
-
thread_id: str = ""
|
|
312
|
-
bind_thread_to_user = False
|
|
313
|
-
channel = message.channel
|
|
314
|
-
|
|
315
|
-
if isinstance(message.channel, discord.Thread):
|
|
316
|
-
thread_name = f"{message.channel.name}"
|
|
317
|
-
thread_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, str(channel.id)))
|
|
318
|
-
elif isinstance(message.channel, discord.ForumChannel):
|
|
319
|
-
thread_name = f"{message.channel.name}"
|
|
320
|
-
thread_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, str(channel.id)))
|
|
321
|
-
elif isinstance(message.channel, discord.DMChannel):
|
|
322
|
-
thread_id = str(
|
|
323
|
-
uuid.uuid5(
|
|
324
|
-
uuid.NAMESPACE_DNS,
|
|
325
|
-
str(channel.id) + datetime.today().strftime("%Y-%m-%d"),
|
|
326
|
-
)
|
|
327
|
-
)
|
|
328
|
-
thread_name = (
|
|
329
|
-
f"{message.author} Discord DM {datetime.today().strftime('%Y-%m-%d')}"
|
|
330
|
-
)
|
|
331
|
-
bind_thread_to_user = True
|
|
332
|
-
elif isinstance(message.channel, discord.GroupChannel):
|
|
333
|
-
thread_id = str(
|
|
334
|
-
uuid.uuid5(
|
|
335
|
-
uuid.NAMESPACE_DNS,
|
|
336
|
-
str(channel.id) + datetime.today().strftime("%Y-%m-%d"),
|
|
337
|
-
)
|
|
338
|
-
)
|
|
339
|
-
thread_name = f"{message.channel.name}"
|
|
340
|
-
elif isinstance(message.channel, discord.TextChannel):
|
|
341
|
-
# Discord limits thread names to 100 characters and does not create
|
|
342
|
-
# threads from empty messages.
|
|
343
|
-
thread_id = str(
|
|
344
|
-
uuid.uuid5(
|
|
345
|
-
uuid.NAMESPACE_DNS,
|
|
346
|
-
str(channel.id) + datetime.today().strftime("%Y-%m-%d"),
|
|
347
|
-
)
|
|
348
|
-
)
|
|
349
|
-
discord_thread_name = clean_content(message)[:100] or "Untitled"
|
|
350
|
-
channel = await message.channel.create_thread(
|
|
351
|
-
name=discord_thread_name, message=message
|
|
352
|
-
)
|
|
353
|
-
thread_name = f"{channel.name}"
|
|
354
|
-
else:
|
|
355
|
-
logger.warning(f"Unsupported channel type: {message.channel.type}")
|
|
356
|
-
return
|
|
357
|
-
|
|
358
|
-
await process_discord_message(
|
|
359
|
-
message=message,
|
|
360
|
-
thread_id=thread_id,
|
|
361
|
-
thread_name=thread_name,
|
|
362
|
-
channel=channel,
|
|
363
|
-
bind_thread_to_user=bind_thread_to_user,
|
|
364
|
-
)
|