use serde::Deserialize;
use serde::Serialize;
use serde_json::Value;
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
pub enum MessageType {
#[serde(rename = "system")]
SystemMessage,
#[serde(rename = "ai")]
AIMessage,
#[serde(rename = "human")]
HumanMessage,
#[serde(rename = "tool")]
ToolMessage,
}
impl Default for MessageType {
fn default() -> Self {
Self::SystemMessage
}
}
impl MessageType {
pub fn to_string(&self) -> String {
match self {
MessageType::SystemMessage => "system".to_owned(),
MessageType::AIMessage => "ai".to_owned(),
MessageType::HumanMessage => "human".to_owned(),
MessageType::ToolMessage => "tool".to_owned(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct ImageContent {
pub image_url: String,
pub detail: Option<String>,
}
impl<S: AsRef<str>> From<S> for ImageContent {
fn from(image_url: S) -> Self {
ImageContent {
image_url: image_url.as_ref().into(),
detail: None,
}
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Message {
pub content: String,
pub message_type: MessageType,
pub id: Option<String>,
pub tool_calls: Option<Value>,
pub images: Option<Vec<ImageContent>>,
}
impl Message {
pub fn new_human_message<T: std::fmt::Display>(content: T) -> Self {
Message {
content: content.to_string(),
message_type: MessageType::HumanMessage,
id: None,
tool_calls: None,
images: None,
}
}
pub fn new_human_message_with_images<T: Into<ImageContent>>(images: Vec<T>) -> Self {
Message {
content: String::default(),
message_type: MessageType::HumanMessage,
id: None,
tool_calls: None,
images: Some(images.into_iter().map(|i| i.into()).collect()),
}
}
pub fn new_system_message<T: std::fmt::Display>(content: T) -> Self {
Message {
content: content.to_string(),
message_type: MessageType::SystemMessage,
id: None,
tool_calls: None,
images: None,
}
}
pub fn new_ai_message<T: std::fmt::Display>(content: T) -> Self {
Message {
content: content.to_string(),
message_type: MessageType::AIMessage,
id: None,
tool_calls: None,
images: None,
}
}
pub fn new_tool_message<T: std::fmt::Display, S: Into<String>>(content: T, id: S) -> Self {
Message {
content: content.to_string(),
message_type: MessageType::ToolMessage,
id: Some(id.into()),
tool_calls: None,
images: None,
}
}
pub fn with_tool_calls(mut self, tool_calls: Value) -> Self {
self.tool_calls = Some(tool_calls);
self
}
pub fn messages_from_value(value: &Value) -> Result<Vec<Message>, serde_json::error::Error> {
serde_json::from_value(value.clone())
}
pub fn messages_to_string(messages: &[Message]) -> String {
messages
.iter()
.map(|m| format!("{:?}: {}", m.message_type, m.content))
.collect::<Vec<String>>()
.join("\n")
}
}