react-native-litert-lm 0.1.1 → 0.2.1
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.
- package/README.md +149 -31
- package/android/src/main/java/com/margelo/nitro/dev/litert/litertlm/HybridLiteRTLM.kt +307 -61
- package/cpp/HybridLiteRTLM.cpp +85 -31
- package/cpp/HybridLiteRTLM.hpp +4 -0
- package/cpp/include/stb_image.h +7988 -0
- package/lib/hooks.d.ts +16 -0
- package/lib/hooks.js +114 -0
- package/lib/index.d.ts +27 -2
- package/lib/index.js +50 -6
- package/lib/modelFactory.d.ts +5 -0
- package/lib/modelFactory.js +42 -0
- package/lib/specs/LiteRTLM.nitro.d.ts +19 -0
- package/lib/templates.d.ts +51 -0
- package/lib/templates.js +81 -0
- package/nitrogen/generated/android/LiteRTLMOnLoad.cpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_double.hpp +75 -0
- package/nitrogen/generated/android/c++/JHybridLiteRTLMSpec.cpp +33 -1
- package/nitrogen/generated/android/c++/JHybridLiteRTLMSpec.hpp +2 -0
- package/nitrogen/generated/android/c++/JLLMConfig.hpp +6 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/dev/litert/litertlm/Func_void_double.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/dev/litert/litertlm/HybridLiteRTLMSpec.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/dev/litert/litertlm/LLMConfig.kt +5 -2
- package/nitrogen/generated/shared/c++/HybridLiteRTLMSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridLiteRTLMSpec.hpp +2 -0
- package/nitrogen/generated/shared/c++/LLMConfig.hpp +7 -2
- package/package.json +1 -1
- package/src/hooks.ts +152 -0
- package/src/index.ts +41 -3
- package/src/modelFactory.ts +49 -0
- package/src/specs/LiteRTLM.nitro.ts +26 -0
- package/src/templates.ts +105 -0
package/cpp/HybridLiteRTLM.cpp
CHANGED
|
@@ -11,9 +11,13 @@
|
|
|
11
11
|
|
|
12
12
|
#include "HybridLiteRTLM.hpp"
|
|
13
13
|
|
|
14
|
+
#define STB_IMAGE_IMPLEMENTATION
|
|
15
|
+
#include "include/stb_image.h"
|
|
16
|
+
|
|
14
17
|
#include <chrono>
|
|
15
18
|
#include <stdexcept>
|
|
16
19
|
#include <sstream>
|
|
20
|
+
#include <fstream>
|
|
17
21
|
|
|
18
22
|
namespace margelo::nitro::litertlm {
|
|
19
23
|
|
|
@@ -229,32 +233,46 @@ std::string HybridLiteRTLM::sendMessageWithImage(
|
|
|
229
233
|
ensureLoaded();
|
|
230
234
|
|
|
231
235
|
#ifdef LITERT_LM_ENABLED
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
" - Note: Image processing not yet implemented, text-only response]";
|
|
243
|
-
|
|
236
|
+
// Load image using stb_image
|
|
237
|
+
int width, height, channels;
|
|
238
|
+
unsigned char* img = stbi_load(imagePath.c_str(), &width, &height, &channels, 3); // Force 3 channels (RGB)
|
|
239
|
+
if (img == nullptr) {
|
|
240
|
+
throw std::runtime_error("Failed to load image from path: " + imagePath);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Create input tensor/buffer for the engine.
|
|
244
|
+
// Note: The exact API for passing image data depends on the LiteRT-LM version.
|
|
245
|
+
// Assuming a structure that accepts raw bytes and dimensions.
|
|
244
246
|
litert::lm::UserMessage lm_message;
|
|
245
247
|
lm_message.role = "user";
|
|
246
|
-
lm_message.content = augmentedMessage;
|
|
247
248
|
|
|
249
|
+
// Construct multimodal content
|
|
250
|
+
// Option A: If UserMessage supports a list of content parts
|
|
251
|
+
litert::lm::ContentPart textPart;
|
|
252
|
+
textPart.type = litert::lm::ContentType::TEXT;
|
|
253
|
+
textPart.text = message;
|
|
254
|
+
lm_message.parts.push_back(textPart);
|
|
255
|
+
|
|
256
|
+
litert::lm::ContentPart imagePart;
|
|
257
|
+
imagePart.type = litert::lm::ContentType::IMAGE;
|
|
258
|
+
imagePart.image.width = width;
|
|
259
|
+
imagePart.image.height = height;
|
|
260
|
+
imagePart.image.channels = channels;
|
|
261
|
+
imagePart.image.data = std::vector<uint8_t>(img, img + (width * height * channels));
|
|
262
|
+
lm_message.parts.push_back(imagePart);
|
|
263
|
+
|
|
264
|
+
stbi_image_free(img);
|
|
265
|
+
|
|
248
266
|
auto response = conversation_->SendMessage(lm_message);
|
|
249
267
|
if (!response.ok()) {
|
|
250
268
|
throw std::runtime_error("Multimodal inference failed: " +
|
|
251
269
|
std::string(response.status().message()));
|
|
252
270
|
}
|
|
253
271
|
|
|
254
|
-
// Add to history
|
|
272
|
+
// Add to history (metadata only)
|
|
255
273
|
Message userMessage;
|
|
256
274
|
userMessage.role = Role::USER;
|
|
257
|
-
userMessage.content = message + " [
|
|
275
|
+
userMessage.content = message + " [Image]";
|
|
258
276
|
history_.push_back(userMessage);
|
|
259
277
|
|
|
260
278
|
Message modelMessage;
|
|
@@ -265,11 +283,34 @@ std::string HybridLiteRTLM::sendMessageWithImage(
|
|
|
265
283
|
return response->content;
|
|
266
284
|
|
|
267
285
|
#else
|
|
268
|
-
//
|
|
269
|
-
|
|
286
|
+
// iOS: LiteRT-LM SDK not yet available, throw clear error
|
|
287
|
+
throw std::runtime_error(
|
|
288
|
+
"sendMessageWithImage is not supported on iOS. "
|
|
289
|
+
"LiteRT-LM iOS SDK is not yet available. "
|
|
290
|
+
"Please use text-only sendMessage() for now.");
|
|
291
|
+
#endif
|
|
292
|
+
}
|
|
293
|
+
|
|
270
294
|
#endif
|
|
271
295
|
}
|
|
272
296
|
|
|
297
|
+
//------------------------------------------------------------------------------
|
|
298
|
+
// downloadModel - Download model file from URL
|
|
299
|
+
//------------------------------------------------------------------------------
|
|
300
|
+
std::future<std::string> HybridLiteRTLM::downloadModel(
|
|
301
|
+
const std::string& url,
|
|
302
|
+
const std::string& fileName,
|
|
303
|
+
const std::optional<std::function<void(double)>>& onProgress) {
|
|
304
|
+
|
|
305
|
+
// Return a future that throws an exception
|
|
306
|
+
return std::async(std::launch::async, []() -> std::string {
|
|
307
|
+
throw std::runtime_error(
|
|
308
|
+
"downloadModel is not supported on iOS yet. "
|
|
309
|
+
"Please download the model manually using a separate library."
|
|
310
|
+
);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
273
314
|
//------------------------------------------------------------------------------
|
|
274
315
|
// sendMessageWithAudio - Multimodal audio + text
|
|
275
316
|
//------------------------------------------------------------------------------
|
|
@@ -281,31 +322,41 @@ std::string HybridLiteRTLM::sendMessageWithAudio(
|
|
|
281
322
|
ensureLoaded();
|
|
282
323
|
|
|
283
324
|
#ifdef LITERT_LM_ENABLED
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
// 3. Create litert::lm::AudioData or equivalent
|
|
290
|
-
// 4. Pass to conversation with multimodal content
|
|
325
|
+
// Load audio file
|
|
326
|
+
std::ifstream audioFile(audioPath, std::ios::binary);
|
|
327
|
+
if (!audioFile) {
|
|
328
|
+
throw std::runtime_error("Failed to open audio file: " + audioPath);
|
|
329
|
+
}
|
|
291
330
|
|
|
292
|
-
|
|
293
|
-
|
|
331
|
+
// Simple WAV header skip (simplistic, assuming standard header size for now or raw)
|
|
332
|
+
// Ideally use a WAV parsing library or miniaudio if available.
|
|
333
|
+
// For this implementation, we read the whole file.
|
|
334
|
+
std::vector<uint8_t> audioData((std::istreambuf_iterator<char>(audioFile)), std::istreambuf_iterator<char>());
|
|
294
335
|
|
|
295
336
|
litert::lm::UserMessage lm_message;
|
|
296
337
|
lm_message.role = "user";
|
|
297
|
-
lm_message.content = augmentedMessage;
|
|
298
338
|
|
|
339
|
+
litert::lm::ContentPart textPart;
|
|
340
|
+
textPart.type = litert::lm::ContentType::TEXT;
|
|
341
|
+
textPart.text = message;
|
|
342
|
+
lm_message.parts.push_back(textPart);
|
|
343
|
+
|
|
344
|
+
litert::lm::ContentPart audioPart;
|
|
345
|
+
audioPart.type = litert::lm::ContentType::AUDIO;
|
|
346
|
+
audioPart.audio.data = audioData;
|
|
347
|
+
// Metadata like sample rate might be needed:
|
|
348
|
+
// audioPart.audio.sample_rate = 16000;
|
|
349
|
+
lm_message.parts.push_back(audioPart);
|
|
350
|
+
|
|
299
351
|
auto response = conversation_->SendMessage(lm_message);
|
|
300
352
|
if (!response.ok()) {
|
|
301
353
|
throw std::runtime_error("Audio inference failed: " +
|
|
302
354
|
std::string(response.status().message()));
|
|
303
355
|
}
|
|
304
356
|
|
|
305
|
-
// Add to history
|
|
306
357
|
Message userMessage;
|
|
307
358
|
userMessage.role = Role::USER;
|
|
308
|
-
userMessage.content = message + " [
|
|
359
|
+
userMessage.content = message + " [Audio]";
|
|
309
360
|
history_.push_back(userMessage);
|
|
310
361
|
|
|
311
362
|
Message modelMessage;
|
|
@@ -316,8 +367,11 @@ std::string HybridLiteRTLM::sendMessageWithAudio(
|
|
|
316
367
|
return response->content;
|
|
317
368
|
|
|
318
369
|
#else
|
|
319
|
-
//
|
|
320
|
-
|
|
370
|
+
// iOS: LiteRT-LM SDK not yet available, throw clear error
|
|
371
|
+
throw std::runtime_error(
|
|
372
|
+
"sendMessageWithAudio is not supported on iOS. "
|
|
373
|
+
"LiteRT-LM iOS SDK is not yet available. "
|
|
374
|
+
"Please use text-only sendMessage() for now.");
|
|
321
375
|
#endif
|
|
322
376
|
}
|
|
323
377
|
|
package/cpp/HybridLiteRTLM.hpp
CHANGED
|
@@ -58,6 +58,10 @@ public:
|
|
|
58
58
|
|
|
59
59
|
std::string sendMessageWithImage(const std::string& message,
|
|
60
60
|
const std::string& imagePath) override;
|
|
61
|
+
|
|
62
|
+
std::future<std::string> downloadModel(const std::string& url,
|
|
63
|
+
const std::string& fileName,
|
|
64
|
+
const std::optional<std::function<void(double)>>& onProgress) override;
|
|
61
65
|
|
|
62
66
|
std::string sendMessageWithAudio(const std::string& message,
|
|
63
67
|
const std::string& audioPath) override;
|