From 640b955e12aab32585290a15d5a690b520e7a109 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Mon, 27 May 2024 16:33:37 +0000 Subject: [PATCH 01/42] feat(util.py/azure.py): Add OIDC support when running in Azure Kubernetes Service (AKS). --- litellm/llms/azure.py | 7 ++++--- litellm/utils.py | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/litellm/llms/azure.py b/litellm/llms/azure.py index 02fe4a08f..4d258cff2 100644 --- a/litellm/llms/azure.py +++ b/litellm/llms/azure.py @@ -136,9 +136,10 @@ def select_azure_base_url_or_endpoint(azure_client_params: dict): def get_azure_ad_token_from_oidc(azure_ad_token: str): azure_client_id = os.getenv("AZURE_CLIENT_ID", None) - azure_tenant = os.getenv("AZURE_TENANT_ID", None) + azure_tenant_id = os.getenv("AZURE_TENANT_ID", None) + azure_authority_host = os.getenv("AZURE_AUTHORITY_HOST", "https://login.microsoftonline.com") - if azure_client_id is None or azure_tenant is None: + if azure_client_id is None or azure_tenant_id is None: raise AzureOpenAIError( status_code=422, message="AZURE_CLIENT_ID and AZURE_TENANT_ID must be set", @@ -153,7 +154,7 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): ) req_token = httpx.post( - f"https://login.microsoftonline.com/{azure_tenant}/oauth2/v2.0/token", + f"{azure_authority_host}/{azure_tenant_id}/oauth2/v2.0/token", data={ "client_id": azure_client_id, "grant_type": "client_credentials", diff --git a/litellm/utils.py b/litellm/utils.py index ea0f46c14..8c18ab88e 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -10085,6 +10085,14 @@ def get_secret( return oidc_token else: raise ValueError("Github OIDC provider failed") + elif oidc_provider == "azure": + # https://azure.github.io/azure-workload-identity/docs/quick-start.html + azure_federated_token_file = os.getenv("AZURE_FEDERATED_TOKEN_FILE") + if azure_federated_token_file is None: + raise ValueError("AZURE_FEDERATED_TOKEN_FILE not found in environment") + with open(azure_federated_token_file, "r") as f: + oidc_token = f.read() + return oidc_token else: raise ValueError("Unsupported OIDC provider") From 73d9d0d7db78afee938e7293a3245bf7c167a855 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Mon, 27 May 2024 17:35:37 +0000 Subject: [PATCH 02/42] feat(azure.py): Add Azure AD cred caching for OIDC flow. --- litellm/llms/azure.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/litellm/llms/azure.py b/litellm/llms/azure.py index 4d258cff2..be8220b0c 100644 --- a/litellm/llms/azure.py +++ b/litellm/llms/azure.py @@ -18,6 +18,9 @@ from .custom_httpx.azure_dall_e_2 import CustomHTTPTransport, AsyncCustomHTTPTra from openai import AzureOpenAI, AsyncAzureOpenAI import uuid import os +from litellm.caching import DualCache + +azure_ad_cache = DualCache() class AzureOpenAIError(Exception): @@ -153,6 +156,17 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): message="OIDC token could not be retrieved from secret manager.", ) + azure_ad_token_cache_key = json.dumps({ + "azure_client_id": azure_client_id, + "azure_tenant_id": azure_tenant_id, + "azure_authority_host": azure_authority_host, + "oidc_token": oidc_token, + }) + + azure_ad_token_access_token = azure_ad_cache.get_cache(azure_ad_token_cache_key) + if azure_ad_token_access_token is not None: + return azure_ad_token_access_token + req_token = httpx.post( f"{azure_authority_host}/{azure_tenant_id}/oauth2/v2.0/token", data={ @@ -170,14 +184,23 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): message=req_token.text, ) - possible_azure_ad_token = req_token.json().get("access_token", None) + azure_ad_token_json = req_token.json() + azure_ad_token_access_token = azure_ad_token_json.get("access_token", None) + azure_ad_token_expires_in = azure_ad_token_json.get("expires_in", None) - if possible_azure_ad_token is None: + if azure_ad_token_access_token is None: raise AzureOpenAIError( - status_code=422, message="Azure AD Token not returned" + status_code=422, message="Azure AD Token access_token not returned" ) - return possible_azure_ad_token + if azure_ad_token_expires_in is None: + raise AzureOpenAIError( + status_code=422, message="Azure AD Token expires_in not returned" + ) + + azure_ad_cache.set_cache(key=azure_ad_token_cache_key, value=azure_ad_token_access_token, ttl=azure_ad_token_expires_in) + + return azure_ad_token_access_token class AzureChatCompletion(BaseLLM): From 240a0da2718948a94b2c610c82af5b1caecf6605 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Fri, 17 May 2024 10:19:25 +0000 Subject: [PATCH 03/42] feat(bedrock_httpx.py): Add AWS IAM cred caching for OIDC flow. --- litellm/llms/bedrock_httpx.py | 64 ++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index dd41a8cb7..c895679f1 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -45,7 +45,9 @@ import httpx # type: ignore from .bedrock import BedrockError, convert_messages_to_prompt, ModelResponseIterator from litellm.types.llms.bedrock import * import urllib.parse +from litellm.caching import DualCache +iam_cache = DualCache() class AmazonCohereChatConfig: """ @@ -285,35 +287,51 @@ class BedrockLLM(BaseLLM): ### CHECK STS ### if aws_web_identity_token is not None and aws_role_name is not None and aws_session_name is not None: - oidc_token = get_secret(aws_web_identity_token) + iam_creds_cache_key = json.dumps({ + "aws_web_identity_token": aws_web_identity_token, + "aws_role_name": aws_role_name, + "aws_session_name": aws_session_name, + "aws_region_name": aws_region_name, + }) - if oidc_token is None: - raise BedrockError( - message="OIDC token could not be retrieved from secret manager.", - status_code=401, + iam_creds_dict = iam_cache.get_cache(iam_creds_cache_key) + if iam_creds_dict is None: + oidc_token = get_secret(aws_web_identity_token) + + if oidc_token is None: + raise BedrockError( + message="OIDC token could not be retrieved from secret manager.", + status_code=401, + ) + + sts_client = boto3.client( + "sts", + region_name=aws_region_name, ) - sts_client = boto3.client( - "sts" - ) + # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html + # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html + sts_response = sts_client.assume_role_with_web_identity( + RoleArn=aws_role_name, + RoleSessionName=aws_session_name, + WebIdentityToken=oidc_token, + DurationSeconds=3600, + ) - # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html - # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html - sts_response = sts_client.assume_role_with_web_identity( - RoleArn=aws_role_name, - RoleSessionName=aws_session_name, - WebIdentityToken=oidc_token, - DurationSeconds=3600, - ) + iam_creds_dict = { + "aws_access_key_id": sts_response["Credentials"]["AccessKeyId"], + "aws_secret_access_key": sts_response["Credentials"]["SecretAccessKey"], + "aws_session_token": sts_response["Credentials"]["SessionToken"], + "region_name": aws_region_name, + } - session = boto3.Session( - aws_access_key_id=sts_response["Credentials"]["AccessKeyId"], - aws_secret_access_key=sts_response["Credentials"]["SecretAccessKey"], - aws_session_token=sts_response["Credentials"]["SessionToken"], - region_name=aws_region_name, - ) + iam_cache.set_cache(key=iam_creds_cache_key, value=json.dumps(iam_creds_dict), ttl=3600 - 60) - return session.get_credentials() + session = boto3.Session(**iam_creds_dict) + + iam_creds = session.get_credentials() + + return iam_creds elif aws_role_name is not None and aws_session_name is not None: sts_client = boto3.client( "sts", From fd16937ad80bdf36298b811002f7e0526c8e7414 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Sat, 1 Jun 2024 01:52:06 +0000 Subject: [PATCH 04/42] fix(bedrock_httpx.py): Fix STS region endpoint. --- litellm/llms/bedrock_httpx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index c895679f1..99e2a8ffe 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -307,6 +307,7 @@ class BedrockLLM(BaseLLM): sts_client = boto3.client( "sts", region_name=aws_region_name, + endpoint_url=f"https://sts.{aws_region_name}.amazonaws.com" ) # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html From 3410367610abc62f4899158cd2dacc467e6423da Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Sat, 1 Jun 2024 15:18:32 +0000 Subject: [PATCH 05/42] test(test_bedrock_completion.py): Add tests to ensure caching isn't breaking anything. --- litellm/tests/test_bedrock_completion.py | 42 +++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/litellm/tests/test_bedrock_completion.py b/litellm/tests/test_bedrock_completion.py index 047f0cb2e..20596d265 100644 --- a/litellm/tests/test_bedrock_completion.py +++ b/litellm/tests/test_bedrock_completion.py @@ -220,13 +220,13 @@ def test_completion_bedrock_claude_sts_oidc_auth(): aws_web_identity_token = "oidc/circleci_v2/" aws_region_name = os.environ["AWS_REGION_NAME"] # aws_role_name = os.environ["AWS_TEMP_ROLE_NAME"] - # TODO: This is using David's IAM role, we should use Litellm's IAM role eventually + # TODO: This is using ai.moda's IAM role, we should use LiteLLM's IAM role eventually aws_role_name = "arn:aws:iam::335785316107:role/litellm-github-unit-tests-circleci" try: litellm.set_verbose = True - response = completion( + response_1 = completion( model="bedrock/anthropic.claude-3-haiku-20240307-v1:0", messages=messages, max_tokens=10, @@ -236,8 +236,40 @@ def test_completion_bedrock_claude_sts_oidc_auth(): aws_role_name=aws_role_name, aws_session_name="my-test-session", ) - # Add any assertions here to check the response - print(response) + print(response_1) + assert len(response_1.choices) > 0 + assert len(response_1.choices[0].message.content) > 0 + + # This second call is to verify that the cache isn't breaking anything + response_2 = completion( + model="bedrock/anthropic.claude-3-haiku-20240307-v1:0", + messages=messages, + max_tokens=5, + temperature=0.2, + aws_region_name=aws_region_name, + aws_web_identity_token=aws_web_identity_token, + aws_role_name=aws_role_name, + aws_session_name="my-test-session", + ) + print(response_2) + assert len(response_2.choices) > 0 + assert len(response_2.choices[0].message.content) > 0 + + # This third call is to verify that the cache isn't used for a different region + response_3 = completion( + model="bedrock/anthropic.claude-3-haiku-20240307-v1:0", + messages=messages, + max_tokens=6, + temperature=0.3, + aws_region_name="us-east-1", + aws_web_identity_token=aws_web_identity_token, + aws_role_name=aws_role_name, + aws_session_name="my-test-session", + ) + print(response_3) + assert len(response_3.choices) > 0 + assert len(response_3.choices[0].message.content) > 0 + except RateLimitError: pass except Exception as e: @@ -254,7 +286,7 @@ def test_completion_bedrock_httpx_command_r_sts_oidc_auth(): aws_web_identity_token = "oidc/circleci_v2/" aws_region_name = os.environ["AWS_REGION_NAME"] # aws_role_name = os.environ["AWS_TEMP_ROLE_NAME"] - # TODO: This is using David's IAM role, we should use Litellm's IAM role eventually + # TODO: This is using ai.moda's IAM role, we should use LiteLLM's IAM role eventually aws_role_name = "arn:aws:iam::335785316107:role/litellm-github-unit-tests-circleci" try: From 1a77c1bf169189c86057844c3204b33959e5cf2d Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Tue, 11 Jun 2024 15:42:09 +0000 Subject: [PATCH 06/42] Revert "fix(bedrock_httpx.py): Fix STS region endpoint." This reverts commit fd16937ad80bdf36298b811002f7e0526c8e7414. --- litellm/llms/bedrock_httpx.py | 1 - 1 file changed, 1 deletion(-) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index 99e2a8ffe..c895679f1 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -307,7 +307,6 @@ class BedrockLLM(BaseLLM): sts_client = boto3.client( "sts", region_name=aws_region_name, - endpoint_url=f"https://sts.{aws_region_name}.amazonaws.com" ) # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html From 4de9e46d4229964c4852051955013d733bc7912a Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Tue, 11 Jun 2024 15:42:18 +0000 Subject: [PATCH 07/42] Revert "feat(bedrock_httpx.py): Add AWS IAM cred caching for OIDC flow." This reverts commit 240a0da2718948a94b2c610c82af5b1caecf6605. --- litellm/llms/bedrock_httpx.py | 64 +++++++++++++---------------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index c895679f1..dd41a8cb7 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -45,9 +45,7 @@ import httpx # type: ignore from .bedrock import BedrockError, convert_messages_to_prompt, ModelResponseIterator from litellm.types.llms.bedrock import * import urllib.parse -from litellm.caching import DualCache -iam_cache = DualCache() class AmazonCohereChatConfig: """ @@ -287,51 +285,35 @@ class BedrockLLM(BaseLLM): ### CHECK STS ### if aws_web_identity_token is not None and aws_role_name is not None and aws_session_name is not None: - iam_creds_cache_key = json.dumps({ - "aws_web_identity_token": aws_web_identity_token, - "aws_role_name": aws_role_name, - "aws_session_name": aws_session_name, - "aws_region_name": aws_region_name, - }) + oidc_token = get_secret(aws_web_identity_token) - iam_creds_dict = iam_cache.get_cache(iam_creds_cache_key) - if iam_creds_dict is None: - oidc_token = get_secret(aws_web_identity_token) - - if oidc_token is None: - raise BedrockError( - message="OIDC token could not be retrieved from secret manager.", - status_code=401, - ) - - sts_client = boto3.client( - "sts", - region_name=aws_region_name, + if oidc_token is None: + raise BedrockError( + message="OIDC token could not be retrieved from secret manager.", + status_code=401, ) - # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html - # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html - sts_response = sts_client.assume_role_with_web_identity( - RoleArn=aws_role_name, - RoleSessionName=aws_session_name, - WebIdentityToken=oidc_token, - DurationSeconds=3600, - ) + sts_client = boto3.client( + "sts" + ) - iam_creds_dict = { - "aws_access_key_id": sts_response["Credentials"]["AccessKeyId"], - "aws_secret_access_key": sts_response["Credentials"]["SecretAccessKey"], - "aws_session_token": sts_response["Credentials"]["SessionToken"], - "region_name": aws_region_name, - } + # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html + # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html + sts_response = sts_client.assume_role_with_web_identity( + RoleArn=aws_role_name, + RoleSessionName=aws_session_name, + WebIdentityToken=oidc_token, + DurationSeconds=3600, + ) - iam_cache.set_cache(key=iam_creds_cache_key, value=json.dumps(iam_creds_dict), ttl=3600 - 60) + session = boto3.Session( + aws_access_key_id=sts_response["Credentials"]["AccessKeyId"], + aws_secret_access_key=sts_response["Credentials"]["SecretAccessKey"], + aws_session_token=sts_response["Credentials"]["SessionToken"], + region_name=aws_region_name, + ) - session = boto3.Session(**iam_creds_dict) - - iam_creds = session.get_credentials() - - return iam_creds + return session.get_credentials() elif aws_role_name is not None and aws_session_name is not None: sts_client = boto3.client( "sts", From cd21c80a15cbdd31b1a2f377c981fa096d8091d5 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Fri, 17 May 2024 10:19:25 +0000 Subject: [PATCH 08/42] feat(bedrock_httpx.py): Add AWS IAM cred caching for OIDC flow. --- litellm/llms/bedrock_httpx.py | 68 +++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index b011d9512..0c1e7c06f 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -53,7 +53,9 @@ from litellm.types.llms.openai import ( ChatCompletionToolCallFunctionChunk, ChatCompletionDeltaChunk, ) +from litellm.caching import DualCache +iam_cache = DualCache() class AmazonCohereChatConfig: """ @@ -325,38 +327,52 @@ class BedrockLLM(BaseLLM): ) = params_to_check ### CHECK STS ### - if ( - aws_web_identity_token is not None - and aws_role_name is not None - and aws_session_name is not None - ): - oidc_token = get_secret(aws_web_identity_token) + if aws_web_identity_token is not None and aws_role_name is not None and aws_session_name is not None: + iam_creds_cache_key = json.dumps({ + "aws_web_identity_token": aws_web_identity_token, + "aws_role_name": aws_role_name, + "aws_session_name": aws_session_name, + "aws_region_name": aws_region_name, + }) - if oidc_token is None: - raise BedrockError( - message="OIDC token could not be retrieved from secret manager.", - status_code=401, + iam_creds_dict = iam_cache.get_cache(iam_creds_cache_key) + if iam_creds_dict is None: + oidc_token = get_secret(aws_web_identity_token) + + if oidc_token is None: + raise BedrockError( + message="OIDC token could not be retrieved from secret manager.", + status_code=401, + ) + + sts_client = boto3.client( + "sts", + region_name=aws_region_name, ) - sts_client = boto3.client("sts") + # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html + # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html + sts_response = sts_client.assume_role_with_web_identity( + RoleArn=aws_role_name, + RoleSessionName=aws_session_name, + WebIdentityToken=oidc_token, + DurationSeconds=3600, + ) - # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html - # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html - sts_response = sts_client.assume_role_with_web_identity( - RoleArn=aws_role_name, - RoleSessionName=aws_session_name, - WebIdentityToken=oidc_token, - DurationSeconds=3600, - ) + iam_creds_dict = { + "aws_access_key_id": sts_response["Credentials"]["AccessKeyId"], + "aws_secret_access_key": sts_response["Credentials"]["SecretAccessKey"], + "aws_session_token": sts_response["Credentials"]["SessionToken"], + "region_name": aws_region_name, + } - session = boto3.Session( - aws_access_key_id=sts_response["Credentials"]["AccessKeyId"], - aws_secret_access_key=sts_response["Credentials"]["SecretAccessKey"], - aws_session_token=sts_response["Credentials"]["SessionToken"], - region_name=aws_region_name, - ) + iam_cache.set_cache(key=iam_creds_cache_key, value=json.dumps(iam_creds_dict), ttl=3600 - 60) - return session.get_credentials() + session = boto3.Session(**iam_creds_dict) + + iam_creds = session.get_credentials() + + return iam_creds elif aws_role_name is not None and aws_session_name is not None: sts_client = boto3.client( "sts", From 7faf0b95861710b81ea11ce9582155ba16016f68 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Sat, 1 Jun 2024 01:52:06 +0000 Subject: [PATCH 09/42] fix(bedrock_httpx.py): Fix STS region endpoint. --- litellm/llms/bedrock_httpx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index 0c1e7c06f..6d4c04fb1 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -348,6 +348,7 @@ class BedrockLLM(BaseLLM): sts_client = boto3.client( "sts", region_name=aws_region_name, + endpoint_url=f"https://sts.{aws_region_name}.amazonaws.com" ) # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html From 7154c2590363ae5dca6fd5d4cc7e9d1262fed762 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Tue, 11 Jun 2024 15:51:59 +0000 Subject: [PATCH 10/42] Revert "feat(azure.py): Add Azure AD cred caching for OIDC flow." This reverts commit 73d9d0d7db78afee938e7293a3245bf7c167a855. --- litellm/llms/azure.py | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/litellm/llms/azure.py b/litellm/llms/azure.py index be8220b0c..4d258cff2 100644 --- a/litellm/llms/azure.py +++ b/litellm/llms/azure.py @@ -18,9 +18,6 @@ from .custom_httpx.azure_dall_e_2 import CustomHTTPTransport, AsyncCustomHTTPTra from openai import AzureOpenAI, AsyncAzureOpenAI import uuid import os -from litellm.caching import DualCache - -azure_ad_cache = DualCache() class AzureOpenAIError(Exception): @@ -156,17 +153,6 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): message="OIDC token could not be retrieved from secret manager.", ) - azure_ad_token_cache_key = json.dumps({ - "azure_client_id": azure_client_id, - "azure_tenant_id": azure_tenant_id, - "azure_authority_host": azure_authority_host, - "oidc_token": oidc_token, - }) - - azure_ad_token_access_token = azure_ad_cache.get_cache(azure_ad_token_cache_key) - if azure_ad_token_access_token is not None: - return azure_ad_token_access_token - req_token = httpx.post( f"{azure_authority_host}/{azure_tenant_id}/oauth2/v2.0/token", data={ @@ -184,23 +170,14 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): message=req_token.text, ) - azure_ad_token_json = req_token.json() - azure_ad_token_access_token = azure_ad_token_json.get("access_token", None) - azure_ad_token_expires_in = azure_ad_token_json.get("expires_in", None) + possible_azure_ad_token = req_token.json().get("access_token", None) - if azure_ad_token_access_token is None: + if possible_azure_ad_token is None: raise AzureOpenAIError( - status_code=422, message="Azure AD Token access_token not returned" + status_code=422, message="Azure AD Token not returned" ) - if azure_ad_token_expires_in is None: - raise AzureOpenAIError( - status_code=422, message="Azure AD Token expires_in not returned" - ) - - azure_ad_cache.set_cache(key=azure_ad_token_cache_key, value=azure_ad_token_access_token, ttl=azure_ad_token_expires_in) - - return azure_ad_token_access_token + return possible_azure_ad_token class AzureChatCompletion(BaseLLM): From 95a4bc46d457e75ecc85cfeec102f995c074eac8 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Tue, 11 Jun 2024 15:52:07 +0000 Subject: [PATCH 11/42] Revert "feat(util.py/azure.py): Add OIDC support when running in Azure Kubernetes Service (AKS)." This reverts commit 640b955e12aab32585290a15d5a690b520e7a109. --- litellm/llms/azure.py | 7 +++---- litellm/utils.py | 8 -------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/litellm/llms/azure.py b/litellm/llms/azure.py index 4d258cff2..02fe4a08f 100644 --- a/litellm/llms/azure.py +++ b/litellm/llms/azure.py @@ -136,10 +136,9 @@ def select_azure_base_url_or_endpoint(azure_client_params: dict): def get_azure_ad_token_from_oidc(azure_ad_token: str): azure_client_id = os.getenv("AZURE_CLIENT_ID", None) - azure_tenant_id = os.getenv("AZURE_TENANT_ID", None) - azure_authority_host = os.getenv("AZURE_AUTHORITY_HOST", "https://login.microsoftonline.com") + azure_tenant = os.getenv("AZURE_TENANT_ID", None) - if azure_client_id is None or azure_tenant_id is None: + if azure_client_id is None or azure_tenant is None: raise AzureOpenAIError( status_code=422, message="AZURE_CLIENT_ID and AZURE_TENANT_ID must be set", @@ -154,7 +153,7 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): ) req_token = httpx.post( - f"{azure_authority_host}/{azure_tenant_id}/oauth2/v2.0/token", + f"https://login.microsoftonline.com/{azure_tenant}/oauth2/v2.0/token", data={ "client_id": azure_client_id, "grant_type": "client_credentials", diff --git a/litellm/utils.py b/litellm/utils.py index 8c18ab88e..ea0f46c14 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -10085,14 +10085,6 @@ def get_secret( return oidc_token else: raise ValueError("Github OIDC provider failed") - elif oidc_provider == "azure": - # https://azure.github.io/azure-workload-identity/docs/quick-start.html - azure_federated_token_file = os.getenv("AZURE_FEDERATED_TOKEN_FILE") - if azure_federated_token_file is None: - raise ValueError("AZURE_FEDERATED_TOKEN_FILE not found in environment") - with open(azure_federated_token_file, "r") as f: - oidc_token = f.read() - return oidc_token else: raise ValueError("Unsupported OIDC provider") From a31fa5fbc80c29ef3b33ca675e9ff9b3c85b8af3 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Mon, 27 May 2024 16:33:37 +0000 Subject: [PATCH 12/42] feat(util.py/azure.py): Add OIDC support when running in Azure Kubernetes Service (AKS). --- litellm/llms/azure.py | 7 ++++--- litellm/utils.py | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/litellm/llms/azure.py b/litellm/llms/azure.py index 834fcbea9..e8bcaff64 100644 --- a/litellm/llms/azure.py +++ b/litellm/llms/azure.py @@ -309,9 +309,10 @@ def select_azure_base_url_or_endpoint(azure_client_params: dict): def get_azure_ad_token_from_oidc(azure_ad_token: str): azure_client_id = os.getenv("AZURE_CLIENT_ID", None) - azure_tenant = os.getenv("AZURE_TENANT_ID", None) + azure_tenant_id = os.getenv("AZURE_TENANT_ID", None) + azure_authority_host = os.getenv("AZURE_AUTHORITY_HOST", "https://login.microsoftonline.com") - if azure_client_id is None or azure_tenant is None: + if azure_client_id is None or azure_tenant_id is None: raise AzureOpenAIError( status_code=422, message="AZURE_CLIENT_ID and AZURE_TENANT_ID must be set", @@ -326,7 +327,7 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): ) req_token = httpx.post( - f"https://login.microsoftonline.com/{azure_tenant}/oauth2/v2.0/token", + f"{azure_authority_host}/{azure_tenant_id}/oauth2/v2.0/token", data={ "client_id": azure_client_id, "grant_type": "client_credentials", diff --git a/litellm/utils.py b/litellm/utils.py index 5e85419dc..b872687b5 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -10050,6 +10050,14 @@ def get_secret( return oidc_token else: raise ValueError("Github OIDC provider failed") + elif oidc_provider == "azure": + # https://azure.github.io/azure-workload-identity/docs/quick-start.html + azure_federated_token_file = os.getenv("AZURE_FEDERATED_TOKEN_FILE") + if azure_federated_token_file is None: + raise ValueError("AZURE_FEDERATED_TOKEN_FILE not found in environment") + with open(azure_federated_token_file, "r") as f: + oidc_token = f.read() + return oidc_token else: raise ValueError("Unsupported OIDC provider") From d9503737689fe7b488d6e609bcbd3d02df03f9e4 Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Mon, 27 May 2024 17:35:37 +0000 Subject: [PATCH 13/42] feat(azure.py): Add Azure AD cred caching for OIDC flow. --- litellm/llms/azure.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/litellm/llms/azure.py b/litellm/llms/azure.py index e8bcaff64..46ab62a8d 100644 --- a/litellm/llms/azure.py +++ b/litellm/llms/azure.py @@ -36,6 +36,9 @@ from ..types.llms.openai import ( AsyncAssistantStreamManager, AssistantStreamManager, ) +from litellm.caching import DualCache + +azure_ad_cache = DualCache() class AzureOpenAIError(Exception): @@ -326,6 +329,17 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): message="OIDC token could not be retrieved from secret manager.", ) + azure_ad_token_cache_key = json.dumps({ + "azure_client_id": azure_client_id, + "azure_tenant_id": azure_tenant_id, + "azure_authority_host": azure_authority_host, + "oidc_token": oidc_token, + }) + + azure_ad_token_access_token = azure_ad_cache.get_cache(azure_ad_token_cache_key) + if azure_ad_token_access_token is not None: + return azure_ad_token_access_token + req_token = httpx.post( f"{azure_authority_host}/{azure_tenant_id}/oauth2/v2.0/token", data={ @@ -343,12 +357,23 @@ def get_azure_ad_token_from_oidc(azure_ad_token: str): message=req_token.text, ) - possible_azure_ad_token = req_token.json().get("access_token", None) + azure_ad_token_json = req_token.json() + azure_ad_token_access_token = azure_ad_token_json.get("access_token", None) + azure_ad_token_expires_in = azure_ad_token_json.get("expires_in", None) - if possible_azure_ad_token is None: - raise AzureOpenAIError(status_code=422, message="Azure AD Token not returned") + if azure_ad_token_access_token is None: + raise AzureOpenAIError( + status_code=422, message="Azure AD Token access_token not returned" + ) - return possible_azure_ad_token + if azure_ad_token_expires_in is None: + raise AzureOpenAIError( + status_code=422, message="Azure AD Token expires_in not returned" + ) + + azure_ad_cache.set_cache(key=azure_ad_token_cache_key, value=azure_ad_token_access_token, ttl=azure_ad_token_expires_in) + + return azure_ad_token_access_token class AzureChatCompletion(BaseLLM): From 9aee0b4a0f2d24ae9edfcc5e5825025ac18ec63a Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Tue, 11 Jun 2024 16:34:32 +0000 Subject: [PATCH 14/42] fix(bedrock_httpx.py): Fix STS region endpoint for converse flow. --- litellm/llms/bedrock_httpx.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index 6d4c04fb1..ee0ae57b4 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -1446,7 +1446,11 @@ class BedrockConverseLLM(BaseLLM): status_code=401, ) - sts_client = boto3.client("sts") + sts_client = boto3.client( + "sts", + region_name=aws_region_name, + endpoint_url=f"https://sts.{aws_region_name}.amazonaws.com" + ) # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html From 844f15f8b056f2c331b1daefdbdaacfe93a5e95b Mon Sep 17 00:00:00 2001 From: David Manouchehri Date: Tue, 11 Jun 2024 16:59:38 +0000 Subject: [PATCH 15/42] fix(bedrock_httpx.py): Add IAM caching for converse flow. --- litellm/llms/bedrock_httpx.py | 71 ++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/litellm/llms/bedrock_httpx.py b/litellm/llms/bedrock_httpx.py index ee0ae57b4..84b61d4cb 100644 --- a/litellm/llms/bedrock_httpx.py +++ b/litellm/llms/bedrock_httpx.py @@ -1433,42 +1433,53 @@ class BedrockConverseLLM(BaseLLM): ) = params_to_check ### CHECK STS ### - if ( - aws_web_identity_token is not None - and aws_role_name is not None - and aws_session_name is not None - ): - oidc_token = get_secret(aws_web_identity_token) + if aws_web_identity_token is not None and aws_role_name is not None and aws_session_name is not None: + iam_creds_cache_key = json.dumps({ + "aws_web_identity_token": aws_web_identity_token, + "aws_role_name": aws_role_name, + "aws_session_name": aws_session_name, + "aws_region_name": aws_region_name, + }) - if oidc_token is None: - raise BedrockError( - message="OIDC token could not be retrieved from secret manager.", - status_code=401, + iam_creds_dict = iam_cache.get_cache(iam_creds_cache_key) + if iam_creds_dict is None: + oidc_token = get_secret(aws_web_identity_token) + + if oidc_token is None: + raise BedrockError( + message="OIDC token could not be retrieved from secret manager.", + status_code=401, + ) + + sts_client = boto3.client( + "sts", + region_name=aws_region_name, + endpoint_url=f"https://sts.{aws_region_name}.amazonaws.com" ) - sts_client = boto3.client( - "sts", - region_name=aws_region_name, - endpoint_url=f"https://sts.{aws_region_name}.amazonaws.com" - ) + # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html + # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html + sts_response = sts_client.assume_role_with_web_identity( + RoleArn=aws_role_name, + RoleSessionName=aws_session_name, + WebIdentityToken=oidc_token, + DurationSeconds=3600, + ) - # https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html - # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts/client/assume_role_with_web_identity.html - sts_response = sts_client.assume_role_with_web_identity( - RoleArn=aws_role_name, - RoleSessionName=aws_session_name, - WebIdentityToken=oidc_token, - DurationSeconds=3600, - ) + iam_creds_dict = { + "aws_access_key_id": sts_response["Credentials"]["AccessKeyId"], + "aws_secret_access_key": sts_response["Credentials"]["SecretAccessKey"], + "aws_session_token": sts_response["Credentials"]["SessionToken"], + "region_name": aws_region_name, + } - session = boto3.Session( - aws_access_key_id=sts_response["Credentials"]["AccessKeyId"], - aws_secret_access_key=sts_response["Credentials"]["SecretAccessKey"], - aws_session_token=sts_response["Credentials"]["SessionToken"], - region_name=aws_region_name, - ) + iam_cache.set_cache(key=iam_creds_cache_key, value=json.dumps(iam_creds_dict), ttl=3600 - 60) - return session.get_credentials() + session = boto3.Session(**iam_creds_dict) + + iam_creds = session.get_credentials() + + return iam_creds elif aws_role_name is not None and aws_session_name is not None: sts_client = boto3.client( "sts", From f09158504b62c2c9069074b5d2825388d4d93e80 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 09:29:51 -0700 Subject: [PATCH 16/42] feat - support vertex ai dimensions --- litellm/__init__.py | 2 +- litellm/llms/vertex_ai.py | 89 +++++++++++++++++++++++++++++++++++---- litellm/utils.py | 17 +++++++- 3 files changed, 97 insertions(+), 11 deletions(-) diff --git a/litellm/__init__.py b/litellm/__init__.py index e18be347d..6dddc8a22 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -765,7 +765,7 @@ from .llms.gemini import GeminiConfig from .llms.nlp_cloud import NLPCloudConfig from .llms.aleph_alpha import AlephAlphaConfig from .llms.petals import PetalsConfig -from .llms.vertex_ai import VertexAIConfig +from .llms.vertex_ai import VertexAIConfig, VertexAITextEmbeddingConfig from .llms.vertex_ai_anthropic import VertexAIAnthropicConfig from .llms.sagemaker import SagemakerConfig from .llms.ollama import OllamaConfig diff --git a/litellm/llms/vertex_ai.py b/litellm/llms/vertex_ai.py index bd9cfaa8d..c35aa502c 100644 --- a/litellm/llms/vertex_ai.py +++ b/litellm/llms/vertex_ai.py @@ -12,7 +12,12 @@ from litellm.llms.prompt_templates.factory import ( convert_to_gemini_tool_call_result, convert_to_gemini_tool_call_invoke, ) -from litellm.types.files import get_file_mime_type_for_file_type, get_file_type_from_extension, is_gemini_1_5_accepted_file_type, is_video_file_type +from litellm.types.files import ( + get_file_mime_type_for_file_type, + get_file_type_from_extension, + is_gemini_1_5_accepted_file_type, + is_video_file_type, +) class VertexAIError(Exception): @@ -301,15 +306,15 @@ def _process_gemini_image(image_url: str) -> PartType: # GCS URIs if "gs://" in image_url: # Figure out file type - extension_with_dot = os.path.splitext(image_url)[-1] # Ex: ".png" - extension = extension_with_dot[1:] # Ex: "png" + extension_with_dot = os.path.splitext(image_url)[-1] # Ex: ".png" + extension = extension_with_dot[1:] # Ex: "png" file_type = get_file_type_from_extension(extension) # Validate the file type is supported by Gemini if not is_gemini_1_5_accepted_file_type(file_type): raise Exception(f"File type not supported by gemini - {file_type}") - + mime_type = get_file_mime_type_for_file_type(file_type) file_data = FileDataType(mime_type=mime_type, file_uri=image_url) @@ -320,7 +325,7 @@ def _process_gemini_image(image_url: str) -> PartType: image = _load_image_from_url(image_url) _blob = BlobType(data=image.data, mime_type=image._mime_type) return PartType(inline_data=_blob) - + # Base64 encoding elif "base64" in image_url: import base64, re @@ -1293,6 +1298,70 @@ async def async_streaming( return streamwrapper +class VertexAITextEmbeddingConfig: + """ + Reference: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api#TextEmbeddingInput + + Args: + auto_truncate: (bool)If True, will truncate input text to fit within the model's max input length. + + """ + + auto_truncate: Optional[bool] = None + + def __init__( + self, + auto_truncate: Optional[bool] = None, + ) -> None: + locals_ = locals() + for key, value in locals_.items(): + if key != "self" and value is not None: + setattr(self.__class__, key, value) + + @classmethod + def get_config(cls): + return { + k: v + for k, v in cls.__dict__.items() + if not k.startswith("__") + and not isinstance( + v, + ( + types.FunctionType, + types.BuiltinFunctionType, + classmethod, + staticmethod, + ), + ) + and v is not None + } + + def get_supported_openai_params(self): + return [ + "dimensions", + ] + + def map_openai_params(self, non_default_params: dict, optional_params: dict): + for param, value in non_default_params.items(): + if param == "dimensions": + optional_params["output_dimensionality"] = value + return optional_params + + def get_mapped_special_auth_params(self) -> dict: + """ + Common auth params across bedrock/vertex_ai/azure/watsonx + """ + return {"project": "vertex_project", "region_name": "vertex_location"} + + def map_special_auth_params(self, non_default_params: dict, optional_params: dict): + mapped_params = self.get_mapped_special_auth_params() + + for param, value in non_default_params.items(): + if param in mapped_params: + optional_params[mapped_params[param]] = value + return optional_params + + def embedding( model: str, input: Union[list, str], @@ -1363,7 +1432,8 @@ def embedding( encoding=encoding, ) - request_str = f"""embeddings = llm_model.get_embeddings({input})""" + _input_dict = {"texts": input, **optional_params} + request_str = f"""embeddings = llm_model.get_embeddings({_input_dict})""" ## LOGGING PRE-CALL logging_obj.pre_call( input=input, @@ -1375,7 +1445,7 @@ def embedding( ) try: - embeddings = llm_model.get_embeddings(input) + embeddings = llm_model.get_embeddings(**_input_dict) except Exception as e: raise VertexAIError(status_code=500, message=str(e)) @@ -1420,7 +1490,8 @@ async def async_embedding( """ Async embedding implementation """ - request_str = f"""embeddings = llm_model.get_embeddings({input})""" + _input_dict = {"texts": input, **optional_params} + request_str = f"""embeddings = llm_model.get_embeddings({_input_dict})""" ## LOGGING PRE-CALL logging_obj.pre_call( input=input, @@ -1432,7 +1503,7 @@ async def async_embedding( ) try: - embeddings = await client.get_embeddings_async(input) + embeddings = await client.get_embeddings_async(**_input_dict) except Exception as e: raise VertexAIError(status_code=500, message=str(e)) diff --git a/litellm/utils.py b/litellm/utils.py index 49ff7cd98..481101d91 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -4898,6 +4898,18 @@ def get_optional_params_embeddings( ) final_params = {**optional_params, **kwargs} return final_params + if custom_llm_provider == "vertex_ai": + supported_params = get_supported_openai_params( + model=model, + custom_llm_provider="vertex_ai", + request_type="embeddings", + ) + _check_valid_arg(supported_params=supported_params) + optional_params = litellm.VertexAITextEmbeddingConfig().map_openai_params( + non_default_params=non_default_params, optional_params={} + ) + final_params = {**optional_params, **kwargs} + return final_params if custom_llm_provider == "vertex_ai": if len(non_default_params.keys()) > 0: if litellm.drop_params is True: # drop the unsupported non-default values @@ -6382,7 +6394,10 @@ def get_supported_openai_params( elif custom_llm_provider == "palm" or custom_llm_provider == "gemini": return ["temperature", "top_p", "stream", "n", "stop", "max_tokens"] elif custom_llm_provider == "vertex_ai": - return litellm.VertexAIConfig().get_supported_openai_params() + if request_type == "chat_completion": + return litellm.VertexAIConfig().get_supported_openai_params() + elif request_type == "embeddings": + return litellm.VertexAITextEmbeddingConfig().get_supported_openai_params() elif custom_llm_provider == "sagemaker": return ["stream", "temperature", "max_tokens", "top_p", "stop", "n"] elif custom_llm_provider == "aleph_alpha": From b9f50d83c40de52e7d205ecf17b386da5a5d8ce0 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 09:32:32 -0700 Subject: [PATCH 17/42] test - support vertex ai ertexai_embedding_embedding --- litellm/tests/test_amazing_vertex_completion.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litellm/tests/test_amazing_vertex_completion.py b/litellm/tests/test_amazing_vertex_completion.py index 84d3a2bfc..c7f3aa03f 100644 --- a/litellm/tests/test_amazing_vertex_completion.py +++ b/litellm/tests/test_amazing_vertex_completion.py @@ -816,8 +816,10 @@ def test_vertexai_embedding_embedding_latest(): litellm.set_verbose = True response = embedding( model="vertex_ai/text-embedding-004", - input=["good morning from litellm", "this is another item"], + input=["hi"], + dimensions=1, ) + assert len(response.data[0]["embedding"]) == 1 print(f"response:", response) except litellm.RateLimitError as e: pass From aaa4a32d65134d82736a403acb4e8f4056e4cfcd Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 10:11:44 -0700 Subject: [PATCH 18/42] feat - support vertex text input --- litellm/llms/vertex_ai.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/litellm/llms/vertex_ai.py b/litellm/llms/vertex_ai.py index c35aa502c..3b35562ec 100644 --- a/litellm/llms/vertex_ai.py +++ b/litellm/llms/vertex_ai.py @@ -1385,7 +1385,7 @@ def embedding( message="vertexai import failed please run `pip install google-cloud-aiplatform`", ) - from vertexai.language_models import TextEmbeddingModel + from vertexai.language_models import TextEmbeddingModel, TextEmbeddingInput import google.auth # type: ignore ## Load credentials with the correct quota project ref: https://github.com/googleapis/python-aiplatform/issues/2557#issuecomment-1709284744 @@ -1416,6 +1416,19 @@ def embedding( if isinstance(input, str): input = [input] + """ + VertexAI supports passing embedding input like this: + input=[ + { + "text": "good morning from litellm", + "task_type": "RETRIEVAL_DOCUMENT" + } + ], + + In this scenario we cast it to TextEmbeddingInput + """ + input = [TextEmbeddingInput(**x) for x in input if isinstance(x, dict)] + try: llm_model = TextEmbeddingModel.from_pretrained(model) except Exception as e: @@ -1453,6 +1466,7 @@ def embedding( logging_obj.post_call(input=input, api_key=None, original_response=embeddings) ## Populate OpenAI compliant dictionary embedding_response = [] + input_tokens: int = 0 for idx, embedding in enumerate(embeddings): embedding_response.append( { @@ -1461,14 +1475,10 @@ def embedding( "embedding": embedding.values, } ) + input_tokens += embedding.statistics.token_count model_response["object"] = "list" model_response["data"] = embedding_response model_response["model"] = model - input_tokens = 0 - - input_str = "".join(input) - - input_tokens += len(encoding.encode(input_str)) usage = Usage( prompt_tokens=input_tokens, completion_tokens=0, total_tokens=input_tokens @@ -1511,6 +1521,7 @@ async def async_embedding( logging_obj.post_call(input=input, api_key=None, original_response=embeddings) ## Populate OpenAI compliant dictionary embedding_response = [] + input_tokens: int = 0 for idx, embedding in enumerate(embeddings): embedding_response.append( { @@ -1519,18 +1530,13 @@ async def async_embedding( "embedding": embedding.values, } ) + input_tokens += embedding.statistics.token_count + model_response["object"] = "list" model_response["data"] = embedding_response model_response["model"] = model - input_tokens = 0 - - input_str = "".join(input) - - input_tokens += len(encoding.encode(input_str)) - usage = Usage( prompt_tokens=input_tokens, completion_tokens=0, total_tokens=input_tokens ) model_response.usage = usage - return model_response From 8dffc8620cc29d4a3518cfd6a674a01f223be6d5 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 10:13:48 -0700 Subject: [PATCH 19/42] test test_vertexai_embedding_embedding_latest --- litellm/tests/test_amazing_vertex_completion.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litellm/tests/test_amazing_vertex_completion.py b/litellm/tests/test_amazing_vertex_completion.py index c7f3aa03f..5291f2691 100644 --- a/litellm/tests/test_amazing_vertex_completion.py +++ b/litellm/tests/test_amazing_vertex_completion.py @@ -816,10 +816,14 @@ def test_vertexai_embedding_embedding_latest(): litellm.set_verbose = True response = embedding( model="vertex_ai/text-embedding-004", - input=["hi"], + input=[ + {"text": "good morning from litellm", "task_type": "RETRIEVAL_DOCUMENT"} + ], dimensions=1, + auto_truncate=True, ) assert len(response.data[0]["embedding"]) == 1 + assert response.usage.prompt_tokens > 0 print(f"response:", response) except litellm.RateLimitError as e: pass From 3f1dfc16611dd818589c8493526b363236ad9fc5 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 10:55:48 -0700 Subject: [PATCH 20/42] docs - task_type vertex ai --- docs/my-website/docs/providers/vertex.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/my-website/docs/providers/vertex.md b/docs/my-website/docs/providers/vertex.md index 3714265ac..a5c8e06c9 100644 --- a/docs/my-website/docs/providers/vertex.md +++ b/docs/my-website/docs/providers/vertex.md @@ -558,6 +558,29 @@ All models listed [here](https://github.com/BerriAI/litellm/blob/57f37f743886a02 | text-embedding-preview-0409 | `embedding(model="vertex_ai/text-embedding-preview-0409", input)` | | text-multilingual-embedding-preview-0409 | `embedding(model="vertex_ai/text-multilingual-embedding-preview-0409", input)` | +### Advanced Use `task_type` and `title` (Vertex Specific Params) + +👉 `task_type` and `title` are vertex specific params + +LiteLLM Supported Vertex Specific Params + +```python +auto_truncate: Optional[bool] = None +task_type: Optional[Literal["RETRIEVAL_QUERY","RETRIEVAL_DOCUMENT", "SEMANTIC_SIMILARITY", "CLASSIFICATION", "CLUSTERING", "QUESTION_ANSWERING", "FACT_VERIFICATION"]] = None +title: Optional[str] = None # The title of the document to be embedded. (only valid with task_type=RETRIEVAL_DOCUMENT). +``` + +**Example Usage with LiteLLM** +```python +response = litellm.embedding( + model="vertex_ai/text-embedding-004", + input=["good morning from litellm", "gm"] + task_type = "RETRIEVAL_DOCUMENT", + dimensions=1, + auto_truncate=True, +) +``` + ## Image Generation Models Usage From 9aa4b6e98c63b2ace88f2ba435bd846dd98522bc Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 10:56:36 -0700 Subject: [PATCH 21/42] vertex embeddings optional_params --- litellm/llms/vertex_ai.py | 53 ++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/litellm/llms/vertex_ai.py b/litellm/llms/vertex_ai.py index 3b35562ec..40c3bed49 100644 --- a/litellm/llms/vertex_ai.py +++ b/litellm/llms/vertex_ai.py @@ -4,6 +4,7 @@ from enum import Enum import requests # type: ignore import time from typing import Callable, Optional, Union, List, Literal, Any +from pydantic import BaseModel from litellm.utils import ModelResponse, Usage, CustomStreamWrapper, map_finish_reason import litellm, uuid import httpx, inspect # type: ignore @@ -1298,20 +1299,45 @@ async def async_streaming( return streamwrapper -class VertexAITextEmbeddingConfig: +class VertexAITextEmbeddingConfig(BaseModel): """ Reference: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api#TextEmbeddingInput Args: - auto_truncate: (bool)If True, will truncate input text to fit within the model's max input length. - + auto_truncate: Optional(bool) If True, will truncate input text to fit within the model's max input length. + task_type: Optional(str) The type of task to be performed. The default is "RETRIEVAL_QUERY". + title: Optional(str) The title of the document to be embedded. (only valid with task_type=RETRIEVAL_DOCUMENT). """ auto_truncate: Optional[bool] = None + task_type: Optional[ + Literal[ + "RETRIEVAL_QUERY", + "RETRIEVAL_DOCUMENT", + "SEMANTIC_SIMILARITY", + "CLASSIFICATION", + "CLUSTERING", + "QUESTION_ANSWERING", + "FACT_VERIFICATION", + ] + ] = None + title: Optional[str] = None def __init__( self, auto_truncate: Optional[bool] = None, + task_type: Optional[ + Literal[ + "RETRIEVAL_QUERY", + "RETRIEVAL_DOCUMENT", + "SEMANTIC_SIMILARITY", + "CLASSIFICATION", + "CLUSTERING", + "QUESTION_ANSWERING", + "FACT_VERIFICATION", + ] + ] = None, + title: Optional[str] = None, ) -> None: locals_ = locals() for key, value in locals_.items(): @@ -1416,18 +1442,15 @@ def embedding( if isinstance(input, str): input = [input] - """ - VertexAI supports passing embedding input like this: - input=[ - { - "text": "good morning from litellm", - "task_type": "RETRIEVAL_DOCUMENT" - } - ], - - In this scenario we cast it to TextEmbeddingInput - """ - input = [TextEmbeddingInput(**x) for x in input if isinstance(x, dict)] + if optional_params is not None and isinstance(optional_params, dict): + if optional_params.get("task_type") or optional_params.get("title"): + # if user passed task_type or title, cast to TextEmbeddingInput + _task_type = optional_params.pop("task_type", None) + _title = optional_params.pop("title", None) + input = [ + TextEmbeddingInput(text=x, task_type=_task_type, title=_title) + for x in input + ] try: llm_model = TextEmbeddingModel.from_pretrained(model) From 37d14a5e8c91fa74cbc897b2f0f5d3676a98e7dc Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 11:00:27 -0700 Subject: [PATCH 22/42] test_vertexai_embedding_embedding_latest --- litellm/tests/test_amazing_vertex_completion.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/litellm/tests/test_amazing_vertex_completion.py b/litellm/tests/test_amazing_vertex_completion.py index 5291f2691..daa8756da 100644 --- a/litellm/tests/test_amazing_vertex_completion.py +++ b/litellm/tests/test_amazing_vertex_completion.py @@ -814,14 +814,15 @@ def test_vertexai_embedding_embedding_latest(): try: load_vertex_ai_credentials() litellm.set_verbose = True + response = embedding( model="vertex_ai/text-embedding-004", - input=[ - {"text": "good morning from litellm", "task_type": "RETRIEVAL_DOCUMENT"} - ], + input=["hi"], dimensions=1, auto_truncate=True, + task_type="RETRIEVAL_QUERY", ) + assert len(response.data[0]["embedding"]) == 1 assert response.usage.prompt_tokens > 0 print(f"response:", response) From d3806977239790d4c923d896811097a5e2061544 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 13:16:39 -0700 Subject: [PATCH 23/42] fix - comment on /user/new --- litellm/proxy/proxy_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index d1591d188..789acf89d 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -8857,7 +8857,7 @@ async def new_user(data: NewUserRequest): - organization_id: Optional[str] - specify the org a user belongs to. - user_email: Optional[str] - Specify a user email. - send_invite_email: Optional[bool] - Specify if an invite email should be sent. - - user_role: Optional[str] - Specify a user role - "admin", "app_owner", "app_user" + - user_role: Optional[str] - Specify a user role - "proxy_admin", "proxy_admin_viewer", "internal_user", "internal_user_viewer", "team", "customer". Info about each role here: `https://github.com/BerriAI/litellm/litellm/proxy/_types.py#L20` - max_budget: Optional[float] - Specify max budget for a given user. - models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models) - tpm_limit: Optional[int] - Specify tpm limit for a given user (Tokens per minute) From 53ca1fe09fb9eea7879239ef2de55a3bd3eb78a6 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 14:16:31 -0700 Subject: [PATCH 24/42] docs - run custom path --- docs/my-website/docs/proxy/deploy.md | 27 +++++++++++++++++++++-- docs/my-website/img/custom_root_path.png | Bin 0 -> 154590 bytes 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 docs/my-website/img/custom_root_path.png diff --git a/docs/my-website/docs/proxy/deploy.md b/docs/my-website/docs/proxy/deploy.md index b756f56e2..a3c8590b5 100644 --- a/docs/my-website/docs/proxy/deploy.md +++ b/docs/my-website/docs/proxy/deploy.md @@ -1,5 +1,6 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +import Image from '@theme/IdealImage'; # 🐳 Docker, Deploying LiteLLM Proxy @@ -537,7 +538,9 @@ ghcr.io/berriai/litellm-database:main-latest --config your_config.yaml ## Advanced Deployment Settings -### Customization of the server root path +### 1. Customization of the server root path (custom Proxy base url) + +💥 Use this when you want to serve LiteLLM on a custom base url path like `https://localhost:4000/api/v1` :::info @@ -548,9 +551,29 @@ In a Kubernetes deployment, it's possible to utilize a shared DNS to host multip Customize the root path to eliminate the need for employing multiple DNS configurations during deployment. 👉 Set `SERVER_ROOT_PATH` in your .env and this will be set as your server root path +``` +export SERVER_ROOT_PATH="/api/v1" +``` +**Step 1. Run Proxy with `SERVER_ROOT_PATH` set in your env ** -### Setting SSL Certification +```shell +docker run --name litellm-proxy \ +-e DATABASE_URL=postgresql://:@:/ \ +-e SERVER_ROOT_PATH="/api/v1" \ +-p 4000:4000 \ +ghcr.io/berriai/litellm-database:main-latest --config your_config.yaml +``` + +After running the proxy you can access it on `http://0.0.0.0:4000/api/v1/` (since we set `SERVER_ROOT_PATH="/api/v1"`) + +**Step 2. Verify Running on correct path** + + + +**That's it**, that's all you need to run the proxy on a custom root path + +### 2. Setting SSL Certification Use this, If you need to set ssl certificates for your on prem litellm proxy diff --git a/docs/my-website/img/custom_root_path.png b/docs/my-website/img/custom_root_path.png new file mode 100644 index 0000000000000000000000000000000000000000..47de019ebba6f5553f43ffa491da0fa2441489d6 GIT binary patch literal 154590 zcmafb1zc3w`!|h%U?3umq983T4I&_oNO$)PIdqD`0@6K*Al)E6)PP8L3qvW*(A~Tj zb$`42m)#dWFn8`f^_=H9&w1i|ZlI#PBt9-FE(!_?zSN87N+>8;#V9D~``565J4MLJ zE#L#gOjJ%31?5v1-l+j5@SWP|g_0Z!iW@Boiq9Jqlw;tQ&k_m>pp(bw_nMSw15h5Q~AajiCvP3&{4e7K(riA8-jWaWtTI0a=3` z_*?`Z{3yW(TwmU1eL(%Ah@+L@19dq?YB3vo6KZajCoE4M2;ovwQw!J|oAN0=m-tm3 z_$K(k+|kjNkCoNg*_p+egT=<)jFpX-mzVVkJ1aXoGf;xr!4>Ri;KB@cp!wOzpY1$1 zaWJyCuywSs0aIVLYhY*taTI*;;IgCt{rnuKqlM{TJ%Js5kp&RQdijKvjpYgJRn<&f zEdHh1<&&S)e$e%^JAuo__%xJE9Biy1m%|cb@P_VZ!0jBcj$bNP5_j`XUe@P#oqJ@izwfb`lkO|n~k{S*U zHehU5KKj2^#cZr?>|fa$7?}vM{i^b}TmQH8kB&6{>WGbp1DLnJI{MqAUsVNIFFF1< z3HT{qKkfqZC4?)$`af9}!u>2lUygzzf+F=?RM`b}brRc0r5V<+Wy8o+;}|}53y(VJ zafP~KV4aY-k=&g?iB)K-M93qC{x9HnZ2MoP@C+NlcLFiV(1NH_IG1HK_PcqU7gtxu zw468Ar`!*OU0Vkix)OG3oDHUr4o$Zoy0r&;#iw1P_CZ1W_kTk&DeV2jEQ<3Zfh%Un zBW>?`|6^@itH&DS;wY#XH${H`2h9@s+#tSVEOj^pTUSLMZ4*W+qF!C}&+5Jsclxd; zT6dJRXVzzKvn{MRWEhI*T-o}MDp2VZRV>9lq&XXyrxMDCH}p*uQ{4V;?|ut1L*cW5_P$p-nv^?5c*f+mN=ZMSgIAq z3??$dR-WPH|54aCpRg_VU4g^~9f`Weflg-AzfV22j|do#QyEJ&(}dkb)7$<;t9kJL zzcWjO50g|7ok4VwtX9}q|Is1F(~$pSEOlQM+Fo~qR#nL z5mJOfgc^-(`J_-iqTZyE{+q0eXkx6q{}>fpW2Q%wQ{P&YXQNYu7wmtM=vZT{|CWAC z^54Y;kS=p2)DVxiX?o)y&0ALn`k${=?R?L(esvELh$skgO#&D zt<&PxBxRyU;T*Dgk;Cz*6jRiJQiEIF>XqaO;PvW8EUd0 zL&?F-=OE6{*1VgzH)@(-5!>6n?W^I%85|qbCjB`<{o7ftWh1!(3-!XtdaYI~-+B+7 zCibYACRQv~NdfPlj(NJP#)KRZrF`lO2}_G9+xJ z6&#oPL~-%(OwNw?*uBp^61YLo>lA#-+uIL{cE>9~j9Oq=hHL`6c>Upbyk$gXk-*j$ z!qi4KP%mpRF>3`X>%~394+7}%%)f`xqAd@MG9jSNMEC@99G!Wlu3b!236G3|&*hZP z6dpuwn9kXxd~M9IO)RYEUmsx^%uRyrv6=FYFhN1$|1xl_J1?SrGb%?!l#wF^;^;4% zo6E7q22utUgwKrKb2K!Q_#lz01)5`LO*e$KTS6%qFAiIU=N1xe2*wY$TB%F`V&iZK zY1_<_J!vZ^of6IYNinp_%p>x3>&A6^y?5~?}9mB{wOO9 zW=-fG3L+a|EzeUbDxj$S!eo~2MXz@C4kuELS%11M;|eegbagR&%hag5&Qk?6 zl4+-Euj;ka&MlmoYMmgrDMp>jqvPjUO3k4pn7@nCrFF#qLc~v<6@FS`POBV1K#`u3 zLan}n=srF5aNQeL6JLZ49F<=xVc1#)Vs17}m;g#CS@wcfHl8|9wE#D?)c11d z34e(uCToM0IImG!g%X=cme-#vw4dxSF6M=BHa-JyAN$*;#abro#%i#S80kd~T z6yCPF+T>^x@J&s9Fy^t-Z8FyuF_5RmO3%z(-gGvcmBpxZx}IIFng5*iHhkZR1-AMpolK=w%ju2L?p;D4B(9a2~EQNC`OPayn0#9ea zGYp4TTJ0xcRIA%ai$3XKtm5PNd6m*KHoSjf;4c!WoiSn)C4miY%v3{bPaVwk)wUtG zM+~RhCpy>~1{pqk9W&wp*-OdGa?m}J`7}1V%l29g%lGwv7!B9v;(c0tIPa#j-4~Wf zN3eJqbAxbN<0kCXdJCFbtuQhs+N%rqXak@oS=HPPkgJV_Kh0zk)|5}wAvhM+*`h(* z`C`|O$5hTkCPDzc=U~O-s4wI2QmeGqBDTj1-J0glI#;$h_rBrT&U0Z7KwU+v2_}(A z_u*44jeyNXD+_Ze^R??{eDI!QVy{$vL@gxjdbXJx>Z9%dUql*5__Vy?n&_Ua4>igbZ{-% zh^gvgh;yCa&yye3#9Y)7$yE)xLtsu8koa~+1=n2p-~6^894*lnF%l!Ck(R8@!4l8M z;>zpLEBnB*9*-D>6=}xLoBx{{{!@yfaXu}7aH^)W(GUycwnk0VYqj3S?XeQuqaW{! zH62S83bAFrdN=%~UPV-K&ELH+5+~)5*0OWZfMMy(vJ}tnPaeI_#SckehQ0QlI{4~a zpjlzRsPW$%uw2yy=M2l&Q0JSDN$l+CemnnNj^%u=rv~=veQcgu5gX1P zt!sg1^y-SH$^XY=s>R4P6esntN6mFZe?vCV;i$TOPuJw zWv%bDQDjEJS`?G@!GFNYgP}wTd~ZRWnl}bI{$&sUQ)U(z6^S?)IMGPO?6)2g>)Bfo zd)q61^K=&Iy`c&71Iz(JW>;nzt-WCDZM~}%<^Nh@09wK|e6a`Vdl9eq8I`$`N*B?l zVIXSfePLK}^#=7nQArk2>3T6Msd@U2ak6OWB3|j124)%>IDfpT+}<}wlkPkDH86O) zlCLGFmHxknVM+}Q!=6N)C02QnZuB}6G3KCzcGC~JsczX4XlKmZNrK({Qz!l!{6D`^ z(_z%cM^L@8M}XJ9%d+frP&iw~5gT-K7 z`O?nR_I%|RE!9$%1&U<<9QvOV`lm`J#u&KEKX9E1{)Wuy1iZGg;&m9$AGe1rDN)@g zsdio_7m(4=kSgxR`bka#ZL$44DIy~#PZhCOi;2fk5KO;E*ZaRVBWFpIEhnp<1 zl1BI_&mBNtG%%bVNxW8bQ%0_o_aomH8Btv^4JoJ?yD{=lKg{`K$}T&x_{{Sx@TBnA zi`%5^Y3o!vEtWbJ_%a@(vRYBS4*jVdT;b0qjNW?#o^#+uZ51EEJ*@MdM`jLJjXn9#-iG5?A+FBx{N1#VYT zwky>LXSxrS*ua{tEkllb4N7dV2dvy`q5x0Us=8ni(hqX(u{PDak7PIz;&6L+sc;m% zQRD0;hMI7(d>}Gll3j=YPhzVomw(UaLBc2&S{}kgC+V*?EREtR$Eo zu4~NcTA@}x%!!<&bBW2nv-e{v>|X*V+_AI4t2_K~l~)sAYs_eO8<7NwS8bm!F*tqZ zQ#D@7BOF+y7e-|qb;>H(zu#-jdv|zm3FA@@MF{aYoo+I++b1U=J1#(}f!7~+KJg6P z+wg#9>rLGKoz-oqsGcXYbP7jonJzZ|+I2n+HV>c1=aFF)+3!Wo!+s2Lpj zlq(OX#wlf<6kqTsHNZMGgW>g^VQSG~DK6$;y1-kWYkqn-%Y74>D$6IouR`ldy8FWjq$b21ICD11 zIE#6B>Mlhq1Vcu(f9c3vuLhT15ldx%MNJ;QZ6qhPS5=&=>hf5$asxcW^IoOMne@9} zbe=|Yi!^;(STU1Mjf9Y9iAW~Pk!Zbcz4G0B#<)jBWK5ud*J#TlsWI2BC*}Q}mmX+2 zFEOlXMSpehBHKr~_-XW};9%})oW^Wd;7+8 zXBKi)I-^6`I$CuBU)^qauy?9hv|b%9tE*G`Y}+fIMl4vf?L*>j_?f#kLtV%CSIvcK z4+J*{+B^9lh5)CQZ^?k_p4YzgPMpC9d9Rq}N5miQ2Oll-{Zzky8|R$ANS%=sX~Q;+ zULdJ#1{i$PUBMu-@ZmH@)`+Tdo7l8`6#rsZIF;O8)%ohZfk)FAINeA1raIq3MALoq zZ#(1{ujowC(P|+FsZ2ZlcHl8l?)c$so&nN$Q5i%Qh#Hb#Ym>7?L_;GmI;K1_hEZ+w ztS8VbD%-s?#My*JKy22+j_!BG&_HZ!qw2U;akc~I_vl%x@g_-%lg5gzQ71d7oa|-? zC-rjdkeAr9Q1 zq9S!|=v<2}Fqpkennh5?|MnpBZ=7n=LA@9bf+r0S((%7Z!KyyhkDDs);gQP;kkf`K zad%V)NyAnKE9Xo1km&(9ng#5)Xz_K$@l=<$(7ID|JGz2K&e|ZEx^|!P+4suiKw2AH zaiD|f2T?&WYJU8hjO|p39A<^fJy^>_Ii=CDv9yqHK&+3Za>72%5ji5aUNxJnq^%u2 z1c4Nkd7WV;@YodA)tdEADJjl)Pa0NM1A!uqI=7gF(u@$t)vx!Rn)^u122#akmdDGj zmaJDNk9HQ@t073)3*2D4 z3>EjEJ1-A#fm{6CN0fywswi@2+r@+LcI0c68Ux9$NSlSXWKV6wcQ>Z>#w%^qTJOS` zbkNrM2Vgt213>Vts(Z!RdA?(Qp+?K}Tz2`+Pyw>nwhx7j_d#Fr#gf55I`Q1FRIgUv zOZN>rAoym3Ud^>y%BkOKLHhgNVJ_`!d)ijFssK5Jr7tvejEls`OXwxvPB>uDqdeX> zN+<)DJMv(2x@3H+F>hpaFTzKf3>FH`_wujbN6OkV0IU48WQyEMMcq7XdUNZ9-E~1t z3A|qps%sUSmW`UlCXhjTsM95%${^nE^ujMAJ2r5Bw#sSG1CTrT{Pbvh(z#Tw*g#*= zd8*d6#Gnalx$mPN4tWe_E3$N}n}@^X^l%VF=sfKihVvexkP9QTsTG~_zJRm4?V9r* zOzcEeOEB^hPI`S0%(`7)HtNQxRv1mFARx*EN_c7)iI8HwrzO+L{yLo&WR=O;i@zwv8r?GePvsB-wL61{FQmPi;H_2zsit zgbGUOdVAVO?J`gDc&?SJMOkhStLaJQ>ZVF_n0ioP6qT*>Z`39(MOH12=4*h^ae?S} ztjFn=q#crbzkLIKp(`)AH!8ZBt5f4ta<)%n^5u_PwC2R^yRP#wadIeDwM*eKcQBw) z4II4!%skT`uLi>MA;2IK(vdt);wKyYq$ip99&l}sOf1?o*WXlxhzO>k_|x4gt@p}Z zXU6_F-$7_bUF3_Bp@KSh@7{e8wnyYNmFIFp%fKIXwL*%AH>DRv!wOA{CIGp(BN zI+-Rr6-u!610+XjfBM3wN~b?AUO{lrc!IC}gU8-56ty%?&r525!a-RnE`UReb7=>D zAs2%H*Qj_MFVn$hUhm9*a9@|PQ2&w+)^3$PF3|}f7_#3VTWss~uD5wIVIbZtan$Qg z84avb$@(MHSXt<9E((4Bb>uW?PeQ9iRehaMZk=<3io=;_M(y z3;s!AVOh_G_Ym=#_9e1ZWnre2Yv1|J$!|WmNGWk24->a_Wd57Z2Hern+5Vnod}z1T zdlO{G{5;j7bnqTh&R_ZUHxfA?>C&PW{3!|Pu5h1Y`a4h_y=oR_rbsR_hPkqK)((qa zK?cT-(HABv`+>X^cj^MBtRi7qQ~bn1SYDiMB~EMA?>xyV9&DBN3I!wJ3PMM1U7|z@ zX^h}z3_70pjmDi`$pstUr4&C9h(c3gaXVMW0#Q*wvAqVw2YIxfS0F<`1mN3A_c|Y-~07$NRkg z&wO1O^$Zr?Fjx%AhmJWGC%|(DREI}rNxR$}&b3J{#&@>Y!gewg(bX0_>NQp&<6xD3 zuT;U%P+uB!^L6LBvCA#H7M&pDIjub=1=iNAL~56B-(-BGaE ze;12GSQs@`=Z*lK^+rCDnQz42xWSIK8&5!1xmH1A45-v#{>7*f(CYStLvP1SWBFp3 z{h7=DnAxOh-N>sfd7M-Er{A6fiJ=4WMUp{->tO=+vPp=MZ3uw_|4TEuQxYs9mr%`JthiKKyR8(fQ!rE=zqq(Rsadf>_O858t)}!k+8s=zC z&XW-55LhYaW5|FM9qBBWJ&^F}bV7irv`?noH`<$STx3ZU+XpjOgbVK9Gg-L7|1f*e z#(Z<{Xfe4oISS8ye|=KYYcDSrQv&>t1b+ zvt0-H;)j~~waV$pvwg($`pM|>exgmiLCN4b4c|n1EO@ed%xnx)Icd@set$pyBH1YP z=xstAxbF1)fViV8fn%W#qVaEFBZ{e8e_E%#l1iWEl;CWy(P)|Q>;@ENWN&R zXwZmPEt5q@f4lDi>oB9CKtYdQ`ILZbJ&DjJapH{#`A3gRoYLCU*&Vc&i+$C+4@1e% zhtS!bmksHem`itbcpuk|uoAHdHftXU*Eti$Zf_5B9~J|-wiIIMqx7bsBk==BPWIQE z+OUalKEw+9;cOJ5$t5$d$>xTW1ppNH*9-% zPyyk!RL5D`!)gORtI&4rf4e;(!-@&eSL8de)5FiRG}{rwc-FaEVOpSL*E}z}DSg8- zd}lc;nH{yX)M~d`C;#qv7~Kb#E{qQsx<;W~Y5|Z19P^tper1JkI6hfo7wz}9&BW}( z2hPssDQN>nV5io+yKGy3dbEE<)Wdnv`oBwhJ^2DU*?PR@S%Ca*qA&h{Cn6y9R((5p zg#S|eu8FWzMti=!XukQu;}MiN9QFCcE(QuA#nSAcuHf2>^Ct@OJYrZqr{GL$>;3_4 z%WHBAO1gGMHcXgqvJqv92S$D+p6r~6%gpQF!a{`F)|9|GczAYC!XZD zoDoMm&a%HcHfYR?&!Zu5V>qW1NCsU)Gf0yNDFKJ2OBjiA`wXQwe=GJ+Q!v#B$~Q znk9}dZd1D@VY?PU<@K0PFOhLDQyfk6OjbfOfM9Lyo9oU(J588?b>;90G5o1SwetqO zp7&Wy!ssgfNrL&zOmP!IB}qVG0kY^Kc&&1s%5%5B1OZMRJ!vr5k@o z!ZD}dT|LB|Hk|+@OvU{PC>Q`~W*0`c8Cx8nRxe9EgD*hy*67R0I2O#K#=dr9l>#&n z)YNZ&7LMob1#>huu9rjml9|s4EcBfkd{7s{3YWZFhN{ESO!MC!?W!jQL}cv1qR;3zyQEDT^+G(O2 zH+ev;#zQxXH&Sp5pGRf!?y#3^cRd65nA(YTb@}xtV%K65U5oE5ov1L*e_^hO*$+!940_}IcnLZfSg$OKC4#gG+j1HkpVT;M z*L}a4I2l_E)oX7!Zoi)ovcd#~?5@{r#G~|oov{->KcuOt11wL>R@Fl7N3B%euVIqD zI4KmA*Lj~BwFI zic(0X*XFc!UMnBftl8w<=TJ*=x``YkP3k_KiJ>4FJv~xSLqNt8IG5j6je7E1N!aRE z5)MzhZ+QA0Lniy+HG^B$kUHVf-)t=uG!5FB*6`FiHg+2=%V={**|QIL`bXtDCeDNx z+NI;VhG+^V&_;dse8alB0a!lwox2@2{$MLKWm7QYPOMB*K)@cAa?=W3lrQI$v9a8R zov-qjYr122U3EcnWWk&}jCjF`rIL#{+kR^6F9`%TMK~TJbes-=Eii_;;_F0`Wyzkd z`N-g?fk(@P|h0U1Uz`k5b{p2GEpni(mhs*B!^TdKz z#;=n;bpSHL2w-ALvv{Bz9jW5Mt9|bPEAEY8rtims$|>5Bc_}KrN_nx;ewhzPUMkIlc5hI_qQA`aRtv8Ee1qJm-^HEWFSKM5j2wH)RCr-V6gm5 z`Ln(e5)RXM35ezUWOq&gM2&HjTy;Fvp!CrakYMWU?I7hee?@pRk5c|gRp3~k>=XRE z7Mqsm9)#+J3>;=&YuxkkMxpo>lm5C{O;Rhip5L|sGXf!YtP>Xd2r~2%er+Lir)XF| zr{^SNezPeodyAsq2>LQpOx_Y}W_NjTPqCl`FkWuf=4M1vV1E{68bzWLJQZmP>#gN2 z(!Lm|^MVZQ04{{pf@A+9T`5TvM%|P5SHW{$NHsJkbN-Qm_@=KK(y}WDt7%BuWVH=3 zPqGzMgKHG+j26Xx^Th6GW0^Fm!*Q`dk?G9EM`rY0N6m0B5PUl80GrthEU|C4r{~ll zfd&!TTocW3S~DgqbpKQ+mVUNo;~j$V#J_F)3`J(qavbotKu_k!%#sUkH4J>5FC({Y z@NInJWJkr&(hhT2#AxbYt3SymE$76O;%MMRn0G`U$jub-xo1m=mpTCZ!J8YHC#1E< zoqC0NYQp7g6!sf&aDn^gJmW220;5tXLfvHj)JfkDi2JD~dmZO==ejK>wP~x8QrE6m z<0$FYs}k@nHKc?9$c7%Q;!OD@%VWZJpMm?^W!I^MCa{V=xUEQ$l?^oX03t-##Z%sV zw>;qG(22*{o+H_tA=o5NUE3mPjkpZ}&YZMmMlV=CQeOSegFRH1$Py3B`tqsw6S^g-#IL98!bBLl-ASi^d zmdIF|j8;WO(bnDJ@tI$Nl@q)I0Aw^>#lC#x(>(+Ao~N*k3CPw6RO+juxSw^k`4gE^ zX-D;DWD&dv>jSVkOYrxGVY!r9*X@ls6^PMT+7{Ic+$JADLYBnwZ2jOT3Ho ze64n;CsmX~ZP)JnYy*2$+h|=q6$0Rj3I=jxaGth4X4Z@z;wzoHPPZZ*d{-P?I#QjU zzF$r{=P2%H*^g$mUh9_6-W2WcX9cBDOHS4B43uVv+%9iC8b`bI-9vzdf{&kz>@_y+ z^`3Xrx`14u`hDlV-BU$ce&A(?bh!O{q)CK24PzHG(;aoqMsh73Prum>nbX>|`1#}| zS$Fs&zs(q3_Sfci3(E zZ$z5uIVL(RJTmshQMA}s$xo$fvvjDovK#EdC(82<3`LSZgL-BpFv2g+Hqun};Ps!c zi>m1(pBMCDVAC{pflL=820pHb@~^v)^$ip*-E=rRIVf@{+MV_K_IAZphx0H+rYzM# zoEd=A0iZ>)wK5W~tq<8v1L6hRt$uu~lK||IYG*|tN+Uir(#C&r0zgE~C)${{0}&+1j~xi$DYUAova1Hs`ez7VgX>2BEScucLJ9y2!~v!TJk3=qwDsj z^xXXhAmnyJmQU58f-0Jtrm?EqHPdI@_h<)nW=ryRr=TkH3#s;tkhL2eOQBXGQs~xD z3ji%Y9q+!jDvxP(CS;DKQnmEtkHXXaN_eTLa^=Pd5nt;E9Hr$6P=RJlb<>{a2^*{D z)N^rR8fIoq+k95`Y-F>vdJ!?CvcTsfN7)gPJ$*JvHlY9_Gj;Kt|ugmF*Esz!4 znn$^93Sp+03&8F^eaZJm(HPlGo9}k|`wCiQnS`_9*hcIg;G^jvS z#cF3_YTlY!fkrCo5Z$?ZrimaHXmk1w>GBhcG386V91MshJ`cbbSS@avU(TXo4ZFd& zG~*`Nl9lXbxR9%9j;NY>Jq=M4+KwlsGbLh|hG?7+uYs zF^%5+*lMigIS^t%BXqR$ULUf4$&sUt(%HQ+Z@DC3Nvhm$fKAMD+D|#}$eGeCcVnFY8QjTuS0&=hctw5@OGRAj=ZI4?OeZ5aRSzpMNz4tws z^*G@58gnJNHM%h(FViA!eg6eg_>`xCJ7zjy{O zbGRkL+xq6Mxc4n%nVzH6E-Ev1%N1fM(2tl1=cR{|*S~fV;AJ=F^~SNp_A3ZckHU9? zUU>OhGclAj=EXN*`tQDWkGE!V-{?D%ML<|f&b;u+pEj(o2#ECS`XhrcPB!2Q>vac| ziLSGHh#^GHYDpeG_mZ}hn%wrbVX4-u%;#tdnxg0_UUrSSIj@AHd8XfCqyjeoU1btp z`}9e#xrl(Z#d-h7*BRnNY~V>CXC8z#$3^kvNEgdlZBvH(0VVf|OxVR<(P(1IY7KX% z%mFd0uA#r+X>j+*;F;~1>tfr1xVO-*dzpFv11*y#e_W2%F>L!WlQ@6YPbcEyZ`sWi z)5CyRU$nBaGIsqWrd!?ls=)c7(Ym7M2+J$k0Ot1sN9EZdFemB}5Ei9*nza-Da)mDZ zu?ysQd3L@5{RS>LH9;M~Gl~@_OOd%wO-CdQ6*=xc0{BEBRQ3Y|_?Mq~dG!Y4^j;)5 zOY=3dy&*`9r}h;Oi8b0QJsWj8P}jX@;CqdG3()UDd-l7gVi}&pPc)sq&LgyU_ZgMI z{{Dlo!rixV6zqycGTY6%^*JX|N5rdsc)=z}g30f@`QR)^a2Bt_gE7K>P4mG_NY_W? z=`j$dEpN;M2H4b9v&%u~`1RRDtvFwPqG^#i3Np;QR-L741`PngTJcXL)c3*9_O-fX zPG2-UTTBX4Et~SkFV~x@sfHfiq8tDnZO_{!%OUAH?)CFwQ@W%GoNkJ3pPyWmSMu-n ziDgt(wN3KPm-l4seh-fLhJG++M#aITzDg?*GCpWpwESKH2wWxMr0j<3@Z$9>Df$4o z@ycl;{PFjW1MS;8$s2?ot+7lR3q zj{x(3ru5#ZJ6IjZL|u~~_U62n=>QVk|C(0P$x`!mBafi@pkMOUd~ROhb{-bum{-Sj zUWJx$fd_!&EoXR_Epk3yELnCmZ#UmjUMAOuA2zdb=gFRA1bZi8iSs+JTXS^2CQ}8G zdmVn;UKG|dS=_4zEF*T)u6sLzON`J2ZrANRr}`%axg@WbnU3qcmoozQHTKSbVA@qE zr71?~VdD!BIm_R~0 z7z4?t!go7nS`v=Mlu2##W_j3naS#3}Hka!hpXDZ_57F}~*&FtU<;ot@6{eKAbv(=T zgLiu(3^{BD-8k-~bZ4@&I^s!7 #L}AkELl(#g=ZA|jrA%IaQil4dKD0Gi=w?r& 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%0D9-(7UyZ_36T_cGm8g=l`E!KS+2>=FG{$8( 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 Date: Wed, 12 Jun 2024 15:00:00 -0700 Subject: [PATCH 25/42] feat - add mistral embedding config --- litellm/__init__.py | 1 + litellm/llms/openai.py | 43 +++++++++++++++++++++++++ litellm/proxy/litellm_pre_call_utils.py | 4 --- litellm/utils.py | 18 +++++++++-- 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/litellm/__init__.py b/litellm/__init__.py index 6dddc8a22..3ac5d0581 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -787,6 +787,7 @@ from .llms.openai import ( OpenAIConfig, OpenAITextCompletionConfig, MistralConfig, + MistralEmbeddingConfig, DeepInfraConfig, ) from .llms.azure import ( diff --git a/litellm/llms/openai.py b/litellm/llms/openai.py index dec86d35d..fa7745af8 100644 --- a/litellm/llms/openai.py +++ b/litellm/llms/openai.py @@ -164,6 +164,49 @@ class MistralConfig: return optional_params +class MistralEmbeddingConfig: + """ + Reference: https://docs.mistral.ai/api/#operation/createEmbedding + """ + + def __init__( + self, + ) -> None: + locals_ = locals().copy() + for key, value in locals_.items(): + if key != "self" and value is not None: + setattr(self.__class__, key, value) + + @classmethod + def get_config(cls): + return { + k: v + for k, v in cls.__dict__.items() + if not k.startswith("__") + and not isinstance( + v, + ( + types.FunctionType, + types.BuiltinFunctionType, + classmethod, + staticmethod, + ), + ) + and v is not None + } + + def get_supported_openai_params(self): + return [ + "encoding_format", + ] + + def map_openai_params(self, non_default_params: dict, optional_params: dict): + for param, value in non_default_params.items(): + if param == "encoding_format": + optional_params["encoding_format"] = value + return optional_params + + class DeepInfraConfig: """ Reference: https://deepinfra.com/docs/advanced/openai_api diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py index 089d469af..d8dc798f0 100644 --- a/litellm/proxy/litellm_pre_call_utils.py +++ b/litellm/proxy/litellm_pre_call_utils.py @@ -79,10 +79,6 @@ async def add_litellm_data_to_request( data["cache"][k] = v verbose_proxy_logger.debug("receiving data: %s", data) - # users can pass in 'user' param to /chat/completions. Don't override it - if data.get("user", None) is None and user_api_key_dict.user_id is not None: - # if users are using user_api_key_auth, set `user` in `data` - data["user"] = user_api_key_dict.user_id if "metadata" not in data: data["metadata"] = {} diff --git a/litellm/utils.py b/litellm/utils.py index 85f5a405a..036e74767 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -4943,7 +4943,18 @@ def get_optional_params_embeddings( message=f"Setting user/encoding format is not supported by {custom_llm_provider}. To drop it from the call, set `litellm.drop_params = True`.", ) return {**non_default_params, **kwargs} - + if custom_llm_provider == "mistral": + supported_params = get_supported_openai_params( + model=model, + custom_llm_provider="mistral", + request_type="embeddings", + ) + _check_valid_arg(supported_params=supported_params) + optional_params = litellm.MistralEmbeddingConfig().map_openai_params( + non_default_params=non_default_params, optional_params={} + ) + final_params = {**optional_params, **kwargs} + return final_params if ( custom_llm_provider != "openai" and custom_llm_provider != "azure" @@ -6352,7 +6363,10 @@ def get_supported_openai_params( "max_retries", ] elif custom_llm_provider == "mistral": - return litellm.MistralConfig().get_supported_openai_params() + if request_type == "chat_completion": + return litellm.MistralConfig().get_supported_openai_params() + elif request_type == "embeddings": + return litellm.MistralEmbeddingConfig().get_supported_openai_params() elif custom_llm_provider == "replicate": return [ "stream", From cb386fda20d5d51a1babf451db4122a7d9b6d411 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 15:10:20 -0700 Subject: [PATCH 26/42] test - making mistral embedding request on proxy --- .circleci/config.yml | 1 + litellm/proxy/proxy_config.yaml | 5 ++--- proxy_server_config.yaml | 3 +++ tests/test_openai_endpoints.py | 8 ++++++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5f4628d26..736bb8e8a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -202,6 +202,7 @@ jobs: -e REDIS_PORT=$REDIS_PORT \ -e AZURE_FRANCE_API_KEY=$AZURE_FRANCE_API_KEY \ -e AZURE_EUROPE_API_KEY=$AZURE_EUROPE_API_KEY \ + -e MISTRAL_API_KEY=$MISTRAL_API_KEY \ -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \ -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \ -e AWS_REGION_NAME=$AWS_REGION_NAME \ diff --git a/litellm/proxy/proxy_config.yaml b/litellm/proxy/proxy_config.yaml index 3c6b2f201..a21378f31 100644 --- a/litellm/proxy/proxy_config.yaml +++ b/litellm/proxy/proxy_config.yaml @@ -14,10 +14,9 @@ model_list: litellm_params: model: openai/* api_key: os.environ/OPENAI_API_KEY - - model_name: my-triton-model + - model_name: mistral-embed litellm_params: - model: triton/any" - api_base: https://exampleopenaiendpoint-production.up.railway.app/triton/embeddings + model: mistral/mistral-embed general_settings: master_key: sk-1234 diff --git a/proxy_server_config.yaml b/proxy_server_config.yaml index f9f77c05a..f1853dc83 100644 --- a/proxy_server_config.yaml +++ b/proxy_server_config.yaml @@ -85,6 +85,9 @@ model_list: litellm_params: model: openai/* api_key: os.environ/OPENAI_API_KEY + - model_name: mistral-embed + litellm_params: + model: mistral/mistral-embed - model_name: gpt-instruct # [PROD TEST] - tests if `/health` automatically infers this to be a text completion model litellm_params: model: text-completion-openai/gpt-3.5-turbo-instruct diff --git a/tests/test_openai_endpoints.py b/tests/test_openai_endpoints.py index 83d387ffb..e2f600b76 100644 --- a/tests/test_openai_endpoints.py +++ b/tests/test_openai_endpoints.py @@ -22,6 +22,7 @@ async def generate_key( "text-embedding-ada-002", "dall-e-2", "fake-openai-endpoint-2", + "mistral-embed", ], ): url = "http://0.0.0.0:4000/key/generate" @@ -197,14 +198,14 @@ async def completion(session, key): return response -async def embeddings(session, key): +async def embeddings(session, key, model="text-embedding-ada-002"): url = "http://0.0.0.0:4000/embeddings" headers = { "Authorization": f"Bearer {key}", "Content-Type": "application/json", } data = { - "model": "text-embedding-ada-002", + "model": model, "input": ["hello world"], } @@ -408,6 +409,9 @@ async def test_embeddings(): key_2 = key_gen["key"] await embeddings(session=session, key=key_2) + # embedding request with non OpenAI model + await embeddings(session=session, key=key, model="mistral-embed") + @pytest.mark.asyncio async def test_image_generation(): From 95aaef4f94da7c8077d54c9e8caacd1e4c45a11a Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 16:32:16 -0700 Subject: [PATCH 27/42] feat - add async support for clarifai --- litellm/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/main.py b/litellm/main.py index 8133e3517..bd657e686 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -335,6 +335,7 @@ async def acompletion( or custom_llm_provider == "predibase" or custom_llm_provider == "bedrock" or custom_llm_provider == "databricks" + or custom_llm_provider == "clarifai" or custom_llm_provider in litellm.openai_compatible_providers ): # currently implemented aiohttp calls for just azure, openai, hf, ollama, vertex ai soon all. init_response = await loop.run_in_executor(None, func_with_context) From 235f068ddbf38f577d8a36014df1d80697d55f43 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 16:33:56 -0700 Subject: [PATCH 28/42] feat - add aysnc support for clarif ai --- litellm/llms/clarifai.py | 57 +++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/litellm/llms/clarifai.py b/litellm/llms/clarifai.py index 4610911e1..785a7ad38 100644 --- a/litellm/llms/clarifai.py +++ b/litellm/llms/clarifai.py @@ -139,6 +139,7 @@ def process_response( def convert_model_to_url(model: str, api_base: str): user_id, app_id, model_id = model.split(".") + model_id = model_id.lower() return f"{api_base}/users/{user_id}/apps/{app_id}/models/{model_id}/outputs" @@ -171,19 +172,55 @@ async def async_completion( async_handler = AsyncHTTPHandler(timeout=httpx.Timeout(timeout=600.0, connect=5.0)) response = await async_handler.post( - api_base, headers=headers, data=json.dumps(data) + url=model, headers=headers, data=json.dumps(data) ) - return process_response( - model=model, - prompt=prompt, - response=response, - model_response=model_response, + logging_obj.post_call( + input=prompt, api_key=api_key, - data=data, - encoding=encoding, - logging_obj=logging_obj, + original_response=response.text, + additional_args={"complete_input_dict": data}, ) + ## RESPONSE OBJECT + try: + completion_response = response.json() + except Exception: + raise ClarifaiError( + message=response.text, status_code=response.status_code, url=model + ) + # print(completion_response) + try: + choices_list = [] + for idx, item in enumerate(completion_response["outputs"]): + if len(item["data"]["text"]["raw"]) > 0: + message_obj = Message(content=item["data"]["text"]["raw"]) + else: + message_obj = Message(content=None) + choice_obj = Choices( + finish_reason="stop", + index=idx + 1, # check + message=message_obj, + ) + choices_list.append(choice_obj) + model_response["choices"] = choices_list + + except Exception as e: + raise ClarifaiError( + message=traceback.format_exc(), status_code=response.status_code, url=model + ) + + # Calculate Usage + prompt_tokens = len(encoding.encode(prompt)) + completion_tokens = len( + encoding.encode(model_response["choices"][0]["message"].get("content")) + ) + model_response["model"] = model + model_response["usage"] = Usage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=prompt_tokens + completion_tokens, + ) + return model_response def completion( @@ -241,7 +278,7 @@ def completion( additional_args={ "complete_input_dict": data, "headers": headers, - "api_base": api_base, + "api_base": model, }, ) if acompletion == True: From 0566f359997be10866deb82cd0b7eec377a7d7d1 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 17:16:48 -0700 Subject: [PATCH 29/42] docs - let users know clarifai streaming --- docs/my-website/docs/providers/clarifai.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/my-website/docs/providers/clarifai.md b/docs/my-website/docs/providers/clarifai.md index 085ab8ed9..cb4986503 100644 --- a/docs/my-website/docs/providers/clarifai.md +++ b/docs/my-website/docs/providers/clarifai.md @@ -1,10 +1,13 @@ # Clarifai Anthropic, OpenAI, Mistral, Llama and Gemini LLMs are Supported on Clarifai. +:::warning + +Streaming is not yet supported on using clarifai and litellm. Tracking support here: https://github.com/BerriAI/litellm/issues/4162 + +::: + ## Pre-Requisites - -`pip install clarifai` - `pip install litellm` ## Required Environment Variables @@ -12,6 +15,7 @@ To obtain your Clarifai Personal access token follow this [link](https://docs.cl ```python os.environ["CLARIFAI_API_KEY"] = "YOUR_CLARIFAI_PAT" # CLARIFAI_PAT + ``` ## Usage @@ -68,7 +72,7 @@ Example Usage - Note: liteLLM supports all models deployed on Clarifai | clarifai/meta.Llama-2.codeLlama-70b-Python | `completion('clarifai/meta.Llama-2.codeLlama-70b-Python', messages)`| | clarifai/meta.Llama-2.codeLlama-70b-Instruct | `completion('clarifai/meta.Llama-2.codeLlama-70b-Instruct', messages)` | -## Mistal LLMs +## Mistral LLMs | Model Name | Function Call | |---------------------------------------------|------------------------------------------------------------------------| | clarifai/mistralai.completion.mixtral-8x22B | `completion('clarifai/mistralai.completion.mixtral-8x22B', messages)` | From c510f6bb18900e7d5e38b61e811a7e9068151347 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 17:42:08 -0700 Subject: [PATCH 30/42] fix - error internal users see on SSO --- litellm/proxy/_types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 1930a0faa..ccc8ed347 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -224,6 +224,7 @@ class LiteLLMRoutes(enum.Enum): "/key/delete", "/global/spend/logs", "/global/predict/spend/logs", + "/sso/get/logout_url", ] management_routes: List = [ # key From 18b28a1631a5b98f038d083ec0dad64b6d3cd6a6 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 19:30:37 -0700 Subject: [PATCH 31/42] fix - don't raise error when logout url does not load --- ui/litellm-dashboard/src/components/networking.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 4a53df12b..0f03b9fe0 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -2405,7 +2405,6 @@ export const getProxyBaseUrlAndLogoutUrl = async ( if (!response.ok) { const errorData = await response.text(); - message.error(errorData, 10); throw new Error("Network response was not ok"); } From 8987f16507a380ed914c31aae6834afa5e6eb2c3 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 19:37:58 -0700 Subject: [PATCH 32/42] fix - sso pass correct role for user --- litellm/proxy/proxy_server.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 789acf89d..1bba35c82 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -879,6 +879,7 @@ async def user_api_key_auth( ## check for cache hit (In-Memory Cache) original_api_key = api_key # (Patch: For DynamoDB Backwards Compatibility) + _user_role = None if api_key.startswith("sk-"): api_key = hash_token(token=api_key) valid_token: Optional[UserAPIKeyAuth] = user_api_key_cache.get_cache( # type: ignore @@ -1512,7 +1513,7 @@ async def user_api_key_auth( ): return UserAPIKeyAuth( api_key=api_key, - user_role="app_owner", + user_role=_user_role, parent_otel_span=parent_otel_span, **valid_token_dict, ) From 490f5265ac2e5fa9eef5a42688b567d113930c65 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 19:38:31 -0700 Subject: [PATCH 33/42] fix model hub not loading --- litellm/router.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/router.py b/litellm/router.py index 251c9eebc..4d7a36a38 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -3618,6 +3618,7 @@ class Router: except Exception: model_info = None # get llm provider + model, llm_provider = "", "" try: model, llm_provider, _, _ = litellm.get_llm_provider( model=litellm_params.model, From 2a3281796333e51563a8ba3a67b3d2c64cdd04f9 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Jun 2024 19:47:56 -0700 Subject: [PATCH 34/42] ui - new build --- litellm/proxy/_experimental/out/404.html | 1 + .../out/_next/static/chunks/131-19b05e5ce40fa85d.js | 8 ++++++++ .../out/_next/static/chunks/131-6a03368053f9d26d.js | 8 -------- .../{759-83a8bdddfe32b5d9.js => 759-d7572f2a46f911d5.js} | 4 ++-- .../_next/static/chunks/app/layout-794e4e48013c2748.js | 1 + .../_next/static/chunks/app/layout-cb827484903e98d8.js | 1 - .../out/_next/static/chunks/app/page-82ef71d4696a12a3.js | 2 +- ...ck-d12f0c7c134d3e60.js => webpack-a4c113736b411114.js} | 2 +- .../css/{f02cb03d96e276ef.css => ffcf7f48a69c1192.css} | 4 +--- .../_buildManifest.js | 0 .../_ssgManifest.js | 0 litellm/proxy/_experimental/out/index.html | 2 +- litellm/proxy/_experimental/out/index.txt | 4 ++-- litellm/proxy/_experimental/out/model_hub.html | 1 + litellm/proxy/_experimental/out/model_hub.txt | 4 ++-- litellm/proxy/_experimental/out/onboarding.html | 1 + litellm/proxy/_experimental/out/onboarding.txt | 2 +- ui/litellm-dashboard/out/404.html | 2 +- .../out/_next/static/chunks/131-19b05e5ce40fa85d.js | 8 ++++++++ .../out/_next/static/chunks/131-6a03368053f9d26d.js | 8 -------- .../{759-83a8bdddfe32b5d9.js => 759-d7572f2a46f911d5.js} | 4 ++-- .../_next/static/chunks/app/layout-794e4e48013c2748.js | 1 + .../_next/static/chunks/app/layout-cb827484903e98d8.js | 1 - .../out/_next/static/chunks/app/page-82ef71d4696a12a3.js | 2 +- ...ck-d12f0c7c134d3e60.js => webpack-a4c113736b411114.js} | 2 +- .../css/{f02cb03d96e276ef.css => ffcf7f48a69c1192.css} | 4 +--- .../_buildManifest.js | 0 .../_ssgManifest.js | 0 ui/litellm-dashboard/out/index.html | 2 +- ui/litellm-dashboard/out/index.txt | 4 ++-- ui/litellm-dashboard/out/model_hub.html | 2 +- ui/litellm-dashboard/out/model_hub.txt | 4 ++-- ui/litellm-dashboard/out/onboarding.html | 2 +- ui/litellm-dashboard/out/onboarding.txt | 2 +- 34 files changed, 46 insertions(+), 47 deletions(-) create mode 100644 litellm/proxy/_experimental/out/404.html create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/131-19b05e5ce40fa85d.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/131-6a03368053f9d26d.js rename litellm/proxy/_experimental/out/_next/static/chunks/{759-83a8bdddfe32b5d9.js => 759-d7572f2a46f911d5.js} (53%) create mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/layout-794e4e48013c2748.js delete mode 100644 litellm/proxy/_experimental/out/_next/static/chunks/app/layout-cb827484903e98d8.js rename ui/litellm-dashboard/out/_next/static/chunks/app/page-bd882aee817406ff.js => litellm/proxy/_experimental/out/_next/static/chunks/app/page-82ef71d4696a12a3.js (99%) rename litellm/proxy/_experimental/out/_next/static/chunks/{webpack-d12f0c7c134d3e60.js => webpack-a4c113736b411114.js} (98%) rename litellm/proxy/_experimental/out/_next/static/css/{f02cb03d96e276ef.css => ffcf7f48a69c1192.css} (99%) rename litellm/proxy/_experimental/out/_next/static/{48nWsJi-LJrUlOLzcK-Yz => ocq1snXodTkVriEIUAg5a}/_buildManifest.js (100%) rename litellm/proxy/_experimental/out/_next/static/{48nWsJi-LJrUlOLzcK-Yz => ocq1snXodTkVriEIUAg5a}/_ssgManifest.js (100%) create mode 100644 litellm/proxy/_experimental/out/model_hub.html create mode 100644 litellm/proxy/_experimental/out/onboarding.html create mode 100644 ui/litellm-dashboard/out/_next/static/chunks/131-19b05e5ce40fa85d.js delete mode 100644 ui/litellm-dashboard/out/_next/static/chunks/131-6a03368053f9d26d.js rename ui/litellm-dashboard/out/_next/static/chunks/{759-83a8bdddfe32b5d9.js => 759-d7572f2a46f911d5.js} (53%) create mode 100644 ui/litellm-dashboard/out/_next/static/chunks/app/layout-794e4e48013c2748.js delete mode 100644 ui/litellm-dashboard/out/_next/static/chunks/app/layout-cb827484903e98d8.js rename litellm/proxy/_experimental/out/_next/static/chunks/app/page-bd882aee817406ff.js => ui/litellm-dashboard/out/_next/static/chunks/app/page-82ef71d4696a12a3.js (99%) rename ui/litellm-dashboard/out/_next/static/chunks/{webpack-d12f0c7c134d3e60.js => webpack-a4c113736b411114.js} (98%) rename ui/litellm-dashboard/out/_next/static/css/{f02cb03d96e276ef.css => ffcf7f48a69c1192.css} (99%) rename ui/litellm-dashboard/out/_next/static/{48nWsJi-LJrUlOLzcK-Yz => ocq1snXodTkVriEIUAg5a}/_buildManifest.js (100%) rename ui/litellm-dashboard/out/_next/static/{48nWsJi-LJrUlOLzcK-Yz => ocq1snXodTkVriEIUAg5a}/_ssgManifest.js (100%) diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404.html new file mode 100644 index 000000000..ced6578a9 --- /dev/null +++ b/litellm/proxy/_experimental/out/404.html @@ -0,0 +1 @@ +404: This page could not be found.LiteLLM Dashboard

404

This page could not be found.

\ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/131-19b05e5ce40fa85d.js b/litellm/proxy/_experimental/out/_next/static/chunks/131-19b05e5ce40fa85d.js new file mode 100644 index 000000000..92aaed0dd --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/131-19b05e5ce40fa85d.js @@ -0,0 +1,8 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[131],{84174:function(e,t,n){n.d(t,{Z:function(){return s}});var a=n(14749),r=n(64090),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"}}]},name:"copy",theme:"outlined"},o=n(60688),s=r.forwardRef(function(e,t){return r.createElement(o.Z,(0,a.Z)({},e,{ref:t,icon:i}))})},50459:function(e,t,n){n.d(t,{Z:function(){return s}});var a=n(14749),r=n(64090),i={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"}}]},name:"right",theme:"outlined"},o=n(60688),s=r.forwardRef(function(e,t){return r.createElement(o.Z,(0,a.Z)({},e,{ref:t,icon:i}))})},92836:function(e,t,n){n.d(t,{Z:function(){return p}});var a=n(69703),r=n(80991),i=n(2898),o=n(99250),s=n(65492),l=n(64090),c=n(41608),d=n(50027);n(18174),n(21871),n(41213);let u=(0,s.fn)("Tab"),p=l.forwardRef((e,t)=>{let{icon:n,className:p,children:g}=e,m=(0,a._T)(e,["icon","className","children"]),b=(0,l.useContext)(c.O),f=(0,l.useContext)(d.Z);return l.createElement(r.O,Object.assign({ref:t,className:(0,o.q)(u("root"),"flex whitespace-nowrap truncate max-w-xs outline-none focus:ring-0 text-tremor-default transition duration-100",f?(0,s.bM)(f,i.K.text).selectTextColor:"solid"===b?"ui-selected:text-tremor-content-emphasis dark:ui-selected:text-dark-tremor-content-emphasis":"ui-selected:text-tremor-brand dark:ui-selected:text-dark-tremor-brand",function(e,t){switch(e){case"line":return(0,o.q)("ui-selected:border-b-2 hover:border-b-2 border-transparent transition duration-100 -mb-px px-2 py-2","hover:border-tremor-content hover:text-tremor-content-emphasis text-tremor-content","dark:hover:border-dark-tremor-content-emphasis dark:hover:text-dark-tremor-content-emphasis dark:text-dark-tremor-content",t?(0,s.bM)(t,i.K.border).selectBorderColor:"ui-selected:border-tremor-brand dark:ui-selected:border-dark-tremor-brand");case"solid":return(0,o.q)("border-transparent border rounded-tremor-small px-2.5 py-1","ui-selected:border-tremor-border ui-selected:bg-tremor-background ui-selected:shadow-tremor-input hover:text-tremor-content-emphasis ui-selected:text-tremor-brand","dark:ui-selected:border-dark-tremor-border dark:ui-selected:bg-dark-tremor-background dark:ui-selected:shadow-dark-tremor-input dark:hover:text-dark-tremor-content-emphasis dark:ui-selected:text-dark-tremor-brand",t?(0,s.bM)(t,i.K.text).selectTextColor:"text-tremor-content dark:text-dark-tremor-content")}}(b,f),p)},m),n?l.createElement(n,{className:(0,o.q)(u("icon"),"flex-none h-5 w-5",g?"mr-2":"")}):null,g?l.createElement("span",null,g):null)});p.displayName="Tab"},26734:function(e,t,n){n.d(t,{Z:function(){return c}});var a=n(69703),r=n(80991),i=n(99250),o=n(65492),s=n(64090);let l=(0,o.fn)("TabGroup"),c=s.forwardRef((e,t)=>{let{defaultIndex:n,index:o,onIndexChange:c,children:d,className:u}=e,p=(0,a._T)(e,["defaultIndex","index","onIndexChange","children","className"]);return s.createElement(r.O.Group,Object.assign({as:"div",ref:t,defaultIndex:n,selectedIndex:o,onChange:c,className:(0,i.q)(l("root"),"w-full",u)},p),d)});c.displayName="TabGroup"},41608:function(e,t,n){n.d(t,{O:function(){return c},Z:function(){return u}});var a=n(69703),r=n(64090),i=n(50027);n(18174),n(21871),n(41213);var o=n(80991),s=n(99250);let l=(0,n(65492).fn)("TabList"),c=(0,r.createContext)("line"),d={line:(0,s.q)("flex border-b space-x-4","border-tremor-border","dark:border-dark-tremor-border"),solid:(0,s.q)("inline-flex p-0.5 rounded-tremor-default space-x-1.5","bg-tremor-background-subtle","dark:bg-dark-tremor-background-subtle")},u=r.forwardRef((e,t)=>{let{color:n,variant:u="line",children:p,className:g}=e,m=(0,a._T)(e,["color","variant","children","className"]);return r.createElement(o.O.List,Object.assign({ref:t,className:(0,s.q)(l("root"),"justify-start overflow-x-clip",d[u],g)},m),r.createElement(c.Provider,{value:u},r.createElement(i.Z.Provider,{value:n},p)))});u.displayName="TabList"},32126:function(e,t,n){n.d(t,{Z:function(){return d}});var a=n(69703);n(50027);var r=n(18174);n(21871);var i=n(41213),o=n(99250),s=n(65492),l=n(64090);let c=(0,s.fn)("TabPanel"),d=l.forwardRef((e,t)=>{let{children:n,className:s}=e,d=(0,a._T)(e,["children","className"]),{selectedValue:u}=(0,l.useContext)(i.Z),p=u===(0,l.useContext)(r.Z);return l.createElement("div",Object.assign({ref:t,className:(0,o.q)(c("root"),"w-full mt-2",p?"":"hidden",s),"aria-selected":p?"true":"false"},d),n)});d.displayName="TabPanel"},23682:function(e,t,n){n.d(t,{Z:function(){return u}});var a=n(69703),r=n(80991);n(50027);var i=n(18174);n(21871);var o=n(41213),s=n(99250),l=n(65492),c=n(64090);let d=(0,l.fn)("TabPanels"),u=c.forwardRef((e,t)=>{let{children:n,className:l}=e,u=(0,a._T)(e,["children","className"]);return c.createElement(r.O.Panels,Object.assign({as:"div",ref:t,className:(0,s.q)(d("root"),"w-full",l)},u),e=>{let{selectedIndex:t}=e;return c.createElement(o.Z.Provider,{value:{selectedValue:t}},c.Children.map(n,(e,t)=>c.createElement(i.Z.Provider,{value:t},e)))})});u.displayName="TabPanels"},50027:function(e,t,n){n.d(t,{Z:function(){return i}});var a=n(64090),r=n(54942);n(99250);let i=(0,a.createContext)(r.fr.Blue)},18174:function(e,t,n){n.d(t,{Z:function(){return a}});let a=(0,n(64090).createContext)(0)},21871:function(e,t,n){n.d(t,{Z:function(){return a}});let a=(0,n(64090).createContext)(void 0)},41213:function(e,t,n){n.d(t,{Z:function(){return a}});let a=(0,n(64090).createContext)({selectedValue:void 0,handleValueChange:void 0})},21467:function(e,t,n){n.d(t,{i:function(){return s}});var a=n(64090),r=n(44329),i=n(54165),o=n(57499);function s(e){return t=>a.createElement(i.ZP,{theme:{token:{motion:!1,zIndexPopupBase:0}}},a.createElement(e,Object.assign({},t)))}t.Z=(e,t,n,i)=>s(s=>{let{prefixCls:l,style:c}=s,d=a.useRef(null),[u,p]=a.useState(0),[g,m]=a.useState(0),[b,f]=(0,r.Z)(!1,{value:s.open}),{getPrefixCls:E}=a.useContext(o.E_),h=E(t||"select",l);a.useEffect(()=>{if(f(!0),"undefined"!=typeof ResizeObserver){let e=new ResizeObserver(e=>{let t=e[0].target;p(t.offsetHeight+8),m(t.offsetWidth)}),t=setInterval(()=>{var a;let r=n?".".concat(n(h)):".".concat(h,"-dropdown"),i=null===(a=d.current)||void 0===a?void 0:a.querySelector(r);i&&(clearInterval(t),e.observe(i))},10);return()=>{clearInterval(t),e.disconnect()}}},[]);let S=Object.assign(Object.assign({},s),{style:Object.assign(Object.assign({},c),{margin:0}),open:b,visible:b,getPopupContainer:()=>d.current});return i&&(S=i(S)),a.createElement("div",{ref:d,style:{paddingBottom:u,position:"relative",minWidth:g}},a.createElement(e,Object.assign({},S)))})},99129:function(e,t,n){let a;n.d(t,{Z:function(){return eY}});var r=n(63787),i=n(64090),o=n(37274),s=n(57499),l=n(54165),c=n(99537),d=n(77136),u=n(20653),p=n(40388),g=n(16480),m=n.n(g),b=n(51761),f=n(47387),E=n(70595),h=n(24750),S=n(89211),y=n(1861),T=n(51350),A=e=>{let{type:t,children:n,prefixCls:a,buttonProps:r,close:o,autoFocus:s,emitEvent:l,isSilent:c,quitOnNullishReturnValue:d,actionFn:u}=e,p=i.useRef(!1),g=i.useRef(null),[m,b]=(0,S.Z)(!1),f=function(){null==o||o.apply(void 0,arguments)};i.useEffect(()=>{let e=null;return s&&(e=setTimeout(()=>{var e;null===(e=g.current)||void 0===e||e.focus()})),()=>{e&&clearTimeout(e)}},[]);let E=e=>{e&&e.then&&(b(!0),e.then(function(){b(!1,!0),f.apply(void 0,arguments),p.current=!1},e=>{if(b(!1,!0),p.current=!1,null==c||!c())return Promise.reject(e)}))};return i.createElement(y.ZP,Object.assign({},(0,T.nx)(t),{onClick:e=>{let t;if(!p.current){if(p.current=!0,!u){f();return}if(l){var n;if(t=u(e),d&&!((n=t)&&n.then)){p.current=!1,f(e);return}}else if(u.length)t=u(o),p.current=!1;else if(!(t=u())){f();return}E(t)}},loading:m,prefixCls:a},r,{ref:g}),n)};let R=i.createContext({}),{Provider:I}=R;var N=()=>{let{autoFocusButton:e,cancelButtonProps:t,cancelTextLocale:n,isSilent:a,mergedOkCancel:r,rootPrefixCls:o,close:s,onCancel:l,onConfirm:c}=(0,i.useContext)(R);return r?i.createElement(A,{isSilent:a,actionFn:l,close:function(){null==s||s.apply(void 0,arguments),null==c||c(!1)},autoFocus:"cancel"===e,buttonProps:t,prefixCls:"".concat(o,"-btn")},n):null},_=()=>{let{autoFocusButton:e,close:t,isSilent:n,okButtonProps:a,rootPrefixCls:r,okTextLocale:o,okType:s,onConfirm:l,onOk:c}=(0,i.useContext)(R);return i.createElement(A,{isSilent:n,type:s||"primary",actionFn:c,close:function(){null==t||t.apply(void 0,arguments),null==l||l(!0)},autoFocus:"ok"===e,buttonProps:a,prefixCls:"".concat(r,"-btn")},o)},v=n(81303),w=n(14749),k=n(80406),C=n(88804),O=i.createContext({}),x=n(5239),L=n(31506),D=n(91010),P=n(4295),M=n(72480);function F(e,t,n){var a=t;return!a&&n&&(a="".concat(e,"-").concat(n)),a}function U(e,t){var n=e["page".concat(t?"Y":"X","Offset")],a="scroll".concat(t?"Top":"Left");if("number"!=typeof n){var r=e.document;"number"!=typeof(n=r.documentElement[a])&&(n=r.body[a])}return n}var B=n(49367),G=n(74084),$=i.memo(function(e){return e.children},function(e,t){return!t.shouldUpdate}),H={width:0,height:0,overflow:"hidden",outline:"none"},z=i.forwardRef(function(e,t){var n,a,r,o=e.prefixCls,s=e.className,l=e.style,c=e.title,d=e.ariaId,u=e.footer,p=e.closable,g=e.closeIcon,b=e.onClose,f=e.children,E=e.bodyStyle,h=e.bodyProps,S=e.modalRender,y=e.onMouseDown,T=e.onMouseUp,A=e.holderRef,R=e.visible,I=e.forceRender,N=e.width,_=e.height,v=e.classNames,k=e.styles,C=i.useContext(O).panel,L=(0,G.x1)(A,C),D=(0,i.useRef)(),P=(0,i.useRef)();i.useImperativeHandle(t,function(){return{focus:function(){var e;null===(e=D.current)||void 0===e||e.focus()},changeActive:function(e){var t=document.activeElement;e&&t===P.current?D.current.focus():e||t!==D.current||P.current.focus()}}});var M={};void 0!==N&&(M.width=N),void 0!==_&&(M.height=_),u&&(n=i.createElement("div",{className:m()("".concat(o,"-footer"),null==v?void 0:v.footer),style:(0,x.Z)({},null==k?void 0:k.footer)},u)),c&&(a=i.createElement("div",{className:m()("".concat(o,"-header"),null==v?void 0:v.header),style:(0,x.Z)({},null==k?void 0:k.header)},i.createElement("div",{className:"".concat(o,"-title"),id:d},c))),p&&(r=i.createElement("button",{type:"button",onClick:b,"aria-label":"Close",className:"".concat(o,"-close")},g||i.createElement("span",{className:"".concat(o,"-close-x")})));var F=i.createElement("div",{className:m()("".concat(o,"-content"),null==v?void 0:v.content),style:null==k?void 0:k.content},r,a,i.createElement("div",(0,w.Z)({className:m()("".concat(o,"-body"),null==v?void 0:v.body),style:(0,x.Z)((0,x.Z)({},E),null==k?void 0:k.body)},h),f),n);return i.createElement("div",{key:"dialog-element",role:"dialog","aria-labelledby":c?d:null,"aria-modal":"true",ref:L,style:(0,x.Z)((0,x.Z)({},l),M),className:m()(o,s),onMouseDown:y,onMouseUp:T},i.createElement("div",{tabIndex:0,ref:D,style:H,"aria-hidden":"true"}),i.createElement($,{shouldUpdate:R||I},S?S(F):F),i.createElement("div",{tabIndex:0,ref:P,style:H,"aria-hidden":"true"}))}),j=i.forwardRef(function(e,t){var n=e.prefixCls,a=e.title,r=e.style,o=e.className,s=e.visible,l=e.forceRender,c=e.destroyOnClose,d=e.motionName,u=e.ariaId,p=e.onVisibleChanged,g=e.mousePosition,b=(0,i.useRef)(),f=i.useState(),E=(0,k.Z)(f,2),h=E[0],S=E[1],y={};function T(){var e,t,n,a,r,i=(n={left:(t=(e=b.current).getBoundingClientRect()).left,top:t.top},r=(a=e.ownerDocument).defaultView||a.parentWindow,n.left+=U(r),n.top+=U(r,!0),n);S(g?"".concat(g.x-i.left,"px ").concat(g.y-i.top,"px"):"")}return h&&(y.transformOrigin=h),i.createElement(B.ZP,{visible:s,onVisibleChanged:p,onAppearPrepare:T,onEnterPrepare:T,forceRender:l,motionName:d,removeOnLeave:c,ref:b},function(s,l){var c=s.className,d=s.style;return i.createElement(z,(0,w.Z)({},e,{ref:t,title:a,ariaId:u,prefixCls:n,holderRef:l,style:(0,x.Z)((0,x.Z)((0,x.Z)({},d),r),y),className:m()(o,c)}))})});function V(e){var t=e.prefixCls,n=e.style,a=e.visible,r=e.maskProps,o=e.motionName,s=e.className;return i.createElement(B.ZP,{key:"mask",visible:a,motionName:o,leavedClassName:"".concat(t,"-mask-hidden")},function(e,a){var o=e.className,l=e.style;return i.createElement("div",(0,w.Z)({ref:a,style:(0,x.Z)((0,x.Z)({},l),n),className:m()("".concat(t,"-mask"),o,s)},r))})}function W(e){var t=e.prefixCls,n=void 0===t?"rc-dialog":t,a=e.zIndex,r=e.visible,o=void 0!==r&&r,s=e.keyboard,l=void 0===s||s,c=e.focusTriggerAfterClose,d=void 0===c||c,u=e.wrapStyle,p=e.wrapClassName,g=e.wrapProps,b=e.onClose,f=e.afterOpenChange,E=e.afterClose,h=e.transitionName,S=e.animation,y=e.closable,T=e.mask,A=void 0===T||T,R=e.maskTransitionName,I=e.maskAnimation,N=e.maskClosable,_=e.maskStyle,v=e.maskProps,C=e.rootClassName,O=e.classNames,U=e.styles,B=(0,i.useRef)(),G=(0,i.useRef)(),$=(0,i.useRef)(),H=i.useState(o),z=(0,k.Z)(H,2),W=z[0],q=z[1],Y=(0,D.Z)();function K(e){null==b||b(e)}var Z=(0,i.useRef)(!1),X=(0,i.useRef)(),Q=null;return(void 0===N||N)&&(Q=function(e){Z.current?Z.current=!1:G.current===e.target&&K(e)}),(0,i.useEffect)(function(){o&&(q(!0),(0,L.Z)(G.current,document.activeElement)||(B.current=document.activeElement))},[o]),(0,i.useEffect)(function(){return function(){clearTimeout(X.current)}},[]),i.createElement("div",(0,w.Z)({className:m()("".concat(n,"-root"),C)},(0,M.Z)(e,{data:!0})),i.createElement(V,{prefixCls:n,visible:A&&o,motionName:F(n,R,I),style:(0,x.Z)((0,x.Z)({zIndex:a},_),null==U?void 0:U.mask),maskProps:v,className:null==O?void 0:O.mask}),i.createElement("div",(0,w.Z)({tabIndex:-1,onKeyDown:function(e){if(l&&e.keyCode===P.Z.ESC){e.stopPropagation(),K(e);return}o&&e.keyCode===P.Z.TAB&&$.current.changeActive(!e.shiftKey)},className:m()("".concat(n,"-wrap"),p,null==O?void 0:O.wrapper),ref:G,onClick:Q,style:(0,x.Z)((0,x.Z)((0,x.Z)({zIndex:a},u),null==U?void 0:U.wrapper),{},{display:W?null:"none"})},g),i.createElement(j,(0,w.Z)({},e,{onMouseDown:function(){clearTimeout(X.current),Z.current=!0},onMouseUp:function(){X.current=setTimeout(function(){Z.current=!1})},ref:$,closable:void 0===y||y,ariaId:Y,prefixCls:n,visible:o&&W,onClose:K,onVisibleChanged:function(e){if(e)!function(){if(!(0,L.Z)(G.current,document.activeElement)){var e;null===(e=$.current)||void 0===e||e.focus()}}();else{if(q(!1),A&&B.current&&d){try{B.current.focus({preventScroll:!0})}catch(e){}B.current=null}W&&(null==E||E())}null==f||f(e)},motionName:F(n,h,S)}))))}j.displayName="Content",n(53850);var q=function(e){var t=e.visible,n=e.getContainer,a=e.forceRender,r=e.destroyOnClose,o=void 0!==r&&r,s=e.afterClose,l=e.panelRef,c=i.useState(t),d=(0,k.Z)(c,2),u=d[0],p=d[1],g=i.useMemo(function(){return{panel:l}},[l]);return(i.useEffect(function(){t&&p(!0)},[t]),a||!o||u)?i.createElement(O.Provider,{value:g},i.createElement(C.Z,{open:t||a||u,autoDestroy:!1,getContainer:n,autoLock:t||u},i.createElement(W,(0,w.Z)({},e,{destroyOnClose:o,afterClose:function(){null==s||s(),p(!1)}})))):null};q.displayName="Dialog";var Y=function(e,t,n){let a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:i.createElement(v.Z,null),r=arguments.length>4&&void 0!==arguments[4]&&arguments[4];if("boolean"==typeof e?!e:void 0===t?!r:!1===t||null===t)return[!1,null];let o="boolean"==typeof t||null==t?a:t;return[!0,n?n(o):o]},K=n(22127),Z=n(86718),X=n(47137),Q=n(92801),J=n(48563);function ee(){}let et=i.createContext({add:ee,remove:ee});var en=n(17094),ea=()=>{let{cancelButtonProps:e,cancelTextLocale:t,onCancel:n}=(0,i.useContext)(R);return i.createElement(y.ZP,Object.assign({onClick:n},e),t)},er=()=>{let{confirmLoading:e,okButtonProps:t,okType:n,okTextLocale:a,onOk:r}=(0,i.useContext)(R);return i.createElement(y.ZP,Object.assign({},(0,T.nx)(n),{loading:e,onClick:r},t),a)},ei=n(4678);function eo(e,t){return i.createElement("span",{className:"".concat(e,"-close-x")},t||i.createElement(v.Z,{className:"".concat(e,"-close-icon")}))}let es=e=>{let t;let{okText:n,okType:a="primary",cancelText:o,confirmLoading:s,onOk:l,onCancel:c,okButtonProps:d,cancelButtonProps:u,footer:p}=e,[g]=(0,E.Z)("Modal",(0,ei.A)()),m={confirmLoading:s,okButtonProps:d,cancelButtonProps:u,okTextLocale:n||(null==g?void 0:g.okText),cancelTextLocale:o||(null==g?void 0:g.cancelText),okType:a,onOk:l,onCancel:c},b=i.useMemo(()=>m,(0,r.Z)(Object.values(m)));return"function"==typeof p||void 0===p?(t=i.createElement(i.Fragment,null,i.createElement(ea,null),i.createElement(er,null)),"function"==typeof p&&(t=p(t,{OkBtn:er,CancelBtn:ea})),t=i.createElement(I,{value:b},t)):t=p,i.createElement(en.n,{disabled:!1},t)};var el=n(11303),ec=n(13703),ed=n(58854),eu=n(80316),ep=n(76585),eg=n(8985);function em(e){return{position:e,inset:0}}let eb=e=>{let{componentCls:t,antCls:n}=e;return[{["".concat(t,"-root")]:{["".concat(t).concat(n,"-zoom-enter, ").concat(t).concat(n,"-zoom-appear")]:{transform:"none",opacity:0,animationDuration:e.motionDurationSlow,userSelect:"none"},["".concat(t).concat(n,"-zoom-leave ").concat(t,"-content")]:{pointerEvents:"none"},["".concat(t,"-mask")]:Object.assign(Object.assign({},em("fixed")),{zIndex:e.zIndexPopupBase,height:"100%",backgroundColor:e.colorBgMask,pointerEvents:"none",["".concat(t,"-hidden")]:{display:"none"}}),["".concat(t,"-wrap")]:Object.assign(Object.assign({},em("fixed")),{zIndex:e.zIndexPopupBase,overflow:"auto",outline:0,WebkitOverflowScrolling:"touch",["&:has(".concat(t).concat(n,"-zoom-enter), &:has(").concat(t).concat(n,"-zoom-appear)")]:{pointerEvents:"none"}})}},{["".concat(t,"-root")]:(0,ec.J$)(e)}]},ef=e=>{let{componentCls:t}=e;return[{["".concat(t,"-root")]:{["".concat(t,"-wrap-rtl")]:{direction:"rtl"},["".concat(t,"-centered")]:{textAlign:"center","&::before":{display:"inline-block",width:0,height:"100%",verticalAlign:"middle",content:'""'},[t]:{top:0,display:"inline-block",paddingBottom:0,textAlign:"start",verticalAlign:"middle"}},["@media (max-width: ".concat(e.screenSMMax,"px)")]:{[t]:{maxWidth:"calc(100vw - 16px)",margin:"".concat((0,eg.bf)(e.marginXS)," auto")},["".concat(t,"-centered")]:{[t]:{flex:1}}}}},{[t]:Object.assign(Object.assign({},(0,el.Wf)(e)),{pointerEvents:"none",position:"relative",top:100,width:"auto",maxWidth:"calc(100vw - ".concat((0,eg.bf)(e.calc(e.margin).mul(2).equal()),")"),margin:"0 auto",paddingBottom:e.paddingLG,["".concat(t,"-title")]:{margin:0,color:e.titleColor,fontWeight:e.fontWeightStrong,fontSize:e.titleFontSize,lineHeight:e.titleLineHeight,wordWrap:"break-word"},["".concat(t,"-content")]:{position:"relative",backgroundColor:e.contentBg,backgroundClip:"padding-box",border:0,borderRadius:e.borderRadiusLG,boxShadow:e.boxShadow,pointerEvents:"auto",padding:e.contentPadding},["".concat(t,"-close")]:Object.assign({position:"absolute",top:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),insetInlineEnd:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),zIndex:e.calc(e.zIndexPopupBase).add(10).equal(),padding:0,color:e.modalCloseIconColor,fontWeight:e.fontWeightStrong,lineHeight:1,textDecoration:"none",background:"transparent",borderRadius:e.borderRadiusSM,width:e.modalCloseBtnSize,height:e.modalCloseBtnSize,border:0,outline:0,cursor:"pointer",transition:"color ".concat(e.motionDurationMid,", background-color ").concat(e.motionDurationMid),"&-x":{display:"flex",fontSize:e.fontSizeLG,fontStyle:"normal",lineHeight:"".concat((0,eg.bf)(e.modalCloseBtnSize)),justifyContent:"center",textTransform:"none",textRendering:"auto"},"&:hover":{color:e.modalIconHoverColor,backgroundColor:e.closeBtnHoverBg,textDecoration:"none"},"&:active":{backgroundColor:e.closeBtnActiveBg}},(0,el.Qy)(e)),["".concat(t,"-header")]:{color:e.colorText,background:e.headerBg,borderRadius:"".concat((0,eg.bf)(e.borderRadiusLG)," ").concat((0,eg.bf)(e.borderRadiusLG)," 0 0"),marginBottom:e.headerMarginBottom,padding:e.headerPadding,borderBottom:e.headerBorderBottom},["".concat(t,"-body")]:{fontSize:e.fontSize,lineHeight:e.lineHeight,wordWrap:"break-word",padding:e.bodyPadding},["".concat(t,"-footer")]:{textAlign:"end",background:e.footerBg,marginTop:e.footerMarginTop,padding:e.footerPadding,borderTop:e.footerBorderTop,borderRadius:e.footerBorderRadius,["> ".concat(e.antCls,"-btn + ").concat(e.antCls,"-btn")]:{marginInlineStart:e.marginXS}},["".concat(t,"-open")]:{overflow:"hidden"}})},{["".concat(t,"-pure-panel")]:{top:"auto",padding:0,display:"flex",flexDirection:"column",["".concat(t,"-content,\n ").concat(t,"-body,\n ").concat(t,"-confirm-body-wrapper")]:{display:"flex",flexDirection:"column",flex:"auto"},["".concat(t,"-confirm-body")]:{marginBottom:"auto"}}}]},eE=e=>{let{componentCls:t}=e;return{["".concat(t,"-root")]:{["".concat(t,"-wrap-rtl")]:{direction:"rtl",["".concat(t,"-confirm-body")]:{direction:"rtl"}}}}},eh=e=>{let t=e.padding,n=e.fontSizeHeading5,a=e.lineHeightHeading5;return(0,eu.TS)(e,{modalHeaderHeight:e.calc(e.calc(a).mul(n).equal()).add(e.calc(t).mul(2).equal()).equal(),modalFooterBorderColorSplit:e.colorSplit,modalFooterBorderStyle:e.lineType,modalFooterBorderWidth:e.lineWidth,modalIconHoverColor:e.colorIconHover,modalCloseIconColor:e.colorIcon,modalCloseBtnSize:e.fontHeight,modalConfirmIconSize:e.fontHeight,modalTitleHeight:e.calc(e.titleFontSize).mul(e.titleLineHeight).equal()})},eS=e=>({footerBg:"transparent",headerBg:e.colorBgElevated,titleLineHeight:e.lineHeightHeading5,titleFontSize:e.fontSizeHeading5,contentBg:e.colorBgElevated,titleColor:e.colorTextHeading,closeBtnHoverBg:e.wireframe?"transparent":e.colorFillContent,closeBtnActiveBg:e.wireframe?"transparent":e.colorFillContentHover,contentPadding:e.wireframe?0:"".concat((0,eg.bf)(e.paddingMD)," ").concat((0,eg.bf)(e.paddingContentHorizontalLG)),headerPadding:e.wireframe?"".concat((0,eg.bf)(e.padding)," ").concat((0,eg.bf)(e.paddingLG)):0,headerBorderBottom:e.wireframe?"".concat((0,eg.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit):"none",headerMarginBottom:e.wireframe?0:e.marginXS,bodyPadding:e.wireframe?e.paddingLG:0,footerPadding:e.wireframe?"".concat((0,eg.bf)(e.paddingXS)," ").concat((0,eg.bf)(e.padding)):0,footerBorderTop:e.wireframe?"".concat((0,eg.bf)(e.lineWidth)," ").concat(e.lineType," ").concat(e.colorSplit):"none",footerBorderRadius:e.wireframe?"0 0 ".concat((0,eg.bf)(e.borderRadiusLG)," ").concat((0,eg.bf)(e.borderRadiusLG)):0,footerMarginTop:e.wireframe?0:e.marginSM,confirmBodyPadding:e.wireframe?"".concat((0,eg.bf)(2*e.padding)," ").concat((0,eg.bf)(2*e.padding)," ").concat((0,eg.bf)(e.paddingLG)):0,confirmIconMarginInlineEnd:e.wireframe?e.margin:e.marginSM,confirmBtnsMarginTop:e.wireframe?e.marginLG:e.marginSM});var ey=(0,ep.I$)("Modal",e=>{let t=eh(e);return[ef(t),eE(t),eb(t),(0,ed._y)(t,"zoom")]},eS,{unitless:{titleLineHeight:!0}}),eT=n(92935),eA=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n};(0,K.Z)()&&window.document.documentElement&&document.documentElement.addEventListener("click",e=>{a={x:e.pageX,y:e.pageY},setTimeout(()=>{a=null},100)},!0);var eR=e=>{var t;let{getPopupContainer:n,getPrefixCls:r,direction:o,modal:l}=i.useContext(s.E_),c=t=>{let{onCancel:n}=e;null==n||n(t)},{prefixCls:d,className:u,rootClassName:p,open:g,wrapClassName:E,centered:h,getContainer:S,closeIcon:y,closable:T,focusTriggerAfterClose:A=!0,style:R,visible:I,width:N=520,footer:_,classNames:w,styles:k}=e,C=eA(e,["prefixCls","className","rootClassName","open","wrapClassName","centered","getContainer","closeIcon","closable","focusTriggerAfterClose","style","visible","width","footer","classNames","styles"]),O=r("modal",d),x=r(),L=(0,eT.Z)(O),[D,P,M]=ey(O,L),F=m()(E,{["".concat(O,"-centered")]:!!h,["".concat(O,"-wrap-rtl")]:"rtl"===o}),U=null!==_&&i.createElement(es,Object.assign({},e,{onOk:t=>{let{onOk:n}=e;null==n||n(t)},onCancel:c})),[B,G]=Y(T,y,e=>eo(O,e),i.createElement(v.Z,{className:"".concat(O,"-close-icon")}),!0),$=function(e){let t=i.useContext(et),n=i.useRef();return(0,J.zX)(a=>{if(a){let r=e?a.querySelector(e):a;t.add(r),n.current=r}else t.remove(n.current)})}(".".concat(O,"-content")),[H,z]=(0,b.Cn)("Modal",C.zIndex);return D(i.createElement(Q.BR,null,i.createElement(X.Ux,{status:!0,override:!0},i.createElement(Z.Z.Provider,{value:z},i.createElement(q,Object.assign({width:N},C,{zIndex:H,getContainer:void 0===S?n:S,prefixCls:O,rootClassName:m()(P,p,M,L),footer:U,visible:null!=g?g:I,mousePosition:null!==(t=C.mousePosition)&&void 0!==t?t:a,onClose:c,closable:B,closeIcon:G,focusTriggerAfterClose:A,transitionName:(0,f.m)(x,"zoom",e.transitionName),maskTransitionName:(0,f.m)(x,"fade",e.maskTransitionName),className:m()(P,u,null==l?void 0:l.className),style:Object.assign(Object.assign({},null==l?void 0:l.style),R),classNames:Object.assign(Object.assign({wrapper:F},null==l?void 0:l.classNames),w),styles:Object.assign(Object.assign({},null==l?void 0:l.styles),k),panelRef:$}))))))};let eI=e=>{let{componentCls:t,titleFontSize:n,titleLineHeight:a,modalConfirmIconSize:r,fontSize:i,lineHeight:o,modalTitleHeight:s,fontHeight:l,confirmBodyPadding:c}=e,d="".concat(t,"-confirm");return{[d]:{"&-rtl":{direction:"rtl"},["".concat(e.antCls,"-modal-header")]:{display:"none"},["".concat(d,"-body-wrapper")]:Object.assign({},(0,el.dF)()),["&".concat(t," ").concat(t,"-body")]:{padding:c},["".concat(d,"-body")]:{display:"flex",flexWrap:"nowrap",alignItems:"start",["> ".concat(e.iconCls)]:{flex:"none",fontSize:r,marginInlineEnd:e.confirmIconMarginInlineEnd,marginTop:e.calc(e.calc(l).sub(r).equal()).div(2).equal()},["&-has-title > ".concat(e.iconCls)]:{marginTop:e.calc(e.calc(s).sub(r).equal()).div(2).equal()}},["".concat(d,"-paragraph")]:{display:"flex",flexDirection:"column",flex:"auto",rowGap:e.marginXS,maxWidth:"calc(100% - ".concat((0,eg.bf)(e.calc(e.modalConfirmIconSize).add(e.marginSM).equal()),")")},["".concat(d,"-title")]:{color:e.colorTextHeading,fontWeight:e.fontWeightStrong,fontSize:n,lineHeight:a},["".concat(d,"-content")]:{color:e.colorText,fontSize:i,lineHeight:o},["".concat(d,"-btns")]:{textAlign:"end",marginTop:e.confirmBtnsMarginTop,["".concat(e.antCls,"-btn + ").concat(e.antCls,"-btn")]:{marginBottom:0,marginInlineStart:e.marginXS}}},["".concat(d,"-error ").concat(d,"-body > ").concat(e.iconCls)]:{color:e.colorError},["".concat(d,"-warning ").concat(d,"-body > ").concat(e.iconCls,",\n ").concat(d,"-confirm ").concat(d,"-body > ").concat(e.iconCls)]:{color:e.colorWarning},["".concat(d,"-info ").concat(d,"-body > ").concat(e.iconCls)]:{color:e.colorInfo},["".concat(d,"-success ").concat(d,"-body > ").concat(e.iconCls)]:{color:e.colorSuccess}}};var eN=(0,ep.bk)(["Modal","confirm"],e=>[eI(eh(e))],eS,{order:-1e3}),e_=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n};function ev(e){let{prefixCls:t,icon:n,okText:a,cancelText:o,confirmPrefixCls:s,type:l,okCancel:g,footer:b,locale:f}=e,h=e_(e,["prefixCls","icon","okText","cancelText","confirmPrefixCls","type","okCancel","footer","locale"]),S=n;if(!n&&null!==n)switch(l){case"info":S=i.createElement(p.Z,null);break;case"success":S=i.createElement(c.Z,null);break;case"error":S=i.createElement(d.Z,null);break;default:S=i.createElement(u.Z,null)}let y=null!=g?g:"confirm"===l,T=null!==e.autoFocusButton&&(e.autoFocusButton||"ok"),[A]=(0,E.Z)("Modal"),R=f||A,v=a||(y?null==R?void 0:R.okText:null==R?void 0:R.justOkText),w=Object.assign({autoFocusButton:T,cancelTextLocale:o||(null==R?void 0:R.cancelText),okTextLocale:v,mergedOkCancel:y},h),k=i.useMemo(()=>w,(0,r.Z)(Object.values(w))),C=i.createElement(i.Fragment,null,i.createElement(N,null),i.createElement(_,null)),O=void 0!==e.title&&null!==e.title,x="".concat(s,"-body");return i.createElement("div",{className:"".concat(s,"-body-wrapper")},i.createElement("div",{className:m()(x,{["".concat(x,"-has-title")]:O})},S,i.createElement("div",{className:"".concat(s,"-paragraph")},O&&i.createElement("span",{className:"".concat(s,"-title")},e.title),i.createElement("div",{className:"".concat(s,"-content")},e.content))),void 0===b||"function"==typeof b?i.createElement(I,{value:k},i.createElement("div",{className:"".concat(s,"-btns")},"function"==typeof b?b(C,{OkBtn:_,CancelBtn:N}):C)):b,i.createElement(eN,{prefixCls:t}))}let ew=e=>{let{close:t,zIndex:n,afterClose:a,open:r,keyboard:o,centered:s,getContainer:l,maskStyle:c,direction:d,prefixCls:u,wrapClassName:p,rootPrefixCls:g,bodyStyle:E,closable:S=!1,closeIcon:y,modalRender:T,focusTriggerAfterClose:A,onConfirm:R,styles:I}=e,N="".concat(u,"-confirm"),_=e.width||416,v=e.style||{},w=void 0===e.mask||e.mask,k=void 0!==e.maskClosable&&e.maskClosable,C=m()(N,"".concat(N,"-").concat(e.type),{["".concat(N,"-rtl")]:"rtl"===d},e.className),[,O]=(0,h.ZP)(),x=i.useMemo(()=>void 0!==n?n:O.zIndexPopupBase+b.u6,[n,O]);return i.createElement(eR,{prefixCls:u,className:C,wrapClassName:m()({["".concat(N,"-centered")]:!!e.centered},p),onCancel:()=>{null==t||t({triggerCancel:!0}),null==R||R(!1)},open:r,title:"",footer:null,transitionName:(0,f.m)(g||"","zoom",e.transitionName),maskTransitionName:(0,f.m)(g||"","fade",e.maskTransitionName),mask:w,maskClosable:k,style:v,styles:Object.assign({body:E,mask:c},I),width:_,zIndex:x,afterClose:a,keyboard:o,centered:s,getContainer:l,closable:S,closeIcon:y,modalRender:T,focusTriggerAfterClose:A},i.createElement(ev,Object.assign({},e,{confirmPrefixCls:N})))};var ek=e=>{let{rootPrefixCls:t,iconPrefixCls:n,direction:a,theme:r}=e;return i.createElement(l.ZP,{prefixCls:t,iconPrefixCls:n,direction:a,theme:r},i.createElement(ew,Object.assign({},e)))},eC=[];let eO="",ex=e=>{var t,n;let{prefixCls:a,getContainer:r,direction:o}=e,l=(0,ei.A)(),c=(0,i.useContext)(s.E_),d=eO||c.getPrefixCls(),u=a||"".concat(d,"-modal"),p=r;return!1===p&&(p=void 0),i.createElement(ek,Object.assign({},e,{rootPrefixCls:d,prefixCls:u,iconPrefixCls:c.iconPrefixCls,theme:c.theme,direction:null!=o?o:c.direction,locale:null!==(n=null===(t=c.locale)||void 0===t?void 0:t.Modal)&&void 0!==n?n:l,getContainer:p}))};function eL(e){let t;let n=(0,l.w6)(),a=document.createDocumentFragment(),s=Object.assign(Object.assign({},e),{close:u,open:!0});function c(){for(var t=arguments.length,n=Array(t),i=0;ie&&e.triggerCancel);e.onCancel&&s&&e.onCancel.apply(e,[()=>{}].concat((0,r.Z)(n.slice(1))));for(let e=0;e{let t=n.getPrefixCls(void 0,eO),r=n.getIconPrefixCls(),s=n.getTheme(),c=i.createElement(ex,Object.assign({},e));(0,o.s)(i.createElement(l.ZP,{prefixCls:t,iconPrefixCls:r,theme:s},n.holderRender?n.holderRender(c):c),a)})}function u(){for(var t=arguments.length,n=Array(t),a=0;a{"function"==typeof e.afterClose&&e.afterClose(),c.apply(this,n)}})).visible&&delete s.visible,d(s)}return d(s),eC.push(u),{destroy:u,update:function(e){d(s="function"==typeof e?e(s):Object.assign(Object.assign({},s),e))}}}function eD(e){return Object.assign(Object.assign({},e),{type:"warning"})}function eP(e){return Object.assign(Object.assign({},e),{type:"info"})}function eM(e){return Object.assign(Object.assign({},e),{type:"success"})}function eF(e){return Object.assign(Object.assign({},e),{type:"error"})}function eU(e){return Object.assign(Object.assign({},e),{type:"confirm"})}var eB=n(21467),eG=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n},e$=(0,eB.i)(e=>{let{prefixCls:t,className:n,closeIcon:a,closable:r,type:o,title:l,children:c,footer:d}=e,u=eG(e,["prefixCls","className","closeIcon","closable","type","title","children","footer"]),{getPrefixCls:p}=i.useContext(s.E_),g=p(),b=t||p("modal"),f=(0,eT.Z)(g),[E,h,S]=ey(b,f),y="".concat(b,"-confirm"),T={};return T=o?{closable:null!=r&&r,title:"",footer:"",children:i.createElement(ev,Object.assign({},e,{prefixCls:b,confirmPrefixCls:y,rootPrefixCls:g,content:c}))}:{closable:null==r||r,title:l,footer:null!==d&&i.createElement(es,Object.assign({},e)),children:c},E(i.createElement(z,Object.assign({prefixCls:b,className:m()(h,"".concat(b,"-pure-panel"),o&&y,o&&"".concat(y,"-").concat(o),n,S,f)},u,{closeIcon:eo(b,a),closable:r},T)))}),eH=n(79474),ez=function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&0>t.indexOf(a)&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);rt.indexOf(a[r])&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n},ej=i.forwardRef((e,t)=>{var n,{afterClose:a,config:o}=e,l=ez(e,["afterClose","config"]);let[c,d]=i.useState(!0),[u,p]=i.useState(o),{direction:g,getPrefixCls:m}=i.useContext(s.E_),b=m("modal"),f=m(),h=function(){d(!1);for(var e=arguments.length,t=Array(e),n=0;ne&&e.triggerCancel);u.onCancel&&a&&u.onCancel.apply(u,[()=>{}].concat((0,r.Z)(t.slice(1))))};i.useImperativeHandle(t,()=>({destroy:h,update:e=>{p(t=>Object.assign(Object.assign({},t),e))}}));let S=null!==(n=u.okCancel)&&void 0!==n?n:"confirm"===u.type,[y]=(0,E.Z)("Modal",eH.Z.Modal);return i.createElement(ek,Object.assign({prefixCls:b,rootPrefixCls:f},u,{close:h,open:c,afterClose:()=>{var e;a(),null===(e=u.afterClose)||void 0===e||e.call(u)},okText:u.okText||(S?null==y?void 0:y.okText:null==y?void 0:y.justOkText),direction:u.direction||g,cancelText:u.cancelText||(null==y?void 0:y.cancelText)},l))});let eV=0,eW=i.memo(i.forwardRef((e,t)=>{let[n,a]=function(){let[e,t]=i.useState([]);return[e,i.useCallback(e=>(t(t=>[].concat((0,r.Z)(t),[e])),()=>{t(t=>t.filter(t=>t!==e))}),[])]}();return i.useImperativeHandle(t,()=>({patchElement:a}),[]),i.createElement(i.Fragment,null,n)}));function eq(e){return eL(eD(e))}eR.useModal=function(){let e=i.useRef(null),[t,n]=i.useState([]);i.useEffect(()=>{t.length&&((0,r.Z)(t).forEach(e=>{e()}),n([]))},[t]);let a=i.useCallback(t=>function(a){var o;let s,l;eV+=1;let c=i.createRef(),d=new Promise(e=>{s=e}),u=!1,p=i.createElement(ej,{key:"modal-".concat(eV),config:t(a),ref:c,afterClose:()=>{null==l||l()},isSilent:()=>u,onConfirm:e=>{s(e)}});return(l=null===(o=e.current)||void 0===o?void 0:o.patchElement(p))&&eC.push(l),{destroy:()=>{function e(){var e;null===(e=c.current)||void 0===e||e.destroy()}c.current?e():n(t=>[].concat((0,r.Z)(t),[e]))},update:e=>{function t(){var t;null===(t=c.current)||void 0===t||t.update(e)}c.current?t():n(e=>[].concat((0,r.Z)(e),[t]))},then:e=>(u=!0,d.then(e))}},[]);return[i.useMemo(()=>({info:a(eP),success:a(eM),error:a(eF),warning:a(eD),confirm:a(eU)}),[]),i.createElement(eW,{key:"modal-holder",ref:e})]},eR.info=function(e){return eL(eP(e))},eR.success=function(e){return eL(eM(e))},eR.error=function(e){return eL(eF(e))},eR.warning=eq,eR.warn=eq,eR.confirm=function(e){return eL(eU(e))},eR.destroyAll=function(){for(;eC.length;){let e=eC.pop();e&&e()}},eR.config=function(e){let{rootPrefixCls:t}=e;eO=t},eR._InternalPanelDoNotUseOrYouWillBeFired=e$;var eY=eR},13703:function(e,t,n){n.d(t,{J$:function(){return s}});var a=n(8985),r=n(59353);let i=new a.E4("antFadeIn",{"0%":{opacity:0},"100%":{opacity:1}}),o=new a.E4("antFadeOut",{"0%":{opacity:1},"100%":{opacity:0}}),s=function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],{antCls:n}=e,a="".concat(n,"-fade"),s=t?"&":"";return[(0,r.R)(a,i,o,e.motionDurationMid,t),{["\n ".concat(s).concat(a,"-enter,\n ").concat(s).concat(a,"-appear\n ")]:{opacity:0,animationTimingFunction:"linear"},["".concat(s).concat(a,"-leave")]:{animationTimingFunction:"linear"}}]}},44056:function(e){e.exports=function(e,n){for(var a,r,i,o=e||"",s=n||"div",l={},c=0;c4&&m.slice(0,4)===o&&s.test(t)&&("-"===t.charAt(4)?b=o+(n=t.slice(5).replace(l,u)).charAt(0).toUpperCase()+n.slice(1):(g=(p=t).slice(4),t=l.test(g)?p:("-"!==(g=g.replace(c,d)).charAt(0)&&(g="-"+g),o+g)),f=r),new f(b,t))};var s=/^data[-\w.:]+$/i,l=/-[a-z]/g,c=/[A-Z]/g;function d(e){return"-"+e.toLowerCase()}function u(e){return e.charAt(1).toUpperCase()}},31872:function(e,t,n){var a=n(96130),r=n(64730),i=n(61861),o=n(46982),s=n(83671),l=n(53618);e.exports=a([i,r,o,s,l])},83671:function(e,t,n){var a=n(7667),r=n(13585),i=a.booleanish,o=a.number,s=a.spaceSeparated;e.exports=r({transform:function(e,t){return"role"===t?t:"aria-"+t.slice(4).toLowerCase()},properties:{ariaActiveDescendant:null,ariaAtomic:i,ariaAutoComplete:null,ariaBusy:i,ariaChecked:i,ariaColCount:o,ariaColIndex:o,ariaColSpan:o,ariaControls:s,ariaCurrent:null,ariaDescribedBy:s,ariaDetails:null,ariaDisabled:i,ariaDropEffect:s,ariaErrorMessage:null,ariaExpanded:i,ariaFlowTo:s,ariaGrabbed:i,ariaHasPopup:null,ariaHidden:i,ariaInvalid:null,ariaKeyShortcuts:null,ariaLabel:null,ariaLabelledBy:s,ariaLevel:o,ariaLive:null,ariaModal:i,ariaMultiLine:i,ariaMultiSelectable:i,ariaOrientation:null,ariaOwns:s,ariaPlaceholder:null,ariaPosInSet:o,ariaPressed:i,ariaReadOnly:i,ariaRelevant:null,ariaRequired:i,ariaRoleDescription:s,ariaRowCount:o,ariaRowIndex:o,ariaRowSpan:o,ariaSelected:i,ariaSetSize:o,ariaSort:null,ariaValueMax:o,ariaValueMin:o,ariaValueNow:o,ariaValueText:null,role:null}})},53618:function(e,t,n){var a=n(7667),r=n(13585),i=n(46640),o=a.boolean,s=a.overloadedBoolean,l=a.booleanish,c=a.number,d=a.spaceSeparated,u=a.commaSeparated;e.exports=r({space:"html",attributes:{acceptcharset:"accept-charset",classname:"class",htmlfor:"for",httpequiv:"http-equiv"},transform:i,mustUseProperty:["checked","multiple","muted","selected"],properties:{abbr:null,accept:u,acceptCharset:d,accessKey:d,action:null,allow:null,allowFullScreen:o,allowPaymentRequest:o,allowUserMedia:o,alt:null,as:null,async:o,autoCapitalize:null,autoComplete:d,autoFocus:o,autoPlay:o,capture:o,charSet:null,checked:o,cite:null,className:d,cols:c,colSpan:null,content:null,contentEditable:l,controls:o,controlsList:d,coords:c|u,crossOrigin:null,data:null,dateTime:null,decoding:null,default:o,defer:o,dir:null,dirName:null,disabled:o,download:s,draggable:l,encType:null,enterKeyHint:null,form:null,formAction:null,formEncType:null,formMethod:null,formNoValidate:o,formTarget:null,headers:d,height:c,hidden:o,high:c,href:null,hrefLang:null,htmlFor:d,httpEquiv:d,id:null,imageSizes:null,imageSrcSet:u,inputMode:null,integrity:null,is:null,isMap:o,itemId:null,itemProp:d,itemRef:d,itemScope:o,itemType:d,kind:null,label:null,lang:null,language:null,list:null,loading:null,loop:o,low:c,manifest:null,max:null,maxLength:c,media:null,method:null,min:null,minLength:c,multiple:o,muted:o,name:null,nonce:null,noModule:o,noValidate:o,onAbort:null,onAfterPrint:null,onAuxClick:null,onBeforePrint:null,onBeforeUnload:null,onBlur:null,onCancel:null,onCanPlay:null,onCanPlayThrough:null,onChange:null,onClick:null,onClose:null,onContextMenu:null,onCopy:null,onCueChange:null,onCut:null,onDblClick:null,onDrag:null,onDragEnd:null,onDragEnter:null,onDragExit:null,onDragLeave:null,onDragOver:null,onDragStart:null,onDrop:null,onDurationChange:null,onEmptied:null,onEnded:null,onError:null,onFocus:null,onFormData:null,onHashChange:null,onInput:null,onInvalid:null,onKeyDown:null,onKeyPress:null,onKeyUp:null,onLanguageChange:null,onLoad:null,onLoadedData:null,onLoadedMetadata:null,onLoadEnd:null,onLoadStart:null,onMessage:null,onMessageError:null,onMouseDown:null,onMouseEnter:null,onMouseLeave:null,onMouseMove:null,onMouseOut:null,onMouseOver:null,onMouseUp:null,onOffline:null,onOnline:null,onPageHide:null,onPageShow:null,onPaste:null,onPause:null,onPlay:null,onPlaying:null,onPopState:null,onProgress:null,onRateChange:null,onRejectionHandled:null,onReset:null,onResize:null,onScroll:null,onSecurityPolicyViolation:null,onSeeked:null,onSeeking:null,onSelect:null,onSlotChange:null,onStalled:null,onStorage:null,onSubmit:null,onSuspend:null,onTimeUpdate:null,onToggle:null,onUnhandledRejection:null,onUnload:null,onVolumeChange:null,onWaiting:null,onWheel:null,open:o,optimum:c,pattern:null,ping:d,placeholder:null,playsInline:o,poster:null,preload:null,readOnly:o,referrerPolicy:null,rel:d,required:o,reversed:o,rows:c,rowSpan:c,sandbox:d,scope:null,scoped:o,seamless:o,selected:o,shape:null,size:c,sizes:null,slot:null,span:c,spellCheck:l,src:null,srcDoc:null,srcLang:null,srcSet:u,start:c,step:null,style:null,tabIndex:c,target:null,title:null,translate:null,type:null,typeMustMatch:o,useMap:null,value:l,width:c,wrap:null,align:null,aLink:null,archive:d,axis:null,background:null,bgColor:null,border:c,borderColor:null,bottomMargin:c,cellPadding:null,cellSpacing:null,char:null,charOff:null,classId:null,clear:null,code:null,codeBase:null,codeType:null,color:null,compact:o,declare:o,event:null,face:null,frame:null,frameBorder:null,hSpace:c,leftMargin:c,link:null,longDesc:null,lowSrc:null,marginHeight:c,marginWidth:c,noResize:o,noHref:o,noShade:o,noWrap:o,object:null,profile:null,prompt:null,rev:null,rightMargin:c,rules:null,scheme:null,scrolling:l,standby:null,summary:null,text:null,topMargin:c,valueType:null,version:null,vAlign:null,vLink:null,vSpace:c,allowTransparency:null,autoCorrect:null,autoSave:null,disablePictureInPicture:o,disableRemotePlayback:o,prefix:null,property:null,results:c,security:null,unselectable:null}})},46640:function(e,t,n){var a=n(25852);e.exports=function(e,t){return a(e,t.toLowerCase())}},25852:function(e){e.exports=function(e,t){return t in e?e[t]:t}},13585:function(e,t,n){var a=n(39900),r=n(94949),i=n(7478);e.exports=function(e){var t,n,o=e.space,s=e.mustUseProperty||[],l=e.attributes||{},c=e.properties,d=e.transform,u={},p={};for(t in c)n=new i(t,d(l,t),c[t],o),-1!==s.indexOf(t)&&(n.mustUseProperty=!0),u[t]=n,p[a(t)]=t,p[a(n.attribute)]=t;return new r(u,p,o)}},7478:function(e,t,n){var a=n(74108),r=n(7667);e.exports=s,s.prototype=new a,s.prototype.defined=!0;var i=["boolean","booleanish","overloadedBoolean","number","commaSeparated","spaceSeparated","commaOrSpaceSeparated"],o=i.length;function s(e,t,n,s){var l,c,d,u=-1;for(s&&(this.space=s),a.call(this,e,t);++u