openai4rs 0.1.9

A non-official Rust crate for calling the OpenAI service
Documentation
use std::collections::HashMap;

use http::{Extensions, HeaderMap};
use serde::{Deserialize, Serialize, de::MapAccess};

fn default_id() -> String {
    "0".into()
}

#[derive(Debug, Clone, Deserialize)]
pub struct CompletionGeneric<T> {
    pub created: i64,
    #[serde(default = "default_id")]
    pub id: String,
    pub model: String,
    pub object: String,
    pub choices: Vec<T>,
    pub service_tier: Option<ServiceTier>,
    pub system_fingerprint: Option<String>,
    pub usage: Option<CompletionUsage>,
    #[serde(flatten)]
    pub extra_fields: Option<HashMap<String, serde_json::Value>>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct CompletionUsage {
    pub completion_tokens: i64,
    pub prompt_tokens: i64,
    pub total_tokens: i64,
    pub completion_tokens_details: Option<CompletionTokensDetails>,
    pub prompt_tokens_details: Option<PromptTokensDetails>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct CompletionTokensDetails {
    pub accepted_prediction_tokens: Option<i64>,
    pub audio_tokens: Option<i64>,
    pub reasoning_tokens: Option<i64>,
    pub rejected_prediction_tokens: Option<i64>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct PromptTokensDetails {
    pub audio_tokens: Option<i64>,
    pub cached_tokens: Option<i64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ServiceTier {
    Auto,
    Default,
}

pub(crate) type Body = serde_json::Map<String, serde_json::Value>;

#[derive(Debug, Clone)]
pub(crate) struct Timeout(pub(crate) std::time::Duration);

#[derive(Debug, Clone)]
pub(crate) struct RetryCount(pub(crate) usize);

pub(crate) struct InParam {
    pub(crate) body: Option<Body>,
    pub(crate) headers: HeaderMap,
    pub(crate) extensions: Extensions,
}

impl InParam {
    pub(crate) fn new() -> Self {
        Self {
            body: None,
            headers: HeaderMap::new(),
            extensions: Extensions::new(),
        }
    }
}

pub(crate) fn extract_optional<T, E>(
    map: &mut HashMap<String, serde_json::Value>,
    key: &str,
) -> Result<Option<T>, E>
where
    T: serde::de::DeserializeOwned,
    E: serde::de::Error,
{
    match map.remove(key) {
        Some(serde_json::Value::Null) => Ok(None),
        Some(value) => serde_json::from_value(value).map_err(serde::de::Error::custom),
        None => Ok(None),
    }
}

pub(crate) fn try_deserialize_or_skip<'de, T, V>(map: &mut V) -> Result<Option<T>, V::Error>
where
    T: serde::de::DeserializeOwned,
    V: MapAccess<'de>,
{
    match map.next_value::<Option<T>>() {
        Ok(value) => Ok(value),
        Err(e) => match map.next_value::<serde_json::Value>() {
            Ok(_) => Ok(None),
            Err(_) => Err(e),
        },
    }
}