deepseek_api/async_impl/
client.rs

1use super::error::ToApiError;
2use super::json_stream::JsonStream;
3use crate::{
4    response::{BalanceResp, ChatResponse, ModelResp},
5    RequestBuilder,
6};
7use anyhow::Result;
8use reqwest::Client as ReqwestClient;
9
10#[derive(Clone)]
11/// A client for interacting with the DeepSeek API.
12///
13/// # Example
14///
15/// ```no_run
16/// #[tokio::main]
17/// async fn main() {
18///     use deepseek_api::DeepSeekClientBuilder;
19///
20///     let api_key = "your_api_key".to_string();
21///     let client = DeepSeekClientBuilder::new(api_key).build().unwrap();
22///
23///     // Get available models
24///     let models = client.models().await.unwrap();
25///
26///     // Get user balance
27///     let balance = client.balance().await.unwrap();
28/// }
29/// ```
30///
31/// # Fields
32///
33/// * `client` - The underlying HTTP client.
34/// * `host` - The base URL for the DeepSeek API.
35pub struct DeepSeekClient {
36    pub(crate) client: ReqwestClient,
37    pub(crate) host: String,
38}
39
40impl DeepSeekClient {
41    /// Retrieves the list of available models from the DeepSeek API.
42    ///
43    /// This method sends a GET request to the `/models` endpoint of the DeepSeek API
44    /// and returns a `Result` containing a `ModelResp` on success.
45    ///
46    /// # Errors
47    ///
48    /// This function will return an error if the request fails or if the response
49    /// cannot be deserialized into a `ModelResp`.
50    ///
51    /// # Example
52    ///
53    /// ```no_run
54    /// #[tokio::main]
55    /// async fn main() {
56    ///     use deepseek_api::DeepSeekClientBuilder;
57    ///
58    ///     let api_key = "your_api_key".to_string();
59    ///     let client = DeepSeekClientBuilder::new(api_key).build().unwrap();
60    ///     let models = client.models().await.unwrap();
61    ///     println!("{:?}", models);
62    /// }
63    /// ```
64    ///
65    /// For more information, see the [DeepSeek API documentation](https://api-docs.deepseek.com/zh-cn/api/list-models).
66    pub async fn models(&self) -> Result<ModelResp> {
67        Ok(self
68            .client
69            .get(self.host.to_owned() + "/models")
70            .send()
71            .await?
72            .json()
73            .await?)
74    }
75
76    /// Retrieves the balance information of the user from the DeepSeek API.
77    ///
78    /// This method sends a GET request to the `/user/balance` endpoint of the DeepSeek API
79    /// and returns a `Result` containing a `BalanceResp` on success.
80    ///
81    /// # Errors
82    ///
83    /// This function will return an error if the request fails or if the response
84    /// cannot be deserialized into a `BalanceResp`.
85    ///
86    /// # Example
87    ///
88    /// ```no_run
89    /// #[tokio::main]
90    /// async fn main() {
91    ///     use deepseek_api::DeepSeekClientBuilder;
92    ///
93    ///     let api_key = "your_api_key".to_string();
94    ///     let client = DeepSeekClientBuilder::new(api_key).build().unwrap();
95    ///     let balance = client.balance().await.unwrap();
96    ///     println!("{:?}", balance);
97    /// }
98    /// ```
99    ///
100    /// For more information, see the [DeepSeek API documentation](https://api-docs.deepseek.com/zh-cn/api/get-user-balance).
101    pub async fn balance(&self) -> Result<BalanceResp> {
102        Ok(self
103            .client
104            .get(self.host.to_owned() + "/user/balance")
105            .send()
106            .await?
107            .json()
108            .await?)
109    }
110
111    /// Sends a completion request to the DeepSeek API.
112    ///
113    /// This method constructs a request using the provided `RequestBuilder` and sends it
114    /// to the appropriate endpoint of the DeepSeek API. Depending on whether the request
115    /// is for a beta feature or not, it will target either the `/beta/completions` or
116    /// `/chat/completions` endpoint. The response can be either a full response or a
117    /// streaming response, based on the `stream` optional of the `RequestBuilder`.
118    ///
119    /// # Type Parameters
120    ///
121    /// * `Builder` - A type that implements the `RequestBuilder` trait, used to construct
122    ///   the request payload.
123    ///
124    /// # Arguments
125    ///
126    /// * `request_builder` - An instance of a type implementing the `RequestBuilder` trait,
127    ///   which is used to build the request payload.
128    ///
129    /// # Returns
130    ///
131    /// A `Result` containing a `ChatResponse` on success. The `ChatResponse` can either be
132    /// a full response or a streaming response, depending on the request.
133    ///
134    /// # Errors
135    ///
136    /// This function will return an error if:
137    /// - The request fails to send.
138    /// - The response contains an API error.
139    /// - The response cannot be deserialized into the expected type.
140    ///
141    /// # Example
142    ///
143    /// ```no_run
144    /// #[tokio::main]
145    /// async fn main() {
146    ///     use deepseek_api::{request::MessageRequest, DeepSeekClientBuilder, CompletionsRequestBuilder};
147    ///     use deepseek_api::response::ChatResponse;
148    ///     use futures_util::StreamExt;
149    ///
150    ///     let api_key = "your_api_key".to_string();
151    ///     let client = DeepSeekClientBuilder::new(api_key).build().unwrap();
152    ///     let msgs = &[MessageRequest::user("Hello, DeepSeek!")];
153    ///     let request_builder = CompletionsRequestBuilder::new(msgs);
154    ///
155    ///     let response = client.send_completion_request(request_builder).await.unwrap();
156    ///     match response {
157    ///         ChatResponse::Full(full_response) => println!("{:?}", full_response),
158    ///         ChatResponse::Stream(mut stream) => {
159    ///             while let Some(item) = stream.next().await {
160    ///                 println!("{:?}", item);
161    ///             }
162    ///         }
163    ///     }
164    /// }
165    /// ```
166    ///
167    /// For more information, see the [DeepSeek API documentation](https://api-docs.deepseek.com/zh-cn/api).
168    pub async fn send_completion_request<Builder>(
169        &self,
170        request_builder: Builder,
171    ) -> Result<ChatResponse<Builder::Response, Builder::Item>>
172    where
173        Builder: RequestBuilder + Send + Sized,
174    {
175        let host = if request_builder.is_beta() {
176            self.host.to_owned() + "/beta/completions"
177        } else {
178            self.host.to_owned() + "/chat/completions"
179        };
180        let is_stream = request_builder.is_stream();
181
182        let request = request_builder.build();
183        let resp = self
184            .client
185            .post(&host)
186            .json(&request)
187            .send()
188            .await?
189            .to_api_err()
190            .await?;
191        if is_stream {
192            Ok(ChatResponse::Stream(JsonStream::new(resp)))
193        } else {
194            Ok(ChatResponse::Full(resp.json().await?))
195        }
196    }
197}