dell_ai/client.py (137 lines of code) (raw):
"""Main client class for the Dell AI SDK."""
from typing import Dict, List, Any, Optional, TYPE_CHECKING
import json
import requests
from dell_ai import constants, auth
from dell_ai.exceptions import (
APIError,
AuthenticationError,
ResourceNotFoundError,
ValidationError,
)
if TYPE_CHECKING:
from dell_ai.models import Model
from dell_ai.platforms import Platform
from dell_ai.apps import App
class DellAIClient:
"""Main client for interacting with the Dell Enterprise Hub (DEH) API."""
def __init__(self, token: Optional[str] = None):
"""
Initialize the Dell AI client.
Args:
token: Hugging Face API token. If not provided, will attempt to load from
the Hugging Face token cache.
Raises:
AuthenticationError: If a token is provided but invalid
"""
self.base_url = constants.API_BASE_URL
self.session = requests.Session()
# Set default headers
self.session.headers.update(
{
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "dell-ai-sdk/python",
}
)
# Set up authentication
self.token = token or auth.get_token()
if self.token:
# If token was explicitly provided, validate it
if token and not auth.validate_token(token):
raise AuthenticationError("Invalid authentication token provided.")
self.session.headers.update({"Authorization": f"Bearer {self.token}"})
def _make_request(
self,
method: str,
endpoint: str,
params: Optional[Dict] = None,
data: Optional[Dict] = None,
) -> Dict[str, Any]:
"""
Make an HTTP request to the API.
Args:
method: HTTP method (GET, POST, etc.)
endpoint: API endpoint
params: Query parameters
data: Request body data
Returns:
Response data as a dictionary
Raises:
AuthenticationError: If authentication fails
APIError: If the API returns an error
ResourceNotFoundError: If the requested resource is not found
ValidationError: If the input parameters are invalid
"""
url = f"{self.base_url}{endpoint}"
try:
response = self.session.request(
method=method, url=url, params=params, json=data
)
response.raise_for_status()
# Ensure we have a valid JSON response
try:
return response.json()
except json.JSONDecodeError:
raise APIError(
"Invalid JSON response from API",
status_code=response.status_code,
response=response.text,
)
except requests.exceptions.HTTPError as e:
error_message = f"HTTP Error: {e}"
try:
error_data = response.json()
if "message" in error_data:
error_message = error_data["message"]
except (json.JSONDecodeError, AttributeError):
# Use the response text if can't parse JSON
if response.text:
error_message = response.text
if response.status_code == 401:
raise AuthenticationError(
"Authentication failed. Please check your token or login again."
)
elif response.status_code == 404:
# Extract resource type and ID from the endpoint
parts = endpoint.strip("/").split("/")
resource_type = parts[0] if parts else "resource"
resource_id = parts[-1] if len(parts) > 1 else "unknown"
raise ResourceNotFoundError(resource_type, resource_id)
elif response.status_code == 400:
raise ValidationError(f"Invalid request: {error_message}")
else:
raise APIError(
error_message,
status_code=response.status_code,
response=response.text,
)
except requests.exceptions.ConnectionError as e:
raise APIError(f"Connection error: {str(e)}")
except requests.exceptions.Timeout as e:
raise APIError(f"Request timed out: {str(e)}")
except requests.exceptions.RequestException as e:
raise APIError(f"Request failed: {str(e)}")
def is_authenticated(self) -> bool:
"""
Check if the client has a valid authentication token.
Returns:
True if the token is valid, False otherwise
"""
if not self.token:
return False
try:
return auth.validate_token(self.token)
except Exception:
return False
def get_user_info(self) -> Dict[str, Any]:
"""
Get information about the authenticated user.
Returns:
A dictionary with user information
Raises:
AuthenticationError: If authentication fails or no token is available
"""
if not self.token:
raise AuthenticationError(
"No authentication token available. Please login first."
)
return auth.get_user_info(self.token)
def list_models(self) -> List[str]:
"""
Get a list of all available model IDs.
Returns:
A list of model IDs in the format "organization/model_name"
Raises:
AuthenticationError: If authentication fails
APIError: If the API returns an error
"""
from dell_ai import models
return models.list_models(self)
def get_model(self, model_id: str) -> "Model":
"""
Get detailed information about a specific model.
Args:
model_id: The model ID in the format "organization/model_name"
Returns:
Detailed model information as a Model object
Raises:
ValidationError: If the model_id format is invalid
ResourceNotFoundError: If the model is not found
AuthenticationError: If authentication fails
APIError: If the API returns an error
"""
from dell_ai import models
return models.get_model(self, model_id)
def list_platforms(self) -> List[str]:
"""
Get a list of all available platform SKU IDs.
Returns:
A list of platform SKU IDs
Raises:
AuthenticationError: If authentication fails
APIError: If the API returns an error
"""
from dell_ai import platforms
return platforms.list_platforms(self)
def get_platform(self, platform_id: str) -> "Platform":
"""
Get detailed information about a specific platform.
Args:
platform_id: The platform SKU ID
Returns:
Detailed platform information as a Platform object
Raises:
ResourceNotFoundError: If the platform is not found
AuthenticationError: If authentication fails
APIError: If the API returns an error
"""
from dell_ai import platforms
return platforms.get_platform(self, platform_id)
def check_model_access(self, model_id: str) -> bool:
"""
Check if the authenticated user has access to a specific model repository.
Args:
model_id: The model ID in the format "organization/model_name"
Returns:
True if the user has access to the model repository
Raises:
AuthenticationError: If no token is available or authentication fails
GatedRepoAccessError: If the repository is gated and the user doesn't have access
ResourceNotFoundError: If the model doesn't exist
"""
from dell_ai import auth
return auth.check_model_access(model_id, self.token)
def get_deployment_snippet(
self,
model_id: str,
platform_id: str,
engine: str,
num_gpus: int,
num_replicas: int,
) -> str:
"""
Get a deployment snippet for the specified model and configuration.
Args:
model_id: The model ID in the format "organization/model_name"
platform_id: The platform SKU ID
engine: The deployment engine ("docker" or "kubernetes")
num_gpus: The number of GPUs to use
num_replicas: The number of replicas to deploy
Returns:
A string containing the deployment snippet (docker command or k8s manifest)
Raises:
ValidationError: If any of the input parameters are invalid
ResourceNotFoundError: If the model or platform is not found
AuthenticationError: If authentication fails
APIError: If the API returns an error
"""
from dell_ai import models
return models.get_deployment_snippet(
self,
model_id=model_id,
platform_id=platform_id,
engine=engine,
num_gpus=num_gpus,
num_replicas=num_replicas,
)
def list_apps(self) -> List[str]:
"""
Get a list of all available application names.
Returns:
A list of application names
Raises:
AuthenticationError: If authentication fails
APIError: If the API returns an error
"""
from dell_ai import apps
return apps.list_apps(self)
def get_app(self, app_id: str) -> "App":
"""
Get detailed information about a specific application.
Args:
app_id: The application ID
Returns:
Detailed application information as an App object
Raises:
ResourceNotFoundError: If the application is not found
AuthenticationError: If authentication fails
APIError: If the API returns an error
"""
from dell_ai import apps
return apps.get_app(self, app_id)
def get_app_snippet(self, app_id: str, config: List[Dict[str, Any]]) -> str:
"""
Get a deployment snippet for the specified app with the provided configuration.
Args:
app_id: The application ID
config: List of configuration parameters with helmPath, type, and value
Returns:
A string containing the deployment snippet (Helm command)
Raises:
ValidationError: If any of the input parameters are invalid
ResourceNotFoundError: If the application is not found
APIError: If the API returns an error
"""
from dell_ai import apps
return apps.get_app_snippet(self, app_id, config)