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