@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.
- package/lib/commonjs/components/TrainingModal.js +341 -83
- package/lib/commonjs/components/TrainingModal.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +0 -14
- package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
- package/lib/commonjs/index.js +53 -13
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiKeyService.js +11 -5
- package/lib/commonjs/services/apiKeyService.js.map +1 -1
- package/lib/module/components/TrainingModal.js +342 -84
- package/lib/module/components/TrainingModal.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +0 -14
- package/lib/module/components/UniversalOnboarding.js.map +1 -1
- package/lib/module/index.js +8 -29
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiKeyService.js +11 -5
- package/lib/module/services/apiKeyService.js.map +1 -1
- package/lib/typescript/components/TrainingModal.d.ts.map +1 -1
- package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
- package/lib/typescript/services/apiKeyService.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/TrainingModal.tsx +336 -75
- package/src/components/UniversalOnboarding.tsx +0 -14
- package/src/services/apiKeyService.ts +12 -5
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
TouchableWithoutFeedback,
|
|
12
12
|
SafeAreaView,
|
|
13
13
|
Image,
|
|
14
|
+
Alert,
|
|
14
15
|
} from 'react-native';
|
|
15
16
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
|
16
17
|
import { io, Socket } from 'socket.io-client';
|
|
@@ -34,10 +35,13 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
34
35
|
const [socketConnected, setSocketConnected] = useState(false);
|
|
35
36
|
const [trainingStatus, setTrainingStatus] = useState('Initializing...');
|
|
36
37
|
const [hasError, setHasError] = useState(false);
|
|
38
|
+
const [errorCode, setErrorCode] = useState<string | null>(null);
|
|
37
39
|
const [isTrainingComplete, setIsTrainingComplete] = useState(false);
|
|
38
40
|
const [userTraits, setUserTraits] = useState<any>(null);
|
|
39
41
|
const [inferenceResults, setInferenceResults] = useState<any>(null);
|
|
40
42
|
const [internalProgress, setInternalProgress] = useState(0);
|
|
43
|
+
const [isEnochSDK, setIsEnochSDK] = useState(false); // Determine if using Enoch SDK
|
|
44
|
+
const [trainingResults, setTrainingResults] = useState<any>(null);
|
|
41
45
|
|
|
42
46
|
// Use internal progress if available, otherwise fall back to prop progress
|
|
43
47
|
const currentProgress = internalProgress > 0 ? internalProgress / 100 : progress;
|
|
@@ -52,36 +56,48 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
52
56
|
name: username || 'mobile_user'
|
|
53
57
|
};
|
|
54
58
|
|
|
55
|
-
//
|
|
56
|
-
|
|
59
|
+
// Check if we should use Enoch SDK (based on modelKey or other criteria)
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
// For now, default to clean training unless specified
|
|
62
|
+
// In real implementation, this would be determined by SDK type
|
|
63
|
+
setIsEnochSDK(modelKey?.includes('enoch') || false);
|
|
64
|
+
}, [modelKey]);
|
|
65
|
+
|
|
66
|
+
// Start training with new API schema
|
|
67
|
+
const startTraining = async (socketId: string) => {
|
|
57
68
|
try {
|
|
58
69
|
setTrainingStatus('Starting training...');
|
|
59
70
|
setInternalProgress(10);
|
|
71
|
+
setHasError(false);
|
|
72
|
+
setErrorCode(null);
|
|
60
73
|
|
|
61
74
|
if (!userToken) {
|
|
62
75
|
throw new Error('No authentication token available');
|
|
63
76
|
}
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
// Determine endpoint based on SDK type
|
|
79
|
+
const endpoint = isEnochSDK ? '/mobile-training/enoch' : '/mobile-training/clean';
|
|
80
|
+
|
|
81
|
+
console.log(`๐ Starting training with endpoint: ${endpoint}`);
|
|
82
|
+
console.log('๐ Production mode: Using new training API schema');
|
|
67
83
|
|
|
68
|
-
// Prepare
|
|
84
|
+
// Prepare training data in new format
|
|
69
85
|
const trainingData = {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
86
|
+
Info: {
|
|
87
|
+
username: userInfo?.username || userInfo?.name || username || 'mobile_user',
|
|
88
|
+
// Mock connected platforms - in real implementation this would come from props
|
|
89
|
+
connectedPlatforms: ['youtube', 'instagram', 'reddit'] // TODO: Get from actual connections
|
|
90
|
+
}
|
|
75
91
|
};
|
|
76
92
|
|
|
77
93
|
console.log('๐ค Sending training data:', trainingData);
|
|
78
94
|
|
|
79
|
-
// Call the
|
|
80
|
-
const response = await fetch(
|
|
95
|
+
// Call the new training API
|
|
96
|
+
const response = await fetch(`https://api2.onairos.uk${endpoint}`, {
|
|
81
97
|
method: 'POST',
|
|
82
98
|
headers: {
|
|
83
99
|
'Content-Type': 'application/json',
|
|
84
|
-
'Authorization': `Bearer ${userToken
|
|
100
|
+
'Authorization': `Bearer ${userToken}` // JWT token authentication
|
|
85
101
|
},
|
|
86
102
|
body: JSON.stringify(trainingData)
|
|
87
103
|
});
|
|
@@ -90,66 +106,142 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
90
106
|
|
|
91
107
|
if (result.success) {
|
|
92
108
|
console.log('๐ Training Started:', result.message);
|
|
93
|
-
setTrainingStatus('Training
|
|
109
|
+
setTrainingStatus('Training initiated...');
|
|
94
110
|
setInternalProgress(20);
|
|
95
111
|
} else {
|
|
96
112
|
console.error('Training start failed:', result.error);
|
|
97
|
-
setTrainingStatus(`Error: ${result.error}`);
|
|
98
|
-
setHasError(true);
|
|
99
113
|
|
|
100
|
-
//
|
|
101
|
-
|
|
114
|
+
// Handle specific error codes from new schema
|
|
115
|
+
if (result.code) {
|
|
116
|
+
setErrorCode(result.code);
|
|
117
|
+
handleTrainingError(result.code, result.error);
|
|
118
|
+
} else {
|
|
119
|
+
setTrainingStatus(`Error: ${result.error}`);
|
|
120
|
+
setHasError(true);
|
|
121
|
+
}
|
|
102
122
|
}
|
|
103
123
|
|
|
104
124
|
} catch (error) {
|
|
105
125
|
console.error('Training start error:', error);
|
|
106
126
|
setTrainingStatus(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
107
127
|
setHasError(true);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Handle training errors with specific error codes
|
|
132
|
+
const handleTrainingError = (code: string, message: string) => {
|
|
133
|
+
console.error(`Training Error [${code}]:`, message);
|
|
134
|
+
setHasError(true);
|
|
135
|
+
|
|
136
|
+
switch (code) {
|
|
137
|
+
case 'PIN_REQUIRED':
|
|
138
|
+
setTrainingStatus('PIN setup required');
|
|
139
|
+
Alert.alert(
|
|
140
|
+
'PIN Required',
|
|
141
|
+
'Please set up your PIN first before training.',
|
|
142
|
+
[
|
|
143
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
144
|
+
{ text: 'Set PIN', onPress: () => {
|
|
145
|
+
// TODO: Navigate to PIN setup
|
|
146
|
+
console.log('Navigate to PIN setup');
|
|
147
|
+
}}
|
|
148
|
+
]
|
|
149
|
+
);
|
|
150
|
+
break;
|
|
151
|
+
|
|
152
|
+
case 'CONNECTIONS_REQUIRED':
|
|
153
|
+
setTrainingStatus('No connected accounts');
|
|
154
|
+
Alert.alert(
|
|
155
|
+
'Connections Required',
|
|
156
|
+
'Please connect at least one social media account before training.',
|
|
157
|
+
[
|
|
158
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
159
|
+
{ text: 'Connect', onPress: () => {
|
|
160
|
+
// TODO: Navigate to connections
|
|
161
|
+
console.log('Navigate to connections');
|
|
162
|
+
}}
|
|
163
|
+
]
|
|
164
|
+
);
|
|
165
|
+
break;
|
|
166
|
+
|
|
167
|
+
case 'INSUFFICIENT_DATA':
|
|
168
|
+
setTrainingStatus('Insufficient data for training');
|
|
169
|
+
Alert.alert(
|
|
170
|
+
'Insufficient Data',
|
|
171
|
+
'We need more interaction data to train your model effectively. Please use your connected platforms more and try again.',
|
|
172
|
+
[{ text: 'OK', style: 'default' }]
|
|
173
|
+
);
|
|
174
|
+
break;
|
|
175
|
+
|
|
176
|
+
case 'ENCRYPTION_REQUIRED':
|
|
177
|
+
setTrainingStatus('Model encryption failed');
|
|
178
|
+
Alert.alert(
|
|
179
|
+
'Encryption Error',
|
|
180
|
+
'Failed to encrypt your model. Please try again.',
|
|
181
|
+
[{ text: 'OK', style: 'default' }]
|
|
182
|
+
);
|
|
183
|
+
break;
|
|
184
|
+
|
|
185
|
+
default:
|
|
186
|
+
setTrainingStatus(`Error: ${message}`);
|
|
187
|
+
Alert.alert(
|
|
188
|
+
'Training Error',
|
|
189
|
+
message || 'An unexpected error occurred during training.',
|
|
190
|
+
[{ text: 'OK', style: 'default' }]
|
|
191
|
+
);
|
|
111
192
|
}
|
|
112
193
|
};
|
|
113
194
|
|
|
114
195
|
// Simulate training progress for test mode
|
|
115
196
|
const simulateTraining = () => {
|
|
116
|
-
console.log('๐งช Starting simulated training...');
|
|
117
|
-
setTrainingStatus('
|
|
118
|
-
setInternalProgress(
|
|
197
|
+
console.log('๐งช Starting simulated training with new schema phases...');
|
|
198
|
+
setTrainingStatus('Validating Requirements');
|
|
199
|
+
setInternalProgress(5);
|
|
119
200
|
|
|
120
|
-
//
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
{ progress:
|
|
124
|
-
{ progress:
|
|
125
|
-
{ progress:
|
|
126
|
-
{ progress:
|
|
127
|
-
{ progress:
|
|
128
|
-
{ progress:
|
|
129
|
-
{ progress: 100, status: 'Complete!', delay: 300 },
|
|
201
|
+
// Simulate all phases from the new schema
|
|
202
|
+
const phases = [
|
|
203
|
+
{ progress: 10, status: 'Validating Requirements', delay: 1000 },
|
|
204
|
+
{ progress: 25, status: 'Training Model', delay: 2000 },
|
|
205
|
+
{ progress: 50, status: 'Training Model', delay: 2000 },
|
|
206
|
+
{ progress: 65, status: 'Model Trained - Running Test Inference', delay: 1500 },
|
|
207
|
+
{ progress: 80, status: 'Encrypting and Compressing Model', delay: 1000 },
|
|
208
|
+
{ progress: 95, status: 'Uploading Encrypted Model to ARDrive', delay: 1500 },
|
|
209
|
+
{ progress: 100, status: 'Complete!', delay: 500 },
|
|
130
210
|
];
|
|
131
211
|
|
|
132
|
-
let
|
|
212
|
+
let currentPhase = 0;
|
|
133
213
|
|
|
134
214
|
const progressInterval = setInterval(() => {
|
|
135
|
-
if (
|
|
136
|
-
const
|
|
137
|
-
setInternalProgress(
|
|
138
|
-
setTrainingStatus(
|
|
215
|
+
if (currentPhase < phases.length) {
|
|
216
|
+
const phase = phases[currentPhase];
|
|
217
|
+
setInternalProgress(phase.progress);
|
|
218
|
+
setTrainingStatus(phase.status);
|
|
139
219
|
|
|
140
|
-
if (
|
|
220
|
+
if (phase.progress === 100) {
|
|
141
221
|
setIsTrainingComplete(true);
|
|
142
222
|
clearInterval(progressInterval);
|
|
143
223
|
|
|
224
|
+
// Mock completion results
|
|
225
|
+
const mockResults = {
|
|
226
|
+
completed: true,
|
|
227
|
+
message: "Model trained, encrypted, and stored successfully",
|
|
228
|
+
storage: "ARDrive",
|
|
229
|
+
encryption: true,
|
|
230
|
+
inference: isEnochSDK, // Only Enoch SDK runs inference
|
|
231
|
+
modelUrl: `https://arweave.net/mock_tx_${Date.now()}`
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
setTrainingResults(mockResults);
|
|
235
|
+
|
|
144
236
|
// Auto-complete after a short delay
|
|
145
237
|
setTimeout(() => {
|
|
146
238
|
onComplete && onComplete();
|
|
147
|
-
},
|
|
239
|
+
}, 1000);
|
|
148
240
|
}
|
|
149
241
|
|
|
150
|
-
|
|
242
|
+
currentPhase++;
|
|
151
243
|
}
|
|
152
|
-
},
|
|
244
|
+
}, phases[currentPhase]?.delay || 1000);
|
|
153
245
|
|
|
154
246
|
// Cleanup interval on unmount
|
|
155
247
|
return () => clearInterval(progressInterval);
|
|
@@ -162,16 +254,17 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
162
254
|
console.log('Setting up socket connection for training...');
|
|
163
255
|
console.log('๐งโ๐ป User info available:', userInfo);
|
|
164
256
|
console.log('๐งช Test mode:', test);
|
|
257
|
+
console.log('๐ง Using Enoch SDK:', isEnochSDK);
|
|
165
258
|
|
|
166
259
|
// If test mode is enabled, use simulation instead of real API
|
|
167
260
|
if (test) {
|
|
168
|
-
console.log('๐งช Test mode enabled - Using simulated training');
|
|
261
|
+
console.log('๐งช Test mode enabled - Using simulated training with new schema');
|
|
169
262
|
setSocketConnected(true);
|
|
170
263
|
simulateTraining();
|
|
171
264
|
return;
|
|
172
265
|
}
|
|
173
266
|
|
|
174
|
-
// Initialize real socket connection
|
|
267
|
+
// Initialize real socket connection
|
|
175
268
|
try {
|
|
176
269
|
console.log('๐ Production mode: Initializing real socket connection');
|
|
177
270
|
|
|
@@ -181,13 +274,13 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
181
274
|
autoConnect: false
|
|
182
275
|
});
|
|
183
276
|
|
|
184
|
-
// Socket event listeners
|
|
277
|
+
// Socket event listeners for new schema
|
|
185
278
|
socketRef.current.on('connect', () => {
|
|
186
279
|
console.log('โ
Socket connected for training');
|
|
187
280
|
setSocketConnected(true);
|
|
188
281
|
const socketId = socketRef.current?.id;
|
|
189
282
|
if (socketId) {
|
|
190
|
-
|
|
283
|
+
startTraining(socketId);
|
|
191
284
|
}
|
|
192
285
|
});
|
|
193
286
|
|
|
@@ -201,42 +294,92 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
201
294
|
setTrainingStatus('Connection failed');
|
|
202
295
|
setHasError(true);
|
|
203
296
|
});
|
|
297
|
+
|
|
298
|
+
// Handle training updates with new schema phases
|
|
299
|
+
socketRef.current.on('trainingUpdate', (data) => {
|
|
300
|
+
console.log('๐ก Training update received:', data);
|
|
301
|
+
|
|
302
|
+
if (data.error) {
|
|
303
|
+
if (data.code) {
|
|
304
|
+
setErrorCode(data.code);
|
|
305
|
+
handleTrainingError(data.code, data.error);
|
|
306
|
+
} else {
|
|
307
|
+
console.error('Training update error:', data.error);
|
|
308
|
+
setTrainingStatus(`Error: ${data.error}`);
|
|
309
|
+
setHasError(true);
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
// Handle different status phases
|
|
313
|
+
if (data.status) {
|
|
314
|
+
setTrainingStatus(data.status);
|
|
315
|
+
|
|
316
|
+
// Update progress based on phase
|
|
317
|
+
switch (data.status) {
|
|
318
|
+
case 'Validating Requirements':
|
|
319
|
+
setInternalProgress(10);
|
|
320
|
+
break;
|
|
321
|
+
case 'Training Model':
|
|
322
|
+
setInternalProgress(data.percent || 40);
|
|
323
|
+
break;
|
|
324
|
+
case 'Model Trained - Running Test Inference':
|
|
325
|
+
setInternalProgress(65);
|
|
326
|
+
break;
|
|
327
|
+
case 'Encrypting and Compressing Model':
|
|
328
|
+
setInternalProgress(80);
|
|
329
|
+
break;
|
|
330
|
+
case 'Uploading Encrypted Model to ARDrive':
|
|
331
|
+
setInternalProgress(90);
|
|
332
|
+
break;
|
|
333
|
+
default:
|
|
334
|
+
if (data.percent) {
|
|
335
|
+
setInternalProgress(data.percent);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (data.progress) {
|
|
341
|
+
setInternalProgress(data.progress);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
204
345
|
|
|
346
|
+
// Handle training completion with new schema
|
|
205
347
|
socketRef.current.on('trainingCompleted', (data) => {
|
|
206
348
|
console.log('โ
Training Complete:', data);
|
|
207
|
-
|
|
208
|
-
|
|
349
|
+
|
|
350
|
+
if (data.completed && data.storage === 'ARDrive' && data.encryption === true) {
|
|
351
|
+
setTrainingStatus('Training completed successfully!');
|
|
352
|
+
setIsTrainingComplete(true);
|
|
353
|
+
setInternalProgress(100);
|
|
354
|
+
setTrainingResults(data);
|
|
355
|
+
|
|
356
|
+
// Display results
|
|
357
|
+
console.log('โ
Model URL:', data.modelUrl);
|
|
358
|
+
console.log('โ
Storage:', data.storage);
|
|
359
|
+
console.log('โ
Encrypted:', data.encryption);
|
|
360
|
+
console.log('โ
Inference:', data.inference);
|
|
361
|
+
|
|
362
|
+
// Auto-complete after a short delay
|
|
363
|
+
setTimeout(() => {
|
|
364
|
+
onComplete && onComplete();
|
|
365
|
+
}, 1500);
|
|
366
|
+
} else {
|
|
367
|
+
console.error('Training completion missing required fields:', data);
|
|
368
|
+
setTrainingStatus('Training completed with warnings');
|
|
369
|
+
setHasError(true);
|
|
370
|
+
}
|
|
209
371
|
});
|
|
210
|
-
|
|
372
|
+
|
|
373
|
+
// Legacy handlers for backward compatibility
|
|
211
374
|
socketRef.current.on('inferenceCompleted', (data) => {
|
|
212
375
|
console.log('๐ง Inference Complete:', data);
|
|
213
|
-
setTrainingStatus('Uploading to S3...');
|
|
214
|
-
setInternalProgress(80);
|
|
215
376
|
setUserTraits(data.traits);
|
|
216
377
|
setInferenceResults(data.inferenceResults);
|
|
217
378
|
});
|
|
218
379
|
|
|
219
380
|
socketRef.current.on('modelStandby', (data) => {
|
|
220
|
-
console.log('๐
|
|
221
|
-
|
|
222
|
-
setTrainingStatus('Complete!');
|
|
223
|
-
setInternalProgress(100);
|
|
224
|
-
|
|
225
|
-
// Auto-complete after a short delay
|
|
226
|
-
setTimeout(() => {
|
|
227
|
-
onComplete && onComplete();
|
|
228
|
-
}, 1500);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
socketRef.current.on('trainingUpdate', (data) => {
|
|
232
|
-
if (data.error) {
|
|
233
|
-
console.error('Training update error:', data.error);
|
|
234
|
-
setTrainingStatus(`Error: ${data.error}`);
|
|
235
|
-
setHasError(true);
|
|
236
|
-
} else if (data.progress) {
|
|
237
|
-
setInternalProgress(data.progress);
|
|
238
|
-
setTrainingStatus(data.status || 'Training in progress...');
|
|
239
|
-
}
|
|
381
|
+
console.log('๐ Model Ready:', data);
|
|
382
|
+
// This is handled by trainingCompleted now
|
|
240
383
|
});
|
|
241
384
|
|
|
242
385
|
// Connect to socket
|
|
@@ -256,7 +399,46 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
256
399
|
socketRef.current = null;
|
|
257
400
|
}
|
|
258
401
|
};
|
|
259
|
-
}, [visible, userInfo, test]);
|
|
402
|
+
}, [visible, userInfo, test, isEnochSDK]);
|
|
403
|
+
|
|
404
|
+
// Render error details for specific error codes
|
|
405
|
+
const renderErrorDetails = () => {
|
|
406
|
+
if (!hasError || !errorCode) return null;
|
|
407
|
+
|
|
408
|
+
const errorDetails = {
|
|
409
|
+
'PIN_REQUIRED': {
|
|
410
|
+
icon: 'lock',
|
|
411
|
+
title: 'PIN Setup Required',
|
|
412
|
+
description: 'Set up your PIN to secure your AI model'
|
|
413
|
+
},
|
|
414
|
+
'CONNECTIONS_REQUIRED': {
|
|
415
|
+
icon: 'link',
|
|
416
|
+
title: 'Connect Accounts',
|
|
417
|
+
description: 'Connect at least one social media account'
|
|
418
|
+
},
|
|
419
|
+
'INSUFFICIENT_DATA': {
|
|
420
|
+
icon: 'data-usage',
|
|
421
|
+
title: 'More Data Needed',
|
|
422
|
+
description: 'We need more interaction data to train effectively'
|
|
423
|
+
},
|
|
424
|
+
'ENCRYPTION_REQUIRED': {
|
|
425
|
+
icon: 'security',
|
|
426
|
+
title: 'Encryption Failed',
|
|
427
|
+
description: 'Failed to encrypt your model securely'
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const details = errorDetails[errorCode];
|
|
432
|
+
if (!details) return null;
|
|
433
|
+
|
|
434
|
+
return (
|
|
435
|
+
<View style={styles.errorDetailsContainer}>
|
|
436
|
+
<Icon name={details.icon} size={32} color="#FF6B6B" />
|
|
437
|
+
<Text style={styles.errorTitle}>{details.title}</Text>
|
|
438
|
+
<Text style={styles.errorDescription}>{details.description}</Text>
|
|
439
|
+
</View>
|
|
440
|
+
);
|
|
441
|
+
};
|
|
260
442
|
|
|
261
443
|
return (
|
|
262
444
|
<Modal
|
|
@@ -282,7 +464,9 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
282
464
|
resizeMode="contain"
|
|
283
465
|
/>
|
|
284
466
|
|
|
285
|
-
<Text style={styles.title}>
|
|
467
|
+
<Text style={styles.title}>
|
|
468
|
+
{isEnochSDK ? 'Training AI with Inference' : 'Training Your AI'}
|
|
469
|
+
</Text>
|
|
286
470
|
|
|
287
471
|
<View style={styles.progressContainer}>
|
|
288
472
|
<View style={styles.progressBar}>
|
|
@@ -307,6 +491,31 @@ export const TrainingModal: React.FC<TrainingModalProps> = ({
|
|
|
307
491
|
</View>
|
|
308
492
|
)}
|
|
309
493
|
|
|
494
|
+
{renderErrorDetails()}
|
|
495
|
+
|
|
496
|
+
{isTrainingComplete && trainingResults && (
|
|
497
|
+
<View style={styles.resultsContainer}>
|
|
498
|
+
<Icon name="check-circle" size={32} color="#4CAF50" />
|
|
499
|
+
<Text style={styles.resultsTitle}>Training Complete!</Text>
|
|
500
|
+
<View style={styles.resultsDetails}>
|
|
501
|
+
<View style={styles.resultItem}>
|
|
502
|
+
<Icon name="cloud-done" size={16} color="#666" />
|
|
503
|
+
<Text style={styles.resultText}>Storage: {trainingResults.storage}</Text>
|
|
504
|
+
</View>
|
|
505
|
+
<View style={styles.resultItem}>
|
|
506
|
+
<Icon name="security" size={16} color="#666" />
|
|
507
|
+
<Text style={styles.resultText}>Encrypted: {trainingResults.encryption ? 'Yes' : 'No'}</Text>
|
|
508
|
+
</View>
|
|
509
|
+
{trainingResults.inference && (
|
|
510
|
+
<View style={styles.resultItem}>
|
|
511
|
+
<Icon name="psychology" size={16} color="#666" />
|
|
512
|
+
<Text style={styles.resultText}>Inference: Completed</Text>
|
|
513
|
+
</View>
|
|
514
|
+
)}
|
|
515
|
+
</View>
|
|
516
|
+
</View>
|
|
517
|
+
)}
|
|
518
|
+
|
|
310
519
|
<View style={styles.footer}>
|
|
311
520
|
<TouchableOpacity
|
|
312
521
|
style={styles.cancelButton}
|
|
@@ -390,6 +599,7 @@ const styles = StyleSheet.create({
|
|
|
390
599
|
fontSize: 14,
|
|
391
600
|
color: COLORS.text.secondary,
|
|
392
601
|
marginBottom: 24,
|
|
602
|
+
textAlign: 'center',
|
|
393
603
|
},
|
|
394
604
|
progressContainer: {
|
|
395
605
|
width: '100%',
|
|
@@ -466,11 +676,62 @@ const styles = StyleSheet.create({
|
|
|
466
676
|
errorContainer: {
|
|
467
677
|
flexDirection: 'row',
|
|
468
678
|
alignItems: 'center',
|
|
469
|
-
marginBottom:
|
|
679
|
+
marginBottom: 16,
|
|
470
680
|
},
|
|
471
681
|
errorText: {
|
|
472
682
|
fontSize: 14,
|
|
473
683
|
color: '#FF6B6B',
|
|
474
684
|
marginLeft: 8,
|
|
475
685
|
},
|
|
686
|
+
errorDetailsContainer: {
|
|
687
|
+
alignItems: 'center',
|
|
688
|
+
marginBottom: 24,
|
|
689
|
+
padding: 16,
|
|
690
|
+
backgroundColor: '#FFF5F5',
|
|
691
|
+
borderRadius: 12,
|
|
692
|
+
borderWidth: 1,
|
|
693
|
+
borderColor: '#FFEBEE',
|
|
694
|
+
},
|
|
695
|
+
errorTitle: {
|
|
696
|
+
fontSize: 16,
|
|
697
|
+
fontWeight: '600',
|
|
698
|
+
color: '#FF6B6B',
|
|
699
|
+
marginTop: 8,
|
|
700
|
+
marginBottom: 4,
|
|
701
|
+
},
|
|
702
|
+
errorDescription: {
|
|
703
|
+
fontSize: 14,
|
|
704
|
+
color: '#666',
|
|
705
|
+
textAlign: 'center',
|
|
706
|
+
},
|
|
707
|
+
resultsContainer: {
|
|
708
|
+
alignItems: 'center',
|
|
709
|
+
marginBottom: 24,
|
|
710
|
+
padding: 16,
|
|
711
|
+
backgroundColor: '#F5F5F5',
|
|
712
|
+
borderRadius: 12,
|
|
713
|
+
borderWidth: 1,
|
|
714
|
+
borderColor: '#E0E0E0',
|
|
715
|
+
},
|
|
716
|
+
resultsTitle: {
|
|
717
|
+
fontSize: 16,
|
|
718
|
+
fontWeight: '600',
|
|
719
|
+
color: '#4CAF50',
|
|
720
|
+
marginTop: 8,
|
|
721
|
+
marginBottom: 12,
|
|
722
|
+
},
|
|
723
|
+
resultsDetails: {
|
|
724
|
+
alignItems: 'flex-start',
|
|
725
|
+
width: '100%',
|
|
726
|
+
},
|
|
727
|
+
resultItem: {
|
|
728
|
+
flexDirection: 'row',
|
|
729
|
+
alignItems: 'center',
|
|
730
|
+
marginBottom: 4,
|
|
731
|
+
},
|
|
732
|
+
resultText: {
|
|
733
|
+
fontSize: 14,
|
|
734
|
+
color: '#666',
|
|
735
|
+
marginLeft: 8,
|
|
736
|
+
},
|
|
476
737
|
});
|
|
@@ -488,20 +488,6 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
|
|
|
488
488
|
console.log('๐งช testMode value:', testMode);
|
|
489
489
|
console.log('๐งช isTestMode computed:', isTestMode);
|
|
490
490
|
|
|
491
|
-
// TEMPORARY TESTFLIGHT DEBUG - REMOVE AFTER FIXING
|
|
492
|
-
const debugInfo = {
|
|
493
|
-
testMode: testMode,
|
|
494
|
-
isTestMode: isTestMode,
|
|
495
|
-
requestEmailVerificationAvailable: typeof requestEmailVerification === 'function',
|
|
496
|
-
email: email?.substring(0, 5) + '...',
|
|
497
|
-
emailLength: email?.length || 0
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
if (__DEV__ || debug) {
|
|
501
|
-
Alert.alert('๐ DEBUG INFO', JSON.stringify(debugInfo, null, 2));
|
|
502
|
-
}
|
|
503
|
-
// END TEMPORARY DEBUG
|
|
504
|
-
|
|
505
491
|
try {
|
|
506
492
|
if (!email || !email.trim()) {
|
|
507
493
|
console.log('โ No email provided');
|
|
@@ -61,8 +61,9 @@ export const initializeApiKey = async (config: OnairosConfig): Promise<void> =>
|
|
|
61
61
|
throw new Error('Developer API key is required for SDK initialization');
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
if (
|
|
65
|
-
|
|
64
|
+
// Check if it's admin key first (admin key is shorter than 32 chars)
|
|
65
|
+
if (!isAdminKey(config.apiKey) && config.apiKey.length < 32) {
|
|
66
|
+
throw new Error('Invalid API key format. Developer keys must be at least 32 characters long.');
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
// Set global configuration
|
|
@@ -84,11 +85,11 @@ export const initializeApiKey = async (config: OnairosConfig): Promise<void> =>
|
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
// Validate the
|
|
88
|
+
// Validate the API key (handles both admin and developer keys)
|
|
88
89
|
const validation = await validateApiKey(config.apiKey);
|
|
89
90
|
|
|
90
91
|
if (!validation.isValid) {
|
|
91
|
-
throw new Error(`
|
|
92
|
+
throw new Error(`API key validation failed: ${validation.error}`);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
// Try to load existing JWT token
|
|
@@ -98,7 +99,13 @@ export const initializeApiKey = async (config: OnairosConfig): Promise<void> =>
|
|
|
98
99
|
|
|
99
100
|
if (globalConfig.enableLogging) {
|
|
100
101
|
console.log('โ
Onairos SDK initialized successfully');
|
|
101
|
-
|
|
102
|
+
|
|
103
|
+
if (isAdminKey(config.apiKey)) {
|
|
104
|
+
console.log('๐ Admin API key ready with full permissions');
|
|
105
|
+
} else {
|
|
106
|
+
console.log('๐ Developer API key ready for app-level operations');
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
if (userToken) {
|
|
103
110
|
console.log('๐ซ User JWT token loaded from storage');
|
|
104
111
|
}
|