ds_api/raw/request/
chat_completion.rs1use serde::{Deserialize, Serialize};
2
3use super::{
4 message::Message, model::Model, response_format::ResponseFormat, stop::Stop,
5 stream_options::StreamOptions, thinking::Thinking, tool::Tool, tool_choice::ToolChoice,
6};
7
8#[derive(Debug, Default, Serialize, Deserialize)]
9#[serde(default)]
10pub struct ChatCompletionRequest {
11 pub messages: Vec<Message>,
13
14 pub model: Model,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub thinking: Option<Thinking>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
25 pub frequency_penalty: Option<f32>,
26
27 #[serde(skip_serializing_if = "Option::is_none")]
29 pub max_tokens: Option<u32>,
30
31 #[serde(skip_serializing_if = "Option::is_none")]
35 pub presence_penalty: Option<f32>,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
41 pub response_format: Option<ResponseFormat>,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub stop: Option<Stop>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub stream: Option<bool>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
55 pub stream_options: Option<StreamOptions>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
61 pub temperature: Option<f32>,
62
63 #[serde(skip_serializing_if = "Option::is_none")]
67 pub top_p: Option<f32>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub tools: Option<Vec<Tool>>,
72
73 #[serde(skip_serializing_if = "Option::is_none")]
80 pub tool_choice: Option<ToolChoice>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
85 pub logprobs: Option<bool>,
86
87 #[serde(skip_serializing_if = "Option::is_none")]
90 pub top_logprobs: Option<u32>,
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::raw::request::message::Role;
97
98 #[test]
99 fn test_chat_completion_request_serialization() {
100 let request = ChatCompletionRequest {
101 messages: vec![Message {
102 role: Role::User,
103 content: Some("Hello, world!".to_string()),
104 name: None,
105 tool_call_id: None,
106 tool_calls: None,
107 reasoning_content: None,
108 prefix: None,
109 }],
110 model: Model::DeepseekChat,
111 thinking: None,
112 frequency_penalty: Some(0.5),
113 max_tokens: Some(100),
114 presence_penalty: None,
115 response_format: None,
116 stop: None,
117 stream: Some(false),
118 stream_options: None,
119 temperature: Some(0.7),
120 top_p: None,
121 tools: None,
122 tool_choice: None,
123 logprobs: None,
124 top_logprobs: None,
125 };
126
127 let json = serde_json::to_string(&request).unwrap();
128 let parsed: ChatCompletionRequest = serde_json::from_str(&json).unwrap();
129
130 assert_eq!(parsed.messages.len(), 1);
131 assert_eq!(
132 parsed.messages[0].content.as_ref().unwrap(),
133 "Hello, world!"
134 );
135 assert!(matches!(parsed.model, Model::DeepseekChat));
136 assert_eq!(parsed.frequency_penalty, Some(0.5));
137 assert_eq!(parsed.max_tokens, Some(100));
138 assert_eq!(parsed.stream, Some(false));
139 assert_eq!(parsed.temperature, Some(0.7));
140 }
141
142 #[test]
143 fn test_default_chat_completion_request() {
144 let request = ChatCompletionRequest::default();
145
146 assert!(request.messages.is_empty());
147 assert!(matches!(request.model, Model::DeepseekChat));
148 assert!(request.thinking.is_none());
149 assert!(request.frequency_penalty.is_none());
150 assert!(request.max_tokens.is_none());
151 assert!(request.presence_penalty.is_none());
152 assert!(request.response_format.is_none());
153 assert!(request.stop.is_none());
154 assert!(request.stream.is_none());
155 assert!(request.stream_options.is_none());
156 assert!(request.temperature.is_none());
157 assert!(request.top_p.is_none());
158 assert!(request.tools.is_none());
159 assert!(request.tool_choice.is_none());
160 assert!(request.logprobs.is_none());
161 assert!(request.top_logprobs.is_none());
162 }
163}