Skip to main content

rig_core/client/
openai.rs

1//! The OpenAI client: an [`OpenAIConfig`] on a transport, and the models it
2//! builds.
3
4use crate::client::macros::http_client;
5use crate::driver::Model;
6use crate::error::ProviderError;
7use crate::model::ModelList;
8use crate::providers::openai::responses_api::wire::Responses;
9
10#[cfg(feature = "image")]
11use crate::providers::openai::wire::Images;
12#[cfg(feature = "audio")]
13use crate::providers::openai::wire::Speech;
14use crate::providers::openai::wire::{
15    Chat, Embeddings, OpenAIConfig, OpenAiWire, Rerank, Transcriptions,
16};
17
18http_client!(
19    /// An OpenAI-shaped provider: its [`OpenAIConfig`] on a transport. Every
20    /// model it builds sends through that transport.
21    ///
22    /// ```no_run
23    /// use rig_core::completion::CompletionRequest;
24    /// use rig_core::providers::openai::{self, OpenAIConfig};
25    ///
26    /// # async fn run(http: rig_core::http_client::DynHttpClient) -> Result<(), Box<dyn std::error::Error>> {
27    /// let openai = OpenAIConfig::from_env()?.connect(http);
28    /// let model = openai.completion(openai::GPT_5_2);
29    /// let response = model.call(CompletionRequest::new("Capital of France?")).await?;
30    /// # let _ = response;
31    /// # Ok(())
32    /// # }
33    /// ```
34    OpenAI,
35    OpenAIConfig
36);
37
38impl OpenAI {
39    /// Official OpenAI with `api_key`, on the shared reqwest client.
40    #[cfg(feature = "reqwest")]
41    #[cfg_attr(docsrs, doc(cfg(feature = "reqwest")))]
42    pub fn new(api_key: impl Into<crate::wire::Secret>) -> Self {
43        OpenAIConfig::new(api_key).client()
44    }
45
46    /// Official OpenAI from `OPENAI_API_KEY` and the optional
47    /// `OPENAI_BASE_URL`, on the shared reqwest client.
48    #[cfg(feature = "reqwest")]
49    #[cfg_attr(docsrs, doc(cfg(feature = "reqwest")))]
50    pub fn from_env() -> Result<Self, crate::client::env::EnvError> {
51        Ok(OpenAIConfig::from_env()?.client())
52    }
53
54    /// The completion model for `model` on the configuration's
55    /// [`completion_route`](OpenAIConfig::completion_route).
56    pub fn completion(&self, model: impl Into<String>) -> Model<OpenAiWire> {
57        self.model(self.config.completion(model))
58    }
59
60    /// The Responses model for `model`: `POST /responses`.
61    pub fn responses(&self, model: impl Into<String>) -> Model<Responses> {
62        self.model(self.config.responses(model))
63    }
64
65    /// The Chat Completions model for `model`.
66    pub fn chat(&self, model: impl Into<String>) -> Model<Chat> {
67        self.model(self.config.chat(model))
68    }
69
70    /// The embedding model for `model`, `ndims` wide when set.
71    pub fn embedding(&self, model: impl Into<String>, ndims: Option<usize>) -> Model<Embeddings> {
72        self.model(self.config.embedding(model, ndims))
73    }
74
75    /// The rerank model for `model`.
76    pub fn rerank(&self, model: impl Into<String>) -> Model<Rerank> {
77        self.model(self.config.rerank(model))
78    }
79
80    /// The transcription model for `model`.
81    pub fn transcription(&self, model: impl Into<String>) -> Model<Transcriptions> {
82        self.model(self.config.transcription(model))
83    }
84
85    /// The image-generation model for `model`.
86    #[cfg(feature = "image")]
87    #[cfg_attr(docsrs, doc(cfg(feature = "image")))]
88    pub fn image_generation(&self, model: impl Into<String>) -> Model<Images> {
89        self.model(self.config.image_generation(model))
90    }
91
92    /// The speech model for `model`.
93    #[cfg(feature = "audio")]
94    #[cfg_attr(docsrs, doc(cfg(feature = "audio")))]
95    pub fn audio_generation(&self, model: impl Into<String>) -> Model<Speech> {
96        self.model(self.config.audio_generation(model))
97    }
98
99    /// The models this provider serves, every page followed.
100    pub async fn list_models(&self) -> Result<ModelList, ProviderError> {
101        self.model(self.config.models()).list().await
102    }
103
104    /// Check that the provider accepts the configured credential. A 401 or
105    /// 403 reply is [`ProviderError::InvalidAuthentication`].
106    pub async fn verify(&self) -> Result<(), ProviderError> {
107        self.model(self.config.verify()).verify().await
108    }
109}