use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionChunk {
pub id: String,
pub object: String,
pub created: i64,
pub model: String,
pub choices: Vec<ChoiceDelta>,
}
impl ChatCompletionChunk {
pub fn new(
id: String,
model: String,
index: u32,
delta: DeltaContent,
finish_reason: Option<String>,
) -> Self {
Self {
id,
object: "chat.completion.chunk".to_string(),
created: chrono::Utc::now().timestamp(),
model,
choices: vec![ChoiceDelta {
index,
delta,
finish_reason,
}],
}
}
pub fn final_chunk(id: String, model: String, finish_reason: &str) -> Self {
Self {
id,
object: "chat.completion.chunk".to_string(),
created: chrono::Utc::now().timestamp(),
model,
choices: vec![ChoiceDelta {
index: 0,
delta: DeltaContent::default(),
finish_reason: Some(finish_reason.to_string()),
}],
}
}
pub fn generate_id() -> String {
format!("chatcmpl-{}", uuid::Uuid::new_v4())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChoiceDelta {
pub index: u32,
pub delta: DeltaContent,
#[serde(skip_serializing_if = "Option::is_none")]
pub finish_reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DeltaContent {
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
}
impl DeltaContent {
pub fn role() -> Self {
Self {
role: Some("assistant".to_string()),
content: None,
}
}
pub fn content(text: impl Into<String>) -> Self {
Self {
role: None,
content: Some(text.into()),
}
}
pub fn empty() -> Self {
Self::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_chunk_serialization() {
let chunk = ChatCompletionChunk::new(
"test-id".to_string(),
"gpt-4".to_string(),
0,
DeltaContent::content("Hello"),
None,
);
let json = serde_json::to_string(&chunk).unwrap();
assert!(json.contains("chat.completion.chunk"));
assert!(json.contains("Hello"));
}
#[test]
fn test_final_chunk() {
let chunk =
ChatCompletionChunk::final_chunk("test-id".to_string(), "gpt-4".to_string(), "stop");
assert_eq!(chunk.choices[0].finish_reason, Some("stop".to_string()));
assert!(chunk.choices[0].delta.content.is_none());
}
}