Crate openai_ergonomic

Crate openai_ergonomic 

Source
Expand description

§openai-ergonomic

Crates.io Documentation CI Coverage MSRV License

Ergonomic Rust wrapper for the OpenAI API, providing type-safe builder patterns and async/await support.

§Features

  • Type-safe - full type safety with builder patterns using bon
  • Async/await - built on tokio and reqwest for modern async Rust
  • Streaming - first-class support for streaming responses
  • Comprehensive - covers all OpenAI API endpoints
  • Azure OpenAI - seamless support for Azure OpenAI deployments
  • Well-tested - extensive test coverage with mock support
  • Well-documented - rich documentation with examples

§Status

Status: under construction. The crate is still in active development and not yet ready for production use.

§Quick Start

Add openai-ergonomic to your Cargo.toml:

[dependencies]
openai-ergonomic = "0.1"
tokio = { version = "1.0", features = ["full"] }

§Basic Usage

use openai_ergonomic::{Client, Config};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build client from environment variables
    let client = Client::from_env()?.build();

    let response = client
        .chat_completions()
        .model("gpt-4")
        .message("user", "Hello, world!")
        .send()
        .await?;

    println!("{}", response.choices[0].message.content);
    Ok(())
}

§Streaming Example

use openai_ergonomic::Client;
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build client from environment variables
    let client = Client::from_env()?.build();

    let builder = client
        .chat()
        .user("Tell me a story");

    let mut stream = client.send_chat_stream(builder).await?;

    while let Some(chunk) = stream.next().await {
        let chunk = chunk?;
        if let Some(content) = chunk.content() {
            print!("{}", content);
        }
    }
    Ok(())
}

§Custom HTTP Client with Retry Logic

You can provide your own reqwest::Client with custom retry, timeout, and middleware configuration. Note: When using a custom HTTP client, you must configure the timeout on the reqwest::Client itself:

use openai_ergonomic::{Client, Config};
use reqwest_middleware::ClientBuilder;
use reqwest_retry::{RetryTransientMiddleware, policies::ExponentialBackoff};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a retry policy with exponential backoff
    let retry_policy = ExponentialBackoff::builder()
        .build_with_max_retries(3);

    // Build a reqwest client with custom timeout
    let reqwest_client = reqwest::Client::builder()
        .timeout(Duration::from_secs(60))  // Configure timeout here
        .build()?;

    // Add retry middleware
    let http_client = ClientBuilder::new(reqwest_client)
        .with(RetryTransientMiddleware::new_with_policy(retry_policy))
        .build();

    // Create OpenAI client with custom HTTP client
    let config = Config::builder()
        .api_key("your-api-key")
        .http_client(http_client)
        .build();

    let client = Client::new(config)?.build();

    // Use the client normally - retries and timeout are handled automatically
    let response = client.chat_simple("Hello!").await?;
    println!("{}", response);
    Ok(())
}

§Azure OpenAI Support

The crate seamlessly supports Azure OpenAI deployments. Azure-specific configuration can be provided through environment variables or programmatically.

§Using Environment Variables
export AZURE_OPENAI_ENDPOINT="https://my-resource.openai.azure.com"
export AZURE_OPENAI_API_KEY="your-azure-api-key"
export AZURE_OPENAI_DEPLOYMENT="gpt-4"
export AZURE_OPENAI_API_VERSION="2024-02-01"  # Optional, defaults to 2024-02-01
use openai_ergonomic::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build client from Azure environment variables
    let client = Client::from_env()?.build();

    // Use exactly the same API as standard OpenAI
    let response = client.chat_simple("Hello from Azure!").await?;
    println!("{}", response);
    Ok(())
}
§Manual Configuration
use openai_ergonomic::{Client, Config};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::builder()
        .api_key("your-azure-api-key")
        .api_base("https://my-resource.openai.azure.com")
        .azure_deployment("gpt-4")
        .azure_api_version("2024-02-01")
        .build();

    let client = Client::new(config)?.build();

    let response = client.chat_simple("Hello!").await?;
    println!("{}", response);
    Ok(())
}

Note: The library automatically handles the differences between Azure OpenAI and standard OpenAI (authentication, URL paths, API versioning). You use the same API regardless of the provider.

§Documentation

§Examples

The examples/ directory contains comprehensive examples for all major OpenAI API features:

§Core Examples

§Media & AI Capabilities

§Advanced APIs

Run any example with:

# Set your OpenAI API key
export OPENAI_API_KEY="your-api-key-here"

# Run an example
cargo run --example quickstart
cargo run --example responses_streaming
cargo run --example vision_chat

Each example includes:

  • Comprehensive documentation and inline comments
  • Error handling best practices
  • Real-world use cases and patterns
  • Progressive complexity from basic to advanced usage

§Contributing

We welcome contributions! Please see our Contributing Guide for details.

§License

Licensed under either of

at your option.

§Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

§openai-ergonomic

An ergonomic Rust wrapper for the OpenAI API, providing type-safe builder patterns and async/await support for all OpenAI endpoints.

§Features

  • Type-safe builders - Use builder patterns with compile-time validation
  • Async/await support - Built on tokio and reqwest for modern async Rust
  • Streaming responses - First-class support for real-time streaming
  • Comprehensive coverage - Support for all OpenAI API endpoints
  • Error handling - Structured error types for robust applications
  • Testing support - Mock-friendly design for unit testing

§Quick Start

use openai_ergonomic::{Client, Config};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a client from environment variables
    let client = Client::from_env()?;

    // Simple chat completion
    let response = client
        .chat_simple("Hello, how are you?")
        .await?;

    println!("{}", response);
    Ok(())
}

§Streaming Example

use openai_ergonomic::Client;
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::from_env()?.build();

    // Stream chat completions
    let builder = client
        .chat()
        .user("Tell me a story");

    let mut stream = client.send_chat_stream(builder).await?;

    while let Some(chunk) = stream.next().await {
        let chunk = chunk?;
        if let Some(content) = chunk.content() {
            print!("{}", content);
        }
    }
    Ok(())
}

§Error Handling

use openai_ergonomic::{Client, Error};

#[tokio::main]
async fn main() {
    let client = Client::from_env().expect("API key required");

    match client.chat_simple("Hello").await {
        Ok(response) => println!("{}", response),
        Err(Error::RateLimit { .. }) => {
            println!("Rate limited, please retry later");
        }
        Err(e) => eprintln!("Error: {}", e),
    }
}

§Custom Configuration

use openai_ergonomic::{Client, Config};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::builder()
        .api_key("your-api-key")
        .organization_id("org-123")
        .timeout(Duration::from_secs(30))
        .max_retries(5)
        .build();

    let client = Client::builder(config)?.build();
    Ok(())
}

§Testing with Mocks

#[cfg(test)]
mod tests {
    use openai_ergonomic::test_utils::MockOpenAIServer;

    #[tokio::test]
    async fn test_chat_completion() {
        let mock = MockOpenAIServer::new();
        mock.mock_chat_completion("Hello!", "Hi there!");

        let client = mock.client();
        let response = client.chat_simple("Hello!").await.unwrap();
        assert_eq!(response, "Hi there!");
    }
}

§Modules

  • builders - Builder pattern implementations for API requests
  • responses - Response type wrappers with ergonomic helpers
  • client - Main client for API interactions
  • config - Configuration management
  • errors - Error types and handling

Re-exports§

pub use client::Client;
pub use config::Config;
pub use config::ConfigBuilder;
pub use errors::Error;
pub use errors::Result;
pub use interceptor::AfterResponseContext;
pub use interceptor::BeforeRequestContext;
pub use interceptor::ErrorContext;
pub use interceptor::Interceptor;
pub use interceptor::StreamChunkContext;
pub use interceptor::StreamEndContext;
pub use langfuse_interceptor::LangfuseConfig;
pub use langfuse_interceptor::LangfuseInterceptor;
pub use langfuse_interceptor::LangfuseState;
pub use builders::audio::SpeechBuilder;
pub use builders::audio::TimestampGranularity;
pub use builders::audio::TranscriptionBuilder;
pub use builders::audio::TranscriptionRequest;
pub use builders::audio::TranslationBuilder;
pub use builders::audio::TranslationRequest;
pub use builders::chat::image_base64_part;
pub use builders::chat::image_base64_part_with_detail;
pub use builders::chat::image_url_part;
pub use builders::chat::image_url_part_with_detail;
pub use builders::chat::system_user;
pub use builders::chat::text_part;
pub use builders::chat::user_message;
pub use builders::embeddings::EmbeddingInput;
pub use builders::embeddings::EmbeddingsBuilder;
pub use builders::images::ImageEditBuilder;
pub use builders::images::ImageEditRequest;
pub use builders::images::ImageGenerationBuilder;
pub use builders::images::ImageVariationBuilder;
pub use builders::images::ImageVariationRequest;
pub use builders::threads::AttachmentTool;
pub use builders::threads::MessageAttachment;
pub use builders::threads::ThreadMessageBuilder;
pub use builders::threads::ThreadRequestBuilder;
pub use builders::uploads::UploadBuilder;
pub use builders::responses::responses_simple;
pub use builders::responses::responses_system_user;
pub use builders::responses::ResponsesBuilder;
pub use builders::Builder;
pub use builders::ChatCompletionBuilder;
pub use builders::Sendable;
pub use responses::chat::ChatCompletionResponseExt;
pub use responses::chat::ToolCallExt;
pub use responses::tool_function;
pub use responses::ChatCompletionResponseWrapper;
pub use responses::Response;
pub use streaming::ChatCompletionChunk;
pub use streaming::ChatCompletionStream;
pub use streaming::InterceptedStream;
pub use bon;

Modules§

azure_middleware
Middleware for Azure OpenAI authentication.
builders
Builder pattern implementations for OpenAI API requests.
client
Client wrapper for ergonomic OpenAI API access.
config
Configuration for the OpenAI ergonomic client.
errors
Error types for the OpenAI ergonomic wrapper.
interceptor
Interceptor system for middleware and observability.
langfuse_interceptor
Langfuse interceptor for OpenTelemetry-based LLM observability.
responses
Response type wrappers and ergonomic helpers.
semantic_conventions
OpenTelemetry Semantic Conventions for Generative AI
streaming
Streaming support for chat completions.

Structs§

ChatChoice
ChatCompletionResponse
CreateChatCompletionResponse : Represents a chat completion response returned by model, based on the provided input.
FunctionCall
ChatCompletionMessageToolCallFunction : The function that the model called.
ResponseChatMessage
ChatCompletionResponseMessage : A chat completion message generated by the model.
Tool
Re-export commonly used types from openai-client-base for convenience ChatCompletionTool : A function tool that can be used to generate a response.
Usage
Re-export commonly used types from openai-client-base for convenience CompletionUsage : Usage statistics for the completion request.

Enums§

Background
Allows to set transparency for the background of the generated image(s). This parameter is only supported for gpt-image-1. Must be one of transparent, opaque or auto (default value). When auto is used, the model will automatically determine the best background for the image. If transparent, the output format needs to support transparency, so it should be set to either png (default value) or webp.
Detail
Specifies the detail level of the image. Learn more in the Vision guide.
ImageInputFidelity
ImageInputFidelity - Untagged union type
ImageInputFidelityTextVariantEnum
ImageInputFidelityTextVariantEnum - String enum type
Moderation
Control the content-moderation level for images generated by gpt-image-1. Must be either low for less restrictive filtering or auto (default value).
OutputFormat
The format in which the generated images are returned. This parameter is only supported for gpt-image-1. Must be one of png, jpeg, or webp.
Quality
The quality of the image that will be generated. - auto (default value) will automatically select the best quality for the given model. - high, medium and low are supported for gpt-image-1. - hd and standard are supported for dall-e-3. - standard is the only option for dall-e-2.
ResponseFormat
The format in which generated images with dall-e-2 and dall-e-3 are returned. Must be one of url or b64_json. URLs are only valid for 60 minutes after the image has been generated. This parameter isn’t supported for gpt-image-1 which will always return base64-encoded images.
Size
The size of the generated images. Must be one of 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait), or auto (default value) for gpt-image-1, one of 256x256, 512x512, or 1024x1024 for dall-e-2, and one of 1024x1024, 1792x1024, or 1024x1792 for dall-e-3.
Style
The style of the generated images. This parameter is only supported for dall-e-3. Must be one of vivid or natural. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.
ToolCall
ToolChoice
Re-export commonly used types from openai-client-base for convenience ChatCompletionToolChoiceOption - Untagged union type
UploadPurpose
The intended purpose of the uploaded file. See the documentation on File purposes.