batch_mode_batch_scribe/
language_model_message.rs

1// ---------------- [ File: batch-mode-batch-scribe/src/language_model_message.rs ]
2crate::ix!();
3
4/// Individual message details in the request body.
5#[derive(Getters,Setters,Clone,Debug, Serialize, Deserialize)]
6#[getset(get="pub")]
7pub struct LanguageModelMessage {
8    /// Role of the participant (system/user).
9    #[serde(with = "message_role")]
10    role: LanguageModelMessageRole,
11    /// Content of the message.
12    content: ChatCompletionRequestUserMessageContent,
13}
14
15impl LanguageModelMessage {
16
17    pub fn system_message(msg: &str) -> Self {
18        Self {
19            role:    LanguageModelMessageRole::System,
20            content: ChatCompletionRequestUserMessageContent::Text(msg.to_string()),
21        }
22    }
23
24    pub fn user_message(msg: &str) -> Self {
25        Self {
26            role:    LanguageModelMessageRole::User,
27            content: ChatCompletionRequestUserMessageContent::Text(msg.to_string()),
28        }
29    }
30
31    pub fn user_message_with_image(msg: &str, image_b64: &str) -> Self {
32
33        let image_url = ImageUrl {
34            url:    image_b64.to_string(),
35            detail: Some(ImageDetail::High),
36        };
37
38        let text_part  =  ChatCompletionRequestMessageContentPartText { text: msg.into() };
39        let image_part = ChatCompletionRequestMessageContentPartImage { image_url };
40
41        let parts = vec![
42            ChatCompletionRequestUserMessageContentPart::Text(text_part),
43            ChatCompletionRequestUserMessageContentPart::ImageUrl(image_part),
44        ];
45
46        Self {
47            role:    LanguageModelMessageRole::User,
48            content: ChatCompletionRequestUserMessageContent::Array(parts),
49        }
50    }
51}
52
53#[cfg(test)]
54mod language_model_message_exhaustive_tests {
55    use super::*;
56
57    #[traced_test]
58    fn system_message_construction_produces_correct_role_and_text() {
59        trace!("===== BEGIN TEST: system_message_construction_produces_correct_role_and_text =====");
60        let msg_text = "System message content";
61        let message = LanguageModelMessage::system_message(msg_text);
62        debug!("Constructed system message: {:?}", message);
63
64        match &message.role {
65            LanguageModelMessageRole::System => {
66                trace!("Message role is correct: System");
67            },
68            _ => {
69                error!("Expected role System, got something else");
70                panic!("Role mismatch");
71            },
72        }
73
74        match &message.content {
75            ChatCompletionRequestUserMessageContent::Text(text) => {
76                debug!("Message content is a text field: {}", text);
77                pretty_assert_eq!(text, msg_text, "Content text should match");
78            },
79            _ => {
80                error!("Expected text content, found a different variant");
81                panic!("Content mismatch");
82            }
83        }
84
85        trace!("===== END TEST: system_message_construction_produces_correct_role_and_text =====");
86    }
87
88    #[traced_test]
89    fn user_message_construction_produces_correct_role_and_text() {
90        trace!("===== BEGIN TEST: user_message_construction_produces_correct_role_and_text =====");
91        let msg_text = "User message content";
92        let message = LanguageModelMessage::user_message(msg_text);
93        debug!("Constructed user message: {:?}", message);
94
95        match &message.role {
96            LanguageModelMessageRole::User => {
97                trace!("Message role is correct: User");
98            },
99            _ => {
100                error!("Expected role User, got something else");
101                panic!("Role mismatch");
102            },
103        }
104
105        match &message.content {
106            ChatCompletionRequestUserMessageContent::Text(text) => {
107                debug!("Message content is a text field: {}", text);
108                pretty_assert_eq!(text, msg_text, "Content text should match");
109            },
110            _ => {
111                error!("Expected text content, found a different variant");
112                panic!("Content mismatch");
113            }
114        }
115
116        trace!("===== END TEST: user_message_construction_produces_correct_role_and_text =====");
117    }
118
119    #[traced_test]
120    fn user_message_with_image_construction_includes_text_and_image() {
121        trace!("===== BEGIN TEST: user_message_with_image_construction_includes_text_and_image =====");
122        let msg_text = "Look at this image";
123        let image_b64 = "base64image==";
124        let message = LanguageModelMessage::user_message_with_image(msg_text, image_b64);
125        debug!("Constructed user message with image: {:?}", message);
126
127        match &message.role {
128            LanguageModelMessageRole::User => {
129                trace!("Message role is correct: User");
130            },
131            _ => {
132                error!("Expected role User, got something else");
133                panic!("Role mismatch");
134            },
135        }
136
137        match &message.content {
138            ChatCompletionRequestUserMessageContent::Array(parts) => {
139                debug!("Message content is an array with {} part(s)", parts.len());
140                pretty_assert_eq!(parts.len(), 2, "Expected two parts: text + image");
141                match (&parts[0], &parts[1]) {
142                    (
143                        ChatCompletionRequestUserMessageContentPart::Text(ChatCompletionRequestMessageContentPartText{ text: t }),
144                        ChatCompletionRequestUserMessageContentPart::ImageUrl(ChatCompletionRequestMessageContentPartImage { image_url: img }),
145                    ) => {
146                        debug!("Text part: {}, Image URL: {}", t, img.url);
147                        pretty_assert_eq!(t, msg_text, "Text part should match original message");
148                        pretty_assert_eq!(&img.url, image_b64, "Image URL should match input");
149                    },
150                    _ => {
151                        error!("Array content did not have the expected (Text, ImageUrl) structure");
152                        panic!("Parts mismatch");
153                    }
154                }
155            },
156            _ => {
157                error!("Expected array content, found a different variant");
158                panic!("Content mismatch");
159            }
160        }
161
162        trace!("===== END TEST: user_message_with_image_construction_includes_text_and_image =====");
163    }
164
165    #[traced_test]
166    fn serialization_and_deserialization_of_system_message() {
167        trace!("===== BEGIN TEST: serialization_and_deserialization_of_system_message =====");
168        let original = LanguageModelMessage::system_message("Hello system");
169        let serialized = serde_json::to_string(&original)
170            .expect("Failed to serialize system message");
171        debug!("Serialized system message: {}", serialized);
172
173        let deserialized: LanguageModelMessage = serde_json::from_str(&serialized)
174            .expect("Failed to deserialize system message");
175        debug!("Deserialized system message: {:?}", deserialized);
176
177        // Compare fields
178        pretty_assert_eq!(format!("{:?}", original.role), format!("{:?}", deserialized.role));
179        pretty_assert_eq!(format!("{:?}", original.content), format!("{:?}", deserialized.content));
180
181        trace!("===== END TEST: serialization_and_deserialization_of_system_message =====");
182    }
183
184    #[traced_test]
185    fn serialization_and_deserialization_of_user_message_with_image() {
186        trace!("===== BEGIN TEST: serialization_and_deserialization_of_user_message_with_image =====");
187        let original = LanguageModelMessage::user_message_with_image("User says hi", "b64encoded==");
188        let serialized = serde_json::to_string(&original)
189            .expect("Failed to serialize user message with image");
190        debug!("Serialized user message with image: {}", serialized);
191
192        let deserialized: LanguageModelMessage = serde_json::from_str(&serialized)
193            .expect("Failed to deserialize user message with image");
194        debug!("Deserialized user message with image: {:?}", deserialized);
195
196        // Compare fields
197        pretty_assert_eq!(format!("{:?}", original.role), format!("{:?}", deserialized.role));
198        pretty_assert_eq!(format!("{:?}", original.content), format!("{:?}", deserialized.content));
199
200        trace!("===== END TEST: serialization_and_deserialization_of_user_message_with_image =====");
201    }
202}