use super::request::Message;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ChatResponse {
pub id: String,
pub object: String,
pub created: u64,
pub model: String,
pub choices: Vec<Choice>,
#[serde(default)]
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<Usage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_fingerprint: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Choice {
pub index: u32,
pub message: Message,
#[serde(skip_serializing_if = "Option::is_none")]
pub finish_reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub logprobs: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Usage {
pub prompt_tokens: u32,
pub completion_tokens: u32,
pub total_tokens: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_hit_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_miss_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_tokens_details: Option<PromptTokensDetails>,
#[serde(skip_serializing_if = "Option::is_none")]
pub completion_tokens_details: Option<CompletionTokensDetails>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PromptTokensDetails {
#[serde(skip_serializing_if = "Option::is_none")]
pub cached_tokens: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompletionTokensDetails {
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_tokens: Option<u32>,
}
impl ChatResponse {
pub fn prompt_tokens(&self) -> u32 {
self.usage.as_ref().map(|u| u.prompt_tokens).unwrap_or(0)
}
pub fn completion_tokens(&self) -> u32 {
self.usage
.as_ref()
.map(|u| u.completion_tokens)
.unwrap_or(0)
}
pub fn total_tokens(&self) -> u32 {
self.usage.as_ref().map(|u| u.total_tokens).unwrap_or(0)
}
pub fn get_usage_safe(&self) -> (u32, u32, u32) {
(self.prompt_tokens(), self.completion_tokens(), self.total_tokens())
}
pub fn get_content(&self) -> Option<&str> {
if self.content.is_empty() { None } else { Some(&self.content) }
}
pub fn populate_reasoning_synonyms(&mut self, raw: &serde_json::Value) {
for choice in &mut self.choices {
choice.message.populate_reasoning_from_json(raw);
}
}
}