devicely 2.2.12 โ†’ 2.2.14

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.
Files changed (48) hide show
  1. package/README.md +182 -81
  2. package/bin/devicely.js +1 -1
  3. package/config/devices.conf +2 -2
  4. package/lib/advanced-logger.js +1 -0
  5. package/lib/aiProviders.js +154 -15
  6. package/lib/aiProviders.js.strategic-backup +657 -0
  7. package/lib/aiProvidersConfig.js +61 -151
  8. package/lib/aiProvidersConfig.js.backup +218 -0
  9. package/lib/androidDeviceDetection.js +1 -1
  10. package/lib/appMappings.js +1 -1
  11. package/lib/commanderService.js +1 -1
  12. package/lib/commanderService.js.backup +5552 -0
  13. package/lib/deviceDetection.js +1 -1
  14. package/lib/devices.js +1 -1
  15. package/lib/devices.js.strategic-backup +57 -0
  16. package/lib/doctor.js +1 -1
  17. package/lib/encryption.js +1 -1
  18. package/lib/encryption.js.strategic-backup +61 -0
  19. package/lib/executor.js +1 -1
  20. package/lib/executor.js.strategic-backup +107 -0
  21. package/lib/frontend/asset-manifest.json +5 -3
  22. package/lib/frontend/index.html +1 -1
  23. package/lib/hybridAI.js +1 -0
  24. package/lib/intelligentLocatorService.js +1 -0
  25. package/lib/lightweightAI.js +1 -0
  26. package/lib/localBuiltInAI.js +1 -0
  27. package/lib/localBuiltInAI_backup.js +1 -0
  28. package/lib/localBuiltInAI_simple.js +1 -0
  29. package/lib/locatorStrategy.js +1 -1
  30. package/lib/logger-demo.js +2 -0
  31. package/lib/logger-integration-examples.js +102 -0
  32. package/lib/logger.js +1 -1
  33. package/lib/package.json +5 -0
  34. package/lib/public/asset-manifest.json +3 -3
  35. package/lib/public/index.html +1 -1
  36. package/lib/quick-start-logger.js +2 -0
  37. package/lib/scriptLoader.js +1 -1
  38. package/lib/server.js +1 -1
  39. package/lib/server.js.strategic-backup +6298 -0
  40. package/lib/tensorflowAI.js +1 -0
  41. package/lib/tensorflowAI.js.strategic-backup +717 -0
  42. package/lib/tinyAI.js +1 -0
  43. package/lib/universalSessionManager.js +1 -0
  44. package/package.json +1 -1
  45. package/scripts/shell/android_device_control.enc +1 -1
  46. package/scripts/shell/connect_ios_usb_multi_final.enc +1 -1
  47. package/scripts/shell/connect_ios_wireless_multi_final.enc +1 -1
  48. package/lib/public/index.html.bak +0 -1
@@ -0,0 +1,717 @@
1
+
2
+ const Logger = require('./logger');
3
+ const logger = new Logger('TensorflowAI');
4
+ /**
5
+ * ๐Ÿง  TENSORFLOW.JS LIGHTWEIGHT AI + GENIUS CONVERTER
6
+ * Uses existing TensorFlow.js infrastructure + Revolutionary Genius AI system
7
+ */
8
+
9
+ let tf = null;
10
+ let GeniusAICommandConverter = null;
11
+
12
+ // Optional dependencies - graceful degradation if not installed
13
+ try {
14
+ tf = require('@tensorflow/tfjs-node');
15
+ } catch (err) {
16
+ logger.warn('[TensorFlowAI] TensorFlow.js not installed - using fallback mode');;
17
+ }
18
+
19
+ try {
20
+ GeniusAICommandConverter = require('../../geniusAIConverter');
21
+ } catch (err) {
22
+ logger.warn('[TensorFlowAI] GeniusAIConverter not available - using simple converter');;
23
+ }
24
+
25
+ class TensorFlowAI {
26
+ constructor() {
27
+ this.logger = console;
28
+
29
+ // Check if dependencies are available
30
+ this.hasTensorFlow = tf !== null;
31
+ this.hasGeniusConverter = GeniusAICommandConverter !== null;
32
+
33
+ // ๐Ÿš€ GENIUS: Initialize Revolutionary AI Converter (if available)
34
+ if (this.hasGeniusConverter) {
35
+ try {
36
+ this.geniusConverter = new GeniusAICommandConverter();
37
+ } catch (err) {
38
+ this.logger.warn('[TensorFlowAI] Failed to initialize GeniusAIConverter:', err.message);
39
+ this.hasGeniusConverter = false;
40
+ this.geniusConverter = null;
41
+ }
42
+ } else {
43
+ this.geniusConverter = null;
44
+ }
45
+
46
+ // Model state
47
+ this.textEmbeddingModel = null;
48
+ this.isLoading = false;
49
+ this.isReady = this.hasTensorFlow; // Only ready if TensorFlow is available
50
+
51
+ // Enhanced command templates with similarity scores
52
+ this.commandTemplates = {
53
+ launch: {
54
+ patterns: ['open', 'launch', 'start', 'run', 'begin'],
55
+ apps: ['settings', 'camera', 'calculator', 'safari', 'maps', 'photos', 'mail', 'notes', 'music', 'calendar']
56
+ },
57
+ click: {
58
+ patterns: ['tap', 'click', 'press', 'touch', 'select', 'choose'],
59
+ elements: ['bluetooth', 'wifi', 'cellular', 'battery', 'display', 'sound', 'general', 'privacy', 'storage']
60
+ },
61
+ swipe: {
62
+ patterns: ['swipe', 'scroll', 'slide', 'drag'],
63
+ directions: ['up', 'down', 'left', 'right', 'upward', 'downward']
64
+ },
65
+ navigation: {
66
+ patterns: ['home', 'back', 'return', 'exit', 'close'],
67
+ targets: ['home screen', 'previous', 'main menu']
68
+ },
69
+ input: {
70
+ patterns: ['type', 'enter', 'input', 'write', 'search'],
71
+ actions: ['text', 'message', 'query', 'search term']
72
+ }
73
+ };
74
+
75
+ // Enhanced rule fallback
76
+ this.ruleBasedAI = null;
77
+
78
+ this.stats = {
79
+ tensorflowSuccess: 0,
80
+ ruleBasedFallback: 0,
81
+ totalRequests: 0,
82
+ avgInferenceTime: 0
83
+ };
84
+ }
85
+
86
+ /**
87
+ * ๐Ÿš€ Initialize TensorFlow.js (simplified approach)
88
+ */
89
+ async initialize() {
90
+ if (this.isReady) return true;
91
+ if (this.isLoading) {
92
+ while (this.isLoading) {
93
+ await new Promise(resolve => setTimeout(resolve, 100));
94
+ }
95
+ return this.isReady;
96
+ }
97
+
98
+ this.isLoading = true;
99
+
100
+ try {
101
+ if (this.hasTensorFlow) {
102
+ this.logger.info('๐Ÿง  TensorFlowAI: Initializing with TensorFlow.js support...');
103
+ // Initialize with simple but effective text similarity
104
+ // This avoids network dependencies and works completely offline
105
+ this.isReady = true;
106
+ this.logger.info('โœ… TensorFlowAI: Enhanced pattern matching ready! (TensorFlow mode)');
107
+ } else {
108
+ this.logger.info('๐Ÿง  TensorFlowAI: Initializing in fallback mode (no TensorFlow)...');
109
+ // Still functional with rule-based processing
110
+ this.isReady = true;
111
+ this.logger.info('โœ… TensorFlowAI: Rule-based pattern matching ready! (Fallback mode)');
112
+ }
113
+
114
+ } catch (error) {
115
+ this.logger.warn('โš ๏ธ TensorFlowAI: Initialization failed, will use basic rule-based fallback');
116
+ this.isReady = false;
117
+ } finally {
118
+ this.isLoading = false;
119
+ }
120
+
121
+ return this.isReady;
122
+ }
123
+
124
+ /**
125
+ * ๐Ÿš€ GENIUS: Main Conversion Method - Revolutionary Approach
126
+ */
127
+ async convertCommand(text, devices = [], options = {}) {
128
+ this.stats.totalRequests++;
129
+ const startTime = Date.now();
130
+
131
+ // ๐Ÿง  GENIUS: Use Revolutionary Genius AI Converter First (if available)
132
+ if (this.hasGeniusConverter && this.geniusConverter) {
133
+ try {
134
+ logger.info('๐Ÿš€ Using GENIUS AI Converter for maximum accuracy...');;
135
+ const geniusResult = await this.geniusConverter.convertCommand(text, devices, options);
136
+
137
+ if (geniusResult.success && geniusResult.confidence > 0.8) {
138
+ logger.info(`โœ… GENIUS AI SUCCESS: ${geniusResult.processingTime}ms, confidence: ${(geniusResult.confidence * 100).toFixed(1)}%, method: ${geniusResult.method}`);;
139
+ this.stats.tensorflowSuccess++; // Count as success
140
+
141
+ return {
142
+ success: true,
143
+ converted: geniusResult.converted,
144
+ confidence: geniusResult.confidence,
145
+ processingTime: geniusResult.processingTime,
146
+ method: geniusResult.method,
147
+ details: geniusResult.details
148
+ };
149
+ }
150
+
151
+ logger.info('๐Ÿ”„ Genius AI confidence low, trying enhanced pattern matching...');;
152
+
153
+ } catch (error) {
154
+ logger.info('โš ๏ธ Genius AI error, falling back to enhanced patterns:', error.message);;
155
+ }
156
+ } else {
157
+ logger.info('๐Ÿ”„ Genius AI not available, using pattern matching...');;
158
+ }
159
+
160
+ // Fallback to enhanced pattern matching
161
+ try {
162
+ // Try enhanced pattern matching first
163
+ if (this.isReady || await this.initialize()) {
164
+ this.logger.info('๐Ÿง  TensorFlowAI: Processing with enhanced pattern matching...');
165
+
166
+ const patternResult = await this.processWithPatternMatching(text);
167
+
168
+ if (patternResult.success && patternResult.confidence > 0.75) {
169
+ this.stats.tensorflowSuccess++;
170
+ const inferenceTime = Date.now() - startTime;
171
+ this.updateAverageInferenceTime(inferenceTime);
172
+
173
+ this.logger.info(`โœ… Enhanced Pattern SUCCESS: ${inferenceTime}ms, confidence: ${(patternResult.confidence * 100).toFixed(1)}%`);
174
+ return {
175
+ ...patternResult,
176
+ processingTime: inferenceTime,
177
+ method: 'enhanced-patterns'
178
+ };
179
+ }
180
+ }
181
+
182
+ // Fallback to enhanced rule-based
183
+ this.logger.info('๐Ÿ”„ TensorFlowAI: Using enhanced rule-based fallback...');
184
+ const ruleResult = await this.getRuleBasedFallback(text, devices, options);
185
+
186
+ this.stats.ruleBasedFallback++;
187
+ return {
188
+ ...ruleResult,
189
+ processingTime: Date.now() - startTime,
190
+ method: 'rule-based-fallback'
191
+ };
192
+
193
+ } catch (error) {
194
+ this.logger.error('โŒ TensorFlowAI: Error during processing:', error.message);
195
+
196
+ return {
197
+ success: false,
198
+ error: error.message,
199
+ processingTime: Date.now() - startTime,
200
+ method: 'error'
201
+ };
202
+ }
203
+ }
204
+
205
+ /**
206
+ * ๐ŸŽฏ Process command using enhanced pattern matching
207
+ */
208
+ async processWithPatternMatching(text) {
209
+ try {
210
+ const cleanText = text.toLowerCase().trim();
211
+
212
+ // ๐Ÿ” First, try to break down into multiple commands
213
+ const multipleCommands = this.parseMultipleCommands(cleanText);
214
+ if (multipleCommands.length > 1) {
215
+ const allCommands = [];
216
+
217
+ for (const commandText of multipleCommands) {
218
+ const singleCommand = this.parseSingleCommand(commandText);
219
+ if (singleCommand) {
220
+ allCommands.push(singleCommand);
221
+ }
222
+ }
223
+
224
+ if (allCommands.length > 0) {
225
+ return {
226
+ success: true,
227
+ converted: allCommands.join('\nWAIT 1500\n'),
228
+ confidence: 0.95,
229
+ matchedCategory: 'multi-command',
230
+ commandCount: allCommands.length
231
+ };
232
+ }
233
+ }
234
+
235
+ // ๐ŸŽฏ Fall back to single command parsing
236
+ const singleCommand = this.parseSingleCommand(cleanText);
237
+ if (singleCommand) {
238
+ return {
239
+ success: true,
240
+ converted: singleCommand,
241
+ confidence: 0.9,
242
+ matchedCategory: 'single-command',
243
+ commandCount: 1
244
+ };
245
+ }
246
+
247
+ return { success: false, confidence: 0 };
248
+
249
+ } catch (error) {
250
+ this.logger.error('โŒ Pattern matching error:', error.message);
251
+ return { success: false, error: error.message };
252
+ }
253
+ }
254
+
255
+ /**
256
+ * ๐Ÿ” Parse multiple commands from text
257
+ */
258
+ parseMultipleCommands(text) {
259
+ // Split by common conjunctions and action words
260
+ const separators = [
261
+ 'then', 'and', 'after that', 'next', 'also', 'now',
262
+ 'launch', 'open', 'start', 'click', 'tap', 'swipe', 'scroll',
263
+ 'go', 'goto', 'home', 'back', 'close', 'type', 'enter'
264
+ ];
265
+
266
+ let segments = [text];
267
+
268
+ // Split by separators while preserving the separator as part of next command
269
+ for (const separator of separators) {
270
+ const newSegments = [];
271
+
272
+ for (const segment of segments) {
273
+ const parts = segment.split(new RegExp(`\\b(${separator})\\b`, 'i'));
274
+
275
+ for (let i = 0; i < parts.length; i++) {
276
+ const part = parts[i].trim();
277
+ if (!part || part === separator) continue;
278
+
279
+ // If this part starts with a separator, include it
280
+ if (separators.includes(part.toLowerCase()) && i + 1 < parts.length) {
281
+ const nextPart = parts[i + 1].trim();
282
+ if (nextPart) {
283
+ newSegments.push(part + ' ' + nextPart);
284
+ i++; // Skip the next part since we combined it
285
+ }
286
+ } else if (part.length > 2) {
287
+ newSegments.push(part);
288
+ }
289
+ }
290
+ }
291
+
292
+ if (newSegments.length > segments.length) {
293
+ segments = newSegments;
294
+ }
295
+ }
296
+
297
+ // Clean up segments and filter out noise
298
+ return segments
299
+ .map(s => s.trim())
300
+ .filter(s => s.length > 3)
301
+ .filter(s => !['and', 'then', 'after', 'that', 'next', 'also', 'now'].includes(s.toLowerCase()));
302
+ }
303
+
304
+ /**
305
+ * ๐ŸŽฏ Parse a single command from text - ENHANCED VERSION
306
+ */
307
+ parseSingleCommand(text) {
308
+ const cleanText = text.toLowerCase().trim();
309
+
310
+ // ๐Ÿ“‹ VERSION/DEVICE INFO commands (FIXED - HIGH PRIORITY)
311
+ if (/\b(version|about|info)\b/i.test(cleanText) ||
312
+ (/\bdevice\b/i.test(cleanText) && /\b(check|info|show)\b/i.test(cleanText))) {
313
+
314
+ // Voice-specific version checks
315
+ if (/\bvoice\b/i.test(cleanText)) {
316
+ return 'navigate_to Settings > Accessibility > Voice Control';
317
+ }
318
+ // iOS/Android version checks
319
+ else if (/\b(ios|android|system|device)\b/i.test(cleanText)) {
320
+ return 'navigate_to Settings > General > About';
321
+ }
322
+ // General version/about requests
323
+ else {
324
+ return 'navigate_to Settings > General > About';
325
+ }
326
+ }
327
+
328
+ // ๐ŸŽค VOICE SETTINGS commands (FIXED)
329
+ if (/\bvoice\b/i.test(cleanText) &&
330
+ /\b(settings|show|open|control|accessibility)\b/i.test(cleanText)) {
331
+ return 'navigate_to Settings > Accessibility > Voice Control';
332
+ }
333
+
334
+ // ๐Ÿ“ธ PHOTO/SCREENSHOT commands (FIXED - HIGH PRIORITY)
335
+ if (/\b(take|capture|snap)\b/i.test(cleanText) &&
336
+ /\b(photo|picture|screenshot|pic|image|shot)\b/i.test(cleanText)) {
337
+ return 'screenshot';
338
+ }
339
+
340
+ // ๐Ÿ“ท Camera-specific photo commands (FIXED)
341
+ if (/\bcamera\b/i.test(cleanText) &&
342
+ /\b(photo|picture|take|capture|snap|pic)\b/i.test(cleanText)) {
343
+ return 'screenshot';
344
+ }
345
+
346
+ // ๐Ÿ“ฑ MULTI-COMMAND detection (ENHANCED)
347
+ if (/\b(and|then|after|next)\b/i.test(cleanText)) {
348
+ return this.parseMultiCommand(cleanText);
349
+ }
350
+
351
+ // ๐Ÿš€ LAUNCH/OPEN commands
352
+ if (/\b(launch|open|start|run|begin)\b/i.test(cleanText)) {
353
+ const appName = this.extractAppName(cleanText) || 'settings';
354
+ return `launch ${appName}`;
355
+ }
356
+
357
+ // ๐Ÿ–ฑ๏ธ CLICK/TAP commands
358
+ if (/\b(click|tap|press|touch|select)\b/i.test(cleanText)) {
359
+ const element = this.extractElementName(cleanText);
360
+ return element ? `click ${element}` : null;
361
+ }
362
+
363
+ // ๐Ÿ‘† SWIPE commands
364
+ if (/\b(swipe|scroll|slide|drag)\b/i.test(cleanText)) {
365
+ const direction = this.extractDirection(cleanText) || 'up';
366
+ return `swipe ${direction}`;
367
+ }
368
+
369
+ // ๐Ÿ  HOME/NAVIGATION commands
370
+ if (/\b(home|back|return|exit|close)\b/i.test(cleanText)) {
371
+ if (/\bhome\b/i.test(cleanText)) return 'home';
372
+ if (/\bback\b/i.test(cleanText)) return 'back';
373
+ return 'home';
374
+ }
375
+
376
+ // โŒจ๏ธ TYPE commands
377
+ if (/\b(type|enter|input|write|search)\b/i.test(cleanText)) {
378
+ const textToType = this.extractTextToType(cleanText);
379
+ return textToType ? `type ${textToType}` : null;
380
+ }
381
+
382
+ // ๐Ÿ“ธ PHOTO/SCREENSHOT commands (NEW - HIGH PRIORITY)
383
+ if (/\b(take|capture|snap)\b/i.test(cleanText) &&
384
+ /\b(photo|picture|screenshot|pic|image|shot)\b/i.test(cleanText)) {
385
+ return 'screenshot';
386
+ }
387
+
388
+ // ๐Ÿ“ท Camera-specific photo commands
389
+ if (/\bcamera\b/i.test(cleanText) &&
390
+ /\b(photo|picture|take|capture|snap|pic)\b/i.test(cleanText)) {
391
+ return 'screenshot';
392
+ }
393
+
394
+ // ๐Ÿ“ฑ Check if it contains an app name (implicit launch)
395
+ const appName = this.extractAppName(cleanText);
396
+ if (appName) {
397
+ return `launch ${appName}`;
398
+ }
399
+
400
+ // ๐Ÿ”˜ Check if it contains a UI element (implicit click)
401
+ const element = this.extractElementName(cleanText);
402
+ if (element) {
403
+ return `click ${element}`;
404
+ }
405
+
406
+ return null;
407
+ }
408
+
409
+ /**
410
+ * ๐Ÿ”— ENHANCED: Parse multi-command sequences
411
+ */
412
+ parseMultiCommand(text) {
413
+ const separators = ['and then', 'then', 'and', 'after that', 'next', ','];
414
+ let parts = [text];
415
+
416
+ // Split by separators
417
+ for (const separator of separators) {
418
+ const newParts = [];
419
+ for (const part of parts) {
420
+ const regex = new RegExp(`\\s+${separator}\\s+`, 'i');
421
+ newParts.push(...part.split(regex));
422
+ }
423
+ parts = newParts.filter(p => p.trim().length > 0);
424
+ if (parts.length > 1) break; // Found a separator
425
+ }
426
+
427
+ if (parts.length > 1) {
428
+ const commands = [];
429
+ for (const part of parts) {
430
+ const command = this.parseSingleCommand(part.trim());
431
+ if (command && !command.includes('parseMultiCommand')) {
432
+ commands.push(command);
433
+ }
434
+ }
435
+ return commands.length > 0 ? commands.join('\nWAIT 1500\n') : null;
436
+ }
437
+
438
+ return null;
439
+ }
440
+
441
+ /**
442
+ * ๐Ÿ“Š Calculate similarity score for a category
443
+ */
444
+ calculateCategoryScore(text, config) {
445
+ let maxScore = 0;
446
+
447
+ // Check pattern words
448
+ for (const pattern of config.patterns) {
449
+ const similarity = this.calculateWordSimilarity(text, pattern);
450
+ maxScore = Math.max(maxScore, similarity);
451
+ }
452
+
453
+ // Check specific terms (apps, elements, etc.)
454
+ for (const [key, values] of Object.entries(config)) {
455
+ if (key !== 'patterns' && Array.isArray(values)) {
456
+ for (const value of values) {
457
+ const similarity = this.calculateWordSimilarity(text, value);
458
+ maxScore = Math.max(maxScore, similarity * 0.9); // Slightly lower weight for specific terms
459
+ }
460
+ }
461
+ }
462
+
463
+ return maxScore;
464
+ }
465
+
466
+ /**
467
+ * ๐Ÿ“ Calculate word similarity using simple but effective methods
468
+ */
469
+ calculateWordSimilarity(text, word) {
470
+ // Exact match
471
+ if (text.includes(word)) return 1.0;
472
+
473
+ // Fuzzy matching for typos
474
+ const distance = this.levenshteinDistance(text, word);
475
+ const maxLength = Math.max(text.length, word.length);
476
+ const similarity = 1 - (distance / maxLength);
477
+
478
+ // Boost score if word appears in text
479
+ const words = text.split(/\s+/);
480
+ for (const textWord of words) {
481
+ if (textWord === word) return 1.0;
482
+
483
+ const wordDistance = this.levenshteinDistance(textWord, word);
484
+ const wordSimilarity = 1 - (wordDistance / Math.max(textWord.length, word.length));
485
+
486
+ if (wordSimilarity > 0.8) return wordSimilarity;
487
+ }
488
+
489
+ return Math.max(0, similarity > 0.6 ? similarity : 0);
490
+ }
491
+
492
+ /**
493
+ * ๐Ÿ“ Levenshtein distance for typo tolerance
494
+ */
495
+ levenshteinDistance(str1, str2) {
496
+ const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null));
497
+
498
+ for (let i = 0; i <= str1.length; i += 1) {
499
+ matrix[0][i] = i;
500
+ }
501
+
502
+ for (let j = 0; j <= str2.length; j += 1) {
503
+ matrix[j][0] = j;
504
+ }
505
+
506
+ for (let j = 1; j <= str2.length; j += 1) {
507
+ for (let i = 1; i <= str1.length; i += 1) {
508
+ const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1;
509
+ matrix[j][i] = Math.min(
510
+ matrix[j][i - 1] + 1, // deletion
511
+ matrix[j - 1][i] + 1, // insertion
512
+ matrix[j - 1][i - 1] + indicator, // substitution
513
+ );
514
+ }
515
+ }
516
+
517
+ return matrix[str2.length][str1.length];
518
+ }
519
+
520
+ /**
521
+ * ๐Ÿ” Find best matching pattern/element in category
522
+ */
523
+ findBestMatch(text, config) {
524
+ let bestMatch = null;
525
+ let bestScore = 0;
526
+
527
+ for (const [key, values] of Object.entries(config)) {
528
+ if (Array.isArray(values)) {
529
+ for (const value of values) {
530
+ const score = this.calculateWordSimilarity(text, value);
531
+ if (score > bestScore) {
532
+ bestScore = score;
533
+ bestMatch = value;
534
+ }
535
+ }
536
+ }
537
+ }
538
+
539
+ return bestMatch;
540
+ }
541
+
542
+ /**
543
+ * ๐ŸŽฏ Generate specific commands from category and matches
544
+ */
545
+ generateCommandsFromCategory(inputText, category, bestMatch) {
546
+ const commands = [];
547
+
548
+ switch (category) {
549
+ case 'launch':
550
+ const appName = this.extractAppName(inputText) || 'settings';
551
+ commands.push(`launch ${appName}`);
552
+ break;
553
+
554
+ case 'click':
555
+ const element = this.extractElementName(inputText) || 'button';
556
+ commands.push(`click ${element}`);
557
+ break;
558
+
559
+ case 'swipe':
560
+ const direction = this.extractDirection(inputText) || 'up';
561
+ commands.push(`swipe ${direction}`);
562
+ break;
563
+
564
+ case 'navigation':
565
+ if (inputText.includes('home')) {
566
+ commands.push('home');
567
+ } else if (inputText.includes('back')) {
568
+ commands.push('back');
569
+ } else {
570
+ commands.push('home');
571
+ }
572
+ break;
573
+
574
+ case 'input':
575
+ const textToType = this.extractTextToType(inputText);
576
+ if (textToType) {
577
+ commands.push(`type ${textToType}`);
578
+ } else {
579
+ commands.push('type text');
580
+ }
581
+ break;
582
+
583
+ default:
584
+ commands.push('launch settings');
585
+ }
586
+
587
+ return commands.length > 0 ? commands : ['launch settings'];
588
+ }
589
+
590
+ /**
591
+ * ๐Ÿ” Extract app name from command text (enhanced)
592
+ */
593
+ extractAppName(text) {
594
+ const appKeywords = ['settings', 'camera', 'calculator', 'safari', 'maps', 'photos', 'mail', 'notes', 'music', 'calendar'];
595
+
596
+ // Check for exact matches first
597
+ for (const app of appKeywords) {
598
+ if (text.includes(app)) {
599
+ return app;
600
+ }
601
+ }
602
+
603
+ // Check for close matches
604
+ for (const app of appKeywords) {
605
+ if (this.calculateWordSimilarity(text, app) > 0.8) {
606
+ return app;
607
+ }
608
+ }
609
+
610
+ // Extract word after launch/open keywords
611
+ const match = text.match(/(?:launch|open|start|run)\s+(\w+)/);
612
+ if (match) {
613
+ const candidate = match[1];
614
+ // Check if it's a known app or similar
615
+ for (const app of appKeywords) {
616
+ if (this.calculateWordSimilarity(candidate, app) > 0.7) {
617
+ return app;
618
+ }
619
+ }
620
+ return candidate;
621
+ }
622
+
623
+ return 'settings';
624
+ }
625
+
626
+ /**
627
+ * ๐Ÿ” Extract element name from command text (enhanced)
628
+ */
629
+ extractElementName(text) {
630
+ const elementKeywords = ['bluetooth', 'wifi', 'cellular', 'battery', 'display', 'sound', 'general', 'privacy', 'storage'];
631
+
632
+ for (const element of elementKeywords) {
633
+ if (text.includes(element) || this.calculateWordSimilarity(text, element) > 0.8) {
634
+ return element;
635
+ }
636
+ }
637
+
638
+ const match = text.match(/(?:click|tap|press|touch)\s+(\w+)/);
639
+ return match ? match[1] : 'button';
640
+ }
641
+
642
+ /**
643
+ * ๐Ÿ” Extract direction from command text
644
+ */
645
+ extractDirection(text) {
646
+ const directions = ['up', 'down', 'left', 'right'];
647
+
648
+ for (const direction of directions) {
649
+ if (text.includes(direction)) {
650
+ return direction;
651
+ }
652
+ }
653
+
654
+ return 'up';
655
+ }
656
+
657
+ /**
658
+ * ๐Ÿ” Extract text to type from command
659
+ */
660
+ extractTextToType(text) {
661
+ const match = text.match(/(?:type|enter|input|search)\s+(.+)/);
662
+ return match ? match[1].trim() : null;
663
+ }
664
+
665
+ /**
666
+ * ๐Ÿ”„ Get rule-based AI fallback
667
+ */
668
+ async getRuleBasedFallback(text, devices, options) {
669
+ if (!this.ruleBasedAI) {
670
+ const LocalBuiltInAI = require('./localBuiltInAI');
671
+ this.ruleBasedAI = new LocalBuiltInAI();
672
+ }
673
+
674
+ return await this.ruleBasedAI.convertCommand(text, devices, options);
675
+ }
676
+
677
+ /**
678
+ * ๐Ÿ“Š Update average inference time
679
+ */
680
+ updateAverageInferenceTime(newTime) {
681
+ if (this.stats.tensorflowSuccess === 1) {
682
+ this.stats.avgInferenceTime = newTime;
683
+ } else {
684
+ this.stats.avgInferenceTime = (this.stats.avgInferenceTime * (this.stats.tensorflowSuccess - 1) + newTime) / this.stats.tensorflowSuccess;
685
+ }
686
+ }
687
+
688
+ /**
689
+ * ๐Ÿ“Š Get AI status and performance metrics
690
+ */
691
+ getStatus() {
692
+ return {
693
+ tensorflow: {
694
+ ready: this.isReady,
695
+ loading: this.isLoading,
696
+ modelSize: '0MB (Enhanced Pattern Matching)',
697
+ avgInferenceTime: `${Math.round(this.stats.avgInferenceTime)}ms`,
698
+ mode: 'offline-patterns'
699
+ },
700
+ stats: { ...this.stats },
701
+ efficiency: this.stats.totalRequests > 0
702
+ ? `${(this.stats.tensorflowSuccess / this.stats.totalRequests * 100).toFixed(1)}% handled by enhanced patterns`
703
+ : 'No requests yet',
704
+ memoryUsage: process.memoryUsage()
705
+ };
706
+ }
707
+
708
+ /**
709
+ * ๐Ÿงน Cleanup resources (lightweight - nothing to dispose)
710
+ */
711
+ dispose() {
712
+ this.isReady = false;
713
+ this.logger.info('๐Ÿงน TensorFlowAI: Pattern matching resources cleaned up');
714
+ }
715
+ }
716
+
717
+ module.exports = TensorFlowAI;