use serde::{Deserialize, Serialize};
pub type ContentPartId = String;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ContentPart {
OutputText(OutputTextContent),
InputText(InputTextContent),
InputImage(InputImageContent),
InputFile(InputFileContent),
UrlCitation(UrlCitationContent),
Refusal(RefusalContent),
}
impl ContentPart {
pub fn output_text(text: impl Into<String>) -> Self {
Self::OutputText(OutputTextContent { text: text.into() })
}
pub fn input_text(text: impl Into<String>) -> Self {
Self::InputText(InputTextContent { text: text.into() })
}
pub fn refusal(refusal: impl Into<String>) -> Self {
Self::Refusal(RefusalContent {
refusal: refusal.into(),
})
}
pub fn as_text(&self) -> Option<&str> {
match self {
Self::OutputText(c) => Some(&c.text),
Self::InputText(c) => Some(&c.text),
Self::Refusal(c) => Some(&c.refusal),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OutputTextContent {
pub text: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InputTextContent {
pub text: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InputImageContent {
pub image_url: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub detail: Option<ImageDetail>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ImageDetail {
Low,
High,
#[default]
Auto,
Original,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InputFileContent {
#[serde(skip_serializing_if = "Option::is_none")]
pub filename: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_data: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_url: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UrlCitationContent {
pub url: String,
pub title: String,
pub start_index: usize,
pub end_index: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RefusalContent {
pub refusal: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_content_part_output_text() {
let part = ContentPart::output_text("Hello, world!");
assert_eq!(part.as_text(), Some("Hello, world!"));
}
#[test]
fn test_content_part_serialization() {
let part = ContentPart::output_text("Test");
let json = serde_json::to_string(&part).unwrap();
assert!(json.contains("\"type\":\"output_text\""));
assert!(json.contains("\"text\":\"Test\""));
}
}