diff --git a/coreruntime/nimblenet/data_variable/include/data_variable_enums.hpp b/coreruntime/nimblenet/data_variable/include/data_variable_enums.hpp index 1cab830e..2752f32f 100644 --- a/coreruntime/nimblenet/data_variable/include/data_variable_enums.hpp +++ b/coreruntime/nimblenet/data_variable/include/data_variable_enums.hpp @@ -132,8 +132,8 @@ enum MemberFuncType { ADD_CONTEXT, LIST_COMPATIBLE_LLMS, GET_HARDWARE_INFO, -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) CONVERT_TEXT_TO_PHONEMES, -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) LASTTYPE, // should be last }; diff --git a/coreruntime/nimblenet/data_variable/include/nimble_net_data_variable.hpp b/coreruntime/nimblenet/data_variable/include/nimble_net_data_variable.hpp index 6127a542..e0486a47 100644 --- a/coreruntime/nimblenet/data_variable/include/nimble_net_data_variable.hpp +++ b/coreruntime/nimblenet/data_variable/include/nimble_net_data_variable.hpp @@ -116,9 +116,9 @@ def zeros(shape: list[int], dtype: str) -> Tensor: OpReturnType set_threads(const std::vector& arguments); -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) OpReturnType convert_text_to_phonemes(const std::vector& arguments); -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) OpReturnType call_function(int memberFuncIndex, const std::vector& arguments, CallStack& stack) override; diff --git a/coreruntime/nimblenet/data_variable/src/data_variable.cpp b/coreruntime/nimblenet/data_variable/src/data_variable.cpp index ddad551f..b895d032 100644 --- a/coreruntime/nimblenet/data_variable/src/data_variable.cpp +++ b/coreruntime/nimblenet/data_variable/src/data_variable.cpp @@ -105,9 +105,9 @@ std::map DataVariable::_memberFuncMap = { {"add_context", MemberFuncType::ADD_CONTEXT}, {"list_compatible_llms", MemberFuncType::LIST_COMPATIBLE_LLMS}, {"get_hardware_info", MemberFuncType::GET_HARDWARE_INFO}, -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) {"convert_text_to_phonemes", MemberFuncType::CONVERT_TEXT_TO_PHONEMES}, -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) }; std::map DataVariable::_inverseMemberFuncMap = { @@ -198,9 +198,9 @@ std::map DataVariable::_inverseMemberFuncMap = { {MemberFuncType::ADD_CONTEXT, "add_context"}, {MemberFuncType::LIST_COMPATIBLE_LLMS, "list_compatible_llms"}, {MemberFuncType::GET_HARDWARE_INFO, "get_hardware_info"}, -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) {MemberFuncType::CONVERT_TEXT_TO_PHONEMES, "convert_text_to_phonemes"}, -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) }; int DataVariable::add_and_get_member_func_index(const std::string& memberFuncString) { diff --git a/coreruntime/nimblenet/data_variable/src/nimble_net_data_variable.cpp b/coreruntime/nimblenet/data_variable/src/nimble_net_data_variable.cpp index 5e52f89d..15550d31 100644 --- a/coreruntime/nimblenet/data_variable/src/nimble_net_data_variable.cpp +++ b/coreruntime/nimblenet/data_variable/src/nimble_net_data_variable.cpp @@ -25,7 +25,7 @@ #include "retriever.hpp" #endif // GENAI -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) // TODO (jpuneet): move this chunk to a separate file namespace { // UTF-8 helper function to determine if byte is a continuation byte @@ -229,7 +229,7 @@ std::string process_phonemes(const char* phonemes) { return transform_phonemes(without_stress); } } // anonymous namespace -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) OpReturnType NimbleNetDataVariable::create_tensor(const std::vector& arguments) { THROW_ARGUMENTS_NOT_MATCH(arguments.size(), 2, MemberFuncType::CREATETENSOR); @@ -522,7 +522,7 @@ OpReturnType NimbleNetDataVariable::set_threads(const std::vector& #endif // MINIMAL_BUILD } -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) OpReturnType NimbleNetDataVariable::convert_text_to_phonemes( const std::vector& arguments) { THROW_ARGUMENTS_NOT_MATCH(arguments.size(), 1, MemberFuncType::CONVERT_TEXT_TO_PHONEMES); @@ -536,7 +536,7 @@ OpReturnType NimbleNetDataVariable::convert_text_to_phonemes( } return std::make_shared>(phonemes); } -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) OpReturnType NimbleNetDataVariable::call_function(int memberFuncIndex, const std::vector& arguments, @@ -594,11 +594,11 @@ OpReturnType NimbleNetDataVariable::call_function(int memberFuncIndex, return list_compatible_llms(arguments); case MemberFuncType::GET_HARDWARE_INFO: return get_hardware_info(arguments, stack); -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) case MemberFuncType::CONVERT_TEXT_TO_PHONEMES: // TODO (jpuneet): Should this be a part of another DelitePy module? return convert_text_to_phonemes(arguments); -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) } THROW("%s not implemented for nimblenet", DataVariable::get_member_func_string(memberFuncIndex)); } diff --git a/coreruntime/nimblenet/native_interface/include/native_interface.hpp b/coreruntime/nimblenet/native_interface/include/native_interface.hpp index bab243f0..b6bf6295 100644 --- a/coreruntime/nimblenet/native_interface/include/native_interface.hpp +++ b/coreruntime/nimblenet/native_interface/include/native_interface.hpp @@ -242,8 +242,8 @@ bool schedule_logs_upload(long repeatIntervalInMinutes, long retryIntervalInMinu */ nlohmann::json get_hardware_info(); -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) const char* get_phonemes(const char* text); -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) } // namespace nativeinterface diff --git a/coreruntime/nimblenet/native_interface/src/native_interface.cpp b/coreruntime/nimblenet/native_interface/src/native_interface.cpp index c2cd4a7d..e741a4c7 100644 --- a/coreruntime/nimblenet/native_interface/src/native_interface.cpp +++ b/coreruntime/nimblenet/native_interface/src/native_interface.cpp @@ -416,8 +416,8 @@ nlohmann::json get_hardware_info() { return hardware_info_json; } -#ifdef IOS +#if defined(__ANDROID__) || defined(IOS) const char* get_phonemes(const char* text) { return ::get_phonemes(text); } -#endif // IOS +#endif // defined(__ANDROID__) || defined(IOS) } // namespace nativeinterface diff --git a/coreruntime/platform/android/CMakeLists.txt b/coreruntime/platform/android/CMakeLists.txt index 9851eee3..968eeff5 100644 --- a/coreruntime/platform/android/CMakeLists.txt +++ b/coreruntime/platform/android/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources(nimblenet ${VISIBILITY} src/frontend_data_variable.cpp src/hardware_info_shadow.cpp src/logs_upload_scheduler_shadow.cpp + src/native_request_receiver_shadow.cpp src/networking_shadow.cpp ) diff --git a/coreruntime/platform/android/include/client.h b/coreruntime/platform/android/include/client.h index 4180e71c..c4ac3ebe 100644 --- a/coreruntime/platform/android/include/client.h +++ b/coreruntime/platform/android/include/client.h @@ -181,4 +181,11 @@ bool deallocate_frontend_tensors(CTensors cTensors); */ bool free_frontend_function_context(void* context); +/** + * @brief Return phonemes of the given string. + * + * @return char* Pointer to phoneme string. + */ +char* get_phonemes(const char* text); + #pragma GCC visibility pop diff --git a/coreruntime/platform/android/include/dependency_container_shadow.hpp b/coreruntime/platform/android/include/dependency_container_shadow.hpp index 61dfbaee..399cd50e 100644 --- a/coreruntime/platform/android/include/dependency_container_shadow.hpp +++ b/coreruntime/platform/android/include/dependency_container_shadow.hpp @@ -48,6 +48,14 @@ class DependencyContainerShadow { */ static jobject getLogsUploadSchedulerInstance(JNIEnv *env); + /** + * @brief Retrieves the NativeRequestReceiver instance from the DependencyContainer via JNI. + * + * @param env JNI environment pointer. + * @return jobject Java NativeRequestReceiver instance. + */ + static jobject getNativeRequestReceiverInstance(JNIEnv *env); + private: inline static jobject dependencyContainerInstance = nullptr; /**< Global reference to DependencyContainer instance. */ inline static jmethodID getInstanceMethodId = nullptr; /**< Method ID for getInstance. */ @@ -55,6 +63,7 @@ class DependencyContainerShadow { inline static jmethodID getNetworkingMethodId = nullptr; /**< Method ID for getNetworking. */ inline static jmethodID getHardwareInfoMethodId = nullptr; /**< Method ID for getHardwareInfo. */ inline static jmethodID getLogsUploadSchedulerMethodId = nullptr; /**< Method ID for getLogsUploadScheduler. */ + inline static jmethodID getNativeRequestReceiverMethodId = nullptr; /**< Method ID for getNativeRequestReceiver. */ /** * @brief Sets the global DependencyContainer instance via JNI. diff --git a/coreruntime/platform/android/include/native_request_receiver_shadow.hpp b/coreruntime/platform/android/include/native_request_receiver_shadow.hpp new file mode 100644 index 00000000..3ad55772 --- /dev/null +++ b/coreruntime/platform/android/include/native_request_receiver_shadow.hpp @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 DeliteAI Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#include + +class NativeRequestReceiverShadow { + public: + static void init(JNIEnv* env); + static jobject dispatch(JNIEnv* env, const std::string& functionName, int argCount, ...); + + private: + inline static jclass nativeRequestReceiverClass = nullptr; + inline static jmethodID dispatchMethodId = nullptr; + inline static jobject nativeRequestReceiverKotlinInstance = nullptr; +}; diff --git a/coreruntime/platform/android/src/client.cpp b/coreruntime/platform/android/src/client.cpp index 677c46f2..3de61238 100644 --- a/coreruntime/platform/android/src/client.cpp +++ b/coreruntime/platform/android/src/client.cpp @@ -11,6 +11,7 @@ #include "file_download_state_transition_shadow.h" #include "hardware_info_shadow.hpp" #include "logs_upload_scheduler_shadow.hpp" +#include "native_request_receiver_shadow.hpp" #include "nimble_net_util.hpp" JavaVM *globalJvm; @@ -310,3 +311,72 @@ bool schedule_logs_upload(long repeatIntervalInMinutes, long retryIntervalInMinu bool deallocate_frontend_tensors(CTensors cTensors) { return true; } bool free_frontend_function_context(void *context) { return true; } + +namespace { + +/** + * @brief Private helper function to convert jstring to persistent C string. + * + * @param env JNI environment pointer. + * @param jStr Java string to convert. + * @return char* Persistent C string (caller must free), or nullptr on failure. + */ +char* jstring_to_cstring(JNIEnv* env, jstring jStr) { + if (!jStr) return nullptr; + + const char* chars = env->GetStringUTFChars(jStr, nullptr); + if (!chars) return nullptr; + + char* result = strdup(chars); + env->ReleaseStringUTFChars(jStr, chars); + + return result; +} + +} // namespace + +char* get_phonemes(const char* text) { + if (!text) { + return nullptr; + } + + JNIEnv* env; + bool attached = false; + int getEnvStatus = globalJvm->GetEnv((void **)&env, JNI_VERSION_1_6); + + if (getEnvStatus == JNI_EDETACHED) { + attached = true; + JavaVMAttachArgs args; + args.version = JNI_VERSION_1_6; + args.name = NULL; + args.group = NULL; + + if (globalJvm->AttachCurrentThread(&env, NULL) != 0) { + return nullptr; + } + } + + jstring jText = env->NewStringUTF(text); + if (!jText) { + if (attached) { + globalJvm->DetachCurrentThread(); + } + return nullptr; + } + + jobject result = NativeRequestReceiverShadow::dispatch(env, "getPhonemes", 1, jText); + + env->DeleteLocalRef(jText); + + char* phonemes = nullptr; + if (result) { + phonemes = jstring_to_cstring(env, (jstring)result); + env->DeleteLocalRef(result); + } + + if (attached) { + globalJvm->DetachCurrentThread(); + } + + return phonemes; +} diff --git a/coreruntime/platform/android/src/dependency_container_shadow.cpp b/coreruntime/platform/android/src/dependency_container_shadow.cpp index fbf259b9..fd5740e2 100644 --- a/coreruntime/platform/android/src/dependency_container_shadow.cpp +++ b/coreruntime/platform/android/src/dependency_container_shadow.cpp @@ -20,6 +20,8 @@ void DependencyContainerShadow::setMethodIds(JNIEnv *env) { "()Ldev/deliteai/impl/common/HardwareInfo;"); getLogsUploadSchedulerMethodId = env->GetMethodID(dependencyContainerClass, "getLogsUploadScheduler", "()Ldev/deliteai/impl/loggers/workManager/LogsUploadScheduler;"); + getNativeRequestReceiverMethodId = env->GetMethodID(dependencyContainerClass, "getNativeRequestReceiver", + "()Ldev/deliteai/impl/nativeBridge/NativeRequestReceiver;"); } void DependencyContainerShadow::setDependencyContainerInstance(JNIEnv *env) { @@ -81,3 +83,14 @@ jobject DependencyContainerShadow::getLogsUploadSchedulerInstance(JNIEnv *env) { return env->CallObjectMethod(dependencyContainerInstance, getLogsUploadSchedulerMethodId); } + +jobject DependencyContainerShadow::getNativeRequestReceiverInstance(JNIEnv *env) { + if (!getNativeRequestReceiverMethodId || !dependencyContainerClass) { + throw std::runtime_error("encountered nullptr in getNativeRequestReceiverInstance()"); + } + if (!dependencyContainerInstance) { + throw std::runtime_error("dependencyContainerClass is not initialized"); + } + + return env->CallObjectMethod(dependencyContainerInstance, getNativeRequestReceiverMethodId); +} diff --git a/coreruntime/platform/android/src/native_request_receiver_shadow.cpp b/coreruntime/platform/android/src/native_request_receiver_shadow.cpp new file mode 100644 index 00000000..f6337a3f --- /dev/null +++ b/coreruntime/platform/android/src/native_request_receiver_shadow.cpp @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 DeliteAI Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_request_receiver_shadow.hpp" + +#include +#include + +#include "../../jni/utils/jni_logger.h" +#include "client.h" +#include "dependency_container_shadow.hpp" + +void NativeRequestReceiverShadow::init(JNIEnv* env) { + if (!env) return; + + jclass localClass = env->FindClass("dev/deliteai/impl/nativeBridge/NativeRequestReceiver"); + if (!localClass) { + LOGE("Class dev.deliteai.impl.nativeBridge.NativeRequestReceiver not found.\n"); + return; + } + + nativeRequestReceiverClass = static_cast(env->NewGlobalRef(localClass)); + env->DeleteLocalRef(localClass); + + if (!nativeRequestReceiverClass) { + LOGE("Failed to create global reference for NativeRequestReceiver class.\n"); + return; + } + + dispatchMethodId = + env->GetMethodID(nativeRequestReceiverClass, "dispatch", + "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;"); + if (!dispatchMethodId) { + LOGE("Method dispatch not found.\n"); + } + + auto nativeRequestReceiverKotlinInstanceLocal = DependencyContainerShadow::getNativeRequestReceiverInstance(env); + nativeRequestReceiverKotlinInstance = env->NewGlobalRef(nativeRequestReceiverKotlinInstanceLocal); + env->DeleteLocalRef(nativeRequestReceiverKotlinInstanceLocal); +} + +jobject NativeRequestReceiverShadow::dispatch(JNIEnv* env, const std::string& functionName, int argCount, ...) { + if (!nativeRequestReceiverKotlinInstance) { + LOGE("nativeRequestReceiverKotlinInstance is null in dispatch.\n"); + return nullptr; + } + + jstring jFunctionName = env->NewStringUTF(functionName.c_str()); + + // Create an array with the specified number of arguments + jclass objectClass = env->FindClass("java/lang/Object"); + jobjectArray argsArray = env->NewObjectArray(argCount, objectClass, nullptr); + env->DeleteLocalRef(objectClass); + + // Process variable arguments + va_list args; + va_start(args, argCount); + for (int i = 0; i < argCount; i++) { + jobject arg = va_arg(args, jobject); + env->SetObjectArrayElement(argsArray, i, arg); + } + va_end(args); + + jobject result = + env->CallObjectMethod(nativeRequestReceiverKotlinInstance, dispatchMethodId, jFunctionName, argsArray); + + env->DeleteLocalRef(jFunctionName); + env->DeleteLocalRef(argsArray); + + return result; +} diff --git a/sdks/android/app/src/main/kotlin/dev/deliteai/android/sampleapp/MainActivity.kt b/sdks/android/app/src/main/kotlin/dev/deliteai/android/sampleapp/MainActivity.kt index 6cd7c87d..fd0c10cf 100644 --- a/sdks/android/app/src/main/kotlin/dev/deliteai/android/sampleapp/MainActivity.kt +++ b/sdks/android/app/src/main/kotlin/dev/deliteai/android/sampleapp/MainActivity.kt @@ -8,6 +8,7 @@ package dev.deliteai.android.sampleapp import android.app.Application import android.os.Bundle +import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.ScrollState @@ -39,6 +40,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import dev.deliteai.NimbleNet import dev.deliteai.android.sampleapp.ui.theme.DeliteAiTheme +import dev.deliteai.client.TextToSpeech import dev.deliteai.datamodels.NimbleNetConfig import dev.deliteai.impl.common.NIMBLENET_VARIANTS import kotlinx.coroutines.CoroutineScope @@ -166,15 +168,11 @@ fun addEvent() = NimbleNet.addEvent( ), "ContestJoinedClient" ).toString() -fun getDummyPreprocessorList() = List(30) { - mapOf( - "productid" to 800, - "contestType" to "special", - "roundid" to 97, - "winnerPercent" to 0.29, - "prizeAmount" to 900, - "entryFee" to 50 - ) +class TextToSpeechImpl : TextToSpeech { + override fun getPhonemes(text: String): String { + Log.e("BRIDGE", "getPhonemes: Oh! yes! working!!1", ) + return "dummy phonemes" + } } // Config @@ -187,5 +185,6 @@ private val nimblenetConfig = NimbleNetConfig( initTimeOutInMs = 1000000000, compatibilityTag = "android-output-verification", libraryVariant = NIMBLENET_VARIANTS.STATIC, - online = true + online = true, + textToSpeechImpl = TextToSpeechImpl() ) diff --git a/sdks/android/nimblenet_core/src/main/cpp/jni/jni.cpp b/sdks/android/nimblenet_core/src/main/cpp/jni/jni.cpp index f56a2e42..c4b8630b 100644 --- a/sdks/android/nimblenet_core/src/main/cpp/jni/jni.cpp +++ b/sdks/android/nimblenet_core/src/main/cpp/jni/jni.cpp @@ -26,6 +26,7 @@ #include "../coreruntime/nimblenet/llm_executors/include/gemini_nano_executor.hpp" #include "file_download_state_transition_shadow.h" #include "mutable_map_shadow.h" +#include "native_request_receiver_shadow.hpp" #include "nimble_net_error_shadow.h" #include "nimble_net_result_shadow.h" #include "user_event_data_shadow.h" @@ -96,6 +97,7 @@ void JNICALL Java_dev_deliteai_impl_nativeBridge_impl_CoreRuntimeImpl_initialize FileDownloadStateTransitionShadow::init(env); HardwareInfoShadow::init(env); LogsUploadSchedulerShadow::init(env); + NativeRequestReceiverShadow::init(env); #ifdef GEMINI geminiNanoHandlerShadow = GeminiNanoHandlerShadow(env); #endif // GEMINI diff --git a/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/client/TextToSpeech.kt b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/client/TextToSpeech.kt new file mode 100644 index 00000000..7ac077e7 --- /dev/null +++ b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/client/TextToSpeech.kt @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 DeliteAI Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package dev.deliteai.client + +interface TextToSpeech { + fun getPhonemes(text: String): String? +} diff --git a/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/datamodels/NimbleNetConfig.kt b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/datamodels/NimbleNetConfig.kt index 17bceed9..f7b83d63 100644 --- a/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/datamodels/NimbleNetConfig.kt +++ b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/datamodels/NimbleNetConfig.kt @@ -6,6 +6,7 @@ package dev.deliteai.datamodels +import dev.deliteai.client.TextToSpeech import dev.deliteai.impl.common.NIMBLENET_VARIANTS import dev.deliteai.impl.common.SDK_CONSTANTS import org.json.JSONObject @@ -32,6 +33,7 @@ import org.json.JSONObject * - [showDownloadProgress]: Display download progress indicators for models in the notification bar * - [online]: Flag to control whether the SDK should connect to cloud to download assets or if the * assets already bundled with the app + * - [textToSpeechImpl]: Optional TextToSpeech implementation for phoneme generation * * ## Usage Examples * @@ -93,6 +95,8 @@ import org.json.JSONObject * Default: false * @param online Whether the assets will be downloaded from cloud or they are already bundled * with the app Default: false + * @param textToSpeechImpl Optional TextToSpeech implementation for phoneme generation. Default: + * null * @see NIMBLENET_VARIANTS * @see SDK_CONSTANTS * @since 1.0.0 @@ -112,6 +116,7 @@ class NimbleNetConfig( val libraryVariant: NIMBLENET_VARIANTS = NIMBLENET_VARIANTS.STATIC, val showDownloadProgress: Boolean = false, val online: Boolean = false, + val textToSpeechImpl: TextToSpeech? = null, ) { private var internalDeviceId: String? = null @@ -136,6 +141,7 @@ class NimbleNetConfig( libraryVariant: NIMBLENET_VARIANTS = this.libraryVariant, showDownloadProgress: Boolean = this.showDownloadProgress, online: Boolean = this.online, + textToSpeechImpl: TextToSpeech? = this.textToSpeechImpl, ): NimbleNetConfig { return NimbleNetConfig( clientId = clientId, @@ -152,6 +158,7 @@ class NimbleNetConfig( libraryVariant = libraryVariant, showDownloadProgress = showDownloadProgress, online = online, + textToSpeechImpl = textToSpeechImpl, ) .apply { this.internalDeviceId = this@NimbleNetConfig.internalDeviceId } } @@ -181,6 +188,8 @@ class NimbleNetConfig( "internalDeviceId" to this.internalDeviceId, "showDownloadProgress" to this.showDownloadProgress, "online" to this.online, + // textToSpeechImpl is not serialized as it's used in the Kotlin layer and doesn't + // get passed to the core SDK ) // conditional entries @@ -234,6 +243,8 @@ class NimbleNetConfig( } ?: arrayOf(), showDownloadProgress = jsonObject.optBoolean("showDownloadProgress", false), online = jsonObject.optBoolean("online", false), + // textToSpeechImpl is not deserialized as it's used in the Kotlin layer and + // doesn't get passed to the core SDK ) .apply { if (jsonObject.has("internalDeviceId")) { diff --git a/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/impl/DependencyContainer.kt b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/impl/DependencyContainer.kt index 8fe9c74f..10d9868d 100644 --- a/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/impl/DependencyContainer.kt +++ b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/impl/DependencyContainer.kt @@ -29,6 +29,7 @@ import dev.deliteai.impl.moduleInstallers.ModuleInstaller import dev.deliteai.impl.moduleInstallers.impl.GoogleDynamicModuleInstaller import dev.deliteai.impl.moduleInstallers.impl.StaticModuleInstaller import dev.deliteai.impl.nativeBridge.CoreRuntime +import dev.deliteai.impl.nativeBridge.NativeRequestReceiver import dev.deliteai.impl.nativeBridge.impl.CoreRuntimeImpl import okhttp3.OkHttpClient @@ -127,6 +128,10 @@ private constructor( Networking(okHttpClient, localLoggerSingleton, chunkDownloadManagerSingleton) } + private val nativeRequestReceiverSingleton: NativeRequestReceiver by lazy { + NativeRequestReceiver(nimbleNetConfig.textToSpeechImpl) + } + // nimblenet_ktx fun getNimbleNetController(): NimbleNetController = nimbleNetControllerSingleton @@ -147,6 +152,8 @@ private constructor( fun getLogsUploadScheduler(): LogsUploadScheduler = logsUploadSchedulerSingleton + fun getNativeRequestReceiver(): NativeRequestReceiver = nativeRequestReceiverSingleton + // integration test fun getFileUtils(): FileUtils = fileUtilitySingleton diff --git a/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/impl/nativeBridge/NativeRequestReceiver.kt b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/impl/nativeBridge/NativeRequestReceiver.kt new file mode 100644 index 00000000..9eef2c10 --- /dev/null +++ b/sdks/android/nimblenet_ktx/src/main/kotlin/dev/deliteai/impl/nativeBridge/NativeRequestReceiver.kt @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 DeliteAI Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package dev.deliteai.impl.nativeBridge + +import dev.deliteai.client.TextToSpeech + +internal class NativeRequestReceiver(private val textToSpeech: TextToSpeech?) { + fun dispatch(functionName: String, vararg args: Any?): Any? = + when (functionName) { + "getPhonemes" -> handleGetPhonemes(*args) + + else -> throw IllegalArgumentException("Unknown function: $functionName") + } + + private fun handleGetPhonemes(vararg args: Any?): String? { + if (textToSpeech == null) throw Exception("TextToSpeechImpl not found in NimbleNetConfig") + + val txt = + args.getOrNull(0) as? String + ?: throw IllegalArgumentException("get_phonemes requires a String") + + return textToSpeech.getPhonemes(txt) + } +} diff --git a/sdks/config.yml b/sdks/config.yml index 67ba914c..135ef08b 100644 --- a/sdks/config.yml +++ b/sdks/config.yml @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 common: - sdk_version: "0.0.1-dev-1751904491" + sdk_version: "0.0.1-dev-43b1948-20250808" cmake_args: "-DONNX_EXECUTOR=1 -DONNXGENAI_EXECUTOR=1 -DCMAKE_BUILD_TYPE=Debug -DSCRIPTING=1 -DNOSQL=1 -DTESTING=0 -DGENAI=1 -DORT_EXTENSIONS=1 -DREGEX_ENABLED=1 -DJNITESTING=0" android: