async_llm/request/
message.rs

1use serde::{Deserialize, Serialize};
2
3use crate::types::{
4    AssistantAudio, AssistantContent, AssistantFunctionCall, AssistantToolCall, Content, ImageUrl,
5    UserContent, UserContentPart,
6};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9#[serde(tag = "role")]
10#[serde(rename_all = "lowercase")]
11pub enum ChatMessage {
12    Developer {
13        /// The contents of the developer message.
14        content: Content,
15        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
16        #[serde(skip_serializing_if = "Option::is_none")]
17        name: Option<String>,
18    },
19    System {
20        /// The contents of the developer message.
21        content: Content,
22        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
23        #[serde(skip_serializing_if = "Option::is_none")]
24        name: Option<String>,
25    },
26    User {
27        /// The contents of the user message.
28        content: UserContent,
29        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
30        #[serde(skip_serializing_if = "Option::is_none")]
31        name: Option<String>,
32    },
33    Assistant {
34        /// The contents of the assistant message. Required unless `tool_calls` or `function_call` is specified.
35        #[serde(skip_serializing_if = "Option::is_none")]
36        content: Option<AssistantContent>,
37
38        /// The refusal message by the assistant.
39        #[serde(skip_serializing_if = "Option::is_none")]
40        refusal: Option<String>,
41
42        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
43        #[serde(skip_serializing_if = "Option::is_none")]
44        name: Option<String>,
45
46        /// Data about a previous audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio).
47        #[serde(skip_serializing_if = "Option::is_none")]
48        audio: Option<AssistantAudio>,
49
50        /// The tool calls generated by the model, such as function calls.
51        #[serde(skip_serializing_if = "Option::is_none")]
52        tool_calls: Option<Vec<AssistantToolCall>>,
53
54        /// Deprecated and replaced by tool_calls. The name and arguments of a function that should be called, as generated by the model.
55        #[deprecated]
56        #[serde(skip_serializing_if = "Option::is_none")]
57        function_call: Option<AssistantFunctionCall>,
58    },
59    Tool {
60        /// The contents of the tool message.
61        content: Content,
62
63        /// Tool call that this message is responding to.
64        tool_call_id: String,
65    },
66}
67
68impl ChatMessage {
69    pub fn name(self, name: impl Into<String>) -> Self {
70        match self {
71            ChatMessage::Developer { content, name: _ } => ChatMessage::Developer {
72                content,
73                name: Some(name.into()),
74            },
75            ChatMessage::System { content, name: _ } => ChatMessage::System {
76                content,
77                name: Some(name.into()),
78            },
79            ChatMessage::User { content, name: _ } => ChatMessage::User {
80                content,
81                name: Some(name.into()),
82            },
83            _ => self,
84        }
85    }
86}
87
88impl ChatMessage {
89    pub fn system(content: impl Into<Content>) -> Self {
90        Self::System {
91            content: content.into(),
92            name: None,
93        }
94    }
95    pub fn developer(content: impl Into<Content>) -> Self {
96        Self::Developer {
97            content: content.into(),
98            name: None,
99        }
100    }
101
102    pub fn user(content: impl Into<String>) -> Self {
103        Self::User {
104            content: UserContent::Text(content.into()),
105            name: None,
106        }
107    }
108
109    pub fn user_image(image_url: impl Into<ImageUrl>) -> Self {
110        Self::User {
111            content: UserContent::Array(vec![UserContentPart::image(image_url)]),
112            name: None,
113        }
114    }
115
116    pub fn user_image_with_text(text: impl Into<String>, image_url: impl Into<ImageUrl>) -> Self {
117        Self::user_parts(vec![
118            UserContentPart::text(text),
119            UserContentPart::image(image_url),
120        ])
121    }
122
123    pub fn user_parts(parts: Vec<UserContentPart>) -> Self {
124        Self::User {
125            content: UserContent::Array(parts),
126            name: None,
127        }
128    }
129
130    pub fn assistant(content: impl Into<AssistantContent>) -> Self {
131        Self::Assistant {
132            content: Some(content.into()),
133            refusal: None,
134            name: None,
135            audio: None,
136            tool_calls: None,
137            function_call: None,
138        }
139    }
140
141    pub fn tool(content: impl Into<Content>, tool_call_id: impl Into<String>) -> Self {
142        Self::Tool {
143            content: content.into(),
144            tool_call_id: tool_call_id.into(),
145        }
146    }
147}
148
149// impl TryInto<ChatCompletionRequestMessage> for ChatMessage {
150//     type Error = Error;
151//     fn try_into(self) -> Result<ChatCompletionRequestMessage, Self::Error> {
152//         Ok(match self {
153//             ChatMessage::Developer(message_content) => {
154//                 ChatCompletionRequestDeveloperMessageBuilder::default()
155//                     .content(message_content)
156//                     .build()?
157//                     .into()
158//             }
159//             ChatMessage::System(message_content) => {
160//                 ChatCompletionRequestSystemMessageBuilder::default()
161//                     .content(message_content)
162//                     .build()?
163//                     .into()
164//             }
165//             ChatMessage::User(message_content) => {
166//                 ChatCompletionRequestUserMessageBuilder::default()
167//                     .content(message_content)
168//                     .build()?
169//                     .into()
170//             }
171//             ChatMessage::Tool {
172//                 message_content,
173//                 tool_call_id,
174//             } => ChatCompletionRequestToolMessageBuilder::default()
175//                 .content(message_content)
176//                 .tool_call_id(tool_call_id)
177//                 .build()?
178//                 .into(),
179//             ChatMessage::Assistant {
180//                 message_content,
181//                 refusal,
182//                 audio,
183//             } => match message_content {
184//                 Some(message_content) => {
185//                     let assistant_content: AssistantContent = message_content.try_into()?;
186//                     ChatCompletionRequestAssistantMessageBuilder::default()
187//                         .content(assistant_content)
188//                         .build()?
189//                         .into()
190//                 }
191//                 None => todo!(),
192//             },
193//         })
194//     }
195// }