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// }