openai_ergonomic/lib.rs
1#![doc = include_str!("../README.md")]
2#![forbid(unsafe_code)]
3#![warn(missing_docs)]
4#![allow(clippy::missing_const_for_fn)]
5#![allow(clippy::use_self)]
6#![allow(clippy::io_other_error)]
7#![allow(async_fn_in_trait)]
8
9//! # openai-ergonomic
10//!
11//! An ergonomic Rust wrapper for the `OpenAI` API, providing type-safe builder patterns
12//! and async/await support for all `OpenAI` endpoints.
13//!
14//! ## Features
15//!
16//! - **Type-safe builders** - Use builder patterns with compile-time validation
17//! - **Async/await support** - Built on tokio and reqwest for modern async Rust
18//! - **Streaming responses** - First-class support for real-time streaming
19//! - **Comprehensive coverage** - Support for all `OpenAI` API endpoints
20//! - **Error handling** - Structured error types for robust applications
21//! - **Testing support** - Mock-friendly design for unit testing
22//!
23//! ## Quick Start
24//!
25//! ```rust,ignore
26//! use openai_ergonomic::{Client, Config};
27//!
28//! #[tokio::main]
29//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
30//! // Create a client from environment variables
31//! let client = Client::from_env()?;
32//!
33//! // Simple chat completion
34//! let response = client
35//! .chat_simple("Hello, how are you?")
36//! .await?;
37//!
38//! println!("{}", response);
39//! Ok(())
40//! }
41//! ```
42//!
43//! ## Streaming Example
44//!
45//! ```rust,ignore
46//! use openai_ergonomic::{Client, Config};
47//! use futures::StreamExt;
48//!
49//! #[tokio::main]
50//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
51//! let client = Client::from_env()?;
52//!
53//! // Stream chat completions
54//! let mut stream = client
55//! .chat()
56//! .user("Tell me a story")
57//! .stream()
58//! .await?;
59//!
60//! while let Some(chunk) = stream.next().await {
61//! print!("{}", chunk?.content());
62//! }
63//! Ok(())
64//! }
65//! ```
66//!
67//! ## Error Handling
68//!
69//! ```rust,ignore
70//! use openai_ergonomic::{Client, Error};
71//!
72//! #[tokio::main]
73//! async fn main() {
74//! let client = Client::from_env().expect("API key required");
75//!
76//! match client.chat_simple("Hello").await {
77//! Ok(response) => println!("{}", response),
78//! Err(Error::RateLimit { .. }) => {
79//! println!("Rate limited, please retry later");
80//! }
81//! Err(e) => eprintln!("Error: {}", e),
82//! }
83//! }
84//! ```
85//!
86//! ## Custom Configuration
87//!
88//! ```rust,ignore
89//! use openai_ergonomic::{Client, Config};
90//! use std::time::Duration;
91//!
92//! #[tokio::main]
93//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
94//! let config = Config::builder()
95//! .api_key("your-api-key")
96//! .organization_id("org-123")
97//! .timeout(Duration::from_secs(30))
98//! .max_retries(5)
99//! .build();
100//!
101//! let client = Client::builder(config)?.build();
102//! Ok(())
103//! }
104//! ```
105//!
106//! ## Testing with Mocks
107//!
108//! ```rust,ignore
109//! #[cfg(test)]
110//! mod tests {
111//! use openai_ergonomic::test_utils::MockOpenAIServer;
112//!
113//! #[tokio::test]
114//! async fn test_chat_completion() {
115//! let mock = MockOpenAIServer::new();
116//! mock.mock_chat_completion("Hello!", "Hi there!");
117//!
118//! let client = mock.client();
119//! let response = client.chat_simple("Hello!").await.unwrap();
120//! assert_eq!(response, "Hi there!");
121//! }
122//! }
123//! ```
124//!
125//! # Modules
126//!
127//! - [`builders`] - Builder pattern implementations for API requests
128//! - [`responses`] - Response type wrappers with ergonomic helpers
129//! - [`client`] - Main client for API interactions
130//! - [`config`] - Configuration management
131//! - [`errors`] - Error types and handling
132
133// Re-export bon for builder macros
134pub use bon;
135
136// Core modules
137pub mod azure_middleware;
138pub mod builders;
139pub mod client;
140pub mod config;
141pub mod errors;
142pub mod interceptor;
143pub mod langfuse_interceptor;
144pub mod responses;
145pub mod semantic_conventions;
146
147// Re-export commonly used types
148pub use client::Client;
149pub use config::{Config, ConfigBuilder};
150pub use errors::{Error, Result};
151pub use interceptor::{
152 AfterResponseContext, BeforeRequestContext, ErrorContext, Interceptor, StreamChunkContext,
153 StreamEndContext,
154};
155pub use langfuse_interceptor::{LangfuseConfig, LangfuseInterceptor, LangfuseState};
156
157// Re-export specific builder and response types for convenience
158// NOTE: We avoid wildcard re-exports to prevent naming conflicts between modules
159pub use builders::audio::{
160 SpeechBuilder, TimestampGranularity, TranscriptionBuilder, TranscriptionRequest,
161 TranslationBuilder, TranslationRequest,
162};
163pub use builders::chat::{
164 image_base64_part, image_base64_part_with_detail, image_url_part, image_url_part_with_detail,
165 system_user, text_part, user_message,
166};
167pub use builders::embeddings::{EmbeddingInput, EmbeddingsBuilder};
168pub use builders::images::{
169 Background, ImageEditBuilder, ImageEditRequest, ImageGenerationBuilder, ImageInputFidelity,
170 ImageInputFidelityTextVariantEnum, ImageVariationBuilder, ImageVariationRequest, Moderation,
171 OutputFormat, Quality, ResponseFormat, Size, Style,
172};
173pub use builders::threads::{
174 AttachmentTool, MessageAttachment, ThreadMessageBuilder, ThreadRequestBuilder,
175};
176pub use builders::uploads::UploadBuilder;
177// Re-export vision types for convenience
178pub use builders::responses::{responses_simple, responses_system_user, ResponsesBuilder};
179pub use builders::{Builder, ChatCompletionBuilder, Sendable};
180pub use openai_client_base::models::chat_completion_request_message_content_part_image_image_url::Detail;
181pub use openai_client_base::models::create_upload_request::Purpose as UploadPurpose;
182pub use responses::chat::{
183 ChatChoice, ChatCompletionResponse, ChatCompletionResponseExt,
184 ChatMessage as ResponseChatMessage, FunctionCall, ToolCall, ToolCallExt,
185};
186pub use responses::{tool_function, tool_web_search, ChatCompletionResponseWrapper};
187pub use responses::{Response, Tool, ToolChoice, Usage};
188
189// Test utilities (feature-gated)
190#[cfg(feature = "test-utils")]
191pub mod test_utils;
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn test_config_creation() {
199 let config = Config::builder().api_key("test-key").build();
200 assert_eq!(config.api_key(), "test-key");
201 }
202
203 #[test]
204 fn test_client_creation_with_config() {
205 let config = Config::builder().api_key("test-key").build();
206 let result = Client::builder(config);
207 assert!(result.is_ok());
208 }
209}