chainlit 1.0.401__py3-none-any.whl → 2.0.4__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 +98 -279
- chainlit/_utils.py +8 -0
- chainlit/action.py +12 -10
- chainlit/{auth.py → auth/__init__.py} +28 -36
- chainlit/auth/cookie.py +123 -0
- chainlit/auth/jwt.py +39 -0
- chainlit/cache.py +4 -6
- chainlit/callbacks.py +362 -0
- chainlit/chat_context.py +64 -0
- chainlit/chat_settings.py +3 -1
- chainlit/cli/__init__.py +77 -8
- chainlit/config.py +191 -102
- chainlit/context.py +42 -13
- chainlit/copilot/dist/index.js +8750 -903
- chainlit/data/__init__.py +101 -416
- chainlit/data/acl.py +6 -2
- chainlit/data/base.py +107 -0
- chainlit/data/chainlit_data_layer.py +614 -0
- chainlit/data/dynamodb.py +590 -0
- chainlit/data/literalai.py +500 -0
- chainlit/data/sql_alchemy.py +721 -0
- chainlit/data/storage_clients/__init__.py +0 -0
- chainlit/data/storage_clients/azure.py +81 -0
- chainlit/data/storage_clients/azure_blob.py +89 -0
- chainlit/data/storage_clients/base.py +26 -0
- chainlit/data/storage_clients/gcs.py +88 -0
- chainlit/data/storage_clients/s3.py +75 -0
- chainlit/data/utils.py +29 -0
- chainlit/discord/__init__.py +6 -0
- chainlit/discord/app.py +354 -0
- chainlit/element.py +91 -33
- chainlit/emitter.py +81 -29
- chainlit/frontend/dist/assets/DailyMotion-Ce9dQoqZ.js +1 -0
- chainlit/frontend/dist/assets/Dataframe-C1XonMcV.js +22 -0
- chainlit/frontend/dist/assets/Facebook-DVVt6lrr.js +1 -0
- chainlit/frontend/dist/assets/FilePlayer-c7stW4vz.js +1 -0
- chainlit/frontend/dist/assets/Kaltura-BmMmgorA.js +1 -0
- chainlit/frontend/dist/assets/Mixcloud-Cw8hDmiO.js +1 -0
- chainlit/frontend/dist/assets/Mux-DiRZfeUf.js +1 -0
- chainlit/frontend/dist/assets/Preview-6Jt2mRHx.js +1 -0
- chainlit/frontend/dist/assets/SoundCloud-DKwcT58_.js +1 -0
- chainlit/frontend/dist/assets/Streamable-BVdxrEeX.js +1 -0
- chainlit/frontend/dist/assets/Twitch-DFqZR7Gu.js +1 -0
- chainlit/frontend/dist/assets/Vidyard-0BQAAtVk.js +1 -0
- chainlit/frontend/dist/assets/Vimeo-CRFSH0Vu.js +1 -0
- chainlit/frontend/dist/assets/Wistia-CKrmdQaG.js +1 -0
- chainlit/frontend/dist/assets/YouTube-CQpL-rvU.js +1 -0
- chainlit/frontend/dist/assets/index-DQmLRKyv.css +1 -0
- chainlit/frontend/dist/assets/index-QdmxtIMQ.js +8665 -0
- chainlit/frontend/dist/assets/react-plotly-B9hvVpUG.js +3484 -0
- chainlit/frontend/dist/index.html +2 -4
- chainlit/haystack/callbacks.py +4 -7
- chainlit/input_widget.py +8 -4
- chainlit/langchain/callbacks.py +103 -68
- chainlit/langflow/__init__.py +1 -0
- chainlit/llama_index/callbacks.py +65 -40
- chainlit/markdown.py +22 -6
- chainlit/message.py +54 -56
- chainlit/mistralai/__init__.py +50 -0
- chainlit/oauth_providers.py +266 -8
- chainlit/openai/__init__.py +10 -18
- chainlit/secret.py +1 -1
- chainlit/server.py +789 -228
- chainlit/session.py +108 -90
- chainlit/slack/__init__.py +6 -0
- chainlit/slack/app.py +397 -0
- chainlit/socket.py +199 -116
- chainlit/step.py +141 -89
- chainlit/sync.py +2 -1
- chainlit/teams/__init__.py +6 -0
- chainlit/teams/app.py +338 -0
- chainlit/translations/bn.json +244 -0
- chainlit/translations/en-US.json +122 -8
- chainlit/translations/gu.json +244 -0
- chainlit/translations/he-IL.json +244 -0
- chainlit/translations/hi.json +244 -0
- chainlit/translations/ja.json +242 -0
- chainlit/translations/kn.json +244 -0
- chainlit/translations/ml.json +244 -0
- chainlit/translations/mr.json +244 -0
- chainlit/translations/nl-NL.json +242 -0
- chainlit/translations/ta.json +244 -0
- chainlit/translations/te.json +244 -0
- chainlit/translations/zh-CN.json +243 -0
- chainlit/translations.py +60 -0
- chainlit/types.py +133 -28
- chainlit/user.py +14 -3
- chainlit/user_session.py +6 -3
- chainlit/utils.py +52 -5
- chainlit/version.py +3 -2
- {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/METADATA +48 -50
- chainlit-2.0.4.dist-info/RECORD +107 -0
- chainlit/cli/utils.py +0 -24
- chainlit/frontend/dist/assets/index-9711593e.js +0 -723
- chainlit/frontend/dist/assets/index-d088547c.css +0 -1
- chainlit/frontend/dist/assets/react-plotly-d8762cc2.js +0 -3602
- chainlit/playground/__init__.py +0 -2
- chainlit/playground/config.py +0 -40
- chainlit/playground/provider.py +0 -108
- chainlit/playground/providers/__init__.py +0 -13
- chainlit/playground/providers/anthropic.py +0 -118
- chainlit/playground/providers/huggingface.py +0 -75
- chainlit/playground/providers/langchain.py +0 -89
- chainlit/playground/providers/openai.py +0 -408
- chainlit/playground/providers/vertexai.py +0 -171
- chainlit/translations/pt-BR.json +0 -155
- chainlit-1.0.401.dist-info/RECORD +0 -66
- /chainlit/copilot/dist/assets/{logo_dark-2a3cf740.svg → logo_dark-IkGJ_IwC.svg} +0 -0
- /chainlit/copilot/dist/assets/{logo_light-b078e7bc.svg → logo_light-Bb_IPh6r.svg} +0 -0
- /chainlit/frontend/dist/assets/{logo_dark-2a3cf740.svg → logo_dark-IkGJ_IwC.svg} +0 -0
- /chainlit/frontend/dist/assets/{logo_light-b078e7bc.svg → logo_light-Bb_IPh6r.svg} +0 -0
- {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/WHEEL +0 -0
- {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
{
|
|
2
|
+
"components": {
|
|
3
|
+
"atoms": {
|
|
4
|
+
"buttons": {
|
|
5
|
+
"userButton": {
|
|
6
|
+
"menu": {
|
|
7
|
+
"settings": "设置",
|
|
8
|
+
"settingsKey": "S",
|
|
9
|
+
"APIKeys": "API 密钥",
|
|
10
|
+
"logout": "登出"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"molecules": {
|
|
16
|
+
"newChatButton": {
|
|
17
|
+
"newChat": "新建对话"
|
|
18
|
+
},
|
|
19
|
+
"tasklist": {
|
|
20
|
+
"TaskList": {
|
|
21
|
+
"title": "\ud83d\uddd2\ufe0f 任务列表",
|
|
22
|
+
"loading": "加载中...",
|
|
23
|
+
"error": "发生错误"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"attachments": {
|
|
27
|
+
"cancelUpload": "取消上传",
|
|
28
|
+
"removeAttachment": "移除附件"
|
|
29
|
+
},
|
|
30
|
+
"newChatDialog": {
|
|
31
|
+
"createNewChat": "创建新对话?",
|
|
32
|
+
"clearChat": "这将清除当前消息并开始新的对话。",
|
|
33
|
+
"cancel": "取消",
|
|
34
|
+
"confirm": "确认"
|
|
35
|
+
},
|
|
36
|
+
"settingsModal": {
|
|
37
|
+
"settings": "设置",
|
|
38
|
+
"expandMessages": "展开消息",
|
|
39
|
+
"hideChainOfThought": "隐藏思考链",
|
|
40
|
+
"darkMode": "暗色模式"
|
|
41
|
+
},
|
|
42
|
+
"detailsButton": {
|
|
43
|
+
"using": "使用",
|
|
44
|
+
"used": "已用"
|
|
45
|
+
},
|
|
46
|
+
"auth": {
|
|
47
|
+
"authLogin": {
|
|
48
|
+
"title": "登录以访问应用。",
|
|
49
|
+
"form": {
|
|
50
|
+
"email": "电子邮箱地址",
|
|
51
|
+
"password": "密码",
|
|
52
|
+
"noAccount": "没有账户?",
|
|
53
|
+
"alreadyHaveAccount": "已有账户?",
|
|
54
|
+
"signup": "注册",
|
|
55
|
+
"signin": "登录",
|
|
56
|
+
"or": "或者",
|
|
57
|
+
"continue": "继续",
|
|
58
|
+
"forgotPassword": "忘记密码?",
|
|
59
|
+
"passwordMustContain": "您的密码必须包含:",
|
|
60
|
+
"emailRequired": "电子邮箱是必填项",
|
|
61
|
+
"passwordRequired": "密码是必填项"
|
|
62
|
+
},
|
|
63
|
+
"error": {
|
|
64
|
+
"default": "无法登录。",
|
|
65
|
+
"signin": "尝试使用不同的账户登录。",
|
|
66
|
+
"oauthsignin": "尝试使用不同的账户登录。",
|
|
67
|
+
"redirect_uri_mismatch": "重定向URI与OAuth应用配置不匹配。",
|
|
68
|
+
"oauthcallbackerror": "尝试使用不同的账户登录。",
|
|
69
|
+
"oauthcreateaccount": "尝试使用不同的账户登录。",
|
|
70
|
+
"emailcreateaccount": "尝试使用不同的账户登录。",
|
|
71
|
+
"callback": "尝试使用不同的账户登录。",
|
|
72
|
+
"oauthaccountnotlinked": "为了验证您的身份,请使用最初使用的同一账户登录。",
|
|
73
|
+
"emailsignin": "无法发送邮件。",
|
|
74
|
+
"emailverify": "请验证您的电子邮件,已发送一封新邮件。",
|
|
75
|
+
"credentialssignin": "登录失败。请检查您提供的详细信息是否正确。",
|
|
76
|
+
"sessionrequired": "请登录以访问此页面。"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"authVerifyEmail": {
|
|
80
|
+
"almostThere": "您快成功了!我们已向 ",
|
|
81
|
+
"verifyEmailLink": "请单击该邮件中的链接以完成注册。",
|
|
82
|
+
"didNotReceive": "没找到邮件?",
|
|
83
|
+
"resendEmail": "重新发送邮件",
|
|
84
|
+
"goBack": "返回",
|
|
85
|
+
"emailSent": "邮件已成功发送。",
|
|
86
|
+
"verifyEmail": "验证您的电子邮件地址"
|
|
87
|
+
},
|
|
88
|
+
"providerButton": {
|
|
89
|
+
"continue": "使用{{provider}}继续",
|
|
90
|
+
"signup": "使用{{provider}}注册"
|
|
91
|
+
},
|
|
92
|
+
"authResetPassword": {
|
|
93
|
+
"newPasswordRequired": "新密码是必填项",
|
|
94
|
+
"passwordsMustMatch": "密码必须一致",
|
|
95
|
+
"confirmPasswordRequired": "确认密码是必填项",
|
|
96
|
+
"newPassword": "新密码",
|
|
97
|
+
"confirmPassword": "确认密码",
|
|
98
|
+
"resetPassword": "重置密码"
|
|
99
|
+
},
|
|
100
|
+
"authForgotPassword": {
|
|
101
|
+
"email": "电子邮箱地址",
|
|
102
|
+
"emailRequired": "电子邮箱是必填项",
|
|
103
|
+
"emailSent": "请检查电子邮箱{{email}}以获取重置密码的指示。",
|
|
104
|
+
"enterEmail": "请输入您的电子邮箱地址,我们将发送重置密码的指示。",
|
|
105
|
+
"resendEmail": "重新发送邮件",
|
|
106
|
+
"continue": "继续",
|
|
107
|
+
"goBack": "返回"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"organisms": {
|
|
112
|
+
"chat": {
|
|
113
|
+
"history": {
|
|
114
|
+
"index": {
|
|
115
|
+
"showHistory": "显示历史",
|
|
116
|
+
"lastInputs": "最后输入",
|
|
117
|
+
"noInputs": "如此空旷...",
|
|
118
|
+
"loading": "加载中..."
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"inputBox": {
|
|
122
|
+
"input": {
|
|
123
|
+
"placeholder": "在这里输入您的消息..."
|
|
124
|
+
},
|
|
125
|
+
"speechButton": {
|
|
126
|
+
"start": "开始录音",
|
|
127
|
+
"stop": "停止录音",
|
|
128
|
+
"loading": "连接中"
|
|
129
|
+
},
|
|
130
|
+
"SubmitButton": {
|
|
131
|
+
"sendMessage": "发送消息",
|
|
132
|
+
"stopTask": "停止任务"
|
|
133
|
+
},
|
|
134
|
+
"UploadButton": {
|
|
135
|
+
"attachFiles": "附加文件"
|
|
136
|
+
},
|
|
137
|
+
"waterMark": {
|
|
138
|
+
"text": "使用"
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"Messages": {
|
|
142
|
+
"index": {
|
|
143
|
+
"running": "运行中",
|
|
144
|
+
"executedSuccessfully": "执行成功",
|
|
145
|
+
"failed": "失败",
|
|
146
|
+
"feedbackUpdated": "反馈更新",
|
|
147
|
+
"updating": "正在更新"
|
|
148
|
+
},
|
|
149
|
+
"copyButton": {
|
|
150
|
+
"copyToClipboard": "拷贝到剪贴板",
|
|
151
|
+
"copied": "已拷贝!"
|
|
152
|
+
},
|
|
153
|
+
"feedbackButton": {
|
|
154
|
+
"helpful": "Helpful",
|
|
155
|
+
"notHelpful": "Not helpful",
|
|
156
|
+
"editFeedback": "Edit feedback"
|
|
157
|
+
},
|
|
158
|
+
"feedbackDialog": {
|
|
159
|
+
"dialogTitle": "Add a comment",
|
|
160
|
+
"submitButton": "Submit feedback"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"dropScreen": {
|
|
164
|
+
"dropYourFilesHere": "在这里拖放您的文件"
|
|
165
|
+
},
|
|
166
|
+
"index": {
|
|
167
|
+
"failedToUpload": "上传失败",
|
|
168
|
+
"cancelledUploadOf": "取消上传",
|
|
169
|
+
"couldNotReachServer": "无法连接到服务器",
|
|
170
|
+
"continuingChat": "继续之前的对话"
|
|
171
|
+
},
|
|
172
|
+
"settings": {
|
|
173
|
+
"settingsPanel": "设置面板",
|
|
174
|
+
"reset": "重置",
|
|
175
|
+
"cancel": "取消",
|
|
176
|
+
"confirm": "确认"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"threadHistory": {
|
|
180
|
+
"sidebar": {
|
|
181
|
+
"filters": {
|
|
182
|
+
"FeedbackSelect": {
|
|
183
|
+
"feedbackAll": "反馈:全部",
|
|
184
|
+
"feedbackPositive": "反馈:正面",
|
|
185
|
+
"feedbackNegative": "反馈:负面"
|
|
186
|
+
},
|
|
187
|
+
"SearchBar": {
|
|
188
|
+
"search": "搜索"
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"DeleteThreadButton": {
|
|
192
|
+
"confirmMessage": "这将删除线程及其消息和元素。",
|
|
193
|
+
"cancel": "取消",
|
|
194
|
+
"confirm": "确认",
|
|
195
|
+
"deletingChat": "删除对话",
|
|
196
|
+
"chatDeleted": "对话已删除"
|
|
197
|
+
},
|
|
198
|
+
"index": {
|
|
199
|
+
"pastChats": "过往对话"
|
|
200
|
+
},
|
|
201
|
+
"ThreadList": {
|
|
202
|
+
"empty": "空的...",
|
|
203
|
+
"today": "今天",
|
|
204
|
+
"yesterday": "昨天",
|
|
205
|
+
"previous7days": "前7天",
|
|
206
|
+
"previous30days": "前30天"
|
|
207
|
+
},
|
|
208
|
+
"TriggerButton": {
|
|
209
|
+
"closeSidebar": "关闭侧边栏",
|
|
210
|
+
"openSidebar": "打开侧边栏"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"Thread": {
|
|
214
|
+
"backToChat": "返回对话",
|
|
215
|
+
"chatCreatedOn": "此对话创建于"
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
"header": {
|
|
219
|
+
"chat": "对话",
|
|
220
|
+
"readme": "说明"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
"hooks": {
|
|
225
|
+
"useLLMProviders": {
|
|
226
|
+
"failedToFetchProviders": "获取提供者失败:"
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"pages": {
|
|
230
|
+
"Design": {},
|
|
231
|
+
"Env": {
|
|
232
|
+
"savedSuccessfully": "保存成功",
|
|
233
|
+
"requiredApiKeys": "必需的API密钥",
|
|
234
|
+
"requiredApiKeysInfo": "要使用此应用,需要以下API密钥。这些密钥存储在您的设备本地存储中。"
|
|
235
|
+
},
|
|
236
|
+
"Page": {
|
|
237
|
+
"notPartOfProject": "您不是此项目的一部分。"
|
|
238
|
+
},
|
|
239
|
+
"ResumeButton": {
|
|
240
|
+
"resumeChat": "恢复对话"
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
chainlit/translations.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# TODO:
|
|
2
|
+
# - Support linting plural
|
|
3
|
+
# - Support interpolation
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def compare_json_structures(truth, to_compare, path=""):
|
|
7
|
+
"""
|
|
8
|
+
Compare the structure of two deeply nested JSON objects.
|
|
9
|
+
Args:
|
|
10
|
+
truth (dict): The 'truth' JSON object.
|
|
11
|
+
to_compare (dict): The 'to_compare' JSON object.
|
|
12
|
+
path (str): The current path for error reporting (used internally).
|
|
13
|
+
Returns:
|
|
14
|
+
A list of differences found.
|
|
15
|
+
"""
|
|
16
|
+
if not isinstance(truth, dict) or not isinstance(to_compare, dict):
|
|
17
|
+
raise ValueError("Both inputs must be dictionaries.")
|
|
18
|
+
|
|
19
|
+
errors = []
|
|
20
|
+
|
|
21
|
+
truth_keys = set(truth.keys())
|
|
22
|
+
to_compare_keys = set(to_compare.keys())
|
|
23
|
+
|
|
24
|
+
extra_keys = to_compare_keys - truth_keys
|
|
25
|
+
missing_keys = truth_keys - to_compare_keys
|
|
26
|
+
|
|
27
|
+
for key in extra_keys:
|
|
28
|
+
errors.append(f"⚠️ Extra key: '{path + '.' + key if path else key}'")
|
|
29
|
+
|
|
30
|
+
for key in missing_keys:
|
|
31
|
+
errors.append(f"❌ Missing key: '{path + '.' + key if path else key}'")
|
|
32
|
+
|
|
33
|
+
for key in truth_keys & to_compare_keys:
|
|
34
|
+
if isinstance(truth[key], dict) and isinstance(to_compare[key], dict):
|
|
35
|
+
# Recursive call to navigate through nested dictionaries
|
|
36
|
+
errors += compare_json_structures(
|
|
37
|
+
truth[key], to_compare[key], path + "." + key if path else key
|
|
38
|
+
)
|
|
39
|
+
elif not isinstance(truth[key], dict) and not isinstance(to_compare[key], dict):
|
|
40
|
+
# If both are not dicts, we are at leaf nodes and structure matches; skip value comparison
|
|
41
|
+
continue
|
|
42
|
+
else:
|
|
43
|
+
# Structure mismatch: one is a dict, the other is not
|
|
44
|
+
errors.append(
|
|
45
|
+
f"❌ Structure mismatch at: '{path + '.' + key if path else key}'"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
return errors
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def lint_translation_json(file, truth, to_compare):
|
|
52
|
+
print(f"\nLinting {file}...")
|
|
53
|
+
|
|
54
|
+
errors = compare_json_structures(truth, to_compare)
|
|
55
|
+
|
|
56
|
+
if errors:
|
|
57
|
+
for error in errors:
|
|
58
|
+
print(f"{error}")
|
|
59
|
+
else:
|
|
60
|
+
print(f"✅ No errors found in {file}")
|
chainlit/types.py
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import (
|
|
4
|
+
TYPE_CHECKING,
|
|
5
|
+
Any,
|
|
6
|
+
Dict,
|
|
7
|
+
Generic,
|
|
8
|
+
List,
|
|
9
|
+
Literal,
|
|
10
|
+
Optional,
|
|
11
|
+
Protocol,
|
|
12
|
+
TypedDict,
|
|
13
|
+
TypeVar,
|
|
14
|
+
Union,
|
|
15
|
+
)
|
|
3
16
|
|
|
4
17
|
if TYPE_CHECKING:
|
|
5
18
|
from chainlit.element import ElementDict
|
|
6
|
-
from chainlit.user import UserDict
|
|
7
19
|
from chainlit.step import StepDict
|
|
8
20
|
|
|
9
21
|
from dataclasses_json import DataClassJsonMixin
|
|
10
|
-
from literalai import ChatGeneration, CompletionGeneration
|
|
11
22
|
from pydantic import BaseModel
|
|
12
23
|
from pydantic.dataclasses import dataclass
|
|
13
24
|
|
|
@@ -20,7 +31,8 @@ class ThreadDict(TypedDict):
|
|
|
20
31
|
id: str
|
|
21
32
|
createdAt: str
|
|
22
33
|
name: Optional[str]
|
|
23
|
-
|
|
34
|
+
userId: Optional[str]
|
|
35
|
+
userIdentifier: Optional[str]
|
|
24
36
|
tags: Optional[List[str]]
|
|
25
37
|
metadata: Optional[Dict]
|
|
26
38
|
steps: List["StepDict"]
|
|
@@ -33,11 +45,68 @@ class Pagination(BaseModel):
|
|
|
33
45
|
|
|
34
46
|
|
|
35
47
|
class ThreadFilter(BaseModel):
|
|
36
|
-
feedback: Optional[Literal[
|
|
37
|
-
|
|
48
|
+
feedback: Optional[Literal[0, 1]] = None
|
|
49
|
+
userId: Optional[str] = None
|
|
38
50
|
search: Optional[str] = None
|
|
39
51
|
|
|
40
52
|
|
|
53
|
+
@dataclass
|
|
54
|
+
class PageInfo:
|
|
55
|
+
hasNextPage: bool
|
|
56
|
+
startCursor: Optional[str]
|
|
57
|
+
endCursor: Optional[str]
|
|
58
|
+
|
|
59
|
+
def to_dict(self):
|
|
60
|
+
return {
|
|
61
|
+
"hasNextPage": self.hasNextPage,
|
|
62
|
+
"startCursor": self.startCursor,
|
|
63
|
+
"endCursor": self.endCursor,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def from_dict(cls, page_info_dict: Dict) -> "PageInfo":
|
|
68
|
+
hasNextPage = page_info_dict.get("hasNextPage", False)
|
|
69
|
+
startCursor = page_info_dict.get("startCursor", None)
|
|
70
|
+
endCursor = page_info_dict.get("endCursor", None)
|
|
71
|
+
return cls(
|
|
72
|
+
hasNextPage=hasNextPage, startCursor=startCursor, endCursor=endCursor
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
T = TypeVar("T", covariant=True)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class HasFromDict(Protocol[T]):
|
|
80
|
+
@classmethod
|
|
81
|
+
def from_dict(cls, obj_dict: Any) -> T:
|
|
82
|
+
raise NotImplementedError
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class PaginatedResponse(Generic[T]):
|
|
87
|
+
pageInfo: PageInfo
|
|
88
|
+
data: List[T]
|
|
89
|
+
|
|
90
|
+
def to_dict(self):
|
|
91
|
+
return {
|
|
92
|
+
"pageInfo": self.pageInfo.to_dict(),
|
|
93
|
+
"data": [
|
|
94
|
+
(d.to_dict() if hasattr(d, "to_dict") and callable(d.to_dict) else d)
|
|
95
|
+
for d in self.data
|
|
96
|
+
],
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def from_dict(
|
|
101
|
+
cls, paginated_response_dict: Dict, the_class: HasFromDict[T]
|
|
102
|
+
) -> "PaginatedResponse[T]":
|
|
103
|
+
pageInfo = PageInfo.from_dict(paginated_response_dict.get("pageInfo", {}))
|
|
104
|
+
|
|
105
|
+
data = [the_class.from_dict(d) for d in paginated_response_dict.get("data", [])]
|
|
106
|
+
|
|
107
|
+
return cls(pageInfo=pageInfo, data=data)
|
|
108
|
+
|
|
109
|
+
|
|
41
110
|
@dataclass
|
|
42
111
|
class FileSpec(DataClassJsonMixin):
|
|
43
112
|
accept: Union[List[str], Dict[str, List[str]]]
|
|
@@ -75,16 +144,37 @@ class FileReference(TypedDict):
|
|
|
75
144
|
class FileDict(TypedDict):
|
|
76
145
|
id: str
|
|
77
146
|
name: str
|
|
78
|
-
path:
|
|
147
|
+
path: Path
|
|
79
148
|
size: int
|
|
80
149
|
type: str
|
|
81
150
|
|
|
82
151
|
|
|
83
|
-
class
|
|
152
|
+
class MessagePayload(TypedDict):
|
|
84
153
|
message: "StepDict"
|
|
85
154
|
fileReferences: Optional[List[FileReference]]
|
|
86
155
|
|
|
87
156
|
|
|
157
|
+
class InputAudioChunkPayload(TypedDict):
|
|
158
|
+
isStart: bool
|
|
159
|
+
mimeType: str
|
|
160
|
+
elapsedTime: float
|
|
161
|
+
data: bytes
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@dataclass
|
|
165
|
+
class InputAudioChunk:
|
|
166
|
+
isStart: bool
|
|
167
|
+
mimeType: str
|
|
168
|
+
elapsedTime: float
|
|
169
|
+
data: bytes
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class OutputAudioChunk(TypedDict):
|
|
173
|
+
track: str
|
|
174
|
+
mimeType: str
|
|
175
|
+
data: bytes
|
|
176
|
+
|
|
177
|
+
|
|
88
178
|
@dataclass
|
|
89
179
|
class AskFileResponse:
|
|
90
180
|
id: str
|
|
@@ -96,43 +186,55 @@ class AskFileResponse:
|
|
|
96
186
|
|
|
97
187
|
class AskActionResponse(TypedDict):
|
|
98
188
|
name: str
|
|
99
|
-
|
|
189
|
+
payload: Dict
|
|
100
190
|
label: str
|
|
101
|
-
|
|
191
|
+
tooltip: str
|
|
102
192
|
forId: str
|
|
103
193
|
id: str
|
|
104
|
-
collapsed: bool
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class GenerationRequest(BaseModel):
|
|
108
|
-
chatGeneration: Optional[ChatGeneration] = None
|
|
109
|
-
completionGeneration: Optional[CompletionGeneration] = None
|
|
110
|
-
userEnv: Dict[str, str]
|
|
111
194
|
|
|
112
|
-
@property
|
|
113
|
-
def generation(self):
|
|
114
|
-
if self.chatGeneration:
|
|
115
|
-
return self.chatGeneration
|
|
116
|
-
return self.completionGeneration
|
|
117
195
|
|
|
118
|
-
|
|
119
|
-
|
|
196
|
+
class UpdateThreadRequest(BaseModel):
|
|
197
|
+
threadId: str
|
|
198
|
+
name: str
|
|
120
199
|
|
|
121
200
|
|
|
122
201
|
class DeleteThreadRequest(BaseModel):
|
|
123
202
|
threadId: str
|
|
124
203
|
|
|
125
204
|
|
|
205
|
+
class DeleteFeedbackRequest(BaseModel):
|
|
206
|
+
feedbackId: str
|
|
207
|
+
|
|
208
|
+
|
|
126
209
|
class GetThreadsRequest(BaseModel):
|
|
127
210
|
pagination: Pagination
|
|
128
211
|
filter: ThreadFilter
|
|
129
212
|
|
|
130
213
|
|
|
214
|
+
class CallActionRequest(BaseModel):
|
|
215
|
+
action: Dict
|
|
216
|
+
sessionId: str
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class ElementRequest(BaseModel):
|
|
220
|
+
element: Dict
|
|
221
|
+
sessionId: str
|
|
222
|
+
|
|
223
|
+
|
|
131
224
|
class Theme(str, Enum):
|
|
132
225
|
light = "light"
|
|
133
226
|
dark = "dark"
|
|
134
227
|
|
|
135
228
|
|
|
229
|
+
@dataclass
|
|
230
|
+
class Starter(DataClassJsonMixin):
|
|
231
|
+
"""Specification for a starter that can be chosen by the user at the thread start."""
|
|
232
|
+
|
|
233
|
+
label: str
|
|
234
|
+
message: str
|
|
235
|
+
icon: Optional[str] = None
|
|
236
|
+
|
|
237
|
+
|
|
136
238
|
@dataclass
|
|
137
239
|
class ChatProfile(DataClassJsonMixin):
|
|
138
240
|
"""Specification for a chat profile that can be chosen by the user at the thread start."""
|
|
@@ -140,22 +242,25 @@ class ChatProfile(DataClassJsonMixin):
|
|
|
140
242
|
name: str
|
|
141
243
|
markdown_description: str
|
|
142
244
|
icon: Optional[str] = None
|
|
245
|
+
default: bool = False
|
|
246
|
+
starters: Optional[List[Starter]] = None
|
|
143
247
|
|
|
144
248
|
|
|
145
249
|
FeedbackStrategy = Literal["BINARY"]
|
|
146
250
|
|
|
147
251
|
|
|
148
252
|
class FeedbackDict(TypedDict):
|
|
149
|
-
|
|
150
|
-
|
|
253
|
+
forId: str
|
|
254
|
+
id: Optional[str]
|
|
255
|
+
value: Literal[0, 1]
|
|
151
256
|
comment: Optional[str]
|
|
152
257
|
|
|
153
258
|
|
|
154
259
|
@dataclass
|
|
155
260
|
class Feedback:
|
|
156
261
|
forId: str
|
|
157
|
-
value: Literal[
|
|
158
|
-
|
|
262
|
+
value: Literal[0, 1]
|
|
263
|
+
threadId: Optional[str] = None
|
|
159
264
|
id: Optional[str] = None
|
|
160
265
|
comment: Optional[str] = None
|
|
161
266
|
|
chainlit/user.py
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
|
-
from typing import Dict, Literal, TypedDict
|
|
1
|
+
from typing import Dict, Literal, Optional, TypedDict
|
|
2
2
|
|
|
3
3
|
from dataclasses_json import DataClassJsonMixin
|
|
4
|
-
from pydantic
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
from pydantic.dataclasses import dataclass
|
|
5
6
|
|
|
6
7
|
Provider = Literal[
|
|
7
|
-
"credentials",
|
|
8
|
+
"credentials",
|
|
9
|
+
"header",
|
|
10
|
+
"github",
|
|
11
|
+
"google",
|
|
12
|
+
"azure-ad",
|
|
13
|
+
"azure-ad-hybrid",
|
|
14
|
+
"okta",
|
|
15
|
+
"auth0",
|
|
16
|
+
"descope",
|
|
8
17
|
]
|
|
9
18
|
|
|
10
19
|
|
|
11
20
|
class UserDict(TypedDict):
|
|
12
21
|
id: str
|
|
13
22
|
identifier: str
|
|
23
|
+
display_name: Optional[str]
|
|
14
24
|
metadata: Dict
|
|
15
25
|
|
|
16
26
|
|
|
@@ -18,6 +28,7 @@ class UserDict(TypedDict):
|
|
|
18
28
|
@dataclass
|
|
19
29
|
class User(DataClassJsonMixin):
|
|
20
30
|
identifier: str
|
|
31
|
+
display_name: Optional[str] = None
|
|
21
32
|
metadata: Dict = Field(default_factory=dict)
|
|
22
33
|
|
|
23
34
|
|
chainlit/user_session.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Dict
|
|
2
2
|
|
|
3
|
-
from chainlit.context import context
|
|
3
|
+
from chainlit.context import WebsocketSession, context
|
|
4
4
|
|
|
5
5
|
user_sessions: Dict[str, Dict] = {}
|
|
6
6
|
|
|
@@ -27,9 +27,12 @@ class UserSession:
|
|
|
27
27
|
user_session["chat_settings"] = context.session.chat_settings
|
|
28
28
|
user_session["user"] = context.session.user
|
|
29
29
|
user_session["chat_profile"] = context.session.chat_profile
|
|
30
|
+
user_session["http_referer"] = context.session.http_referer
|
|
31
|
+
user_session["client_type"] = context.session.client_type
|
|
32
|
+
user_session["http_cookie"] = context.session.http_cookie
|
|
30
33
|
|
|
31
|
-
if context.session
|
|
32
|
-
user_session["
|
|
34
|
+
if isinstance(context.session, WebsocketSession):
|
|
35
|
+
user_session["languages"] = context.session.languages
|
|
33
36
|
|
|
34
37
|
return user_session.get(key, default)
|
|
35
38
|
|
chainlit/utils.py
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import importlib
|
|
3
3
|
import inspect
|
|
4
|
+
import os
|
|
5
|
+
from asyncio import CancelledError
|
|
4
6
|
from typing import Callable
|
|
5
7
|
|
|
8
|
+
import click
|
|
9
|
+
from fastapi import FastAPI
|
|
10
|
+
from packaging import version
|
|
11
|
+
|
|
12
|
+
from chainlit.auth import ensure_jwt_secret
|
|
6
13
|
from chainlit.context import context
|
|
7
14
|
from chainlit.logger import logger
|
|
8
15
|
from chainlit.message import ErrorMessage
|
|
9
|
-
from packaging import version
|
|
10
16
|
|
|
11
17
|
|
|
12
18
|
def wrap_user_function(user_function: Callable, with_task=False) -> Callable:
|
|
@@ -39,13 +45,14 @@ def wrap_user_function(user_function: Callable, with_task=False) -> Callable:
|
|
|
39
45
|
return await user_function(**params_values)
|
|
40
46
|
else:
|
|
41
47
|
return user_function(**params_values)
|
|
42
|
-
except
|
|
48
|
+
except CancelledError:
|
|
43
49
|
pass
|
|
44
50
|
except Exception as e:
|
|
45
51
|
logger.exception(e)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
if with_task:
|
|
53
|
+
await ErrorMessage(
|
|
54
|
+
content=str(e) or e.__class__.__name__, author="Error"
|
|
55
|
+
).send()
|
|
49
56
|
finally:
|
|
50
57
|
if with_task:
|
|
51
58
|
await context.emitter.task_end()
|
|
@@ -85,3 +92,43 @@ def check_module_version(name, required_version):
|
|
|
85
92
|
except ModuleNotFoundError:
|
|
86
93
|
return False
|
|
87
94
|
return version.parse(module.__version__) >= version.parse(required_version)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def check_file(target: str):
|
|
98
|
+
# Define accepted file extensions for Chainlit
|
|
99
|
+
ACCEPTED_FILE_EXTENSIONS = ("py", "py3")
|
|
100
|
+
|
|
101
|
+
_, extension = os.path.splitext(target)
|
|
102
|
+
|
|
103
|
+
# Check file extension
|
|
104
|
+
if extension[1:] not in ACCEPTED_FILE_EXTENSIONS:
|
|
105
|
+
if extension[1:] == "":
|
|
106
|
+
raise click.BadArgumentUsage(
|
|
107
|
+
"Chainlit requires raw Python (.py) files, but the provided file has no extension."
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
raise click.BadArgumentUsage(
|
|
111
|
+
f"Chainlit requires raw Python (.py) files, not {extension}."
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if not os.path.exists(target):
|
|
115
|
+
raise click.BadParameter(f"File does not exist: {target}")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def mount_chainlit(app: FastAPI, target: str, path="/chainlit"):
|
|
119
|
+
os.environ["CHAINLIT_ROOT_PATH"] = path
|
|
120
|
+
os.environ["CHAINLIT_SUBMOUNT"] = "true"
|
|
121
|
+
from chainlit.config import config, load_module
|
|
122
|
+
from chainlit.server import app as chainlit_app
|
|
123
|
+
|
|
124
|
+
config.run.root_path = path
|
|
125
|
+
config.run.debug = os.environ.get("CHAINLIT_DEBUG", False)
|
|
126
|
+
|
|
127
|
+
check_file(target)
|
|
128
|
+
# Load the module provided by the user
|
|
129
|
+
config.run.module_name = target
|
|
130
|
+
load_module(config.run.module_name)
|
|
131
|
+
|
|
132
|
+
ensure_jwt_secret()
|
|
133
|
+
|
|
134
|
+
app.mount(path, chainlit_app)
|