core: swap out hardcoded LlamaAndroid library loading
This commit is contained in:
parent
1b79db877d
commit
53ac8af67a
|
|
@ -1,6 +1,8 @@
|
||||||
package com.example.llama.legacy
|
package com.example.llama.legacy
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.llama.cpp.LLamaAndroid
|
import android.llama.cpp.LLamaAndroid
|
||||||
|
import android.llama.cpp.LLamaLibraryLoader
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -10,15 +12,16 @@ import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LegacyViewModel(
|
class LegacyViewModel(context: Context): ViewModel() {
|
||||||
private val llamaAndroid: LLamaAndroid = LLamaAndroid.instance()
|
|
||||||
): ViewModel() {
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val tag = LegacyViewModel::class.java.simpleName
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private val NanosPerSecond = 1_000_000_000.0
|
private val NanosPerSecond = 1_000_000_000.0
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tag: String? = this::class.simpleName
|
val llamaAndroid: LLamaAndroid = LLamaLibraryLoader.createInstance(context)
|
||||||
|
?: throw InstantiationException("Cannot instantiate LlamaAndroid!")
|
||||||
|
|
||||||
var messages by mutableStateOf(listOf("Initializing..."))
|
var messages by mutableStateOf(listOf("Initializing..."))
|
||||||
private set
|
private set
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.example.llama.revamp.di
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.llama.cpp.InferenceEngine
|
import android.llama.cpp.InferenceEngine
|
||||||
import android.llama.cpp.LLamaAndroid
|
import android.llama.cpp.LLamaLibraryLoader
|
||||||
import com.example.llama.revamp.data.local.AppDatabase
|
import com.example.llama.revamp.data.local.AppDatabase
|
||||||
import com.example.llama.revamp.data.remote.HuggingFaceApiService
|
import com.example.llama.revamp.data.remote.HuggingFaceApiService
|
||||||
import com.example.llama.revamp.data.remote.HuggingFaceRemoteDataSource
|
import com.example.llama.revamp.data.remote.HuggingFaceRemoteDataSource
|
||||||
|
|
@ -58,10 +58,15 @@ internal abstract class AppModule {
|
||||||
): HuggingFaceRemoteDataSource
|
): HuggingFaceRemoteDataSource
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val USE_REAL_ENGINE = true
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideInferenceEngine(): InferenceEngine {
|
fun provideInferenceEngine(@ApplicationContext context: Context): InferenceEngine {
|
||||||
val useRealEngine = true
|
return if (USE_REAL_ENGINE) {
|
||||||
return if (useRealEngine) LLamaAndroid.instance() else StubInferenceEngine()
|
LLamaLibraryLoader.createInstance(context) ?: throw InstantiationException("Cannot instantiate LlamaAndroid!")
|
||||||
|
} else {
|
||||||
|
StubInferenceEngine()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,11 @@ import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jetbrains.annotations.TestOnly
|
|
||||||
import org.jetbrains.annotations.VisibleForTesting
|
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stub [InferenceEngine] for agile development & testing
|
* A stub [InferenceEngine] for agile development & testing
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
|
||||||
@TestOnly
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class StubInferenceEngine : InferenceEngine {
|
class StubInferenceEngine : InferenceEngine {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package android.llama.cpp
|
package android.llama.cpp
|
||||||
|
|
||||||
import android.llama.cpp.InferenceEngine.State
|
import android.llama.cpp.InferenceEngine.State
|
||||||
import android.llama.cpp.LLamaAndroid.Companion.instance
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -37,7 +36,35 @@ import java.io.File
|
||||||
*
|
*
|
||||||
* @see llama-android.cpp for the native implementation details
|
* @see llama-android.cpp for the native implementation details
|
||||||
*/
|
*/
|
||||||
class LLamaAndroid private constructor() : InferenceEngine {
|
class LLamaAndroid private constructor(private val tier: LLamaTier) : InferenceEngine {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = LLamaAndroid::class.java.simpleName
|
||||||
|
|
||||||
|
private var initialized = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create LLamaAndroid instance with specific tier
|
||||||
|
*/
|
||||||
|
internal fun createWithTier(tier: LLamaTier): LLamaAndroid? {
|
||||||
|
if (initialized) {
|
||||||
|
Log.w(TAG, "LLamaAndroid already initialized")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Log.i(TAG, "Instantiating LLamaAndroid w/ ${tier.libraryName}")
|
||||||
|
val instance = LLamaAndroid(tier)
|
||||||
|
initialized = true
|
||||||
|
return instance
|
||||||
|
|
||||||
|
} catch (e: UnsatisfiedLinkError) {
|
||||||
|
Log.e(TAG, "Failed to load ${tier.libraryName}", e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JNI methods
|
* JNI methods
|
||||||
* @see llama-android.cpp
|
* @see llama-android.cpp
|
||||||
|
|
@ -74,13 +101,14 @@ class LLamaAndroid private constructor() : InferenceEngine {
|
||||||
check(_state.value is State.Uninitialized) {
|
check(_state.value is State.Uninitialized) {
|
||||||
"Cannot load native library in ${_state.value.javaClass.simpleName}!"
|
"Cannot load native library in ${_state.value.javaClass.simpleName}!"
|
||||||
}
|
}
|
||||||
|
|
||||||
_state.value = State.Initializing
|
_state.value = State.Initializing
|
||||||
Log.i(TAG, "Loading native library $LIB_LLAMA_ANDROID")
|
Log.i(TAG, "Loading native library for $tier")
|
||||||
System.loadLibrary(LIB_LLAMA_ANDROID)
|
|
||||||
|
System.loadLibrary(tier.libraryName)
|
||||||
init()
|
init()
|
||||||
_state.value = State.Initialized
|
_state.value = State.Initialized
|
||||||
Log.i(TAG, "Native library loaded! System info: \n${systemInfo()}")
|
Log.i(TAG, "Native library loaded! System info: \n${systemInfo()}")
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Failed to load native library", e)
|
Log.e(TAG, "Failed to load native library", e)
|
||||||
throw e
|
throw e
|
||||||
|
|
@ -235,15 +263,4 @@ class LLamaAndroid private constructor() : InferenceEngine {
|
||||||
else -> { unload(); shutdown() }
|
else -> { unload(); shutdown() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val TAG = LLamaAndroid::class.simpleName
|
|
||||||
|
|
||||||
// TODO-han.yin: replace with dynamic loader
|
|
||||||
private const val LIB_LLAMA_ANDROID = "llama_android_t3"
|
|
||||||
|
|
||||||
// Enforce only one instance of Llm.
|
|
||||||
private val _instance: LLamaAndroid = LLamaAndroid()
|
|
||||||
fun instance(): LLamaAndroid = _instance
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue