-
Notifications
You must be signed in to change notification settings - Fork 7
Adding the dar-ai-api-clients and corresponding tests #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
KNanda552
merged 9 commits into
main
from
ICNMLSALESSERVICESWDF2-4541-add-ai-api-client
Feb 19, 2025
+539
−1
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
cfccbe9
Adding the dar-ai-api-clients and corresponding tests
223219f
Updating the requirements.txt and upgrading the version
bce1eda
Updating setup.py
9f33041
Replacing 'str | None' with 'Optional' as it is not supported by pyth…
3f4d343
Upgrading ai-api-client-sdk verison
29d5412
Fixing setup.py
aa2e094
Updating the aenum version
b2b2c83
Adding comments
11d212f
Modifying comments
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| cfenv==0.5.3 | ||
| requests==2.25.1 | ||
| typing-extensions==4.0.0 | ||
| ai-api-client-sdk==2.4.0 | ||
| # Pinning aenum to <=3.1.12 because versions >3.1.12 omit the 'NoneType' | ||
| # attribute on PyPy3 (see https://github.com/ethanfurman/aenum/issues/32). | ||
| aenum==3.1.12 | ||
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| """Base client for DAR AI API.""" | ||
|
|
||
| from typing import Callable | ||
| from typing import Optional | ||
|
|
||
| from ai_api_client_sdk.ai_api_v2_client import AIAPIV2Client | ||
| from sap.aibus.dar.client.aiapi.dar_ai_api_file_upload_client import ( | ||
| DARAIAPIFileUploadClient, | ||
| ) | ||
|
|
||
|
|
||
| class DARAIAPIClient(AIAPIV2Client): | ||
| """Base client for DAR AI API.""" | ||
|
|
||
| # pylint: disable=too-many-arguments | ||
| def __init__( | ||
| self, | ||
| base_url: str, | ||
| auth_url: Optional[str] = None, | ||
| client_id: Optional[str] = None, | ||
| client_secret: Optional[str] = None, | ||
| cert_str: Optional[str] = None, | ||
| key_str: Optional[str] = None, | ||
| cert_file_path: Optional[str] = None, | ||
| key_file_path: Optional[str] = None, | ||
| token_creator: Optional[Callable[[], str]] = None, | ||
| ): | ||
| """ | ||
| Initialize the DARAIAPIClient. | ||
|
|
||
| :param base_url: The base URL of the DAR AI API. | ||
| :param auth_url: The URL of the authorization endpoint, defaults to None | ||
| :param client_id: The client id to be used for authorization, | ||
| defaults to None | ||
| :param client_secret: The client secret to be used for authorization, | ||
| defaults to None | ||
| :param cert_str: The certificate file content, needs to be provided alongside | ||
| the key_str parameter, defaults to None | ||
| :param key_str: The key file content, needs to be provided alongside | ||
| the cert_str parameter, defaults to None | ||
| :param cert_file_path: The path to the certificate file, needs to be provided | ||
| alongside the key_file_path parameter, defaults to None | ||
| :param key_file_path: The path to the key file, needs to be provided alongside | ||
| the cert_file_path parameter, defaults to None | ||
| :param token_creator: The function which returns the Bearer token, | ||
| when called, defaults to None. | ||
| """ | ||
| super().__init__( | ||
| base_url=base_url, | ||
| auth_url=auth_url, | ||
| client_id=client_id, | ||
| client_secret=client_secret, | ||
| cert_str=cert_str, | ||
| key_str=key_str, | ||
| cert_file_path=cert_file_path, | ||
| key_file_path=key_file_path, | ||
| token_creator=token_creator, | ||
| ) | ||
|
|
||
| self.file_upload_client = DARAIAPIFileUploadClient( | ||
| base_url=base_url, get_token=self.rest_client.get_token | ||
| ) |
104 changes: 104 additions & 0 deletions
104
sap/aibus/dar/client/aiapi/dar_ai_api_file_upload_client.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| """Client for DAR File Upload AI API.""" | ||
|
|
||
| import urllib.parse | ||
| from typing import Any, Callable | ||
|
|
||
| import requests | ||
| from requests import Response | ||
|
|
||
|
|
||
| class DARAIAPIFileUploadClient: | ||
| """Client for DAR File Upload AI API. | ||
|
|
||
| This client provides methods to upload and delete files on the DAR service, | ||
| handling authentication and request preparation internally. | ||
| """ | ||
|
|
||
| def __init__(self, base_url: str, get_token: Callable[[], str]): | ||
| """Initialize the DARFileUploadAIAPIClient. | ||
|
|
||
| :param base_url: The base URL of the DAR AI API. | ||
| :param get_token: A callable to fetch the authorization token. | ||
| """ | ||
| self.base_url = base_url + "/files" | ||
| self.get_token = get_token | ||
|
|
||
| def delete_file(self, remote_path: str) -> Response: | ||
| """Delete file under defined remote path. | ||
|
|
||
| :param remote_path: The path to the file to delete on the server. | ||
|
|
||
| :returns: The HTTP response object from the API call. | ||
| """ | ||
| url = self.base_url + remote_path | ||
|
|
||
| return self._send("DELETE", url) | ||
|
|
||
| def put_file( | ||
| self, local_path: str, remote_path: str, overwrite: bool = False | ||
| ) -> Response: | ||
| """Upload file to the defined remote path. | ||
|
|
||
| :param local_path: The local path of the file to upload. | ||
| :param remote_path: The destination path for the file on the server. | ||
| :param overwrite: Whether to overwrite the file if it already exists, | ||
| defaults to False. | ||
|
|
||
| :returns: The HTTP response object from the API call. | ||
| """ | ||
| url = self.base_url + remote_path | ||
| headers = { | ||
| # Content-Type MUST be application/octet-stream, even when uploading | ||
| # e.g. CSV files | ||
| "Content-Type": "application/octet-stream", | ||
| } | ||
| params = {"overwrite": overwrite} | ||
| with open(local_path, "rb") as file: | ||
| return self._send( | ||
| method="PUT", url=url, headers=headers, params=params, data=file | ||
| ) | ||
|
|
||
| def get_file_from_url(self, url: str) -> Response: | ||
| """Download file under defined url. | ||
|
|
||
| :param url: The url to the file that needs to be downloaded | ||
|
|
||
| :returns: The downloaded file on the server from the url. | ||
| """ | ||
| return self._send("GET", url) | ||
|
|
||
| def _send( # pylint: disable=too-many-arguments | ||
| self, | ||
| method: str, | ||
| url: str, | ||
| headers: dict = None, | ||
| data: Any = None, | ||
| params: dict = None, | ||
| ) -> Response: | ||
| """Send an HTTP request using the `requests` library. | ||
|
|
||
| :param method: The HTTP method (e.g., 'GET', 'POST', 'PUT', 'DELETE'). | ||
| :param url: The full URL for the request. | ||
| :param headers: The headers for the request,defaults to None. | ||
| :param data: The data payload for the request (e.g., file data), | ||
| defaults to None. | ||
| :param params: The query parameters for the URL,defaults to None. | ||
|
|
||
| :returns: The HTTP response object from the API call. | ||
| """ | ||
| session = requests.Session() | ||
| auth_headers = { | ||
| "Authorization": self.get_token(), | ||
| } | ||
| if headers: | ||
| auth_headers.update(headers) | ||
|
|
||
| req = requests.Request( | ||
| method=method, url=url, headers=auth_headers, data=data, params=params | ||
| ) | ||
| prep = req.prepare() | ||
| prep.url = url | ||
| if params: | ||
| prep.url += "?" + urllib.parse.urlencode(params) | ||
| response = session.send(prep, verify=True) | ||
| return response |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| from sap.aibus.dar.client.aiapi.dar_ai_api_client import DARAIAPIClient | ||
| import unittest | ||
|
|
||
| from sap.aibus.dar.client.aiapi.dar_ai_api_file_upload_client import ( | ||
| DARAIAPIFileUploadClient, | ||
| ) | ||
|
|
||
| BASE_URL = "https://dar-dummy.cfapps.sap.hana.ondemand.com/model-manager/v2/lm" | ||
| AUTH_URL = "https://dummy.authentication.sap.hana.ondemand.com/oauth/token" | ||
|
|
||
|
|
||
| class TestDARAIAPIClient(unittest.TestCase): | ||
| base_url = BASE_URL | ||
| auth_url = AUTH_URL | ||
| client_id = "a-client-id" | ||
| client_secret = "a-client-secret" | ||
| token = "1234567890" | ||
|
|
||
| def test_constructor(self): | ||
| """Test the basic constructor.""" | ||
| client = DARAIAPIClient( | ||
| base_url=self.base_url, | ||
| auth_url=self.auth_url, | ||
| client_id=self.client_id, | ||
| client_secret=self.client_secret, | ||
| ) | ||
| assert client.base_url == self.base_url | ||
| assert isinstance(client.file_upload_client, DARAIAPIFileUploadClient) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.