react-native-yolo 0.0.1 → 0.0.3

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 CHANGED
@@ -1,18 +1,29 @@
1
1
  # react-native-yolo
2
2
 
3
- react-native-yolo is a react native package built with Nitro
3
+ 🚧 **Work in Progress**
4
+
5
+ `react-native-yolo` is currently under active development and is **not yet ready for production use**. APIs, features, and installation steps may change between releases.
6
+
7
+ The goal of this project is to provide YOLO-based object detection capabilities for React Native applications using Nitro Modules.
4
8
 
5
9
  [![Version](https://img.shields.io/npm/v/react-native-yolo.svg)](https://www.npmjs.com/package/react-native-yolo)
6
10
  [![Downloads](https://img.shields.io/npm/dm/react-native-yolo.svg)](https://www.npmjs.com/package/react-native-yolo)
7
11
  [![License](https://img.shields.io/npm/l/react-native-yolo.svg)](https://github.com/patrickkabwe/react-native-yolo/LICENSE)
8
12
 
13
+ ## Current Status
14
+
15
+ * 🚧 Under active development
16
+ * ⚠️ Breaking changes may occur between releases
17
+ * ⚠️ Documentation is incomplete
18
+ * ⚠️ Features are still being implemented and tested
19
+
9
20
  ## Requirements
10
21
 
11
- - React Native v0.76.0 or higher
12
- - Node 18.0.0 or higher
22
+ * React Native v0.76.0 or higher
23
+ * Node 18.0.0 or higher
13
24
 
14
- > [!IMPORTANT]
15
- > To Support `Nitro Views` you need to install React Native version v0.78.0 or higher.
25
+ > [!IMPORTANT]
26
+ > To support `Nitro Views`, you need React Native v0.78.0 or higher.
16
27
 
17
28
  ## Installation
18
29
 
@@ -20,10 +31,21 @@ react-native-yolo is a react native package built with Nitro
20
31
  npm install react-native-yolo react-native-nitro-modules
21
32
  ```
22
33
 
34
+ ## Roadmap
35
+
36
+ Planned features include:
37
+
38
+ * YOLO model loading
39
+ * Real-time object detection
40
+ * Camera integration
41
+ * Android support
42
+ * iOS support
43
+ * Performance optimizations
44
+
23
45
  ## Credits
24
46
 
25
47
  Bootstrapped with [create-nitro-module](https://github.com/patrickkabwe/create-nitro-module).
26
48
 
27
49
  ## Contributing
28
50
 
29
- Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
51
+ Contributions, bug reports, and feature requests are welcome. Since the project is still under development, feedback is especially appreciated.
@@ -137,6 +137,11 @@ dependencies {
137
137
 
138
138
  // Add a dependency on NitroModules
139
139
  implementation project(":react-native-nitro-modules")
140
+
141
+ // Add TensorFlow Lite dependencies
142
+ implementation "com.google.ai.edge.litert:litert:1.4.2"
143
+ implementation "com.google.ai.edge.litert:litert-support-api:1.4.2"
144
+ implementation "com.google.ai.edge.litert:litert-gpu:1.4.2"
140
145
  }
141
146
 
142
147
  if (isNewArchitectureEnabled()) {
@@ -1,12 +1,42 @@
1
1
  package com.yolo
2
2
 
3
+ import android.net.Uri
4
+ import android.util.Log
5
+ import com.margelo.nitro.NitroModules
3
6
  import com.margelo.nitro.yolo.HybridYoloSpec
7
+ import java.io.File
8
+ import java.io.RandomAccessFile
9
+ import java.net.URL
10
+ import java.nio.MappedByteBuffer
11
+ import java.nio.channels.FileChannel
12
+ import org.tensorflow.lite.Interpreter
13
+ import org.tensorflow.lite.support.common.FileUtil
14
+ import yolo.com.loader.YoloModelLoader
15
+
16
+ class HybridYolo : HybridYoloSpec() {
17
+ private var interpreter: Interpreter? = null
18
+ private val modelLoader = YoloModelLoader()
4
19
 
5
- class HybridYolo: HybridYoloSpec() {
6
20
  override fun sum(num1: Double, num2: Double): Double {
7
21
  return num1 + num2
8
22
  }
9
- override fun subtract(num1: Double, num2: Double): Double {
10
- return num1 - num2
23
+
24
+ override fun loadModel(modelPath: String) {
25
+ val context =
26
+ NitroModules.applicationContext ?: throw IllegalStateException("Context is null")
27
+
28
+ Log.d("YOLO_TAG", "Trying to load: $modelPath")
29
+
30
+ try {
31
+ val modelBuffer = modelLoader.load(modelPath)
32
+
33
+ interpreter?.close()
34
+ interpreter = Interpreter(modelBuffer)
35
+
36
+ Log.d("YOLO_TAG", "✅ Model loaded successfully!")
37
+ } catch (e: Exception) {
38
+ Log.e("YOLO_TAG", "❌ Failed to load model: ${e.message}", e)
39
+ }
11
40
  }
41
+
12
42
  }
@@ -0,0 +1,130 @@
1
+ package yolo.com.loader
2
+
3
+ import android.net.Uri
4
+ import android.util.Log
5
+ import com.yolo.utils.ContextProvider
6
+ import java.io.File
7
+ import java.io.RandomAccessFile
8
+ import java.net.URL
9
+ import java.nio.MappedByteBuffer
10
+ import java.nio.channels.FileChannel
11
+ import org.tensorflow.lite.support.common.FileUtil
12
+
13
+
14
+
15
+ /**
16
+ * A utility class for loading YOLO models from various sources, including URLs, file URIs, absolute paths, and APK assets.
17
+ * This class provides methods to load a model into a MappedByteBuffer, which can be used with TensorFlow Lite's Interpreter for inference.
18
+ * It also includes methods to copy raw resources to the cache directory and map files for efficient reading
19
+ */
20
+ class YoloModelLoader {
21
+ companion object {
22
+ private const val TAG = "YOLO_TAG_LOADER"
23
+ }
24
+
25
+ /**
26
+ * Loads a YOLO model from the specified path. The path can be a URL, a file URI, an absolute
27
+ * path, or an asset name.
28
+ * @param modelPath The path to the YOLO model.
29
+ * @return A MappedByteBuffer containing the model data.
30
+ * @throws IllegalArgumentException if the model cannot be loaded from the specified path.
31
+ */
32
+ fun load(modelPath: String): MappedByteBuffer {
33
+ val context = ContextProvider.context
34
+
35
+ return when {
36
+ modelPath.startsWith("http://") || modelPath.startsWith("https://") -> {
37
+ Log.d(TAG, "Loading model from URL")
38
+ val cachedFile = downloadToCache(modelPath)
39
+ mapFile(cachedFile)
40
+ }
41
+ modelPath.startsWith("file://") -> {
42
+ Log.d(TAG, "Loading model from file URI")
43
+ val file = File(Uri.parse(modelPath).path!!)
44
+ mapFile(file)
45
+ }
46
+ modelPath.startsWith("/") -> {
47
+ Log.d(TAG, "Loading model from absolute path")
48
+ mapFile(File(modelPath))
49
+ }
50
+ modelPath.startsWith("assets_") -> {
51
+ Log.d(TAG, "Loading model from RN raw resource")
52
+ val file = copyRawResourceToCache(modelPath)
53
+ mapFile(file)
54
+ }
55
+ else -> {
56
+ Log.d(TAG, "Loading model from APK assets")
57
+ FileUtil.loadMappedFile(context, modelPath)
58
+ }
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Copies a raw resource to the cache directory and returns the corresponding File object.
64
+ * @param resourceName The name of the raw resource (without the file extension).
65
+ * @return The File object pointing to the copied resource in the cache directory.
66
+ * @throws IllegalArgumentException if the raw resource is not found.
67
+ */
68
+ private fun copyRawResourceToCache(resourceName: String): File {
69
+ val context = ContextProvider.context
70
+
71
+ val resId = context.resources.getIdentifier(resourceName, "raw", context.packageName)
72
+
73
+ if (resId == 0) {
74
+ throw IllegalArgumentException("Raw resource not found: $resourceName")
75
+ }
76
+
77
+ val file = File(context.cacheDir, "$resourceName.tflite")
78
+
79
+ context.resources.openRawResource(resId).use { input ->
80
+ file.outputStream().use { output -> input.copyTo(output) }
81
+ }
82
+
83
+ Log.d(TAG, "Copied raw resource to: ${file.absolutePath}")
84
+ Log.d(TAG, "Copied raw resource size: ${file.length()} bytes")
85
+
86
+ return file
87
+ }
88
+
89
+ /**
90
+ * Maps a file to a MappedByteBuffer for efficient reading.
91
+ * @param file The file to be mapped.
92
+ * @return A MappedByteBuffer containing the file data.
93
+ * @throws IllegalArgumentException if the file does not exist or is empty.
94
+ */
95
+ private fun mapFile(file: File): MappedByteBuffer {
96
+ if (!file.exists()) {
97
+ throw IllegalArgumentException("Model file does not exist: ${file.absolutePath}")
98
+ }
99
+
100
+ if (file.length() <= 0) {
101
+ throw IllegalArgumentException("Model file is empty: ${file.absolutePath}")
102
+ }
103
+
104
+ val randomAccessFile = RandomAccessFile(file, "r")
105
+ val fileChannel = randomAccessFile.channel
106
+
107
+ return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size())
108
+ }
109
+
110
+ /**
111
+ * Downloads a file from a URL to the cache directory and returns the corresponding File object.
112
+ * @param urlString The URL of the file to download.
113
+ * @return The File object pointing to the downloaded file in the cache directory.
114
+ * @throws IllegalArgumentException if the file cannot be downloaded.
115
+ */
116
+ private fun downloadToCache(urlString: String): File {
117
+ val context = ContextProvider.context
118
+
119
+ val file = File(context.cacheDir, "yolo_model.tflite")
120
+
121
+ URL(urlString).openStream().use { input ->
122
+ file.outputStream().use { output -> input.copyTo(output) }
123
+ }
124
+
125
+ Log.d(TAG, "Downloaded model to: ${file.absolutePath}")
126
+ Log.d(TAG, "Downloaded model size: ${file.length()} bytes")
127
+
128
+ return file
129
+ }
130
+ }
@@ -0,0 +1,14 @@
1
+ package com.yolo.utils
2
+
3
+ import android.content.Context
4
+ import com.margelo.nitro.NitroModules
5
+
6
+ /**
7
+ * Provides a way to access the application context from anywhere in the app.
8
+ * This is useful for classes that do not have a direct reference to a Context object.
9
+ */
10
+ object ContextProvider {
11
+ val context: Context
12
+ get() = NitroModules.applicationContext
13
+ ?: throw IllegalStateException("Context is null")
14
+ }
package/ios/Bridge.h CHANGED
@@ -2,7 +2,7 @@
2
2
  // Bridge.h
3
3
  // yolo
4
4
  //
5
- // Created by Khaoula-Ghalimi on 17/06/2026
5
+ // Created by Khaoula-Ghalimi on 22/06/2026
6
6
  //
7
7
 
8
8
  #pragma once
@@ -2,7 +2,7 @@
2
2
  // HybridYolo.swift
3
3
  // Pods
4
4
  //
5
- // Created by Khaoula-Ghalimi on 17/06/2026.
5
+ // Created by Khaoula-Ghalimi on 22/06/2026.
6
6
  //
7
7
 
8
8
  import Foundation
@@ -4,6 +4,6 @@ export interface Yolo extends HybridObject<{
4
4
  android: 'kotlin';
5
5
  }> {
6
6
  sum(num1: number, num2: number): number;
7
- subtract(num1: number, num2: number): number;
7
+ loadModel(modelPath: string): void;
8
8
  }
9
9
  //# sourceMappingURL=yolo.nitro.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"yolo.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/yolo.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,IAAK,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IAC7E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAC7C"}
1
+ {"version":3,"file":"yolo.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/yolo.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,IAAK,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IAC7E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACvC,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACnC"}
@@ -9,7 +9,7 @@
9
9
 
10
10
 
11
11
 
12
-
12
+ #include <string>
13
13
 
14
14
  namespace margelo::nitro::yolo {
15
15
 
@@ -49,10 +49,9 @@ namespace margelo::nitro::yolo {
49
49
  auto __result = method(_javaPart, num1, num2);
50
50
  return __result;
51
51
  }
52
- double JHybridYoloSpec::subtract(double num1, double num2) {
53
- static const auto method = _javaPart->javaClassStatic()->getMethod<double(double /* num1 */, double /* num2 */)>("subtract");
54
- auto __result = method(_javaPart, num1, num2);
55
- return __result;
52
+ void JHybridYoloSpec::loadModel(const std::string& modelPath) {
53
+ static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* modelPath */)>("loadModel");
54
+ method(_javaPart, jni::make_jstring(modelPath));
56
55
  }
57
56
 
58
57
  } // namespace margelo::nitro::yolo
@@ -55,7 +55,7 @@ namespace margelo::nitro::yolo {
55
55
  public:
56
56
  // Methods
57
57
  double sum(double num1, double num2) override;
58
- double subtract(double num1, double num2) override;
58
+ void loadModel(const std::string& modelPath) override;
59
59
 
60
60
  private:
61
61
  jni::global_ref<JHybridYoloSpec::JavaPart> _javaPart;
@@ -34,7 +34,7 @@ abstract class HybridYoloSpec: HybridObject() {
34
34
 
35
35
  @DoNotStrip
36
36
  @Keep
37
- abstract fun subtract(num1: Double, num2: Double): Double
37
+ abstract fun loadModel(modelPath: String): Unit
38
38
 
39
39
  // Default implementation of `HybridObject.toString()`
40
40
  override fun toString(): String {
@@ -47,5 +47,14 @@ namespace margelo::nitro::yolo::bridge::swift {
47
47
  inline Result_double_ create_Result_double_(const std::exception_ptr& error) noexcept {
48
48
  return Result<double>::withError(error);
49
49
  }
50
+
51
+ // pragma MARK: Result<void>
52
+ using Result_void_ = Result<void>;
53
+ inline Result_void_ create_Result_void_() noexcept {
54
+ return Result<void>::withValue();
55
+ }
56
+ inline Result_void_ create_Result_void_(const std::exception_ptr& error) noexcept {
57
+ return Result<void>::withError(error);
58
+ }
50
59
 
51
60
  } // namespace margelo::nitro::yolo::bridge::swift
@@ -16,6 +16,7 @@ namespace margelo::nitro::yolo { class HybridYoloSpec; }
16
16
  #include <NitroModules/Result.hpp>
17
17
  #include <exception>
18
18
  #include <memory>
19
+ #include <string>
19
20
 
20
21
  // C++ helpers for Swift
21
22
  #include "Yolo-Swift-Cxx-Bridge.hpp"
@@ -14,7 +14,7 @@ namespace Yolo { class HybridYoloSpec_cxx; }
14
14
 
15
15
 
16
16
 
17
-
17
+ #include <string>
18
18
 
19
19
  #include "Yolo-Swift-Cxx-Umbrella.hpp"
20
20
 
@@ -74,13 +74,11 @@ namespace margelo::nitro::yolo {
74
74
  auto __value = std::move(__result.value());
75
75
  return __value;
76
76
  }
77
- inline double subtract(double num1, double num2) override {
78
- auto __result = _swiftPart.subtract(std::forward<decltype(num1)>(num1), std::forward<decltype(num2)>(num2));
77
+ inline void loadModel(const std::string& modelPath) override {
78
+ auto __result = _swiftPart.loadModel(modelPath);
79
79
  if (__result.hasError()) [[unlikely]] {
80
80
  std::rethrow_exception(__result.error());
81
81
  }
82
- auto __value = std::move(__result.value());
83
- return __value;
84
82
  }
85
83
 
86
84
  private:
@@ -14,7 +14,7 @@ public protocol HybridYoloSpec_protocol: HybridObject {
14
14
 
15
15
  // Methods
16
16
  func sum(num1: Double, num2: Double) throws -> Double
17
- func subtract(num1: Double, num2: Double) throws -> Double
17
+ func loadModel(modelPath: String) throws -> Void
18
18
  }
19
19
 
20
20
  public extension HybridYoloSpec_protocol {
@@ -137,14 +137,13 @@ open class HybridYoloSpec_cxx {
137
137
  }
138
138
 
139
139
  @inline(__always)
140
- public final func subtract(num1: Double, num2: Double) -> bridge.Result_double_ {
140
+ public final func loadModel(modelPath: std.string) -> bridge.Result_void_ {
141
141
  do {
142
- let __result = try self.__implementation.subtract(num1: num1, num2: num2)
143
- let __resultCpp = __result
144
- return bridge.create_Result_double_(__resultCpp)
142
+ try self.__implementation.loadModel(modelPath: String(modelPath))
143
+ return bridge.create_Result_void_()
145
144
  } catch (let __error) {
146
145
  let __exceptionPtr = __error.toCpp()
147
- return bridge.create_Result_double_(__exceptionPtr)
146
+ return bridge.create_Result_void_(__exceptionPtr)
148
147
  }
149
148
  }
150
149
  }
@@ -15,7 +15,7 @@ namespace margelo::nitro::yolo {
15
15
  // load custom methods/properties
16
16
  registerHybrids(this, [](Prototype& prototype) {
17
17
  prototype.registerHybridMethod("sum", &HybridYoloSpec::sum);
18
- prototype.registerHybridMethod("subtract", &HybridYoloSpec::subtract);
18
+ prototype.registerHybridMethod("loadModel", &HybridYoloSpec::loadModel);
19
19
  });
20
20
  }
21
21
 
@@ -15,7 +15,7 @@
15
15
 
16
16
 
17
17
 
18
-
18
+ #include <string>
19
19
 
20
20
  namespace margelo::nitro::yolo {
21
21
 
@@ -49,7 +49,7 @@ namespace margelo::nitro::yolo {
49
49
  public:
50
50
  // Methods
51
51
  virtual double sum(double num1, double num2) = 0;
52
- virtual double subtract(double num1, double num2) = 0;
52
+ virtual void loadModel(const std::string& modelPath) = 0;
53
53
 
54
54
  protected:
55
55
  // Hybrid Setup
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-yolo",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "react-native-yolo is a react native package built with Nitro",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/module/index.js",
@@ -119,4 +119,4 @@
119
119
  ]
120
120
  ]
121
121
  }
122
- }
122
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import { NitroModules } from 'react-native-nitro-modules'
2
2
  import type { Yolo as YoloSpec } from './specs/yolo.nitro'
3
+ import { Image } from 'react-native'
3
4
 
4
- export const Yolo =
5
- NitroModules.createHybridObject<YoloSpec>('Yolo')
5
+ const NativeYolo = NitroModules.createHybridObject<YoloSpec>('Yolo')
6
+
7
+ export const Yolo = Object.assign(NativeYolo, {
8
+ loadModelTest(modelAssetId: number){
9
+ const { uri } = Image.resolveAssetSource(modelAssetId);
10
+ return NativeYolo.loadModel(uri)
11
+ },
12
+ })
@@ -1,6 +1,7 @@
1
1
  import type { HybridObject } from 'react-native-nitro-modules'
2
2
 
3
+
3
4
  export interface Yolo extends HybridObject<{ ios: 'swift', android: 'kotlin' }> {
4
5
  sum(num1: number, num2: number): number
5
- subtract(num1: number, num2: number): number
6
+ loadModel(modelPath: string): void
6
7
  }