Skip to content

Releases: igorbenav/clientai

0.2.1

28 Oct 06:27
983526b
Compare
Choose a tag to compare

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: 401
  • RateLimitError: 429
  • ModelError: 404
  • InvalidRequestError: 400
  • TimeoutError: 408
  • APIError: 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

Full Changelog: v0.2.0...v0.2.1

0.2.0

25 Oct 06:26
3676ebf
Compare
Choose a tag to compare

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

  1. Exception Hierarchy
  2. Handling Errors
  3. Provider-Specific Error Mapping
  4. Best Practices

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

  1. Specific Exception Handling: Catch specific exceptions when you need to handle them differently.

  2. 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)
  3. 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)
  4. 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

New Contributors

Full Changelog: v0.1.2...v0.2.0

0.1.2

15 Oct 06:05
Compare
Choose a tag to compare

Full Changelog: v0.1.1...v0.1.2

0.1.1

12 Oct 06:42
Compare
Choose a tag to compare

ClientAI

ClientAI logo

A unified client for seamless interaction with multiple AI providers.

Tests PyPi Version Supported Python Versions


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 – @igormagalhaesrigormagalhaesr@gmail.com
github.com/igorbenav