litellm-rs 0.8.2

A high-performance AI Gateway written in Rust, providing OpenAI-compatible APIs with intelligent routing, load balancing, and enterprise features
Documentation
use crate::core::providers::unified_provider::ProviderError;
use crate::core::providers::{Provider, ProviderType, bfl, stability};

pub(crate) fn build_image_provider(
    provider_type: ProviderType,
    mut config: serde_json::Value,
) -> Result<Provider, ProviderError> {
    normalize_native_image_endpoint(&mut config);
    match provider_type {
        ProviderType::Stability => {
            let mut typed: stability::StabilityConfig = serde_json::from_value(config.clone())
                .map_err(|error| ProviderError::configuration("stability", error.to_string()))?;
            merge_custom_headers(&mut typed.base.headers, &config);
            Ok(Provider::Stability(stability::StabilityProvider::new(
                typed,
            )?))
        }
        ProviderType::BlackForestLabs => {
            let mut typed: bfl::BflConfig =
                serde_json::from_value(config.clone()).map_err(|error| {
                    ProviderError::configuration("black_forest_labs", error.to_string())
                })?;
            merge_custom_headers(&mut typed.base.headers, &config);
            Ok(Provider::BlackForestLabs(Box::new(bfl::BflProvider::new(
                typed,
            )?)))
        }
        _ => Err(ProviderError::configuration(
            "media",
            "unsupported native image provider type",
        )),
    }
}

fn normalize_native_image_endpoint(config: &mut serde_json::Value) {
    let Some(config) = config.as_object_mut() else {
        return;
    };
    let endpoint = config
        .get("base_url")
        .and_then(serde_json::Value::as_str)
        .or_else(|| config.get("api_base").and_then(serde_json::Value::as_str))
        .map(str::to_string);
    if let Some(endpoint) = endpoint {
        config.insert("api_base".to_string(), endpoint.into());
    }
    config.remove("base_url");
}

fn merge_custom_headers(
    headers: &mut std::collections::HashMap<String, String>,
    config: &serde_json::Value,
) {
    let Some(custom_headers) = config
        .get("custom_headers")
        .and_then(serde_json::Value::as_object)
    else {
        return;
    };
    for (key, value) in custom_headers {
        if let Some(value) = value.as_str() {
            headers.insert(key.clone(), value.to_string());
        }
    }
}