1use serde::{de::DeserializeOwned, Deserialize, Serialize};
2use std::fmt;
3
4use crate::json_stream::JsonStream;
5
6#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq)]
8pub enum ModelType {
9 #[default]
11 #[serde(rename = "deepseek-chat")]
12 DeepSeekChat,
13
14 #[serde(rename = "deepseek-reasoner")]
16 DeepSeekReasoner,
17}
18
19impl ModelType {
20 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 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#[derive(Clone, Serialize, Deserialize, Debug)]
62pub struct Model {
63 pub id: String,
65 pub object: String,
67 pub owned_by: String,
69}
70
71#[derive(Clone, Serialize, Deserialize, Debug)]
73pub struct ModelResp {
74 pub object: String,
76 pub data: Vec<Model>,
78}
79
80#[derive(Clone, Serialize, Deserialize, Debug)]
82pub struct BalanceInfo {
83 pub currency: String,
85 pub total_balance: String,
87 pub granted_balance: String,
89 pub topped_up_balance: String,
91}
92
93#[derive(Clone, Serialize, Deserialize, Debug)]
95pub struct BalanceResp {
96 pub is_available: bool,
98 pub balance_infos: Vec<BalanceInfo>,
100}
101
102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
104pub struct Function {
105 pub name: String,
107 pub arguments: String,
109}
110
111#[derive(Clone, Serialize, Deserialize, Debug)]
113pub struct ToolCall {
114 pub id: String,
116 #[serde(rename = "type")]
117 pub tool_type: String,
118 pub function: Function,
120}
121
122#[derive(Clone, Serialize, Deserialize, Debug, Default)]
124pub struct AssistantMessage {
125 pub content: String,
127 pub reasoning_content: Option<String>,
129 pub tool_calls: Option<Vec<ToolCall>>,
131 pub name: Option<String>,
132 #[serde(default)]
133 pub prefix: bool,
134}
135
136impl AssistantMessage {
137 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 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#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
177pub enum FinishReason {
178 #[serde(rename = "stop")]
180 Stop,
181 #[serde(rename = "length")]
183 Length,
184 #[serde(rename = "content_filter")]
186 ContentFilter,
187 #[serde(rename = "tool_calls")]
189 ToolCalls,
190 #[serde(rename = "insufficient_system_resource")]
192 InsufficientSystemResource,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct LogProbWrap {
198 pub content: Vec<LogProb>,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct LogProb {
205 pub token: String,
207 pub logprob: f32,
209 pub bytes: Option<Vec<u8>>,
211 pub top_logprobs: Vec<TopLogProb>,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct TopLogProb {
218 pub token: String,
220 pub logprob: f32,
222 pub bytes: Option<Vec<u8>>,
224}
225
226#[derive(Clone, Serialize, Deserialize, Debug)]
228pub struct Choice {
229 pub finish_reason: FinishReason,
231 pub index: usize,
233 pub text: Option<String>,
235 pub message: Option<AssistantMessage>,
237 pub logprobs: Option<LogProbWrap>,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct Usage {
244 pub completion_tokens: u64,
246 pub prompt_tokens: u64,
248 pub prompt_cache_hit_tokens: u64,
250 pub prompt_cache_miss_tokens: u64,
252 pub total_tokens: u64,
254 pub completion_tokens_details: Option<CompletionTokensDetails>,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct CompletionTokensDetails {
261 pub reasoning_tokens: u64,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct ChatCompletion {
268 pub id: String,
270 pub choices: Vec<Choice>,
272 pub created: u32,
274 pub model: String,
276 pub system_fingerprint: String,
278 pub object: String,
280 pub usage: Usage,
281}
282
283#[derive(Clone, Serialize, Deserialize, Debug)]
285pub struct Delta {
286 pub content: Option<String>,
288 #[serde(default)]
290 pub reasoning_content: Option<String>,
291 #[serde(default)]
293 pub role: String,
294}
295
296#[derive(Clone, Serialize, Deserialize, Debug)]
298pub struct JSONChoiceStream {
299 pub delta: Delta,
301 pub finish_reason: Option<FinishReason>,
303 pub index: usize,
305}
306
307#[derive(Clone, Serialize, Deserialize, Debug)]
309pub struct TextChoiceStream {
310 pub text: String,
312 pub finish_reason: Option<FinishReason>,
314 pub index: usize,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct ChatCompletionStream<T> {
321 pub id: String,
323 pub choices: Vec<T>,
325 pub created: u32,
327 pub model: String,
329 pub system_fingerprint: String,
331 pub object: String,
333}
334
335pub 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}