#![allow(dead_code)]
use std::ffi::c_char;
use blazen_llm::providers::base::BaseProvider;
use blazen_llm::traits::CompletionModel;
use blazen_llm::types::{ChatMessage, CompletionRequest, ToolDefinition};
use crate::error::BlazenError;
use crate::future::BlazenFuture;
use crate::provider_defaults::BlazenCompletionProviderDefaults;
use crate::string::{alloc_cstring, cstr_to_str};
#[repr(C)]
pub struct BlazenBaseProvider(pub(crate) BaseProvider);
impl BlazenBaseProvider {
pub(crate) fn into_ptr(self) -> *mut BlazenBaseProvider {
Box::into_raw(Box::new(self))
}
}
impl From<BaseProvider> for BlazenBaseProvider {
fn from(inner: BaseProvider) -> Self {
Self(inner)
}
}
unsafe fn with_inner<F: FnOnce(BaseProvider) -> BaseProvider>(
handle: *mut BlazenBaseProvider,
f: F,
) {
unsafe {
let bp = std::ptr::read(&raw const (*handle).0);
let new_bp = f(bp);
std::ptr::write(&raw mut (*handle).0, new_bp);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_with_system_prompt(
handle: *mut BlazenBaseProvider,
s: *const c_char,
) {
if handle.is_null() {
return;
}
let Some(s) = (unsafe { cstr_to_str(s) }) else {
return;
};
let owned = s.to_owned();
unsafe { with_inner(handle, |bp| bp.with_system_prompt(owned)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_with_tools_json(
handle: *mut BlazenBaseProvider,
json: *const c_char,
) {
if handle.is_null() {
return;
}
let Some(s) = (unsafe { cstr_to_str(json) }) else {
return;
};
let tools = serde_json::from_str::<Vec<ToolDefinition>>(s).unwrap_or_default();
unsafe { with_inner(handle, |bp| bp.with_tools(tools)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_with_response_format_json(
handle: *mut BlazenBaseProvider,
json: *const c_char,
) {
if handle.is_null() {
return;
}
let Some(s) = (unsafe { cstr_to_str(json) }) else {
return;
};
let value = serde_json::from_str::<serde_json::Value>(s).unwrap_or(serde_json::Value::Null);
unsafe { with_inner(handle, |bp| bp.with_response_format(value)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_with_defaults(
handle: *mut BlazenBaseProvider,
d: *const BlazenCompletionProviderDefaults,
) {
if handle.is_null() || d.is_null() {
return;
}
let defaults_clone = unsafe { &*d }.0.clone();
unsafe { with_inner(handle, |bp| bp.set_defaults(defaults_clone)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_defaults(
handle: *const BlazenBaseProvider,
) -> *mut BlazenCompletionProviderDefaults {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
BlazenCompletionProviderDefaults::from(r.0.defaults().clone()).into_ptr()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_model_id(
handle: *const BlazenBaseProvider,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
alloc_cstring(r.0.model_id())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_provider_id(
handle: *const BlazenBaseProvider,
) -> *mut c_char {
if handle.is_null() {
return std::ptr::null_mut();
}
let r = unsafe { &*handle };
alloc_cstring(r.0.model_id())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_free(handle: *mut BlazenBaseProvider) {
if handle.is_null() {
return;
}
drop(unsafe { Box::from_raw(handle) });
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_base_provider_extract(
handle: *const BlazenBaseProvider,
schema_json: *const c_char,
messages_json: *const c_char,
) -> *mut BlazenFuture {
if handle.is_null() {
return std::ptr::null_mut();
}
let Some(schema_str) = (unsafe { cstr_to_str(schema_json) }) else {
return std::ptr::null_mut();
};
let Some(messages_str) = (unsafe { cstr_to_str(messages_json) }) else {
return std::ptr::null_mut();
};
let Ok(schema) = serde_json::from_str::<serde_json::Value>(schema_str) else {
return std::ptr::null_mut();
};
let Ok(messages) = serde_json::from_str::<Vec<ChatMessage>>(messages_str) else {
return std::ptr::null_mut();
};
let provider = unsafe { &*handle }.0.clone();
let request = CompletionRequest::new(messages).with_response_format(schema);
BlazenFuture::spawn::<String, _>(async move {
let resp = provider.complete(request).await?;
Ok(resp.content.unwrap_or_default())
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_extract_result(
fut: *mut BlazenFuture,
out: *mut *mut c_char,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<String>(fut) } {
Ok(s) => {
if !out.is_null() {
unsafe {
*out = alloc_cstring(&s);
}
}
0
}
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}