///|
/// Fluent builder for a multimodal message, so callers can assemble mixed
/// text/image content without manually constructing the `Content` enum.
///
/// Example:
/// ```
/// let msg = MessageBuilder::user()
/// .text("What is in these images?")
/// .image_url("https://a/1.png")
/// .image_url("https://a/2.png")
/// .build()
/// ```
pub struct MessageBuilder {
role : Role
parts : Array[ContentPart]
mut name : String?
}
///|
/// Start building a message with the given role.
pub fn MessageBuilder::new(role : Role) -> MessageBuilder {
{ role, parts: [], name: None }
}
///|
/// Start building a `user` message.
pub fn MessageBuilder::user() -> MessageBuilder {
MessageBuilder::new(User)
}
///|
/// Start building an `assistant` message.
pub fn MessageBuilder::assistant() -> MessageBuilder {
MessageBuilder::new(Assistant)
}
///|
/// Start building a `system` message.
pub fn MessageBuilder::system() -> MessageBuilder {
MessageBuilder::new(System)
}
///|
/// Append a text part.
pub fn MessageBuilder::text(
self : MessageBuilder,
s : String,
) -> MessageBuilder {
self.parts.push(Text(s))
self
}
///|
/// Append an image-URL part.
pub fn MessageBuilder::image_url(
self : MessageBuilder,
url : String,
) -> MessageBuilder {
self.parts.push(ImageUrl(url))
self
}
///|
/// Append a base64 image part.
pub fn MessageBuilder::image_base64(
self : MessageBuilder,
mime : String,
data : String,
) -> MessageBuilder {
self.parts.push(ImageUrl("data:" + mime + ";base64," + data))
self
}
///|
/// Set the optional author name.
pub fn MessageBuilder::name(
self : MessageBuilder,
n : String,
) -> MessageBuilder {
self.name = Some(n)
self
}
///|
/// Finalize into a `Message`.
///
/// If the builder holds exactly one text part and no name, it collapses to a
/// plain string content (the common case); otherwise it emits a parts array.
pub fn MessageBuilder::build(self : MessageBuilder) -> Message {
let content = if self.parts.length() == 1 && self.parts[0] is Text(t) {
Str(t)
} else {
Parts(self.parts)
}
{
role: self.role,
content,
tool_calls: None,
tool_call_id: None,
name: self.name,
}
}
///|
/// The number of content parts accumulated so far.
pub fn MessageBuilder::part_count(self : MessageBuilder) -> Int {
self.parts.length()
}
///|
/// Whether the message contains any image part.
pub fn Message::has_image(self : Message) -> Bool {
match self.content {
Str(_) => false
Parts(parts) => {
for p in parts {
if p is ImageUrl(_) {
return true
}
}
false
}
}
}
///|
/// Count the image parts in a message.
pub fn Message::image_count(self : Message) -> Int {
match self.content {
Str(_) => 0
Parts(parts) => {
let mut n = 0
for p in parts {
if p is ImageUrl(_) {
n = n + 1
}
}
n
}
}
}