#![allow(dead_code)]
use std::ffi::c_char;
use std::sync::Arc;
use blazen_uniffi::compute::{
ImageGenModel as InnerImageGenModel, ImageGenResult as InnerImageGenResult,
SttModel as InnerSttModel, SttResult as InnerSttResult, TtsModel as InnerTtsModel,
TtsResult as InnerTtsResult,
};
use crate::compute_records::{BlazenImageGenResult, BlazenSttResult, BlazenTtsResult};
use crate::error::BlazenError;
use crate::future::BlazenFuture;
use crate::runtime::runtime;
use crate::string::{cstr_to_opt_string, cstr_to_str};
#[inline]
fn opt_u32_from_i32(v: i32) -> Option<u32> {
if v < 0 {
None
} else {
Some(u32::try_from(v).unwrap_or(0))
}
}
pub struct BlazenTtsModel(pub(crate) Arc<InnerTtsModel>);
impl BlazenTtsModel {
pub(crate) fn into_ptr(self) -> *mut BlazenTtsModel {
Box::into_raw(Box::new(self))
}
}
impl From<Arc<InnerTtsModel>> for BlazenTtsModel {
fn from(inner: Arc<InnerTtsModel>) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_tts_model_synthesize_blocking(
model: *const BlazenTtsModel,
text: *const c_char,
voice: *const c_char,
language: *const c_char,
out_result: *mut *mut BlazenTtsResult,
out_err: *mut *mut BlazenError,
) -> i32 {
if model.is_null() {
return -2;
}
let model = unsafe { &*model };
let Some(text) = (unsafe { cstr_to_str(text) }) else {
return -2;
};
let text = text.to_owned();
let voice = unsafe { cstr_to_opt_string(voice) };
let language = unsafe { cstr_to_opt_string(language) };
let inner = Arc::clone(&model.0);
let result = runtime().block_on(async move { inner.synthesize(text, voice, language).await });
match result {
Ok(v) => {
if !out_result.is_null() {
unsafe {
*out_result = BlazenTtsResult::from(v).into_ptr();
}
}
0
}
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_tts_model_synthesize(
model: *const BlazenTtsModel,
text: *const c_char,
voice: *const c_char,
language: *const c_char,
) -> *mut BlazenFuture {
if model.is_null() {
return std::ptr::null_mut();
}
let model = unsafe { &*model };
let Some(text) = (unsafe { cstr_to_str(text) }) else {
return std::ptr::null_mut();
};
let text = text.to_owned();
let voice = unsafe { cstr_to_opt_string(voice) };
let language = unsafe { cstr_to_opt_string(language) };
let inner = Arc::clone(&model.0);
BlazenFuture::spawn::<InnerTtsResult, _>(async move {
inner.synthesize(text, voice, language).await
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_tts_model_free(model: *mut BlazenTtsModel) {
if model.is_null() {
return;
}
drop(unsafe { Box::from_raw(model) });
}
pub struct BlazenSttModel(pub(crate) Arc<InnerSttModel>);
impl BlazenSttModel {
pub(crate) fn into_ptr(self) -> *mut BlazenSttModel {
Box::into_raw(Box::new(self))
}
}
impl From<Arc<InnerSttModel>> for BlazenSttModel {
fn from(inner: Arc<InnerSttModel>) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_stt_model_transcribe_blocking(
model: *const BlazenSttModel,
audio_source: *const c_char,
language: *const c_char,
out_result: *mut *mut BlazenSttResult,
out_err: *mut *mut BlazenError,
) -> i32 {
if model.is_null() {
return -2;
}
let model = unsafe { &*model };
let Some(audio_source) = (unsafe { cstr_to_str(audio_source) }) else {
return -2;
};
let audio_source = audio_source.to_owned();
let language = unsafe { cstr_to_opt_string(language) };
let inner = Arc::clone(&model.0);
let result = runtime().block_on(async move { inner.transcribe(audio_source, language).await });
match result {
Ok(v) => {
if !out_result.is_null() {
unsafe {
*out_result = BlazenSttResult::from(v).into_ptr();
}
}
0
}
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_stt_model_transcribe(
model: *const BlazenSttModel,
audio_source: *const c_char,
language: *const c_char,
) -> *mut BlazenFuture {
if model.is_null() {
return std::ptr::null_mut();
}
let model = unsafe { &*model };
let Some(audio_source) = (unsafe { cstr_to_str(audio_source) }) else {
return std::ptr::null_mut();
};
let audio_source = audio_source.to_owned();
let language = unsafe { cstr_to_opt_string(language) };
let inner = Arc::clone(&model.0);
BlazenFuture::spawn::<InnerSttResult, _>(async move {
inner.transcribe(audio_source, language).await
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_stt_model_free(model: *mut BlazenSttModel) {
if model.is_null() {
return;
}
drop(unsafe { Box::from_raw(model) });
}
pub struct BlazenImageGenModel(pub(crate) Arc<InnerImageGenModel>);
impl BlazenImageGenModel {
pub(crate) fn into_ptr(self) -> *mut BlazenImageGenModel {
Box::into_raw(Box::new(self))
}
}
impl From<Arc<InnerImageGenModel>> for BlazenImageGenModel {
fn from(inner: Arc<InnerImageGenModel>) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_image_gen_model_generate_blocking(
model: *const BlazenImageGenModel,
prompt: *const c_char,
negative_prompt: *const c_char,
width: i32,
height: i32,
num_images: i32,
model_override: *const c_char,
out_result: *mut *mut BlazenImageGenResult,
out_err: *mut *mut BlazenError,
) -> i32 {
if model.is_null() {
return -2;
}
let model_ref = unsafe { &*model };
let Some(prompt) = (unsafe { cstr_to_str(prompt) }) else {
return -2;
};
let prompt = prompt.to_owned();
let negative_prompt = unsafe { cstr_to_opt_string(negative_prompt) };
let width = opt_u32_from_i32(width);
let height = opt_u32_from_i32(height);
let num_images = opt_u32_from_i32(num_images);
let model_override = unsafe { cstr_to_opt_string(model_override) };
let inner = Arc::clone(&model_ref.0);
let result = runtime().block_on(async move {
inner
.generate(
prompt,
negative_prompt,
width,
height,
num_images,
model_override,
)
.await
});
match result {
Ok(v) => {
if !out_result.is_null() {
unsafe {
*out_result = BlazenImageGenResult::from(v).into_ptr();
}
}
0
}
Err(e) => {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_image_gen_model_generate(
model: *const BlazenImageGenModel,
prompt: *const c_char,
negative_prompt: *const c_char,
width: i32,
height: i32,
num_images: i32,
model_override: *const c_char,
) -> *mut BlazenFuture {
if model.is_null() {
return std::ptr::null_mut();
}
let model_ref = unsafe { &*model };
let Some(prompt) = (unsafe { cstr_to_str(prompt) }) else {
return std::ptr::null_mut();
};
let prompt = prompt.to_owned();
let negative_prompt = unsafe { cstr_to_opt_string(negative_prompt) };
let width = opt_u32_from_i32(width);
let height = opt_u32_from_i32(height);
let num_images = opt_u32_from_i32(num_images);
let model_override = unsafe { cstr_to_opt_string(model_override) };
let inner = Arc::clone(&model_ref.0);
BlazenFuture::spawn::<InnerImageGenResult, _>(async move {
inner
.generate(
prompt,
negative_prompt,
width,
height,
num_images,
model_override,
)
.await
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_image_gen_model_free(model: *mut BlazenImageGenModel) {
if model.is_null() {
return;
}
drop(unsafe { Box::from_raw(model) });
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_tts_result(
fut: *mut BlazenFuture,
out: *mut *mut BlazenTtsResult,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<InnerTtsResult>(fut) } {
Ok(v) => {
if !out.is_null() {
unsafe {
*out = BlazenTtsResult::from(v).into_ptr();
}
}
0
}
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_stt_result(
fut: *mut BlazenFuture,
out: *mut *mut BlazenSttResult,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<InnerSttResult>(fut) } {
Ok(v) => {
if !out.is_null() {
unsafe {
*out = BlazenSttResult::from(v).into_ptr();
}
}
0
}
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_image_gen_result(
fut: *mut BlazenFuture,
out: *mut *mut BlazenImageGenResult,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<InnerImageGenResult>(fut) } {
Ok(v) => {
if !out.is_null() {
unsafe {
*out = BlazenImageGenResult::from(v).into_ptr();
}
}
0
}
Err(e) => {
if !err.is_null() {
unsafe {
*err = BlazenError::from(e).into_ptr();
}
}
-1
}
}
}