@dr33m/react-native-litert-lm 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -58,6 +58,10 @@ class HybridLiteRTLM : HybridLiteRTLMSpec() {
|
|
|
58
58
|
/** Cached result of OpenCL availability probe (null = not yet checked). */
|
|
59
59
|
@Volatile
|
|
60
60
|
private var openCLAvailable: Boolean? = null
|
|
61
|
+
|
|
62
|
+
/** Cached result of NPU/QNN availability probe (null = not yet checked). */
|
|
63
|
+
@Volatile
|
|
64
|
+
private var npuAvailable: Boolean? = null
|
|
61
65
|
|
|
62
66
|
/**
|
|
63
67
|
* Initialize the native library.
|
|
@@ -197,6 +201,41 @@ class HybridLiteRTLM : HybridLiteRTLMSpec() {
|
|
|
197
201
|
}
|
|
198
202
|
}
|
|
199
203
|
|
|
204
|
+
// NPU hardware check: probe for QNN HTP runtime libraries.
|
|
205
|
+
// LiteRT-LM's NPU delegate requires Qualcomm QNN HTP (Hexagon Tensor
|
|
206
|
+
// Processor) runtime. Without it, Engine() crashes with SIGSEGV
|
|
207
|
+
// that Kotlin's try/catch cannot intercept.
|
|
208
|
+
// Unlike GPU (which throws a catchable Java exception on failure),
|
|
209
|
+
// NPU failure is a native crash — so we MUST detect before attempting.
|
|
210
|
+
if (npuAvailable == null) {
|
|
211
|
+
val hasNpu = run {
|
|
212
|
+
// Check for QNN HTP libraries in system vendor paths.
|
|
213
|
+
// These are only present on devices with Qualcomm NPU support.
|
|
214
|
+
val qnnPaths = arrayOf(
|
|
215
|
+
"/vendor/lib64/libQnnHtp.so",
|
|
216
|
+
"/vendor/lib/libQnnHtp.so",
|
|
217
|
+
"/system/vendor/lib64/libQnnHtp.so",
|
|
218
|
+
"/system/lib64/libQnnHtp.so",
|
|
219
|
+
"/vendor/lib64/libQnnSystem.so",
|
|
220
|
+
"/vendor/lib/libQnnSystem.so"
|
|
221
|
+
)
|
|
222
|
+
var found = false
|
|
223
|
+
for (path in qnnPaths) {
|
|
224
|
+
if (java.io.File(path).exists()) {
|
|
225
|
+
found = true
|
|
226
|
+
break
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
found
|
|
230
|
+
}
|
|
231
|
+
npuAvailable = hasNpu
|
|
232
|
+
if (!hasNpu) {
|
|
233
|
+
Log.w(TAG, "QNN HTP libraries not found — NPU backend unavailable")
|
|
234
|
+
} else {
|
|
235
|
+
Log.i(TAG, "QNN HTP libraries found — NPU backend may be available")
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
200
239
|
// Detect multimodal support. Check config.multimodal flag first, then fall back to filename sniffing.
|
|
201
240
|
// Only Gemma 3n bundles vision/audio executors; Gemma 4 E2B is text-only.
|
|
202
241
|
// Passing vision/audio backends to a text-only model causes
|
|
@@ -259,12 +298,13 @@ class HybridLiteRTLM : HybridLiteRTLMSpec() {
|
|
|
259
298
|
}
|
|
260
299
|
}
|
|
261
300
|
Backend.NPU -> {
|
|
301
|
+
val hasNpu = npuAvailable ?: false
|
|
262
302
|
val nativeLibDir = LiteRTLMInitProvider.applicationContext?.applicationInfo?.nativeLibraryDir
|
|
263
|
-
Log.i(TAG, "NPU backend requested - nativeLibraryDir=$nativeLibDir")
|
|
264
|
-
if (nativeLibDir != null) {
|
|
303
|
+
Log.i(TAG, "NPU backend requested - available=$hasNpu, nativeLibraryDir=$nativeLibDir")
|
|
304
|
+
if (hasNpu && nativeLibDir != null) {
|
|
265
305
|
com.google.ai.edge.litertlm.Backend.NPU(nativeLibraryDir = nativeLibDir)
|
|
266
306
|
} else {
|
|
267
|
-
Log.w(TAG, "NPU requested but
|
|
307
|
+
Log.w(TAG, "NPU requested but hardware unavailable — using CPU directly")
|
|
268
308
|
backend = Backend.CPU
|
|
269
309
|
com.google.ai.edge.litertlm.Backend.CPU()
|
|
270
310
|
}
|
|
@@ -662,10 +702,10 @@ class HybridLiteRTLM : HybridLiteRTLMSpec() {
|
|
|
662
702
|
tool(apiTool)
|
|
663
703
|
}
|
|
664
704
|
|
|
665
|
-
// Create conversation
|
|
666
|
-
//
|
|
705
|
+
// Create conversation config. NPU backend does not support SamplerConfig
|
|
706
|
+
// (matching Gallery app pattern — setting sampler params on NPU causes crashes).
|
|
667
707
|
val convConfig = ConversationConfig(
|
|
668
|
-
samplerConfig = SamplerConfig(
|
|
708
|
+
samplerConfig = if (backend == Backend.NPU) null else SamplerConfig(
|
|
669
709
|
topK = topK,
|
|
670
710
|
topP = topP.toDouble(),
|
|
671
711
|
temperature = temperature.toDouble(),
|