openai_api_rs/v1/chat_completion/
mod.rs1use crate::v1::types;
2use serde::de::{self, MapAccess, SeqAccess, Visitor};
3use serde::ser::SerializeMap;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt;
6
7#[allow(clippy::module_inception)]
8pub mod chat_completion;
9pub mod chat_completion_stream;
10
11#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
12pub enum ToolChoiceType {
13 None,
14 Auto,
15 Required,
16 ToolChoice { tool: Tool },
17}
18
19#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
20#[serde(rename_all = "lowercase")]
21pub enum ReasoningEffort {
22 Low,
23 Medium,
24 High,
25}
26
27#[derive(Debug, Serialize, Deserialize, Clone)]
28#[serde(untagged)]
29pub enum ReasoningMode {
30 Effort { effort: ReasoningEffort },
31 MaxTokens { max_tokens: i64 },
32}
33
34#[derive(Debug, Serialize, Deserialize, Clone)]
35pub struct Reasoning {
36 #[serde(flatten)]
37 pub mode: Option<ReasoningMode>,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub exclude: Option<bool>,
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub enabled: Option<bool>,
42}
43
44#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
45#[allow(non_camel_case_types)]
46pub enum MessageRole {
47 user,
48 system,
49 assistant,
50 function,
51 tool,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub enum Content {
56 Text(String),
57 ImageUrl(Vec<ImageUrl>),
58}
59
60impl serde::Serialize for Content {
61 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62 where
63 S: serde::Serializer,
64 {
65 match *self {
66 Content::Text(ref text) => {
67 if text.is_empty() {
68 serializer.serialize_none()
69 } else {
70 serializer.serialize_str(text)
71 }
72 }
73 Content::ImageUrl(ref image_url) => image_url.serialize(serializer),
74 }
75 }
76}
77
78impl<'de> Deserialize<'de> for Content {
79 fn deserialize<D>(deserializer: D) -> Result<Content, D::Error>
80 where
81 D: Deserializer<'de>,
82 {
83 struct ContentVisitor;
84
85 impl<'de> Visitor<'de> for ContentVisitor {
86 type Value = Content;
87
88 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
89 formatter.write_str("a valid content type")
90 }
91
92 fn visit_str<E>(self, value: &str) -> Result<Content, E>
93 where
94 E: de::Error,
95 {
96 Ok(Content::Text(value.to_string()))
97 }
98
99 fn visit_seq<A>(self, seq: A) -> Result<Content, A::Error>
100 where
101 A: SeqAccess<'de>,
102 {
103 let image_urls: Vec<ImageUrl> =
104 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))?;
105 Ok(Content::ImageUrl(image_urls))
106 }
107
108 fn visit_map<M>(self, map: M) -> Result<Content, M::Error>
109 where
110 M: MapAccess<'de>,
111 {
112 let image_urls: Vec<ImageUrl> =
113 Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?;
114 Ok(Content::ImageUrl(image_urls))
115 }
116
117 fn visit_none<E>(self) -> Result<Self::Value, E>
118 where
119 E: de::Error,
120 {
121 Ok(Content::Text(String::new()))
122 }
123
124 fn visit_unit<E>(self) -> Result<Self::Value, E>
125 where
126 E: de::Error,
127 {
128 Ok(Content::Text(String::new()))
129 }
130 }
131
132 deserializer.deserialize_any(ContentVisitor)
133 }
134}
135
136#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
137#[allow(non_camel_case_types)]
138pub enum ContentType {
139 text,
140 image_url,
141}
142
143#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
144#[allow(non_camel_case_types)]
145pub struct ImageUrlType {
146 pub url: String,
147}
148
149#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
150#[allow(non_camel_case_types)]
151pub struct ImageUrl {
152 pub r#type: ContentType,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub text: Option<String>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub image_url: Option<ImageUrlType>,
157}
158
159#[derive(Debug, Deserialize, Serialize, Clone)]
160pub struct ChatCompletionMessage {
161 pub role: MessageRole,
162 pub content: Content,
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub name: Option<String>,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub tool_calls: Option<Vec<ToolCall>>,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub tool_call_id: Option<String>,
169}
170
171#[derive(Debug, Deserialize, Serialize, Clone)]
172pub struct ChatCompletionMessageForResponse {
173 pub role: MessageRole,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub content: Option<String>,
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub reasoning_content: Option<String>,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub name: Option<String>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub tool_calls: Option<Vec<ToolCall>>,
182}
183
184#[derive(Debug, Deserialize, Serialize)]
185pub struct ChatCompletionChoice {
186 pub index: i64,
187 pub message: ChatCompletionMessageForResponse,
188 pub finish_reason: Option<FinishReason>,
189 pub finish_details: Option<FinishDetails>,
190}
191
192#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
193#[allow(non_camel_case_types)]
194pub enum FinishReason {
195 stop,
196 length,
197 content_filter,
198 tool_calls,
199 null,
200}
201
202#[derive(Debug, Deserialize, Serialize)]
203#[allow(non_camel_case_types)]
204pub struct FinishDetails {
205 pub r#type: FinishReason,
206 pub stop: String,
207}
208
209#[derive(Debug, Deserialize, Serialize, Clone)]
210pub struct ToolCall {
211 pub id: String,
212 pub r#type: String,
213 pub function: ToolCallFunction,
214}
215
216#[derive(Debug, Deserialize, Serialize, Clone)]
217pub struct ToolCallFunction {
218 #[serde(skip_serializing_if = "Option::is_none")]
219 pub name: Option<String>,
220 #[serde(skip_serializing_if = "Option::is_none")]
221 pub arguments: Option<String>,
222}
223
224pub fn serialize_tool_choice<S>(
225 value: &Option<ToolChoiceType>,
226 serializer: S,
227) -> Result<S::Ok, S::Error>
228where
229 S: Serializer,
230{
231 match value {
232 Some(ToolChoiceType::None) => serializer.serialize_str("none"),
233 Some(ToolChoiceType::Auto) => serializer.serialize_str("auto"),
234 Some(ToolChoiceType::Required) => serializer.serialize_str("required"),
235 Some(ToolChoiceType::ToolChoice { tool }) => {
236 let mut map = serializer.serialize_map(Some(2))?;
237 map.serialize_entry("type", &tool.r#type)?;
238 map.serialize_entry("function", &tool.function)?;
239 map.end()
240 }
241 None => serializer.serialize_none(),
242 }
243}
244
245#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
246pub struct Tool {
247 pub r#type: ToolType,
248 pub function: types::Function,
249}
250
251#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq)]
252#[serde(rename_all = "snake_case")]
253pub enum ToolType {
254 Function,
255}