Releases: igorbenav/clientai
0.2.1
Extended Error Handling in ClientAI
Changes
- Added HTTP status codes to Ollama error handling by @igorbenav in #2
Changes
Ollama errors now include standard HTTP status codes for better error handling and compatibility:
AuthenticationError
: 401RateLimitError
: 429ModelError
: 404InvalidRequestError
: 400TimeoutError
: 408APIError
: 500
This improves error handling consistency across all providers and enables better error status tracking.
Example:
try:
response = client.generate_text("Hello", model="llama2")
except RateLimitError as e:
print(e) # Will now show: "[429] Rate limit exceeded"
print(e.status_code) # Will return: 429
What's Changed
- advanced docs by @igorbenav in #2
- ollama exceptions now with status_codes by @igorbenav in #3
- project version bumped to 0.2.1 by @igorbenav in #4
Full Changelog: v0.2.0...v0.2.1
0.2.0
Error Handling in ClientAI
ClientAI now provides an error handling system that unifies exceptions across different AI providers. This guide covers how to handle potential errors when using ClientAI.
Table of Contents
Exception Hierarchy
ClientAI uses a custom exception hierarchy to provide consistent error handling across different AI providers:
from clientai.exceptions import (
ClientAIError,
AuthenticationError,
RateLimitError,
InvalidRequestError,
ModelError,
TimeoutError,
APIError
)
ClientAIError
: Base exception class for all ClientAI errors.AuthenticationError
: Raised when there's an authentication problem with the AI provider.RateLimitError
: Raised when the AI provider's rate limit is exceeded.InvalidRequestError
: Raised when the request to the AI provider is invalid.ModelError
: Raised when there's an issue with the specified model.TimeoutError
: Raised when a request to the AI provider times out.APIError
: Raised when there's an API-related error from the AI provider.
Handling Errors
Here's how to handle potential errors when using ClientAI:
from clientai import ClientAI
from clientai.exceptions import (
ClientAIError,
AuthenticationError,
RateLimitError,
InvalidRequestError,
ModelError,
TimeoutError,
APIError
)
client = ClientAI('openai', api_key="your-openai-api-key")
try:
response = client.generate_text("Tell me a joke", model="gpt-3.5-turbo")
print(f"Generated text: {response}")
except AuthenticationError as e:
print(f"Authentication error: {e}")
except RateLimitError as e:
print(f"Rate limit exceeded: {e}")
except InvalidRequestError as e:
print(f"Invalid request: {e}")
except ModelError as e:
print(f"Model error: {e}")
except TimeoutError as e:
print(f"Request timed out: {e}")
except APIError as e:
print(f"API error: {e}")
except ClientAIError as e:
print(f"An unexpected ClientAI error occurred: {e}")
Provider-Specific Error Mapping
ClientAI maps provider-specific errors to its custom exception hierarchy. For example:
OpenAI
def _map_exception_to_clientai_error(self, e: Exception) -> None:
error_message = str(e)
status_code = getattr(e, 'status_code', None)
if isinstance(e, OpenAIAuthenticationError) or "incorrect api key" in error_message.lower():
raise AuthenticationError(error_message, status_code, original_error=e)
elif status_code == 429 or "rate limit" in error_message.lower():
raise RateLimitError(error_message, status_code, original_error=e)
elif status_code == 404 or "not found" in error_message.lower():
raise ModelError(error_message, status_code, original_error=e)
elif status_code == 400 or "invalid" in error_message.lower():
raise InvalidRequestError(error_message, status_code, original_error=e)
elif status_code == 408 or "timeout" in error_message.lower():
raise TimeoutError(error_message, status_code, original_error=e)
elif status_code and status_code >= 500:
raise APIError(error_message, status_code, original_error=e)
raise ClientAIError(error_message, status_code, original_error=e)
Replicate
def _map_exception_to_clientai_error(self, e: Exception, status_code: int = None) -> ClientAIError:
error_message = str(e)
status_code = status_code or getattr(e, 'status_code', None)
if "authentication" in error_message.lower() or "unauthorized" in error_message.lower():
return AuthenticationError(error_message, status_code, original_error=e)
elif "rate limit" in error_message.lower():
return RateLimitError(error_message, status_code, original_error=e)
elif "not found" in error_message.lower():
return ModelError(error_message, status_code, original_error=e)
elif "invalid" in error_message.lower():
return InvalidRequestError(error_message, status_code, original_error=e)
elif "timeout" in error_message.lower() or status_code == 408:
return TimeoutError(error_message, status_code, original_error=e)
elif status_code == 400:
return InvalidRequestError(error_message, status_code, original_error=e)
else:
return APIError(error_message, status_code, original_error=e)
Best Practices
-
Specific Exception Handling: Catch specific exceptions when you need to handle them differently.
-
Logging: Log errors for debugging and monitoring purposes.
import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) try: response = client.generate_text("Tell me a joke", model="gpt-3.5-turbo") except ClientAIError as e: logger.error(f"An error occurred: {e}", exc_info=True)
-
Retry Logic: Implement retry logic for transient errors like rate limiting.
import time from clientai.exceptions import RateLimitError def retry_generate(prompt, model, max_retries=3, delay=1): for attempt in range(max_retries): try: return client.generate_text(prompt, model=model) except RateLimitError as e: if attempt == max_retries - 1: raise wait_time = e.retry_after if hasattr(e, 'retry_after') else delay * (2 ** attempt) logger.warning(f"Rate limit reached. Waiting for {wait_time} seconds...") time.sleep(wait_time)
-
Graceful Degradation: Implement fallback options when errors occur.
def generate_with_fallback(prompt, primary_client, fallback_client): try: return primary_client.generate_text(prompt, model="gpt-3.5-turbo") except ClientAIError as e: logger.warning(f"Primary client failed: {e}. Falling back to secondary client.") return fallback_client.generate_text(prompt, model="llama-2-70b-chat")
By following these practices and utilizing ClientAI's unified error handling system, you can create more robust and maintainable applications that gracefully handle errors across different AI providers.
See this in the docs.
What's Changed
- unified error handling by @igorbenav in #1
New Contributors
- @igorbenav made their first contribution in #1
Full Changelog: v0.1.2...v0.2.0
0.1.2
Full Changelog: v0.1.1...v0.1.2
0.1.1
ClientAI
A unified client for seamless interaction with multiple AI providers.
ClientAI is a Python package that provides a unified interface for interacting with multiple AI providers, including OpenAI, Replicate, and Ollama. It offers seamless integration and consistent methods for text generation and chat functionality across different AI platforms.
Documentation: igorbenav.github.io/clientai/
Features
- 🔄 Unified Interface: Consistent methods for text generation and chat across multiple AI providers.
- 🔌 Multiple Providers: Support for OpenAI, Replicate, and Ollama, with easy extensibility for future providers.
- 🌊 Streaming Support: Efficient streaming of responses for real-time applications.
- 🎛️ Flexible Configuration: Easy setup with provider-specific configurations.
- 🔧 Customizable: Extensible design for adding new providers or customizing existing ones.
- 🧠 Type Hinting: Comprehensive type annotations for better development experience.
- 🔒 Provider Isolation: Optional installation of provider-specific dependencies to keep your environment lean.
Requirements
Before installing ClientAI, ensure you have the following:
- Python: Version 3.9 or newer.
- Dependencies: The core ClientAI package has minimal dependencies. Provider-specific packages (e.g.,
openai
,replicate
,ollama
) are optional and can be installed separately.
Installing
To install ClientAI with all providers, run:
pip install clientai[all]
Or, if you prefer to install only specific providers:
pip install clientai[openai] # For OpenAI support
pip install clientai[replicate] # For Replicate support
pip install clientai[ollama] # For Ollama support
Usage
ClientAI provides a simple and consistent way to interact with different AI providers. Here are some examples:
Initializing the Client
from clientai import ClientAI
# Initialize with OpenAI
openai_client = ClientAI('openai', api_key="your-openai-key")
# Initialize with Replicate
replicate_client = ClientAI('replicate', api_key="your-replicate-key")
# Initialize with Ollama
ollama_client = ClientAI('ollama', host="your-ollama-host")
Generating Text
# Using OpenAI
response = openai_client.generate_text(
"Tell me a joke",
model="gpt-3.5-turbo",
)
# Using Replicate
response = replicate_client.generate_text(
"Explain quantum computing",
model="meta/llama-2-70b-chat:latest",
)
# Using Ollama
response = ollama_client.generate_text(
"What is the capital of France?",
model="llama2",
)
Chat Functionality
messages = [
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "Paris."},
{"role": "user", "content": "What is its population?"}
]
# Using OpenAI
response = openai_client.chat(
messages,
model="gpt-3.5-turbo",
)
# Using Replicate
response = replicate_client.chat(
messages,
model="meta/llama-2-70b-chat:latest",
)
# Using Ollama
response = ollama_client.chat(
messages,
model="llama2",
)
Streaming Responses
for chunk in client.generate_text(
"Tell me a long story",
model="gpt-3.5-turbo",
stream=True
):
print(chunk, end="", flush=True)
Contributing
Contributions to ClientAI are welcome! Please refer to our Contributing Guidelines for more information.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contact
Igor Magalhaes – @igormagalhaesr – igormagalhaesr@gmail.com
github.com/igorbenav