@onairos/react-native 3.1.2 → 3.1.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.
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
- import { View, Text, StyleSheet, TouchableOpacity, Dimensions, Modal, TouchableWithoutFeedback, SafeAreaView, Image } from 'react-native';
2
+ import { View, Text, StyleSheet, TouchableOpacity, Dimensions, Modal, TouchableWithoutFeedback, SafeAreaView, Image, Alert } from 'react-native';
3
3
  import Icon from 'react-native-vector-icons/MaterialIcons';
4
4
  import { io } from 'socket.io-client';
5
5
  import { COLORS } from '../constants';
@@ -22,10 +22,13 @@ export const TrainingModal = ({
22
22
  const [socketConnected, setSocketConnected] = useState(false);
23
23
  const [trainingStatus, setTrainingStatus] = useState('Initializing...');
24
24
  const [hasError, setHasError] = useState(false);
25
+ const [errorCode, setErrorCode] = useState(null);
25
26
  const [isTrainingComplete, setIsTrainingComplete] = useState(false);
26
27
  const [userTraits, setUserTraits] = useState(null);
27
28
  const [inferenceResults, setInferenceResults] = useState(null);
28
29
  const [internalProgress, setInternalProgress] = useState(0);
30
+ const [isEnochSDK, setIsEnochSDK] = useState(false); // Determine if using Enoch SDK
31
+ const [trainingResults, setTrainingResults] = useState(null);
29
32
 
30
33
  // Use internal progress if available, otherwise fall back to prop progress
31
34
  const currentProgress = internalProgress > 0 ? internalProgress / 100 : progress;
@@ -40,115 +43,193 @@ export const TrainingModal = ({
40
43
  name: username || 'mobile_user'
41
44
  };
42
45
 
43
- // Start Enoch training via API
44
- const startEnochTraining = async socketId => {
46
+ // Check if we should use Enoch SDK (based on modelKey or other criteria)
47
+ useEffect(() => {
48
+ // For now, default to clean training unless specified
49
+ // In real implementation, this would be determined by SDK type
50
+ setIsEnochSDK((modelKey === null || modelKey === void 0 ? void 0 : modelKey.includes('enoch')) || false);
51
+ }, [modelKey]);
52
+
53
+ // Start training with new API schema
54
+ const startTraining = async socketId => {
45
55
  try {
46
56
  setTrainingStatus('Starting training...');
47
57
  setInternalProgress(10);
58
+ setHasError(false);
59
+ setErrorCode(null);
48
60
  if (!userToken) {
49
61
  throw new Error('No authentication token available');
50
62
  }
51
- console.log('🚀 Starting Enoch training with socketId:', socketId);
52
- console.log('🔍 Production mode: Using live training API');
53
63
 
54
- // Prepare user data for training
64
+ // Determine endpoint based on SDK type
65
+ const endpoint = isEnochSDK ? '/mobile-training/enoch' : '/mobile-training/clean';
66
+ console.log(`🚀 Starting training with endpoint: ${endpoint}`);
67
+ console.log('🔍 Production mode: Using new training API schema');
68
+
69
+ // Prepare training data in new format
55
70
  const trainingData = {
56
- socketId,
57
- username: (userInfo === null || userInfo === void 0 ? void 0 : userInfo.username) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.name) || username || 'mobile_user',
58
- email: (userInfo === null || userInfo === void 0 ? void 0 : userInfo.email) || null,
59
- modelKey: modelKey || null,
60
- userId: (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id) || null
71
+ Info: {
72
+ username: (userInfo === null || userInfo === void 0 ? void 0 : userInfo.username) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.name) || username || 'mobile_user',
73
+ // Mock connected platforms - in real implementation this would come from props
74
+ connectedPlatforms: ['youtube', 'instagram', 'reddit'] // TODO: Get from actual connections
75
+ }
61
76
  };
62
77
  console.log('📤 Sending training data:', trainingData);
63
78
 
64
- // Call the actual training API - backend confirmed this is working
65
- const response = await fetch('https://api2.onairos.uk/enoch/trainModel/mobile', {
79
+ // Call the new training API
80
+ const response = await fetch(`https://api2.onairos.uk${endpoint}`, {
66
81
  method: 'POST',
67
82
  headers: {
68
83
  'Content-Type': 'application/json',
69
- 'Authorization': `Bearer ${userToken || 'temp-token'}` // Backend has JWT auth working
84
+ 'Authorization': `Bearer ${userToken}` // JWT token authentication
70
85
  },
71
86
  body: JSON.stringify(trainingData)
72
87
  });
73
88
  const result = await response.json();
74
89
  if (result.success) {
75
90
  console.log('🚀 Training Started:', result.message);
76
- setTrainingStatus('Training model...');
91
+ setTrainingStatus('Training initiated...');
77
92
  setInternalProgress(20);
78
93
  } else {
79
94
  console.error('Training start failed:', result.error);
80
- setTrainingStatus(`Error: ${result.error}`);
81
- setHasError(true);
82
95
 
83
- // In production mode, don't fallback to simulation on API failure
84
- console.error('🚨 Production mode: Training failed, not falling back to simulation');
96
+ // Handle specific error codes from new schema
97
+ if (result.code) {
98
+ setErrorCode(result.code);
99
+ handleTrainingError(result.code, result.error);
100
+ } else {
101
+ setTrainingStatus(`Error: ${result.error}`);
102
+ setHasError(true);
103
+ }
85
104
  }
86
105
  } catch (error) {
87
106
  console.error('Training start error:', error);
88
107
  setTrainingStatus(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
89
108
  setHasError(true);
109
+ }
110
+ };
90
111
 
91
- // In production mode, show the actual error
92
- console.error('🚨 Production mode: Training failed with error:', error);
112
+ // Handle training errors with specific error codes
113
+ const handleTrainingError = (code, message) => {
114
+ console.error(`Training Error [${code}]:`, message);
115
+ setHasError(true);
116
+ switch (code) {
117
+ case 'PIN_REQUIRED':
118
+ setTrainingStatus('PIN setup required');
119
+ Alert.alert('PIN Required', 'Please set up your PIN first before training.', [{
120
+ text: 'Cancel',
121
+ style: 'cancel'
122
+ }, {
123
+ text: 'Set PIN',
124
+ onPress: () => {
125
+ // TODO: Navigate to PIN setup
126
+ console.log('Navigate to PIN setup');
127
+ }
128
+ }]);
129
+ break;
130
+ case 'CONNECTIONS_REQUIRED':
131
+ setTrainingStatus('No connected accounts');
132
+ Alert.alert('Connections Required', 'Please connect at least one social media account before training.', [{
133
+ text: 'Cancel',
134
+ style: 'cancel'
135
+ }, {
136
+ text: 'Connect',
137
+ onPress: () => {
138
+ // TODO: Navigate to connections
139
+ console.log('Navigate to connections');
140
+ }
141
+ }]);
142
+ break;
143
+ case 'INSUFFICIENT_DATA':
144
+ setTrainingStatus('Insufficient data for training');
145
+ Alert.alert('Insufficient Data', 'We need more interaction data to train your model effectively. Please use your connected platforms more and try again.', [{
146
+ text: 'OK',
147
+ style: 'default'
148
+ }]);
149
+ break;
150
+ case 'ENCRYPTION_REQUIRED':
151
+ setTrainingStatus('Model encryption failed');
152
+ Alert.alert('Encryption Error', 'Failed to encrypt your model. Please try again.', [{
153
+ text: 'OK',
154
+ style: 'default'
155
+ }]);
156
+ break;
157
+ default:
158
+ setTrainingStatus(`Error: ${message}`);
159
+ Alert.alert('Training Error', message || 'An unexpected error occurred during training.', [{
160
+ text: 'OK',
161
+ style: 'default'
162
+ }]);
93
163
  }
94
164
  };
95
165
 
96
166
  // Simulate training progress for test mode
97
167
  const simulateTraining = () => {
98
- var _stages$currentStage;
99
- console.log('🧪 Starting simulated training...');
100
- setTrainingStatus('Initializing training...');
101
- setInternalProgress(10);
168
+ var _phases$currentPhase;
169
+ console.log('🧪 Starting simulated training with new schema phases...');
170
+ setTrainingStatus('Validating Requirements');
171
+ setInternalProgress(5);
102
172
 
103
- // Fast training for test mode (shorter delays)
104
- const baseDelay = 800;
105
- const stages = [{
106
- progress: 20,
107
- status: 'Analyzing data patterns...',
108
- delay: baseDelay
173
+ // Simulate all phases from the new schema
174
+ const phases = [{
175
+ progress: 10,
176
+ status: 'Validating Requirements',
177
+ delay: 1000
109
178
  }, {
110
- progress: 35,
111
- status: 'Building neural network...',
112
- delay: baseDelay
179
+ progress: 25,
180
+ status: 'Training Model',
181
+ delay: 2000
113
182
  }, {
114
183
  progress: 50,
115
- status: 'Training model...',
116
- delay: baseDelay
184
+ status: 'Training Model',
185
+ delay: 2000
117
186
  }, {
118
187
  progress: 65,
119
- status: 'Optimizing parameters...',
120
- delay: baseDelay
188
+ status: 'Model Trained - Running Test Inference',
189
+ delay: 1500
121
190
  }, {
122
191
  progress: 80,
123
- status: 'Running test inference...',
124
- delay: baseDelay
192
+ status: 'Encrypting and Compressing Model',
193
+ delay: 1000
125
194
  }, {
126
195
  progress: 95,
127
- status: 'Finalizing model...',
128
- delay: baseDelay
196
+ status: 'Uploading Encrypted Model to ARDrive',
197
+ delay: 1500
129
198
  }, {
130
199
  progress: 100,
131
200
  status: 'Complete!',
132
- delay: 300
201
+ delay: 500
133
202
  }];
134
- let currentStage = 0;
203
+ let currentPhase = 0;
135
204
  const progressInterval = setInterval(() => {
136
- if (currentStage < stages.length) {
137
- const stage = stages[currentStage];
138
- setInternalProgress(stage.progress);
139
- setTrainingStatus(stage.status);
140
- if (stage.progress === 100) {
205
+ if (currentPhase < phases.length) {
206
+ const phase = phases[currentPhase];
207
+ setInternalProgress(phase.progress);
208
+ setTrainingStatus(phase.status);
209
+ if (phase.progress === 100) {
141
210
  setIsTrainingComplete(true);
142
211
  clearInterval(progressInterval);
143
212
 
213
+ // Mock completion results
214
+ const mockResults = {
215
+ completed: true,
216
+ message: "Model trained, encrypted, and stored successfully",
217
+ storage: "ARDrive",
218
+ encryption: true,
219
+ inference: isEnochSDK,
220
+ // Only Enoch SDK runs inference
221
+ modelUrl: `https://arweave.net/mock_tx_${Date.now()}`
222
+ };
223
+ setTrainingResults(mockResults);
224
+
144
225
  // Auto-complete after a short delay
145
226
  setTimeout(() => {
146
227
  onComplete && onComplete();
147
- }, 800);
228
+ }, 1000);
148
229
  }
149
- currentStage++;
230
+ currentPhase++;
150
231
  }
151
- }, ((_stages$currentStage = stages[currentStage]) === null || _stages$currentStage === void 0 ? void 0 : _stages$currentStage.delay) || baseDelay);
232
+ }, ((_phases$currentPhase = phases[currentPhase]) === null || _phases$currentPhase === void 0 ? void 0 : _phases$currentPhase.delay) || 1000);
152
233
 
153
234
  // Cleanup interval on unmount
154
235
  return () => clearInterval(progressInterval);
@@ -160,16 +241,17 @@ export const TrainingModal = ({
160
241
  console.log('Setting up socket connection for training...');
161
242
  console.log('🧑‍💻 User info available:', userInfo);
162
243
  console.log('🧪 Test mode:', test);
244
+ console.log('🔧 Using Enoch SDK:', isEnochSDK);
163
245
 
164
246
  // If test mode is enabled, use simulation instead of real API
165
247
  if (test) {
166
- console.log('🧪 Test mode enabled - Using simulated training');
248
+ console.log('🧪 Test mode enabled - Using simulated training with new schema');
167
249
  setSocketConnected(true);
168
250
  simulateTraining();
169
251
  return;
170
252
  }
171
253
 
172
- // Initialize real socket connection - backend confirmed this is working
254
+ // Initialize real socket connection
173
255
  try {
174
256
  console.log('🔌 Production mode: Initializing real socket connection');
175
257
 
@@ -179,14 +261,14 @@ export const TrainingModal = ({
179
261
  autoConnect: false
180
262
  });
181
263
 
182
- // Socket event listeners
264
+ // Socket event listeners for new schema
183
265
  socketRef.current.on('connect', () => {
184
266
  var _socketRef$current;
185
267
  console.log('✅ Socket connected for training');
186
268
  setSocketConnected(true);
187
269
  const socketId = (_socketRef$current = socketRef.current) === null || _socketRef$current === void 0 ? void 0 : _socketRef$current.id;
188
270
  if (socketId) {
189
- startEnochTraining(socketId);
271
+ startTraining(socketId);
190
272
  }
191
273
  });
192
274
  socketRef.current.on('disconnect', () => {
@@ -198,38 +280,88 @@ export const TrainingModal = ({
198
280
  setTrainingStatus('Connection failed');
199
281
  setHasError(true);
200
282
  });
283
+
284
+ // Handle training updates with new schema phases
285
+ socketRef.current.on('trainingUpdate', data => {
286
+ console.log('📡 Training update received:', data);
287
+ if (data.error) {
288
+ if (data.code) {
289
+ setErrorCode(data.code);
290
+ handleTrainingError(data.code, data.error);
291
+ } else {
292
+ console.error('Training update error:', data.error);
293
+ setTrainingStatus(`Error: ${data.error}`);
294
+ setHasError(true);
295
+ }
296
+ } else {
297
+ // Handle different status phases
298
+ if (data.status) {
299
+ setTrainingStatus(data.status);
300
+
301
+ // Update progress based on phase
302
+ switch (data.status) {
303
+ case 'Validating Requirements':
304
+ setInternalProgress(10);
305
+ break;
306
+ case 'Training Model':
307
+ setInternalProgress(data.percent || 40);
308
+ break;
309
+ case 'Model Trained - Running Test Inference':
310
+ setInternalProgress(65);
311
+ break;
312
+ case 'Encrypting and Compressing Model':
313
+ setInternalProgress(80);
314
+ break;
315
+ case 'Uploading Encrypted Model to ARDrive':
316
+ setInternalProgress(90);
317
+ break;
318
+ default:
319
+ if (data.percent) {
320
+ setInternalProgress(data.percent);
321
+ }
322
+ }
323
+ }
324
+ if (data.progress) {
325
+ setInternalProgress(data.progress);
326
+ }
327
+ }
328
+ });
329
+
330
+ // Handle training completion with new schema
201
331
  socketRef.current.on('trainingCompleted', data => {
202
332
  console.log('✅ Training Complete:', data);
203
- setTrainingStatus('Running test inference...');
204
- setInternalProgress(60);
333
+ if (data.completed && data.storage === 'ARDrive' && data.encryption === true) {
334
+ setTrainingStatus('Training completed successfully!');
335
+ setIsTrainingComplete(true);
336
+ setInternalProgress(100);
337
+ setTrainingResults(data);
338
+
339
+ // Display results
340
+ console.log('✅ Model URL:', data.modelUrl);
341
+ console.log('✅ Storage:', data.storage);
342
+ console.log('✅ Encrypted:', data.encryption);
343
+ console.log('✅ Inference:', data.inference);
344
+
345
+ // Auto-complete after a short delay
346
+ setTimeout(() => {
347
+ onComplete && onComplete();
348
+ }, 1500);
349
+ } else {
350
+ console.error('Training completion missing required fields:', data);
351
+ setTrainingStatus('Training completed with warnings');
352
+ setHasError(true);
353
+ }
205
354
  });
355
+
356
+ // Legacy handlers for backward compatibility
206
357
  socketRef.current.on('inferenceCompleted', data => {
207
358
  console.log('🧠 Inference Complete:', data);
208
- setTrainingStatus('Uploading to S3...');
209
- setInternalProgress(80);
210
359
  setUserTraits(data.traits);
211
360
  setInferenceResults(data.inferenceResults);
212
361
  });
213
362
  socketRef.current.on('modelStandby', data => {
214
- console.log('🎉 All Complete:', data);
215
- setIsTrainingComplete(true);
216
- setTrainingStatus('Complete!');
217
- setInternalProgress(100);
218
-
219
- // Auto-complete after a short delay
220
- setTimeout(() => {
221
- onComplete && onComplete();
222
- }, 1500);
223
- });
224
- socketRef.current.on('trainingUpdate', data => {
225
- if (data.error) {
226
- console.error('Training update error:', data.error);
227
- setTrainingStatus(`Error: ${data.error}`);
228
- setHasError(true);
229
- } else if (data.progress) {
230
- setInternalProgress(data.progress);
231
- setTrainingStatus(data.status || 'Training in progress...');
232
- }
363
+ console.log('🎉 Model Ready:', data);
364
+ // This is handled by trainingCompleted now
233
365
  });
234
366
 
235
367
  // Connect to socket
@@ -248,7 +380,47 @@ export const TrainingModal = ({
248
380
  socketRef.current = null;
249
381
  }
250
382
  };
251
- }, [visible, userInfo, test]);
383
+ }, [visible, userInfo, test, isEnochSDK]);
384
+
385
+ // Render error details for specific error codes
386
+ const renderErrorDetails = () => {
387
+ if (!hasError || !errorCode) return null;
388
+ const errorDetails = {
389
+ 'PIN_REQUIRED': {
390
+ icon: 'lock',
391
+ title: 'PIN Setup Required',
392
+ description: 'Set up your PIN to secure your AI model'
393
+ },
394
+ 'CONNECTIONS_REQUIRED': {
395
+ icon: 'link',
396
+ title: 'Connect Accounts',
397
+ description: 'Connect at least one social media account'
398
+ },
399
+ 'INSUFFICIENT_DATA': {
400
+ icon: 'data-usage',
401
+ title: 'More Data Needed',
402
+ description: 'We need more interaction data to train effectively'
403
+ },
404
+ 'ENCRYPTION_REQUIRED': {
405
+ icon: 'security',
406
+ title: 'Encryption Failed',
407
+ description: 'Failed to encrypt your model securely'
408
+ }
409
+ };
410
+ const details = errorDetails[errorCode];
411
+ if (!details) return null;
412
+ return /*#__PURE__*/React.createElement(View, {
413
+ style: styles.errorDetailsContainer
414
+ }, /*#__PURE__*/React.createElement(Icon, {
415
+ name: details.icon,
416
+ size: 32,
417
+ color: "#FF6B6B"
418
+ }), /*#__PURE__*/React.createElement(Text, {
419
+ style: styles.errorTitle
420
+ }, details.title), /*#__PURE__*/React.createElement(Text, {
421
+ style: styles.errorDescription
422
+ }, details.description));
423
+ };
252
424
  return /*#__PURE__*/React.createElement(Modal, {
253
425
  visible: visible,
254
426
  transparent: true,
@@ -273,7 +445,7 @@ export const TrainingModal = ({
273
445
  resizeMode: "contain"
274
446
  }), /*#__PURE__*/React.createElement(Text, {
275
447
  style: styles.title
276
- }, "Training Your AI"), /*#__PURE__*/React.createElement(View, {
448
+ }, isEnochSDK ? 'Training AI with Inference' : 'Training Your AI'), /*#__PURE__*/React.createElement(View, {
277
449
  style: styles.progressContainer
278
450
  }, /*#__PURE__*/React.createElement(View, {
279
451
  style: styles.progressBar
@@ -293,7 +465,41 @@ export const TrainingModal = ({
293
465
  color: "#FF6B6B"
294
466
  }), /*#__PURE__*/React.createElement(Text, {
295
467
  style: styles.errorText
296
- }, "Training encountered an error")), /*#__PURE__*/React.createElement(View, {
468
+ }, "Training encountered an error")), renderErrorDetails(), isTrainingComplete && trainingResults && /*#__PURE__*/React.createElement(View, {
469
+ style: styles.resultsContainer
470
+ }, /*#__PURE__*/React.createElement(Icon, {
471
+ name: "check-circle",
472
+ size: 32,
473
+ color: "#4CAF50"
474
+ }), /*#__PURE__*/React.createElement(Text, {
475
+ style: styles.resultsTitle
476
+ }, "Training Complete!"), /*#__PURE__*/React.createElement(View, {
477
+ style: styles.resultsDetails
478
+ }, /*#__PURE__*/React.createElement(View, {
479
+ style: styles.resultItem
480
+ }, /*#__PURE__*/React.createElement(Icon, {
481
+ name: "cloud-done",
482
+ size: 16,
483
+ color: "#666"
484
+ }), /*#__PURE__*/React.createElement(Text, {
485
+ style: styles.resultText
486
+ }, "Storage: ", trainingResults.storage)), /*#__PURE__*/React.createElement(View, {
487
+ style: styles.resultItem
488
+ }, /*#__PURE__*/React.createElement(Icon, {
489
+ name: "security",
490
+ size: 16,
491
+ color: "#666"
492
+ }), /*#__PURE__*/React.createElement(Text, {
493
+ style: styles.resultText
494
+ }, "Encrypted: ", trainingResults.encryption ? 'Yes' : 'No')), trainingResults.inference && /*#__PURE__*/React.createElement(View, {
495
+ style: styles.resultItem
496
+ }, /*#__PURE__*/React.createElement(Icon, {
497
+ name: "psychology",
498
+ size: 16,
499
+ color: "#666"
500
+ }), /*#__PURE__*/React.createElement(Text, {
501
+ style: styles.resultText
502
+ }, "Inference: Completed")))), /*#__PURE__*/React.createElement(View, {
297
503
  style: styles.footer
298
504
  }, /*#__PURE__*/React.createElement(TouchableOpacity, {
299
505
  style: styles.cancelButton,
@@ -362,7 +568,8 @@ const styles = StyleSheet.create({
362
568
  statusText: {
363
569
  fontSize: 14,
364
570
  color: COLORS.text.secondary,
365
- marginBottom: 24
571
+ marginBottom: 24,
572
+ textAlign: 'center'
366
573
  },
367
574
  progressContainer: {
368
575
  width: '100%',
@@ -439,12 +646,63 @@ const styles = StyleSheet.create({
439
646
  errorContainer: {
440
647
  flexDirection: 'row',
441
648
  alignItems: 'center',
442
- marginBottom: 24
649
+ marginBottom: 16
443
650
  },
444
651
  errorText: {
445
652
  fontSize: 14,
446
653
  color: '#FF6B6B',
447
654
  marginLeft: 8
655
+ },
656
+ errorDetailsContainer: {
657
+ alignItems: 'center',
658
+ marginBottom: 24,
659
+ padding: 16,
660
+ backgroundColor: '#FFF5F5',
661
+ borderRadius: 12,
662
+ borderWidth: 1,
663
+ borderColor: '#FFEBEE'
664
+ },
665
+ errorTitle: {
666
+ fontSize: 16,
667
+ fontWeight: '600',
668
+ color: '#FF6B6B',
669
+ marginTop: 8,
670
+ marginBottom: 4
671
+ },
672
+ errorDescription: {
673
+ fontSize: 14,
674
+ color: '#666',
675
+ textAlign: 'center'
676
+ },
677
+ resultsContainer: {
678
+ alignItems: 'center',
679
+ marginBottom: 24,
680
+ padding: 16,
681
+ backgroundColor: '#F5F5F5',
682
+ borderRadius: 12,
683
+ borderWidth: 1,
684
+ borderColor: '#E0E0E0'
685
+ },
686
+ resultsTitle: {
687
+ fontSize: 16,
688
+ fontWeight: '600',
689
+ color: '#4CAF50',
690
+ marginTop: 8,
691
+ marginBottom: 12
692
+ },
693
+ resultsDetails: {
694
+ alignItems: 'flex-start',
695
+ width: '100%'
696
+ },
697
+ resultItem: {
698
+ flexDirection: 'row',
699
+ alignItems: 'center',
700
+ marginBottom: 4
701
+ },
702
+ resultText: {
703
+ fontSize: 14,
704
+ color: '#666',
705
+ marginLeft: 8
448
706
  }
449
707
  });
450
708
  //# sourceMappingURL=TrainingModal.js.map