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/src/index.tsx CHANGED
@@ -1,76 +1,82 @@
1
1
  /**
2
2
  * react-native-ai-core
3
3
  *
4
- * Capa de abstracción JS sobre el TurboModule nativo.
5
- * Proporciona una API limpia y tipada para usar Gemini Nano
6
- * en local a través del SDK de Google AI Edge (MediaPipe).
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('¿Qué es JSI?');
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
- // ── Tipos públicos ────────────────────────────────────────────────────────────
19
-
20
- /** Estado de disponibilidad de Gemini Nano en el dispositivo */
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
- /** Callbacks del streaming de respuesta */
31
+ /** Streaming response callbacks */
24
32
  export interface StreamCallbacks {
25
33
  /**
26
- * Invocado por cada token recibido.
27
- * @param token Fragmento de texto parcial.
28
- * @param done `true` cuando el modelo ha terminado de generar.
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
- /** Invocado cuando la generación completa ha finalizado. */
39
+ /** Called when the full generation has completed. */
32
40
  onComplete: () => void;
33
- /** Invocado si ocurre un error durante el streaming. */
41
+ /** Called if an error occurs during streaming. */
34
42
  onError: (error: AIError) => void;
35
43
  }
36
44
 
37
- /** Estructura de error normalizada */
45
+ /** Normalised error structure */
38
46
  export interface AIError {
39
47
  code: string;
40
48
  message: string;
41
49
  }
42
50
 
43
- // ── Nombres de eventos (deben coincidir con los del módulo Kotlin) ─────────────
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: módulo nativo no disponible en ${Platform.OS}. ` +
58
- 'Este módulo requiere Android con soporte de NPU.'
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 pública ───────────────────────────────────────────────────────────────
68
+ // ── Public API ───────────────────────────────────────────────────────────────────
64
69
 
65
70
  /**
66
- * Inicializa el motor de inferencia LLM con el modelo indicado.
71
+ * Initialises the LLM inference engine with the given model.
67
72
  *
68
- * @param modelPath Ruta absoluta al archivo `.bin` del modelo en el dispositivo.
69
- * @returns `true` si la inicialización fue correcta.
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` si el archivo no existe en `modelPath`.
72
- * @throws `NPU_UNSUPPORTED` si la NPU del dispositivo no es compatible.
73
- * @throws `INIT_FAILED` si el motor no pudo arrancar por otro motivo.
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
- * Genera una respuesta completa (no streaming) para el prompt dado.
90
+ * Generates a complete (non-streaming) response for the given prompt.
85
91
  *
86
- * @param prompt Texto de entrada para el modelo.
87
- * @returns Respuesta completa como string.
92
+ * @param prompt Input text for the model.
93
+ * @returns Full response as a string.
88
94
  *
89
- * @throws `NOT_INITIALIZED` si `initialize()` no fue llamado antes.
90
- * @throws `GENERATION_ERROR` si el modelo falla durante la inferencia.
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('Explícame los TurboModules');
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
- * Genera una respuesta token a token mediante streaming.
102
- * Los tokens se entregan en tiempo real a través de los callbacks.
107
+ * Generates a response token-by-token via streaming.
108
+ * Tokens are delivered in real time through the callbacks.
103
109
  *
104
- * @param prompt Texto de entrada para el modelo.
110
+ * @param prompt Input text for the model.
105
111
  * @param callbacks `{ onToken, onComplete, onError }`.
106
- * @returns Función de limpieza llámala para cancelar las suscripciones.
112
+ * @returns Cleanup functioncall it to remove the event subscriptions.
107
113
  *
108
114
  * @example
109
- * const unsubscribe = generateResponseStream('¿Qué es MediaPipe?', {
115
+ * const unsubscribe = generateResponseStream('What is MediaPipe?', {
110
116
  * onToken: (token, done) => console.log(token),
111
- * onComplete: () => console.log('¡Listo!'),
117
+ * onComplete: () => console.log('Done!'),
112
118
  * onError: (err) => console.error(err),
113
119
  * });
114
120
  *
115
- * // Al desmontar el componente:
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 no está disponible en ${Platform.OS}.`,
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
- * Comprueba si Gemini Nano está disponible en este dispositivo.
169
+ * Checks whether Gemini Nano is available on this device.
166
170
  *
167
171
  * @returns
168
- * - `'AVAILABLE'` → El modelo está listo para usarse.
169
- * - `'NEED_DOWNLOAD'` → El dispositivo es compatible pero el modelo no está descargado.
170
- * - `'UNSUPPORTED'` → El dispositivo no cumple los requisitos mínimos.
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
- * // Mostrar UI de descarga del modelo
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
- * Libera el modelo de la memoria de la NPU.
185
- * **Recomendado**: llamar en el `useEffect` cleanup del componente raíz.
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
- * Limpia el historial de conversación en el motor nativo sin liberar el modelo.
200
- * El siguiente `generateResponse` comenzará sin contexto previo.
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(); // nueva conversación, mismo motor
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
- // ── Exportación por defecto (objeto API) ─────────────────────────────────────
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,