#![allow(dead_code)]
use std::ffi::c_char;
use blazen_llm::providers::custom::ApiProtocol;
use blazen_llm::providers::openai_compat::{AuthMethod, OpenAiCompatConfig};
use crate::string::{alloc_cstring, cstr_to_opt_string, cstr_to_str};
#[inline]
fn auth_method_from_code(code: u32, header_name: Option<String>) -> AuthMethod {
match code {
1 => AuthMethod::ApiKeyHeader(header_name.unwrap_or_default()),
2 => AuthMethod::AzureApiKey,
3 => AuthMethod::KeyPrefix,
_ => AuthMethod::Bearer,
}
}
#[inline]
fn auth_method_to_code(m: &AuthMethod) -> u32 {
match m {
AuthMethod::Bearer => 0,
AuthMethod::ApiKeyHeader(_) => 1,
AuthMethod::AzureApiKey => 2,
AuthMethod::KeyPrefix => 3,
}
}
#[repr(C)]
pub struct BlazenOpenAiCompatConfig(pub(crate) OpenAiCompatConfig);
impl BlazenOpenAiCompatConfig {
pub(crate) fn into_ptr(self) -> *mut BlazenOpenAiCompatConfig {
Box::into_raw(Box::new(self))
}
}
impl From<OpenAiCompatConfig> for BlazenOpenAiCompatConfig {
fn from(inner: OpenAiCompatConfig) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_new(
provider_name: *const c_char,
base_url: *const c_char,
api_key: *const c_char,
default_model: *const c_char,
auth_code: u32,
auth_header_name: *const c_char,
supports_model_listing: bool,
) -> *mut BlazenOpenAiCompatConfig {
let Some(provider_name) = (unsafe { cstr_to_str(provider_name) }) else {
return std::ptr::null_mut();
};
let Some(base_url) = (unsafe { cstr_to_str(base_url) }) else {
return std::ptr::null_mut();
};
let Some(api_key) = (unsafe { cstr_to_str(api_key) }) else {
return std::ptr::null_mut();
};
let Some(default_model) = (unsafe { cstr_to_str(default_model) }) else {
return std::ptr::null_mut();
};
let auth_header_name = unsafe { cstr_to_opt_string(auth_header_name) };
let cfg = OpenAiCompatConfig {
provider_name: provider_name.to_owned(),
base_url: base_url.to_owned(),
api_key: api_key.to_owned(),
default_model: default_model.to_owned(),
auth_method: auth_method_from_code(auth_code, auth_header_name),
extra_headers: Vec::new(),
query_params: Vec::new(),
supports_model_listing,
};
BlazenOpenAiCompatConfig(cfg).into_ptr()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_push_extra_header(
handle: *mut BlazenOpenAiCompatConfig,
name: *const c_char,
value: *const c_char,
) {
if handle.is_null() {
return;
}
let Some(name) = (unsafe { cstr_to_str(name) }) else {
return;
};
let value = unsafe { cstr_to_opt_string(value) }.unwrap_or_default();
let r = unsafe { &mut *handle };
r.0.extra_headers.push((name.to_owned(), value));
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_push_query_param(
handle: *mut BlazenOpenAiCompatConfig,
name: *const c_char,
value: *const c_char,
) {
if handle.is_null() {
return;
}
let Some(name) = (unsafe { cstr_to_str(name) }) else {
return;
};
let value = unsafe { cstr_to_opt_string(value) }.unwrap_or_default();
let r = unsafe { &mut *handle };
r.0.query_params.push((name.to_owned(), value));
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_provider_name(
handle: *const BlazenOpenAiCompatConfig,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
alloc_cstring(&r.0.provider_name)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_base_url(
handle: *const BlazenOpenAiCompatConfig,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
alloc_cstring(&r.0.base_url)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_api_key(
handle: *const BlazenOpenAiCompatConfig,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
alloc_cstring(&r.0.api_key)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_default_model(
handle: *const BlazenOpenAiCompatConfig,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
alloc_cstring(&r.0.default_model)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_auth_code(
handle: *const BlazenOpenAiCompatConfig,
) -> u32 {
if handle.is_null() {
return 0;
}
let r = unsafe { &*handle };
auth_method_to_code(&r.0.auth_method)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_auth_header_name(
handle: *const BlazenOpenAiCompatConfig,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
match &r.0.auth_method {
AuthMethod::ApiKeyHeader(s) => alloc_cstring(s),
_ => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_supports_model_listing(
handle: *const BlazenOpenAiCompatConfig,
) -> bool {
if handle.is_null() {
return false;
}
let r = unsafe { &*handle };
r.0.supports_model_listing
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_extra_headers_len(
handle: *const BlazenOpenAiCompatConfig,
) -> usize {
if handle.is_null() {
return 0;
}
let r = unsafe { &*handle };
r.0.extra_headers.len()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_extra_header_name(
handle: *const BlazenOpenAiCompatConfig,
index: usize,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
r.0.extra_headers
.get(index)
.map_or(std::ptr::null_mut(), |(k, _)| alloc_cstring(k))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_extra_header_value(
handle: *const BlazenOpenAiCompatConfig,
index: usize,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
r.0.extra_headers
.get(index)
.map_or(std::ptr::null_mut(), |(_, v)| alloc_cstring(v))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_query_params_len(
handle: *const BlazenOpenAiCompatConfig,
) -> usize {
if handle.is_null() {
return 0;
}
let r = unsafe { &*handle };
r.0.query_params.len()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_query_param_name(
handle: *const BlazenOpenAiCompatConfig,
index: usize,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
r.0.query_params
.get(index)
.map_or(std::ptr::null_mut(), |(k, _)| alloc_cstring(k))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_query_param_value(
handle: *const BlazenOpenAiCompatConfig,
index: usize,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
r.0.query_params
.get(index)
.map_or(std::ptr::null_mut(), |(_, v)| alloc_cstring(v))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_openai_compat_config_free(handle: *mut BlazenOpenAiCompatConfig) {
if handle.is_null() {
return;
}
drop(unsafe { Box::from_raw(handle) });
}
#[repr(C)]
pub struct BlazenApiProtocol(pub(crate) ApiProtocol);
impl BlazenApiProtocol {
pub(crate) fn into_ptr(self) -> *mut BlazenApiProtocol {
Box::into_raw(Box::new(self))
}
}
impl From<ApiProtocol> for BlazenApiProtocol {
fn from(inner: ApiProtocol) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_api_protocol_openai(
config: *const BlazenOpenAiCompatConfig,
) -> *mut BlazenApiProtocol {
if config.is_null() {
return std::ptr::null_mut();
}
let cfg = unsafe { &*config };
BlazenApiProtocol(ApiProtocol::OpenAi(cfg.0.clone())).into_ptr()
}
#[unsafe(no_mangle)]
pub extern "C" fn blazen_api_protocol_custom() -> *mut BlazenApiProtocol {
BlazenApiProtocol(ApiProtocol::Custom).into_ptr()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_api_protocol_kind(handle: *const BlazenApiProtocol) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
let kind = match r.0 {
ApiProtocol::OpenAi(_) => "openai",
ApiProtocol::Custom => "custom",
};
alloc_cstring(kind)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_api_protocol_config(
handle: *const BlazenApiProtocol,
) -> *mut BlazenOpenAiCompatConfig {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
match &r.0 {
ApiProtocol::OpenAi(cfg) => BlazenOpenAiCompatConfig(cfg.clone()).into_ptr(),
ApiProtocol::Custom => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_api_protocol_free(handle: *mut BlazenApiProtocol) {
if handle.is_null() {
return;
}
drop(unsafe { Box::from_raw(handle) });
}