deepseek_api/
response.rs

1use serde::{de::DeserializeOwned, Deserialize, Serialize};
2use std::fmt;
3
4use crate::json_stream::JsonStream;
5
6/// Represents different types of models available in the deep seek.
7#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq)]
8pub enum ModelType {
9    /// Default model type for chat-based interactions.
10    #[default]
11    #[serde(rename = "deepseek-chat")]
12    DeepSeekChat,
13
14    /// Model type for reasoning-based interactions.
15    #[serde(rename = "deepseek-reasoner")]
16    DeepSeekReasoner,
17}
18
19impl ModelType {
20    /// Retrieves the limit information for the model.
21    ///
22    /// Returns a tuple containing:
23    /// - `context_len`: Maximum context length unit KB.
24    /// - `thought_chain_len`: Optional maximum thought chain length.
25    /// - `output_len`: Maximum output length.
26    pub fn get_limit_info(&self) -> (u32, Option<u32>, u32) {
27        match self {
28            ModelType::DeepSeekChat => (64, None, 8),
29            ModelType::DeepSeekReasoner => (64, Some(32), 8),
30        }
31    }
32}
33
34impl fmt::Display for ModelType {
35    /// Formats the model type into a human-readable string.
36    ///
37    /// The output includes context length, thought chain length (if applicable),
38    /// output length, and pricing information.
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        let (context_len, thought_chain_len, output_len) = self.get_limit_info();
41        match self {
42            ModelType::DeepSeekChat => {
43                write!(
44                    f,
45                    "DeepSeekChat: Context Length = {}K, Max Output Length = {}K",
46                    context_len, output_len
47                )
48            }
49            ModelType::DeepSeekReasoner => {
50                write!(
51                    f,
52                    "DeepSeekReasoner: Context Length = {}K, Max Thought Chain Length = {:?}K, Max Output Length = {}K",
53                    context_len, thought_chain_len, output_len
54                )
55            }
56        }
57    }
58}
59
60/// Represents a model with its associated metadata.
61#[derive(Clone, Serialize, Deserialize, Debug)]
62pub struct Model {
63    /// Unique identifier for the model.
64    pub id: String,
65    /// Type of the object.
66    pub object: String,
67    /// Owner of the model.
68    pub owned_by: String,
69}
70
71/// Response structure containing a list of models.
72#[derive(Clone, Serialize, Deserialize, Debug)]
73pub struct ModelResp {
74    /// Type of the object.
75    pub object: String,
76    /// List of models.
77    pub data: Vec<Model>,
78}
79
80/// Information about the balance of a user.
81#[derive(Clone, Serialize, Deserialize, Debug)]
82pub struct BalanceInfo {
83    /// Currency type.
84    pub currency: String,
85    /// Total balance available.
86    pub total_balance: String,
87    /// Granted balance.
88    pub granted_balance: String,
89    /// Topped up balance.
90    pub topped_up_balance: String,
91}
92
93/// Response structure containing balance information.
94#[derive(Clone, Serialize, Deserialize, Debug)]
95pub struct BalanceResp {
96    /// Indicates if the balance is available.
97    pub is_available: bool,
98    /// List of balance information.
99    pub balance_infos: Vec<BalanceInfo>,
100}
101
102/// Represents a function with its name and parameters.
103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
104pub struct Function {
105    /// Name of the function.
106    pub name: String,
107    /// Arguments of the function, its argument .
108    pub arguments: String,
109}
110
111/// Represents a tool call with its associated function.
112#[derive(Clone, Serialize, Deserialize, Debug)]
113pub struct ToolCall {
114    /// Unique identifier for the tool call.
115    pub id: String,
116    #[serde(rename = "type")]
117    pub tool_type: String,
118    /// Function associated with the tool call.
119    pub function: Function,
120}
121
122/// Represents a message with its content and optional reasoning content and tool calls.
123#[derive(Clone, Serialize, Deserialize, Debug, Default)]
124pub struct AssistantMessage {
125    /// Content of the message.
126    pub content: String,
127    /// Optional reasoning content.
128    pub reasoning_content: Option<String>,
129    /// Optional list of tool calls.
130    pub tool_calls: Option<Vec<ToolCall>>,
131    pub name: Option<String>,
132    #[serde(default)]
133    pub prefix: bool,
134}
135
136impl AssistantMessage {
137    /// Creates a new `AssistantMessage` instance.
138    ///
139    /// # Arguments
140    ///
141    /// * `msg` - A string slice representing the message content.
142    pub fn new(msg: &str) -> Self {
143        AssistantMessage {
144            content: msg.to_string(),
145            name: None,
146            prefix: false,
147            reasoning_content: None,
148            ..Default::default()
149        }
150    }
151
152    /// Creates a new `AssistantMessage` instance with a name.
153    ///
154    /// # Arguments
155    ///
156    /// * `name` - A string slice representing the name.
157    /// * `msg` - A string slice representing the message content.
158    pub fn new_with_name(name: &str, msg: &str) -> Self {
159        AssistantMessage {
160            content: msg.to_string(),
161            name: Some(name.to_string()),
162            prefix: false,
163            reasoning_content: None,
164            ..Default::default()
165        }
166    }
167
168    pub fn set_prefix(mut self, content: &str) -> Self {
169        self.prefix = true;
170        self.content = content.to_string();
171        self
172    }
173}
174
175/// Enum representing the reason for finishing a process.
176#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
177pub enum FinishReason {
178    /// Process stopped.
179    #[serde(rename = "stop")]
180    Stop,
181    /// Process finished due to length limit.
182    #[serde(rename = "length")]
183    Length,
184    /// Process finished due to content filter.
185    #[serde(rename = "content_filter")]
186    ContentFilter,
187    /// Process finished due to tool calls.
188    #[serde(rename = "tool_calls")]
189    ToolCalls,
190    /// Process finished due to insufficient system resources.
191    #[serde(rename = "insufficient_system_resource")]
192    InsufficientSystemResource,
193}
194
195/// Wrapper for log probability information.
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct LogProbWrap {
198    /// List of log probabilities.
199    pub content: Vec<LogProb>,
200}
201
202/// Represents log probability information for a token.
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct LogProb {
205    /// Token string.
206    pub token: String,
207    /// Log probability of the token.
208    pub logprob: f32,
209    /// Optional bytes representation of the token.
210    pub bytes: Option<Vec<u8>>,
211    /// List of top log probabilities.
212    pub top_logprobs: Vec<TopLogProb>,
213}
214
215/// Represents top log probability information for a token.
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct TopLogProb {
218    /// Token string.
219    pub token: String,
220    /// Log probability of the token.
221    pub logprob: f32,
222    /// Optional bytes representation of the token.
223    pub bytes: Option<Vec<u8>>,
224}
225
226/// Represents a choice made during a process.
227#[derive(Clone, Serialize, Deserialize, Debug)]
228pub struct Choice {
229    /// Reason for finishing the process.
230    pub finish_reason: FinishReason,
231    /// Index of the choice.
232    pub index: usize,
233    /// Message associated with the choice.
234    pub text: Option<String>,
235    /// Message associated with the choice.
236    pub message: Option<AssistantMessage>,
237    /// Optional log probability information.
238    pub logprobs: Option<LogProbWrap>,
239}
240
241/// Represents usage information for a process.
242#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct Usage {
244    /// Number of completion tokens used.
245    pub completion_tokens: u64,
246    /// Number of prompt tokens used.
247    pub prompt_tokens: u64,
248    /// Number of prompt cache hit tokens.
249    pub prompt_cache_hit_tokens: u64,
250    /// Number of prompt cache miss tokens.
251    pub prompt_cache_miss_tokens: u64,
252    /// Total number of tokens used.
253    pub total_tokens: u64,
254    /// Details of completion tokens used.
255    pub completion_tokens_details: Option<CompletionTokensDetails>,
256}
257
258/// Details of completion tokens used.
259#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct CompletionTokensDetails {
261    /// Number of reasoning tokens used.
262    pub reasoning_tokens: u64,
263}
264
265/// Represents a chat completion with its associated metadata.
266#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct ChatCompletion {
268    /// Unique identifier for the chat completion.
269    pub id: String,
270    /// List of choices made during the chat completion.
271    pub choices: Vec<Choice>,
272    /// Timestamp of when the chat completion was created.
273    pub created: u32,
274    /// Model used for the chat completion.
275    pub model: String,
276    /// System fingerprint associated with the chat completion.
277    pub system_fingerprint: String,
278    /// Type of the object.
279    pub object: String,
280    pub usage: Usage,
281}
282
283/// Represents a delta change in a choice stream.
284#[derive(Clone, Serialize, Deserialize, Debug)]
285pub struct Delta {
286    /// Content of the delta change.
287    pub content: Option<String>,
288    /// Reasoning content of the delta change.
289    #[serde(default)]
290    pub reasoning_content: Option<String>,
291    /// Role of the delta change sender.
292    #[serde(default)]
293    pub role: String,
294}
295
296/// Represents a choice stream with its associated delta change.
297#[derive(Clone, Serialize, Deserialize, Debug)]
298pub struct JSONChoiceStream {
299    /// Delta change in the choice stream.
300    pub delta: Delta,
301    /// Reason for finishing the choice stream.
302    pub finish_reason: Option<FinishReason>,
303    /// Index of the choice stream.
304    pub index: usize,
305}
306
307/// Represents a choice stream with its associated delta change.
308#[derive(Clone, Serialize, Deserialize, Debug)]
309pub struct TextChoiceStream {
310    /// Delta change in the choice stream.
311    pub text: String,
312    /// Reason for finishing the choice stream.
313    pub finish_reason: Option<FinishReason>,
314    /// Index of the choice stream.
315    pub index: usize,
316}
317
318/// Represents a chat completion stream with its associated metadata.
319#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct ChatCompletionStream<T> {
321    /// Unique identifier for the chat completion stream.
322    pub id: String,
323    /// List of choice streams made during the chat completion stream.
324    pub choices: Vec<T>,
325    /// Timestamp of when the chat completion stream was created.
326    pub created: u32,
327    /// Model used for the chat completion stream.
328    pub model: String,
329    /// System fingerprint associated with the chat completion stream.
330    pub system_fingerprint: String,
331    /// Type of the object.
332    pub object: String,
333}
334
335/// Represents a chat response which can either be a full response or a stream of items.
336///
337/// This enum is generic over the response type `RESP` and the item type `ITEM`.
338///
339/// # Variants
340///
341/// - `Full(RESP)`: Represents a complete response of type `RESP`.
342/// - `Stream(JsonStream<ITEM>)`: Represents a stream of items of type `ITEM`.
343///
344/// # Type Parameters
345///
346/// - `RESP`: The type of the full response. Must implement `DeserializeOwned`.
347/// - `ITEM`: The type of the items in the stream. Must implement `DeserializeOwned`.
348///
349/// # Methods
350///
351/// - `must_response(self) -> RESP`: Consumes the enum and returns the full response if it is the `Full` variant. Panics if it is the `Stream` variant.
352/// - `must_stream(self) -> JsonStream<ITEM>`: Consumes the enum and returns the stream if it is the `Stream` variant. Panics if it is the `Full` variant.
353pub enum ChatResponse<RESP, ITEM>
354where
355    RESP: DeserializeOwned,
356    ITEM: DeserializeOwned,
357{
358    Full(RESP),
359    Stream(JsonStream<ITEM>),
360}
361
362impl<RESP, ITEM> ChatResponse<RESP, ITEM>
363where
364    RESP: DeserializeOwned,
365    ITEM: DeserializeOwned,
366{
367    pub fn must_response(self) -> RESP {
368        match self {
369            ChatResponse::Full(resp) => resp,
370            ChatResponse::Stream(_) => panic!("Expected Full variant, found Stream"),
371        }
372    }
373
374    pub fn must_stream(self) -> JsonStream<ITEM> {
375        match self {
376            ChatResponse::Stream(stream) => stream,
377            ChatResponse::Full(_) => panic!("Expected Stream variant, found Full"),
378        }
379    }
380}
381
382#[cfg(test)]
383mod tests {
384    use super::*;
385    use serde_json::json;
386
387    #[test]
388    fn test_deserialize_chat_completion_stream() {
389        let json_data = json!({
390          "id": "6f81a959-b76a-4f5a-94c5-77089b7c646d",
391          "object": "chat.completion.chunk",
392          "created": 1746341234,
393          "model": "deepseek-reasoner",
394          "system_fingerprint": "fp_5417b77867_prod0425fp8",
395          "choices": [
396            {
397              "index": 0,
398              "delta": {
399                "role": "assistant",
400                "content": null,
401                "reasoning_content": ""
402              },
403              "logprobs": null,
404              "finish_reason": null
405            }
406          ]
407        });
408
409        let deserialized: ChatCompletionStream<JSONChoiceStream> =
410            serde_json::from_value(json_data).unwrap();
411
412        assert_eq!(deserialized.id, "6f81a959-b76a-4f5a-94c5-77089b7c646d");
413        assert_eq!(deserialized.object, "chat.completion.chunk");
414        assert_eq!(deserialized.created, 1746341234);
415        assert_eq!(deserialized.model, "deepseek-reasoner");
416        assert_eq!(deserialized.system_fingerprint, "fp_5417b77867_prod0425fp8");
417        assert_eq!(deserialized.choices.len(), 1);
418
419        let choice = &deserialized.choices[0];
420        assert_eq!(choice.index, 0);
421        assert_eq!(choice.delta.role, "assistant");
422        assert!(choice.delta.content.is_none());
423        assert_eq!(choice.delta.reasoning_content.as_ref().unwrap(), "");
424        assert!(choice.finish_reason.is_none());
425    }
426}