chainlit 1.1.202__py3-none-any.whl → 1.1.300__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 +22 -4
- chainlit/cli/__init__.py +53 -6
- chainlit/config.py +25 -18
- chainlit/context.py +9 -0
- chainlit/copilot/dist/index.js +443 -410
- chainlit/data/__init__.py +19 -5
- chainlit/data/dynamodb.py +586 -0
- chainlit/data/sql_alchemy.py +47 -28
- chainlit/discord/app.py +4 -2
- chainlit/element.py +36 -20
- chainlit/emitter.py +8 -7
- chainlit/frontend/dist/assets/{DailyMotion-53376209.js → DailyMotion-578b63e6.js} +1 -1
- chainlit/frontend/dist/assets/{Facebook-aee41f5b.js → Facebook-b825e5bb.js} +1 -1
- chainlit/frontend/dist/assets/{FilePlayer-b2cdb30f.js → FilePlayer-bcba3b4e.js} +1 -1
- chainlit/frontend/dist/assets/{Kaltura-51db0377.js → Kaltura-fc1c9497.js} +1 -1
- chainlit/frontend/dist/assets/{Mixcloud-cb900886.js → Mixcloud-4cfb2724.js} +1 -1
- chainlit/frontend/dist/assets/{Mux-79ac59e6.js → Mux-aa92055c.js} +1 -1
- chainlit/frontend/dist/assets/{Preview-cfe7584c.js → Preview-9f55905a.js} +1 -1
- chainlit/frontend/dist/assets/{SoundCloud-a985707c.js → SoundCloud-f991fe03.js} +1 -1
- chainlit/frontend/dist/assets/{Streamable-3d89aab5.js → Streamable-53128f49.js} +1 -1
- chainlit/frontend/dist/assets/{Twitch-bf016588.js → Twitch-fce8b9f5.js} +1 -1
- chainlit/frontend/dist/assets/{Vidyard-1891ecd7.js → Vidyard-e35c6102.js} +1 -1
- chainlit/frontend/dist/assets/{Vimeo-0645662c.js → Vimeo-fff35f8e.js} +1 -1
- chainlit/frontend/dist/assets/{Wistia-3b449fe2.js → Wistia-ec07dc64.js} +1 -1
- chainlit/frontend/dist/assets/{YouTube-5ea2381e.js → YouTube-ad068e2a.js} +1 -1
- chainlit/frontend/dist/assets/index-aaf974a9.css +1 -0
- chainlit/frontend/dist/assets/index-d40d41cc.js +727 -0
- chainlit/frontend/dist/assets/{react-plotly-2ff19c9f.js → react-plotly-b2c6442b.js} +1 -1
- chainlit/frontend/dist/index.html +2 -3
- chainlit/langchain/callbacks.py +4 -2
- chainlit/llama_index/callbacks.py +2 -2
- chainlit/message.py +30 -25
- chainlit/oauth_providers.py +118 -0
- chainlit/server.py +208 -83
- chainlit/slack/app.py +2 -3
- chainlit/socket.py +27 -23
- chainlit/step.py +44 -30
- chainlit/teams/__init__.py +6 -0
- chainlit/teams/app.py +332 -0
- chainlit/translations/en-US.json +2 -4
- chainlit/types.py +17 -17
- chainlit/user.py +9 -1
- chainlit/utils.py +47 -3
- {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/METADATA +22 -14
- chainlit-1.1.300.dist-info/RECORD +79 -0
- chainlit/cli/utils.py +0 -24
- chainlit/frontend/dist/assets/index-a0c5a67e.js +0 -698
- chainlit/frontend/dist/assets/index-d088547c.css +0 -1
- chainlit/playground/__init__.py +0 -2
- chainlit/playground/config.py +0 -36
- chainlit/playground/provider.py +0 -108
- chainlit/playground/providers/__init__.py +0 -11
- 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 -386
- chainlit/playground/providers/vertexai.py +0 -171
- chainlit-1.1.202.dist-info/RECORD +0 -86
- {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/WHEEL +0 -0
- {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/entry_points.txt +0 -0
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<!-- TAG INJECTION PLACEHOLDER -->
|
|
7
|
-
<link rel="icon" href="/favicon" />
|
|
8
7
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
9
|
<!-- FONT START -->
|
|
@@ -22,8 +21,8 @@
|
|
|
22
21
|
<script>
|
|
23
22
|
const global = globalThis;
|
|
24
23
|
</script>
|
|
25
|
-
<script type="module" crossorigin src="/assets/index-
|
|
26
|
-
<link rel="stylesheet" href="/assets/index-
|
|
24
|
+
<script type="module" crossorigin src="/assets/index-d40d41cc.js"></script>
|
|
25
|
+
<link rel="stylesheet" href="/assets/index-aaf974a9.css">
|
|
27
26
|
</head>
|
|
28
27
|
<body>
|
|
29
28
|
<div id="root"></div>
|
chainlit/langchain/callbacks.py
CHANGED
|
@@ -456,7 +456,7 @@ class LangchainTracer(BaseTracer, GenerationHelper, FinalStreamHelper):
|
|
|
456
456
|
elif run.run_type == "llm":
|
|
457
457
|
step_type = "llm"
|
|
458
458
|
elif run.run_type == "retriever":
|
|
459
|
-
step_type = "
|
|
459
|
+
step_type = "tool"
|
|
460
460
|
elif run.run_type == "tool":
|
|
461
461
|
step_type = "tool"
|
|
462
462
|
elif run.run_type == "embedding":
|
|
@@ -533,7 +533,9 @@ class LangchainTracer(BaseTracer, GenerationHelper, FinalStreamHelper):
|
|
|
533
533
|
break
|
|
534
534
|
|
|
535
535
|
current_step.language = "json"
|
|
536
|
-
current_step.output = json.dumps(
|
|
536
|
+
current_step.output = json.dumps(
|
|
537
|
+
message_completion, indent=4, ensure_ascii=False
|
|
538
|
+
)
|
|
537
539
|
else:
|
|
538
540
|
completion_start = self.completion_generations[str(run.id)]
|
|
539
541
|
completion = generation.get("text", "")
|
|
@@ -73,9 +73,9 @@ class LlamaIndexCallbackHandler(TokenCountingHandler):
|
|
|
73
73
|
|
|
74
74
|
step_type: StepType = "undefined"
|
|
75
75
|
if event_type == CBEventType.RETRIEVE:
|
|
76
|
-
step_type = "
|
|
76
|
+
step_type = "tool"
|
|
77
77
|
elif event_type == CBEventType.QUERY:
|
|
78
|
-
step_type = "
|
|
78
|
+
step_type = "tool"
|
|
79
79
|
elif event_type == CBEventType.LLM:
|
|
80
80
|
step_type = "llm"
|
|
81
81
|
else:
|
chainlit/message.py
CHANGED
|
@@ -7,7 +7,7 @@ from typing import Dict, List, Optional, Union, cast
|
|
|
7
7
|
|
|
8
8
|
from chainlit.action import Action
|
|
9
9
|
from chainlit.config import config
|
|
10
|
-
from chainlit.context import context
|
|
10
|
+
from chainlit.context import context, local_steps
|
|
11
11
|
from chainlit.data import get_data_layer
|
|
12
12
|
from chainlit.element import ElementBased
|
|
13
13
|
from chainlit.logger import logger
|
|
@@ -21,7 +21,6 @@ from chainlit.types import (
|
|
|
21
21
|
AskSpec,
|
|
22
22
|
FileDict,
|
|
23
23
|
)
|
|
24
|
-
from literalai import BaseGeneration
|
|
25
24
|
from literalai.helper import utc_now
|
|
26
25
|
from literalai.step import MessageStepType
|
|
27
26
|
|
|
@@ -38,17 +37,22 @@ class MessageBase(ABC):
|
|
|
38
37
|
fail_on_persist_error: bool = False
|
|
39
38
|
persisted = False
|
|
40
39
|
is_error = False
|
|
40
|
+
parent_id: Optional[str] = None
|
|
41
41
|
language: Optional[str] = None
|
|
42
42
|
metadata: Optional[Dict] = None
|
|
43
43
|
tags: Optional[List[str]] = None
|
|
44
44
|
wait_for_answer = False
|
|
45
45
|
indent: Optional[int] = None
|
|
46
|
-
generation: Optional[BaseGeneration] = None
|
|
47
46
|
|
|
48
47
|
def __post_init__(self) -> None:
|
|
49
48
|
trace_event(f"init {self.__class__.__name__}")
|
|
50
49
|
self.thread_id = context.session.thread_id
|
|
51
50
|
|
|
51
|
+
previous_steps = local_steps.get() or []
|
|
52
|
+
parent_step = previous_steps[-1] if previous_steps else None
|
|
53
|
+
if parent_step:
|
|
54
|
+
self.parent_id = parent_step.id
|
|
55
|
+
|
|
52
56
|
if not getattr(self, "id", None):
|
|
53
57
|
self.id = str(uuid.uuid4())
|
|
54
58
|
|
|
@@ -57,6 +61,7 @@ class MessageBase(ABC):
|
|
|
57
61
|
type = _dict.get("type", "assistant_message")
|
|
58
62
|
message = Message(
|
|
59
63
|
id=_dict["id"],
|
|
64
|
+
parent_id=_dict.get("parentId"),
|
|
60
65
|
created_at=_dict["createdAt"],
|
|
61
66
|
content=_dict["output"],
|
|
62
67
|
author=_dict.get("name", config.ui.name),
|
|
@@ -71,6 +76,7 @@ class MessageBase(ABC):
|
|
|
71
76
|
_dict: StepDict = {
|
|
72
77
|
"id": self.id,
|
|
73
78
|
"threadId": self.thread_id,
|
|
79
|
+
"parentId": self.parent_id,
|
|
74
80
|
"createdAt": self.created_at,
|
|
75
81
|
"start": self.created_at,
|
|
76
82
|
"end": self.created_at,
|
|
@@ -84,7 +90,6 @@ class MessageBase(ABC):
|
|
|
84
90
|
"isError": self.is_error,
|
|
85
91
|
"waitForAnswer": self.wait_for_answer,
|
|
86
92
|
"indent": self.indent,
|
|
87
|
-
"generation": self.generation.to_dict() if self.generation else None,
|
|
88
93
|
"metadata": self.metadata or {},
|
|
89
94
|
"tags": self.tags,
|
|
90
95
|
}
|
|
@@ -173,21 +178,21 @@ class MessageBase(ABC):
|
|
|
173
178
|
Sends a token to the UI. This is useful for streaming messages.
|
|
174
179
|
Once all tokens have been streamed, call .send() to end the stream and persist the message if persistence is enabled.
|
|
175
180
|
"""
|
|
176
|
-
|
|
177
|
-
if not self.streaming:
|
|
178
|
-
self.streaming = True
|
|
179
|
-
step_dict = self.to_dict()
|
|
180
|
-
await context.emitter.stream_start(step_dict)
|
|
181
|
-
|
|
182
181
|
if is_sequence:
|
|
183
182
|
self.content = token
|
|
184
183
|
else:
|
|
185
184
|
self.content += token
|
|
186
185
|
|
|
187
186
|
assert self.id
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
|
|
188
|
+
if not self.streaming:
|
|
189
|
+
self.streaming = True
|
|
190
|
+
step_dict = self.to_dict()
|
|
191
|
+
await context.emitter.stream_start(step_dict)
|
|
192
|
+
else:
|
|
193
|
+
await context.emitter.send_token(
|
|
194
|
+
id=self.id, token=token, is_sequence=is_sequence
|
|
195
|
+
)
|
|
191
196
|
|
|
192
197
|
|
|
193
198
|
class Message(MessageBase):
|
|
@@ -196,7 +201,7 @@ class Message(MessageBase):
|
|
|
196
201
|
|
|
197
202
|
Args:
|
|
198
203
|
content (Union[str, Dict]): The content of the message.
|
|
199
|
-
author (str, optional): The author of the message, this will be used in the UI. Defaults to the
|
|
204
|
+
author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
|
|
200
205
|
language (str, optional): Language of the code is the content is code. See https://react-code-blocks-rajinwonderland.vercel.app/?path=/story/codeblock--supported-languages for a list of supported languages.
|
|
201
206
|
actions (List[Action], optional): A list of actions to send with the message.
|
|
202
207
|
elements (List[ElementBased], optional): A list of elements to send with the message.
|
|
@@ -212,15 +217,14 @@ class Message(MessageBase):
|
|
|
212
217
|
elements: Optional[List[ElementBased]] = None,
|
|
213
218
|
disable_feedback: bool = False,
|
|
214
219
|
type: MessageStepType = "assistant_message",
|
|
215
|
-
generation: Optional[BaseGeneration] = None,
|
|
216
220
|
metadata: Optional[Dict] = None,
|
|
217
221
|
tags: Optional[List[str]] = None,
|
|
218
222
|
id: Optional[str] = None,
|
|
223
|
+
parent_id: Optional[str] = None,
|
|
219
224
|
created_at: Union[str, None] = None,
|
|
220
225
|
):
|
|
221
226
|
time.sleep(0.001)
|
|
222
227
|
self.language = language
|
|
223
|
-
self.generation = generation
|
|
224
228
|
if isinstance(content, dict):
|
|
225
229
|
try:
|
|
226
230
|
self.content = json.dumps(content, indent=4, ensure_ascii=False)
|
|
@@ -237,6 +241,9 @@ class Message(MessageBase):
|
|
|
237
241
|
if id:
|
|
238
242
|
self.id = str(id)
|
|
239
243
|
|
|
244
|
+
if parent_id:
|
|
245
|
+
self.parent_id = str(parent_id)
|
|
246
|
+
|
|
240
247
|
if created_at:
|
|
241
248
|
self.created_at = created_at
|
|
242
249
|
|
|
@@ -303,9 +310,7 @@ class ErrorMessage(MessageBase):
|
|
|
303
310
|
|
|
304
311
|
Args:
|
|
305
312
|
content (str): Text displayed above the upload button.
|
|
306
|
-
author (str, optional): The author of the message, this will be used in the UI. Defaults to the
|
|
307
|
-
parent_id (str, optional): If provided, the message will be nested inside the parent in the UI.
|
|
308
|
-
indent (int, optional): If positive, the message will be nested in the UI.
|
|
313
|
+
author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
|
|
309
314
|
"""
|
|
310
315
|
|
|
311
316
|
def __init__(
|
|
@@ -316,7 +321,7 @@ class ErrorMessage(MessageBase):
|
|
|
316
321
|
):
|
|
317
322
|
self.content = content
|
|
318
323
|
self.author = author
|
|
319
|
-
self.type = "
|
|
324
|
+
self.type = "assistant_message"
|
|
320
325
|
self.is_error = True
|
|
321
326
|
self.fail_on_persist_error = fail_on_persist_error
|
|
322
327
|
|
|
@@ -346,7 +351,7 @@ class AskUserMessage(AskMessageBase):
|
|
|
346
351
|
|
|
347
352
|
Args:
|
|
348
353
|
content (str): The content of the prompt.
|
|
349
|
-
author (str, optional): The author of the message, this will be used in the UI. Defaults to the
|
|
354
|
+
author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
|
|
350
355
|
disable_feedback (bool, optional): Hide the feedback buttons for this specific message
|
|
351
356
|
timeout (int, optional): The number of seconds to wait for an answer before raising a TimeoutError.
|
|
352
357
|
raise_on_timeout (bool, optional): Whether to raise a socketio TimeoutError if the user does not answer in time.
|
|
@@ -357,7 +362,7 @@ class AskUserMessage(AskMessageBase):
|
|
|
357
362
|
content: str,
|
|
358
363
|
author: str = config.ui.name,
|
|
359
364
|
type: MessageStepType = "assistant_message",
|
|
360
|
-
disable_feedback: bool =
|
|
365
|
+
disable_feedback: bool = True,
|
|
361
366
|
timeout: int = 60,
|
|
362
367
|
raise_on_timeout: bool = False,
|
|
363
368
|
):
|
|
@@ -411,7 +416,7 @@ class AskFileMessage(AskMessageBase):
|
|
|
411
416
|
accept (Union[List[str], Dict[str, List[str]]]): List of mime type to accept like ["text/csv", "application/pdf"] or a dict like {"text/plain": [".txt", ".py"]}.
|
|
412
417
|
max_size_mb (int, optional): Maximum size per file in MB. Maximum value is 100.
|
|
413
418
|
max_files (int, optional): Maximum number of files to upload. Maximum value is 10.
|
|
414
|
-
author (str, optional): The author of the message, this will be used in the UI. Defaults to the
|
|
419
|
+
author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
|
|
415
420
|
disable_feedback (bool, optional): Hide the feedback buttons for this specific message
|
|
416
421
|
timeout (int, optional): The number of seconds to wait for an answer before raising a TimeoutError.
|
|
417
422
|
raise_on_timeout (bool, optional): Whether to raise a socketio TimeoutError if the user does not answer in time.
|
|
@@ -425,7 +430,7 @@ class AskFileMessage(AskMessageBase):
|
|
|
425
430
|
max_files=1,
|
|
426
431
|
author=config.ui.name,
|
|
427
432
|
type: MessageStepType = "assistant_message",
|
|
428
|
-
disable_feedback: bool =
|
|
433
|
+
disable_feedback: bool = True,
|
|
429
434
|
timeout=90,
|
|
430
435
|
raise_on_timeout=False,
|
|
431
436
|
):
|
|
@@ -501,7 +506,7 @@ class AskActionMessage(AskMessageBase):
|
|
|
501
506
|
content: str,
|
|
502
507
|
actions: List[Action],
|
|
503
508
|
author=config.ui.name,
|
|
504
|
-
disable_feedback=
|
|
509
|
+
disable_feedback=True,
|
|
505
510
|
timeout=90,
|
|
506
511
|
raise_on_timeout=False,
|
|
507
512
|
):
|
chainlit/oauth_providers.py
CHANGED
|
@@ -4,6 +4,7 @@ import urllib.parse
|
|
|
4
4
|
from typing import Dict, List, Optional, Tuple
|
|
5
5
|
|
|
6
6
|
import httpx
|
|
7
|
+
from chainlit.secret import random_secret
|
|
7
8
|
from chainlit.user import User
|
|
8
9
|
from fastapi import HTTPException
|
|
9
10
|
|
|
@@ -186,6 +187,60 @@ class AzureADOAuthProvider(OAuthProvider):
|
|
|
186
187
|
)
|
|
187
188
|
return token
|
|
188
189
|
|
|
190
|
+
|
|
191
|
+
class AzureADHybridOAuthProvider(OAuthProvider):
|
|
192
|
+
id = "azure-ad-hybrid"
|
|
193
|
+
env = [
|
|
194
|
+
"OAUTH_AZURE_AD_HYBRID_CLIENT_ID",
|
|
195
|
+
"OAUTH_AZURE_AD_HYBRID_CLIENT_SECRET",
|
|
196
|
+
"OAUTH_AZURE_AD_HYBRID_TENANT_ID",
|
|
197
|
+
]
|
|
198
|
+
authorize_url = (
|
|
199
|
+
f"https://login.microsoftonline.com/{os.environ.get('OAUTH_AZURE_AD_HYBRID_TENANT_ID', '')}/oauth2/v2.0/authorize"
|
|
200
|
+
if os.environ.get("OAUTH_AZURE_AD_HYBRID_ENABLE_SINGLE_TENANT")
|
|
201
|
+
else "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
|
|
202
|
+
)
|
|
203
|
+
token_url = (
|
|
204
|
+
f"https://login.microsoftonline.com/{os.environ.get('OAUTH_AZURE_AD_HYBRID_TENANT_ID', '')}/oauth2/v2.0/token"
|
|
205
|
+
if os.environ.get("OAUTH_AZURE_AD_HYBRID_ENABLE_SINGLE_TENANT")
|
|
206
|
+
else "https://login.microsoftonline.com/common/oauth2/v2.0/token"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def __init__(self):
|
|
210
|
+
self.client_id = os.environ.get("OAUTH_AZURE_AD_HYBRID_CLIENT_ID")
|
|
211
|
+
self.client_secret = os.environ.get("OAUTH_AZURE_AD_HYBRID_CLIENT_SECRET")
|
|
212
|
+
nonce = random_secret(16)
|
|
213
|
+
self.authorize_params = {
|
|
214
|
+
"tenant": os.environ.get("OAUTH_AZURE_AD_HYBRID_TENANT_ID"),
|
|
215
|
+
"response_type": "code id_token",
|
|
216
|
+
"scope": "https://graph.microsoft.com/User.Read https://graph.microsoft.com/openid",
|
|
217
|
+
"response_mode": "form_post",
|
|
218
|
+
"nonce": nonce,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async def get_token(self, code: str, url: str):
|
|
222
|
+
payload = {
|
|
223
|
+
"client_id": self.client_id,
|
|
224
|
+
"client_secret": self.client_secret,
|
|
225
|
+
"code": code,
|
|
226
|
+
"grant_type": "authorization_code",
|
|
227
|
+
"redirect_uri": url,
|
|
228
|
+
}
|
|
229
|
+
async with httpx.AsyncClient() as client:
|
|
230
|
+
response = await client.post(
|
|
231
|
+
self.token_url,
|
|
232
|
+
data=payload,
|
|
233
|
+
)
|
|
234
|
+
response.raise_for_status()
|
|
235
|
+
json = response.json()
|
|
236
|
+
|
|
237
|
+
token = json["access_token"]
|
|
238
|
+
if not token:
|
|
239
|
+
raise HTTPException(
|
|
240
|
+
status_code=400, detail="Failed to get the access token"
|
|
241
|
+
)
|
|
242
|
+
return token
|
|
243
|
+
|
|
189
244
|
async def get_user_info(self, token: str):
|
|
190
245
|
async with httpx.AsyncClient() as client:
|
|
191
246
|
response = await client.get(
|
|
@@ -475,14 +530,77 @@ class AWSCognitoOAuthProvider(OAuthProvider):
|
|
|
475
530
|
return (cognito_user, user)
|
|
476
531
|
|
|
477
532
|
|
|
533
|
+
class GitlabOAuthProvider(OAuthProvider):
|
|
534
|
+
id = "gitlab"
|
|
535
|
+
env = [
|
|
536
|
+
"OAUTH_GITLAB_CLIENT_ID",
|
|
537
|
+
"OAUTH_GITLAB_CLIENT_SECRET",
|
|
538
|
+
"OAUTH_GITLAB_DOMAIN",
|
|
539
|
+
]
|
|
540
|
+
|
|
541
|
+
def __init__(self):
|
|
542
|
+
self.client_id = os.environ.get("OAUTH_GITLAB_CLIENT_ID")
|
|
543
|
+
self.client_secret = os.environ.get("OAUTH_GITLAB_CLIENT_SECRET")
|
|
544
|
+
# Ensure that the domain does not have a trailing slash
|
|
545
|
+
self.domain = f"https://{os.environ.get('OAUTH_GITLAB_DOMAIN', '').rstrip('/')}"
|
|
546
|
+
|
|
547
|
+
self.authorize_url = f"{self.domain}/oauth/authorize"
|
|
548
|
+
|
|
549
|
+
self.authorize_params = {
|
|
550
|
+
"scope": "openid profile email",
|
|
551
|
+
"response_type": "code",
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
async def get_token(self, code: str, url: str):
|
|
555
|
+
payload = {
|
|
556
|
+
"client_id": self.client_id,
|
|
557
|
+
"client_secret": self.client_secret,
|
|
558
|
+
"code": code,
|
|
559
|
+
"grant_type": "authorization_code",
|
|
560
|
+
"redirect_uri": url,
|
|
561
|
+
}
|
|
562
|
+
async with httpx.AsyncClient() as client:
|
|
563
|
+
response = await client.post(
|
|
564
|
+
f"{self.domain}/oauth/token",
|
|
565
|
+
data=payload,
|
|
566
|
+
)
|
|
567
|
+
response.raise_for_status()
|
|
568
|
+
json_content = response.json()
|
|
569
|
+
token = json_content.get("access_token")
|
|
570
|
+
if not token:
|
|
571
|
+
raise HTTPException(
|
|
572
|
+
status_code=400, detail="Failed to get the access token"
|
|
573
|
+
)
|
|
574
|
+
return token
|
|
575
|
+
|
|
576
|
+
async def get_user_info(self, token: str):
|
|
577
|
+
async with httpx.AsyncClient() as client:
|
|
578
|
+
response = await client.get(
|
|
579
|
+
f"{self.domain}/oauth/userinfo",
|
|
580
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
581
|
+
)
|
|
582
|
+
response.raise_for_status()
|
|
583
|
+
gitlab_user = response.json()
|
|
584
|
+
user = User(
|
|
585
|
+
identifier=gitlab_user.get("email"),
|
|
586
|
+
metadata={
|
|
587
|
+
"image": gitlab_user.get("picture", ""),
|
|
588
|
+
"provider": "gitlab",
|
|
589
|
+
},
|
|
590
|
+
)
|
|
591
|
+
return (gitlab_user, user)
|
|
592
|
+
|
|
593
|
+
|
|
478
594
|
providers = [
|
|
479
595
|
GithubOAuthProvider(),
|
|
480
596
|
GoogleOAuthProvider(),
|
|
481
597
|
AzureADOAuthProvider(),
|
|
598
|
+
AzureADHybridOAuthProvider(),
|
|
482
599
|
OktaOAuthProvider(),
|
|
483
600
|
Auth0OAuthProvider(),
|
|
484
601
|
DescopeOAuthProvider(),
|
|
485
602
|
AWSCognitoOAuthProvider(),
|
|
603
|
+
GitlabOAuthProvider(),
|
|
486
604
|
]
|
|
487
605
|
|
|
488
606
|
|