react-native-ai-core 0.1.0 → 0.2.0
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/LICENSE +1 -1
- package/README.md +70 -0
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/java/com/aicore/AiCoreModule.kt +511 -69
- package/android/src/main/java/com/aicore/InferenceService.kt +85 -0
- package/lib/module/NativeAiCore.js +2 -2
- package/lib/module/NativeAiCore.js.map +1 -1
- package/lib/module/index.js +46 -51
- package/lib/module/index.js.map +1 -1
- package/lib/module/structured.js +729 -0
- package/lib/module/structured.js.map +1 -0
- package/lib/typescript/src/NativeAiCore.d.ts +20 -15
- package/lib/typescript/src/NativeAiCore.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +45 -41
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/structured.d.ts +34 -0
- package/lib/typescript/src/structured.d.ts.map +1 -0
- package/package.json +8 -5
- package/src/NativeAiCore.ts +22 -16
- package/src/index.tsx +60 -55
- package/src/structured.ts +1118 -0
package/src/index.tsx
CHANGED
|
@@ -1,76 +1,82 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* react-native-ai-core
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* JS abstraction layer over the native TurboModule.
|
|
5
|
+
* Provides a clean, typed API for running Gemini Nano on-device
|
|
6
|
+
* via the Google AI Edge SDK (MediaPipe).
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* import AICore from 'react-native-ai-core';
|
|
10
10
|
*
|
|
11
11
|
* await AICore.initialize('/data/local/tmp/gemini-nano.bin');
|
|
12
|
-
* const answer = await AICore.generateResponse('
|
|
12
|
+
* const answer = await AICore.generateResponse('What is JSI?');
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { NativeEventEmitter, Platform } from 'react-native';
|
|
16
16
|
import NativeAiCore from './NativeAiCore';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
import { generateStructuredResponse } from './structured';
|
|
18
|
+
export {
|
|
19
|
+
generateStructuredResponse,
|
|
20
|
+
StructuredOutputError,
|
|
21
|
+
type StructuredGenerateOptions,
|
|
22
|
+
type StructuredSchema,
|
|
23
|
+
type StructuredValidationIssue,
|
|
24
|
+
} from './structured';
|
|
25
|
+
|
|
26
|
+
// ── Public types ────────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
/** Availability status of Gemini Nano on the device */
|
|
21
29
|
export type AvailabilityStatus = 'AVAILABLE' | 'AVAILABLE_NPU' | 'NEED_DOWNLOAD' | 'UNSUPPORTED';
|
|
22
30
|
|
|
23
|
-
/**
|
|
31
|
+
/** Streaming response callbacks */
|
|
24
32
|
export interface StreamCallbacks {
|
|
25
33
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @param token
|
|
28
|
-
* @param done `true`
|
|
34
|
+
* Called for each received token.
|
|
35
|
+
* @param token Partial text fragment.
|
|
36
|
+
* @param done `true` when the model has finished generating.
|
|
29
37
|
*/
|
|
30
38
|
onToken: (token: string, done: boolean) => void;
|
|
31
|
-
/**
|
|
39
|
+
/** Called when the full generation has completed. */
|
|
32
40
|
onComplete: () => void;
|
|
33
|
-
/**
|
|
41
|
+
/** Called if an error occurs during streaming. */
|
|
34
42
|
onError: (error: AIError) => void;
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
/**
|
|
45
|
+
/** Normalised error structure */
|
|
38
46
|
export interface AIError {
|
|
39
47
|
code: string;
|
|
40
48
|
message: string;
|
|
41
49
|
}
|
|
42
50
|
|
|
43
|
-
// ──
|
|
51
|
+
// ── Event names (must match the Kotlin module constants) ───────────────────────
|
|
44
52
|
const EVENT_STREAM_TOKEN = 'AICore_streamToken';
|
|
45
53
|
const EVENT_STREAM_COMPLETE = 'AICore_streamComplete';
|
|
46
54
|
const EVENT_STREAM_ERROR = 'AICore_streamError';
|
|
47
55
|
|
|
48
|
-
// Instancia del emisor de eventos nativo (null en plataformas no soportadas)
|
|
49
56
|
const emitter =
|
|
50
57
|
NativeAiCore != null ? new NativeEventEmitter(NativeAiCore) : null;
|
|
51
58
|
|
|
52
|
-
// ── Guarda de plataforma ──────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
59
|
function assertAvailable(): void {
|
|
55
60
|
if (!NativeAiCore) {
|
|
56
61
|
throw new Error(
|
|
57
|
-
`react-native-ai-core:
|
|
58
|
-
'
|
|
62
|
+
`react-native-ai-core: native module unavailable on ${Platform.OS}. ` +
|
|
63
|
+
'This module requires Android with NPU support.'
|
|
59
64
|
);
|
|
60
65
|
}
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
// ── API
|
|
68
|
+
// ── Public API ───────────────────────────────────────────────────────────────────
|
|
64
69
|
|
|
65
70
|
/**
|
|
66
|
-
*
|
|
71
|
+
* Initialises the LLM inference engine with the given model.
|
|
67
72
|
*
|
|
68
|
-
* @param modelPath
|
|
69
|
-
*
|
|
73
|
+
* @param modelPath Absolute path to the `.bin` model file on the device.
|
|
74
|
+
* Pass an empty string to use ML Kit AICore (Gemini Nano NPU).
|
|
75
|
+
* @returns `true` on success.
|
|
70
76
|
*
|
|
71
|
-
* @throws `MODEL_NOT_FOUND`
|
|
72
|
-
* @throws `NPU_UNSUPPORTED`
|
|
73
|
-
* @throws `INIT_FAILED`
|
|
77
|
+
* @throws `MODEL_NOT_FOUND` if the file does not exist at `modelPath`.
|
|
78
|
+
* @throws `NPU_UNSUPPORTED` if the device NPU is incompatible.
|
|
79
|
+
* @throws `INIT_FAILED` if the engine could not start for another reason.
|
|
74
80
|
*
|
|
75
81
|
* @example
|
|
76
82
|
* const ok = await initialize('/data/local/tmp/gemini-nano.bin');
|
|
@@ -81,16 +87,16 @@ export async function initialize(modelPath: string): Promise<boolean> {
|
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
/**
|
|
84
|
-
*
|
|
90
|
+
* Generates a complete (non-streaming) response for the given prompt.
|
|
85
91
|
*
|
|
86
|
-
* @param prompt
|
|
87
|
-
* @returns
|
|
92
|
+
* @param prompt Input text for the model.
|
|
93
|
+
* @returns Full response as a string.
|
|
88
94
|
*
|
|
89
|
-
* @throws `NOT_INITIALIZED`
|
|
90
|
-
* @throws `GENERATION_ERROR`
|
|
95
|
+
* @throws `NOT_INITIALIZED` if `initialize()` was not called first.
|
|
96
|
+
* @throws `GENERATION_ERROR` if the model fails during inference.
|
|
91
97
|
*
|
|
92
98
|
* @example
|
|
93
|
-
* const response = await generateResponse('
|
|
99
|
+
* const response = await generateResponse('Explain TurboModules');
|
|
94
100
|
*/
|
|
95
101
|
export async function generateResponse(prompt: string): Promise<string> {
|
|
96
102
|
assertAvailable();
|
|
@@ -98,21 +104,21 @@ export async function generateResponse(prompt: string): Promise<string> {
|
|
|
98
104
|
}
|
|
99
105
|
|
|
100
106
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
107
|
+
* Generates a response token-by-token via streaming.
|
|
108
|
+
* Tokens are delivered in real time through the callbacks.
|
|
103
109
|
*
|
|
104
|
-
* @param prompt
|
|
110
|
+
* @param prompt Input text for the model.
|
|
105
111
|
* @param callbacks `{ onToken, onComplete, onError }`.
|
|
106
|
-
* @returns
|
|
112
|
+
* @returns Cleanup function — call it to remove the event subscriptions.
|
|
107
113
|
*
|
|
108
114
|
* @example
|
|
109
|
-
* const unsubscribe = generateResponseStream('
|
|
115
|
+
* const unsubscribe = generateResponseStream('What is MediaPipe?', {
|
|
110
116
|
* onToken: (token, done) => console.log(token),
|
|
111
|
-
* onComplete: () => console.log('
|
|
117
|
+
* onComplete: () => console.log('Done!'),
|
|
112
118
|
* onError: (err) => console.error(err),
|
|
113
119
|
* });
|
|
114
120
|
*
|
|
115
|
-
* //
|
|
121
|
+
* // On component unmount:
|
|
116
122
|
* unsubscribe();
|
|
117
123
|
*/
|
|
118
124
|
export function generateResponseStream(
|
|
@@ -122,7 +128,7 @@ export function generateResponseStream(
|
|
|
122
128
|
if (!NativeAiCore || !emitter) {
|
|
123
129
|
callbacks.onError({
|
|
124
130
|
code: 'UNAVAILABLE',
|
|
125
|
-
message: `react-native-ai-core
|
|
131
|
+
message: `react-native-ai-core is not available on ${Platform.OS}.`,
|
|
126
132
|
});
|
|
127
133
|
return () => {};
|
|
128
134
|
}
|
|
@@ -150,10 +156,8 @@ export function generateResponseStream(
|
|
|
150
156
|
}
|
|
151
157
|
);
|
|
152
158
|
|
|
153
|
-
// Arrancar la inferencia en el lado nativo
|
|
154
159
|
NativeAiCore.generateResponseStream(prompt);
|
|
155
160
|
|
|
156
|
-
// Devuelve función de limpieza para remover los listeners
|
|
157
161
|
return () => {
|
|
158
162
|
tokenSub.remove();
|
|
159
163
|
completeSub.remove();
|
|
@@ -162,17 +166,17 @@ export function generateResponseStream(
|
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
/**
|
|
165
|
-
*
|
|
169
|
+
* Checks whether Gemini Nano is available on this device.
|
|
166
170
|
*
|
|
167
171
|
* @returns
|
|
168
|
-
* - `'AVAILABLE'` →
|
|
169
|
-
* - `'NEED_DOWNLOAD'` →
|
|
170
|
-
* - `'UNSUPPORTED'` →
|
|
172
|
+
* - `'AVAILABLE'` → Model is ready to use.
|
|
173
|
+
* - `'NEED_DOWNLOAD'` → Device is compatible but the model is not yet downloaded.
|
|
174
|
+
* - `'UNSUPPORTED'` → Device does not meet the minimum requirements.
|
|
171
175
|
*
|
|
172
176
|
* @example
|
|
173
177
|
* const status = await checkAvailability();
|
|
174
178
|
* if (status === 'NEED_DOWNLOAD') {
|
|
175
|
-
* //
|
|
179
|
+
* // show model download UI
|
|
176
180
|
* }
|
|
177
181
|
*/
|
|
178
182
|
export async function checkAvailability(): Promise<AvailabilityStatus> {
|
|
@@ -181,8 +185,8 @@ export async function checkAvailability(): Promise<AvailabilityStatus> {
|
|
|
181
185
|
}
|
|
182
186
|
|
|
183
187
|
/**
|
|
184
|
-
*
|
|
185
|
-
* **
|
|
188
|
+
* Releases the model from NPU memory.
|
|
189
|
+
* **Recommended**: call in the root component's `useEffect` cleanup.
|
|
186
190
|
*
|
|
187
191
|
* @example
|
|
188
192
|
* useEffect(() => {
|
|
@@ -196,23 +200,24 @@ export async function release(): Promise<void> {
|
|
|
196
200
|
}
|
|
197
201
|
|
|
198
202
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
203
|
+
* Clears the conversation history in the native engine without releasing the model.
|
|
204
|
+
* The next `generateResponse` call will start without any previous context.
|
|
201
205
|
*
|
|
202
206
|
* @example
|
|
203
|
-
* await resetConversation(); //
|
|
207
|
+
* await resetConversation(); // new conversation, same engine
|
|
204
208
|
*/
|
|
205
209
|
export async function resetConversation(): Promise<void> {
|
|
206
210
|
if (!NativeAiCore) return;
|
|
207
211
|
return NativeAiCore.resetConversation();
|
|
208
212
|
}
|
|
209
213
|
|
|
210
|
-
// ──
|
|
214
|
+
// ── Default export (API object) ───────────────────────────────────────────────
|
|
211
215
|
|
|
212
216
|
const AICore = {
|
|
213
217
|
initialize,
|
|
214
218
|
generateResponse,
|
|
215
219
|
generateResponseStream,
|
|
220
|
+
generateStructuredResponse,
|
|
216
221
|
checkAvailability,
|
|
217
222
|
release,
|
|
218
223
|
resetConversation,
|