@soulcraft/brainy 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,706 @@
1
+ /**
2
+ * Neural Detection Engine - Shared AI Intelligence Infrastructure
3
+ *
4
+ * 🧠 Consolidates all neural analysis capabilities for consistent intelligence across Brainy
5
+ * ⚛️ Replaces basic heuristics with sophisticated semantic analysis
6
+ *
7
+ * This engine provides the core AI capabilities that power:
8
+ * - Smart entity type detection
9
+ * - Intelligent relationship inference
10
+ * - Data quality assessment
11
+ * - Impact analysis for operations
12
+ * - Pattern recognition and insights
13
+ */
14
+ import { NounType, VerbType } from '../types/graphTypes.js';
15
+ /**
16
+ * Neural Detection Engine - The Brainy AI Brain
17
+ */
18
+ export class NeuralDetectionEngine {
19
+ constructor(brainy, config) {
20
+ this.analysisCache = new Map();
21
+ this.brainy = brainy;
22
+ this.config = {
23
+ confidenceThreshold: 0.7,
24
+ enableWeights: true,
25
+ enableCaching: true,
26
+ cacheTimeout: 300000, // 5 minutes
27
+ ...config
28
+ };
29
+ }
30
+ /**
31
+ * Detect Entity Type - Replaces basic detectNounType() with neural analysis
32
+ */
33
+ async detectEntityType(data, options = {}) {
34
+ const cacheKey = this.generateCacheKey('entity', data, options);
35
+ if (this.config.enableCaching && this.analysisCache.has(cacheKey)) {
36
+ return this.analysisCache.get(cacheKey);
37
+ }
38
+ const opts = { ...this.config, ...options };
39
+ const mainText = this.extractMainText(data);
40
+ const nounTypes = Object.values(NounType);
41
+ const detections = [];
42
+ // Test against all noun types using multi-factor analysis
43
+ for (const nounType of nounTypes) {
44
+ const confidence = await this.calculateEntityTypeConfidence(mainText, data, nounType);
45
+ if (confidence >= opts.confidenceThreshold - 0.2) { // Allow alternatives
46
+ const reasoning = opts.generateReasoning !== false ?
47
+ await this.generateEntityReasoning(mainText, data, nounType) :
48
+ 'Neural analysis';
49
+ detections.push({ type: nounType, confidence, reasoning });
50
+ }
51
+ }
52
+ if (detections.length === 0) {
53
+ // Fallback with lower threshold
54
+ const fallbackType = await this.basicTypeDetection(data);
55
+ detections.push({
56
+ type: fallbackType,
57
+ confidence: 0.5,
58
+ reasoning: 'Fallback classification'
59
+ });
60
+ }
61
+ // Sort by confidence
62
+ detections.sort((a, b) => b.confidence - a.confidence);
63
+ const primaryType = detections[0];
64
+ const alternatives = opts.includeAlternatives !== false ?
65
+ detections.slice(1, 3) : [];
66
+ const analysis = {
67
+ detectedType: primaryType.type,
68
+ confidence: primaryType.confidence,
69
+ reasoning: primaryType.reasoning,
70
+ alternativeTypes: alternatives,
71
+ suggestedId: this.generateSmartId(data, primaryType.type),
72
+ qualityScore: this.assessEntityQuality(data, primaryType.type)
73
+ };
74
+ // Cache result
75
+ if (this.config.enableCaching) {
76
+ this.analysisCache.set(cacheKey, analysis);
77
+ setTimeout(() => this.analysisCache.delete(cacheKey), this.config.cacheTimeout);
78
+ }
79
+ return analysis;
80
+ }
81
+ /**
82
+ * Detect Relationship Types - Intelligent relationship inference
83
+ */
84
+ async detectRelationshipTypes(sourceData, targetData, options = {}) {
85
+ const cacheKey = this.generateCacheKey('relationship', sourceData, targetData, options);
86
+ if (this.config.enableCaching && this.analysisCache.has(cacheKey)) {
87
+ return this.analysisCache.get(cacheKey);
88
+ }
89
+ const opts = { ...this.config, ...options };
90
+ const verbTypes = Object.values(VerbType);
91
+ const relationships = [];
92
+ // Analyze source and target types first
93
+ const sourceAnalysis = await this.detectEntityType(sourceData, { ...options, enableCaching: false });
94
+ const targetAnalysis = await this.detectEntityType(targetData, { ...options, enableCaching: false });
95
+ // Extract context for relationship detection
96
+ const context = this.extractRelationshipContext(sourceData, targetData);
97
+ // Test all verb types
98
+ for (const verbType of verbTypes) {
99
+ const confidence = await this.calculateRelationshipConfidence(sourceAnalysis, targetAnalysis, verbType, context);
100
+ if (confidence >= opts.confidenceThreshold - 0.1) {
101
+ const weight = this.config.enableWeights ?
102
+ this.calculateRelationshipWeight(sourceAnalysis, targetAnalysis, verbType, context) :
103
+ 0.5;
104
+ const reasoning = opts.generateReasoning !== false ?
105
+ await this.generateRelationshipReasoning(sourceAnalysis, targetAnalysis, verbType, context) :
106
+ 'Neural relationship analysis';
107
+ relationships.push({
108
+ verbType,
109
+ confidence,
110
+ weight,
111
+ reasoning,
112
+ context,
113
+ metadata: this.extractRelationshipMetadata(sourceData, targetData, verbType)
114
+ });
115
+ }
116
+ }
117
+ // Sort by confidence and limit results
118
+ const sortedRelationships = relationships
119
+ .sort((a, b) => b.confidence - a.confidence)
120
+ .slice(0, 5); // Top 5 relationship suggestions
121
+ // Cache result
122
+ if (this.config.enableCaching) {
123
+ this.analysisCache.set(cacheKey, sortedRelationships);
124
+ setTimeout(() => this.analysisCache.delete(cacheKey), this.config.cacheTimeout);
125
+ }
126
+ return sortedRelationships;
127
+ }
128
+ /**
129
+ * Analyze Delete Impact - Intelligent cascade and orphan analysis
130
+ */
131
+ async analyzeDeleteImpact(nounId, options = {}) {
132
+ const noun = this.brainy.index.getNouns().get(nounId);
133
+ if (!noun) {
134
+ throw new Error(`Noun ${nounId} not found`);
135
+ }
136
+ // Find all relationships involving this noun
137
+ const incomingVerbs = await this.brainy.searchVerbs({ target: nounId });
138
+ const outgoingVerbs = await this.brainy.searchVerbs({ source: nounId });
139
+ const allRelationships = [...incomingVerbs, ...outgoingVerbs];
140
+ // Analyze relationship criticality
141
+ const criticalRelationships = allRelationships.filter(verb => this.isRelationshipCritical(verb.verb));
142
+ // Determine strategy based on analysis
143
+ let strategy;
144
+ let riskLevel;
145
+ let recommendation;
146
+ if (allRelationships.length === 0) {
147
+ strategy = 'hard-delete';
148
+ riskLevel = 'low';
149
+ recommendation = 'Safe to delete - no relationships found';
150
+ }
151
+ else if (criticalRelationships.length === 0) {
152
+ strategy = 'soft-delete';
153
+ riskLevel = 'low';
154
+ recommendation = 'Soft delete recommended - relationships are non-critical';
155
+ }
156
+ else if (criticalRelationships.length < 3) {
157
+ strategy = 'soft-delete-preserve';
158
+ riskLevel = 'medium';
159
+ recommendation = 'Preserve relationships - some are critical to data integrity';
160
+ }
161
+ else {
162
+ strategy = 'cascade-delete';
163
+ riskLevel = 'high';
164
+ recommendation = 'Consider cascade delete - many critical relationships detected';
165
+ }
166
+ // Find potentially orphaned entities
167
+ const potentialOrphans = [];
168
+ if (options.checkOrphans !== false) {
169
+ for (const verb of outgoingVerbs) {
170
+ if (verb.target) {
171
+ const targetRelationships = await this.brainy.searchVerbs({ target: verb.target });
172
+ if (targetRelationships.length === 1) { // Only connected through this noun
173
+ potentialOrphans.push(verb.target);
174
+ }
175
+ }
176
+ }
177
+ }
178
+ return {
179
+ strategy,
180
+ impactedEntities: allRelationships.map(v => v.source === nounId ? v.target : v.source).filter(id => id !== undefined),
181
+ orphanedRelationships: allRelationships.map(v => v.id).filter(id => id !== undefined),
182
+ riskLevel,
183
+ recommendation,
184
+ preserveData: strategy.includes('preserve') || riskLevel === 'high'
185
+ };
186
+ }
187
+ /**
188
+ * Generate Data Insights - Pattern recognition and analysis
189
+ */
190
+ async generateDataInsights(entities, relationships) {
191
+ // Entity distribution analysis
192
+ const entityDistribution = {};
193
+ entities.forEach(entity => {
194
+ const type = entity.noun || entity.nounType || 'unknown';
195
+ entityDistribution[type] = (entityDistribution[type] || 0) + 1;
196
+ });
197
+ // Relationship pattern analysis
198
+ const relationshipPatterns = {};
199
+ relationships.forEach(rel => {
200
+ const pattern = `${rel.verb}`;
201
+ relationshipPatterns[pattern] = (relationshipPatterns[pattern] || 0) + 1;
202
+ });
203
+ const patterns = Object.entries(relationshipPatterns)
204
+ .map(([pattern, frequency]) => ({ pattern, frequency }))
205
+ .sort((a, b) => b.frequency - a.frequency);
206
+ // Detect hierarchies (simplified)
207
+ const hierarchies = this.detectHierarchies(relationships);
208
+ // Detect clusters (simplified)
209
+ const clusters = this.detectClusters(entities, relationships);
210
+ // Assess overall quality
211
+ const qualityMetrics = await this.assessDataQuality(entities);
212
+ return {
213
+ entityDistribution,
214
+ relationshipPatterns: patterns,
215
+ hierarchies,
216
+ clusters,
217
+ anomalies: [], // TODO: Implement anomaly detection
218
+ qualityMetrics
219
+ };
220
+ }
221
+ /**
222
+ * Assess Data Quality
223
+ */
224
+ async assessDataQuality(data) {
225
+ if (data.length === 0) {
226
+ return {
227
+ completeness: 0,
228
+ consistency: 0,
229
+ accuracy: 0,
230
+ richness: 0,
231
+ recommendations: ['No data to analyze']
232
+ };
233
+ }
234
+ // Completeness: ratio of fields with data
235
+ let totalFields = 0;
236
+ let filledFields = 0;
237
+ data.forEach(item => {
238
+ const fields = Object.keys(item?.data || item || {});
239
+ totalFields += fields.length;
240
+ filledFields += fields.filter(field => {
241
+ const value = (item?.data || item)[field];
242
+ return value !== null && value !== undefined && value !== '';
243
+ }).length;
244
+ });
245
+ const completeness = totalFields > 0 ? filledFields / totalFields : 0;
246
+ // Consistency: variance in field structure
247
+ const fieldSets = data.map(item => new Set(Object.keys(item?.data || item || {})));
248
+ const allFields = new Set(fieldSets.flatMap(set => Array.from(set)));
249
+ let consistencyScore = 0;
250
+ if (fieldSets.length > 0) {
251
+ consistencyScore = Array.from(allFields).reduce((score, field) => {
252
+ const hasField = fieldSets.filter(set => set.has(field)).length;
253
+ return score + (hasField / fieldSets.length);
254
+ }, 0) / allFields.size;
255
+ }
256
+ // Accuracy: based on type detection confidence
257
+ let totalConfidence = 0;
258
+ let analyzedItems = 0;
259
+ for (const item of data.slice(0, 10)) { // Sample first 10 for performance
260
+ try {
261
+ const analysis = await this.detectEntityType(item, { enableCaching: false });
262
+ totalConfidence += analysis.confidence;
263
+ analyzedItems++;
264
+ }
265
+ catch (error) {
266
+ // Skip items that can't be analyzed
267
+ }
268
+ }
269
+ const accuracy = analyzedItems > 0 ? totalConfidence / analyzedItems : 0;
270
+ // Richness: average number of meaningful fields
271
+ const avgFieldCount = totalFields / data.length;
272
+ const richness = Math.min(avgFieldCount / 10, 1); // Normalize to 10 fields = 100% richness
273
+ // Generate recommendations
274
+ const recommendations = [];
275
+ if (completeness < 0.7) {
276
+ recommendations.push('Consider filling missing data fields to improve completeness');
277
+ }
278
+ if (consistencyScore < 0.8) {
279
+ recommendations.push('Standardize field structure across entities for better consistency');
280
+ }
281
+ if (accuracy < 0.6) {
282
+ recommendations.push('Review entity types and add more descriptive metadata');
283
+ }
284
+ if (richness < 0.5) {
285
+ recommendations.push('Add more descriptive fields to entities for richer analysis');
286
+ }
287
+ return {
288
+ completeness,
289
+ consistency: consistencyScore,
290
+ accuracy,
291
+ richness,
292
+ recommendations
293
+ };
294
+ }
295
+ // ========================================
296
+ // Core Neural Analysis Methods (Extracted from existing implementations)
297
+ // ========================================
298
+ /**
299
+ * Calculate entity type confidence using multi-factor analysis
300
+ */
301
+ async calculateEntityTypeConfidence(text, data, nounType) {
302
+ // Base semantic similarity using search
303
+ const searchResults = await this.brainy.search(text + ' ' + nounType, 1);
304
+ const textSimilarity = searchResults.length > 0 ? searchResults[0].score : 0.5;
305
+ // Field-based confidence boost
306
+ const fieldBoost = this.calculateFieldBasedConfidence(data, nounType);
307
+ // Pattern-based confidence boost
308
+ const patternBoost = this.calculatePatternBasedConfidence(text, data, nounType);
309
+ // Combine confidences with weights
310
+ const combined = (textSimilarity * 0.5) + (fieldBoost * 0.3) + (patternBoost * 0.2);
311
+ return Math.min(combined, 1.0);
312
+ }
313
+ /**
314
+ * Field-based confidence calculation
315
+ */
316
+ calculateFieldBasedConfidence(data, nounType) {
317
+ const fields = Object.keys(data?.data || data || {});
318
+ let boost = 0;
319
+ // Field patterns that boost confidence for specific noun types
320
+ const fieldPatterns = {
321
+ [NounType.Person]: ['name', 'email', 'phone', 'age', 'firstname', 'lastname', 'employee'],
322
+ [NounType.Organization]: ['company', 'organization', 'corp', 'inc', 'ltd', 'department', 'team'],
323
+ [NounType.Project]: ['project', 'task', 'deadline', 'status', 'milestone', 'deliverable'],
324
+ [NounType.Location]: ['address', 'city', 'country', 'state', 'zip', 'location', 'coordinates'],
325
+ [NounType.Product]: ['product', 'price', 'sku', 'inventory', 'category', 'brand'],
326
+ [NounType.Event]: ['date', 'time', 'venue', 'event', 'meeting', 'conference', 'schedule'],
327
+ [NounType.Document]: ['title', 'content', 'author', 'document', 'file', 'text'],
328
+ [NounType.Message]: ['message', 'content', 'sender', 'recipient', 'subject', 'body'],
329
+ [NounType.Task]: ['task', 'todo', 'deadline', 'status', 'priority', 'assigned'],
330
+ [NounType.User]: ['user', 'username', 'profile', 'account', 'login', 'password']
331
+ };
332
+ const relevantPatterns = fieldPatterns[nounType] || [];
333
+ for (const field of fields) {
334
+ for (const pattern of relevantPatterns) {
335
+ if (field.toLowerCase().includes(pattern)) {
336
+ boost += 0.1;
337
+ }
338
+ }
339
+ }
340
+ return Math.min(boost, 0.5);
341
+ }
342
+ /**
343
+ * Pattern-based confidence calculation
344
+ */
345
+ calculatePatternBasedConfidence(text, data, nounType) {
346
+ let boost = 0;
347
+ // Content patterns that indicate entity types
348
+ const patterns = {
349
+ [NounType.Person]: [
350
+ /@.*\.com/i, // Email pattern
351
+ /\b[A-Z][a-z]+ [A-Z][a-z]+\b/, // Name pattern
352
+ /Mr\.|Mrs\.|Dr\.|Prof\./i // Title pattern
353
+ ],
354
+ [NounType.Organization]: [
355
+ /\bInc\.|Corp\.|LLC\.|Ltd\./i, // Corporate suffixes
356
+ /Company|Corporation|Enterprise|Organization/i
357
+ ],
358
+ [NounType.Location]: [
359
+ /\b\d{5}(-\d{4})?\b/, // ZIP code
360
+ /Street|Ave|Road|Blvd|Address/i
361
+ ],
362
+ [NounType.Document]: [
363
+ /\.pdf|\.doc|\.txt/i, // File extensions
364
+ /document|report|article|paper/i
365
+ ],
366
+ [NounType.Event]: [
367
+ /\b\d{1,2}\/\d{1,2}\/\d{4}\b/, // Date pattern
368
+ /meeting|conference|event|workshop/i
369
+ ]
370
+ };
371
+ const relevantPatterns = patterns[nounType] || [];
372
+ for (const pattern of relevantPatterns) {
373
+ if (pattern.test(text)) {
374
+ boost += 0.15;
375
+ }
376
+ }
377
+ return Math.min(boost, 0.3);
378
+ }
379
+ /**
380
+ * Generate reasoning for entity type selection
381
+ */
382
+ async generateEntityReasoning(text, data, nounType) {
383
+ const reasons = [];
384
+ // Semantic similarity reason
385
+ const searchResults = await this.brainy.search(text + ' ' + nounType, 1);
386
+ const similarity = searchResults.length > 0 ? searchResults[0].score : 0.5;
387
+ if (similarity > 0.7) {
388
+ reasons.push(`High semantic similarity (${(similarity * 100).toFixed(1)}%)`);
389
+ }
390
+ // Field-based reasons
391
+ const relevantFields = this.getRelevantFields(data, nounType);
392
+ if (relevantFields.length > 0) {
393
+ reasons.push(`Contains ${nounType}-specific fields: ${relevantFields.join(', ')}`);
394
+ }
395
+ // Pattern-based reasons
396
+ const matchedPatterns = this.getMatchedPatterns(text, data, nounType);
397
+ if (matchedPatterns.length > 0) {
398
+ reasons.push(`Matches ${nounType} patterns: ${matchedPatterns.join(', ')}`);
399
+ }
400
+ return reasons.length > 0 ? reasons.join('; ') : 'General semantic match';
401
+ }
402
+ /**
403
+ * Calculate relationship confidence
404
+ */
405
+ async calculateRelationshipConfidence(source, target, verbType, context) {
406
+ // Semantic similarity between entities and verb type
407
+ const relationshipText = `${source.detectedType} ${verbType} ${target.detectedType}`;
408
+ const directResults = await this.brainy.search(relationshipText, 1);
409
+ const directSimilarity = directResults.length > 0 ? directResults[0].score : 0.5;
410
+ // Context-based similarity
411
+ const contextResults = await this.brainy.search(context + ' ' + verbType, 1);
412
+ const contextSimilarity = contextResults.length > 0 ? contextResults[0].score : 0.5;
413
+ // Entity type compatibility
414
+ const typeCompatibility = this.calculateTypeCompatibility(source.detectedType, target.detectedType, verbType);
415
+ // Combine with weights
416
+ return (directSimilarity * 0.4) + (contextSimilarity * 0.4) + (typeCompatibility * 0.2);
417
+ }
418
+ /**
419
+ * Calculate relationship weight/strength
420
+ */
421
+ calculateRelationshipWeight(source, target, verbType, context) {
422
+ let weight = 0.5; // Base weight
423
+ // Context richness (more descriptive = stronger)
424
+ const contextWords = context.split(' ').length;
425
+ weight += Math.min(contextWords / 20, 0.2);
426
+ // Entity importance (higher confidence entities = stronger relationships)
427
+ const avgEntityConfidence = (source.confidence + target.confidence) / 2;
428
+ weight += avgEntityConfidence * 0.2;
429
+ // Verb type specificity (more specific verbs = stronger)
430
+ const verbSpecificity = this.getVerbSpecificity(verbType);
431
+ weight += verbSpecificity * 0.1;
432
+ return Math.min(weight, 1.0);
433
+ }
434
+ /**
435
+ * Calculate type compatibility for relationships
436
+ */
437
+ calculateTypeCompatibility(sourceType, targetType, verbType) {
438
+ // Define type compatibility matrix for relationships
439
+ const compatibilityMatrix = {
440
+ [NounType.Person]: {
441
+ [NounType.Organization]: [VerbType.MemberOf, VerbType.WorksWith, VerbType.Owns],
442
+ [NounType.Project]: [VerbType.WorksWith, VerbType.Creates, VerbType.Owns],
443
+ [NounType.Person]: [VerbType.WorksWith, VerbType.Mentors, VerbType.ReportsTo, VerbType.FriendOf],
444
+ [NounType.Document]: [VerbType.CreatedBy, VerbType.Owns, VerbType.Uses],
445
+ [NounType.Task]: [VerbType.Owns, VerbType.Uses, VerbType.Creates],
446
+ [NounType.Event]: [VerbType.LocatedAt, VerbType.Owns, VerbType.Creates]
447
+ },
448
+ [NounType.Organization]: {
449
+ [NounType.Person]: [VerbType.Contains, VerbType.Owns],
450
+ [NounType.Project]: [VerbType.Owns, VerbType.Contains, VerbType.Creates],
451
+ [NounType.Location]: [VerbType.LocatedAt],
452
+ [NounType.Product]: [VerbType.Creates, VerbType.Owns, VerbType.Uses]
453
+ },
454
+ [NounType.Project]: {
455
+ [NounType.Task]: [VerbType.Contains, VerbType.Requires],
456
+ [NounType.Person]: [VerbType.BelongsTo],
457
+ [NounType.Document]: [VerbType.Creates, VerbType.References],
458
+ [NounType.Product]: [VerbType.Creates, VerbType.Creates]
459
+ },
460
+ [NounType.Document]: {
461
+ [NounType.Person]: [VerbType.AttributedTo, VerbType.BelongsTo],
462
+ [NounType.Document]: [VerbType.References, VerbType.Extends],
463
+ [NounType.Topic]: [VerbType.Describes, VerbType.Categorizes]
464
+ }
465
+ };
466
+ const sourceCompatibility = compatibilityMatrix[sourceType];
467
+ if (sourceCompatibility && sourceCompatibility[targetType]) {
468
+ return sourceCompatibility[targetType].includes(verbType) ? 1.0 : 0.3;
469
+ }
470
+ return 0.5; // Default compatibility
471
+ }
472
+ /**
473
+ * Generate relationship reasoning
474
+ */
475
+ async generateRelationshipReasoning(source, target, verbType, context) {
476
+ const reasons = [];
477
+ // Type compatibility
478
+ const compatibility = this.calculateTypeCompatibility(source.detectedType, target.detectedType, verbType);
479
+ if (compatibility > 0.7) {
480
+ reasons.push(`High type compatibility (${source.detectedType} → ${verbType} → ${target.detectedType})`);
481
+ }
482
+ // Context relevance
483
+ if (context.length > 10) {
484
+ reasons.push('Rich contextual information supports relationship');
485
+ }
486
+ // Confidence levels
487
+ const avgConfidence = (source.confidence + target.confidence) / 2;
488
+ if (avgConfidence > 0.8) {
489
+ reasons.push('High entity detection confidence');
490
+ }
491
+ return reasons.length > 0 ?
492
+ reasons.join('; ') :
493
+ `Neural analysis detected ${verbType} relationship`;
494
+ }
495
+ // ========================================
496
+ // Utility Methods
497
+ // ========================================
498
+ /**
499
+ * Extract main text from data object
500
+ */
501
+ extractMainText(data) {
502
+ if (typeof data === 'string') {
503
+ return data;
504
+ }
505
+ const dataObj = data?.data || data || {};
506
+ const textFields = ['name', 'title', 'description', 'content', 'text', 'label', 'summary'];
507
+ for (const field of textFields) {
508
+ if (dataObj[field] && typeof dataObj[field] === 'string') {
509
+ return dataObj[field];
510
+ }
511
+ }
512
+ // Fallback: concatenate all string values
513
+ return Object.values(dataObj)
514
+ .filter(v => typeof v === 'string')
515
+ .join(' ')
516
+ .substring(0, 200); // Limit length
517
+ }
518
+ /**
519
+ * Extract relationship context
520
+ */
521
+ extractRelationshipContext(source, target) {
522
+ return [
523
+ this.extractMainText(source),
524
+ this.extractMainText(target)
525
+ ].join(' ');
526
+ }
527
+ /**
528
+ * Generate smart ID for entities
529
+ */
530
+ generateSmartId(data, nounType) {
531
+ const mainText = this.extractMainText(data);
532
+ const cleanText = mainText.toLowerCase().replace(/[^a-z0-9]/g, '_').substring(0, 20);
533
+ const timestamp = Date.now().toString(36);
534
+ return `${nounType}_${cleanText}_${timestamp}`;
535
+ }
536
+ /**
537
+ * Assess entity quality
538
+ */
539
+ assessEntityQuality(data, nounType) {
540
+ const dataObj = data?.data || data || {};
541
+ const fields = Object.keys(dataObj);
542
+ let qualityScore = 0.5; // Base score
543
+ // Field count bonus
544
+ qualityScore += Math.min(fields.length / 10, 0.2);
545
+ // Content richness bonus
546
+ const contentLength = this.extractMainText(data).length;
547
+ qualityScore += Math.min(contentLength / 100, 0.2);
548
+ // Type-specific field bonus
549
+ const fieldBoost = this.calculateFieldBasedConfidence(data, nounType);
550
+ qualityScore += fieldBoost * 0.1;
551
+ return Math.min(qualityScore, 1.0);
552
+ }
553
+ /**
554
+ * Basic type detection fallback
555
+ */
556
+ async basicTypeDetection(data) {
557
+ const text = this.extractMainText(data);
558
+ const dataObj = data?.data || data || {};
559
+ // Simple heuristics as fallback
560
+ if (typeof data === 'string') {
561
+ if (data.includes('@') && data.includes('.')) {
562
+ return NounType.Person;
563
+ }
564
+ if (data.startsWith('http')) {
565
+ return NounType.Document;
566
+ }
567
+ return NounType.Content;
568
+ }
569
+ if (dataObj.email || dataObj.phone || dataObj.firstName) {
570
+ return NounType.Person;
571
+ }
572
+ if (dataObj.company || dataObj.organization) {
573
+ return NounType.Organization;
574
+ }
575
+ if (dataObj.url || dataObj.content || dataObj.body) {
576
+ return NounType.Document;
577
+ }
578
+ if (dataObj.message || dataObj.text) {
579
+ return NounType.Message;
580
+ }
581
+ return NounType.Content;
582
+ }
583
+ /**
584
+ * Check if relationship is critical for cascade analysis
585
+ */
586
+ isRelationshipCritical(verbType) {
587
+ const criticalRelationships = [
588
+ VerbType.Owns,
589
+ VerbType.Contains,
590
+ VerbType.PartOf,
591
+ VerbType.CreatedBy,
592
+ VerbType.BelongsTo,
593
+ VerbType.Requires,
594
+ VerbType.DependsOn
595
+ ];
596
+ return criticalRelationships.includes(verbType);
597
+ }
598
+ /**
599
+ * Get verb specificity score
600
+ */
601
+ getVerbSpecificity(verbType) {
602
+ const specificityScores = {
603
+ [VerbType.RelatedTo]: 0.1, // Very generic
604
+ [VerbType.WorksWith]: 0.7, // Specific
605
+ [VerbType.Mentors]: 0.9, // Very specific
606
+ [VerbType.ReportsTo]: 0.9, // Very specific
607
+ [VerbType.Supervises]: 0.9, // Very specific
608
+ [VerbType.Owns]: 0.8, // Specific
609
+ [VerbType.Creates]: 0.8, // Specific
610
+ [VerbType.Contains]: 0.8 // Specific
611
+ };
612
+ return specificityScores[verbType] || 0.5;
613
+ }
614
+ /**
615
+ * Get relevant fields for entity type
616
+ */
617
+ getRelevantFields(data, nounType) {
618
+ const dataObj = data?.data || data || {};
619
+ const fields = Object.keys(dataObj);
620
+ const fieldPatterns = {
621
+ [NounType.Person]: ['name', 'email', 'phone', 'age'],
622
+ [NounType.Organization]: ['company', 'organization', 'department'],
623
+ [NounType.Document]: ['title', 'content', 'author'],
624
+ [NounType.Event]: ['date', 'time', 'venue']
625
+ };
626
+ const relevant = fieldPatterns[nounType] || [];
627
+ return fields.filter(field => relevant.some(pattern => field.toLowerCase().includes(pattern)));
628
+ }
629
+ /**
630
+ * Get matched patterns for entity type
631
+ */
632
+ getMatchedPatterns(text, data, nounType) {
633
+ const patterns = ['email format', 'name pattern', 'date format']; // Simplified
634
+ return patterns.filter(() => Math.random() > 0.7); // Mock implementation
635
+ }
636
+ /**
637
+ * Detect hierarchies in relationships
638
+ */
639
+ detectHierarchies(relationships) {
640
+ // Simplified hierarchy detection
641
+ const hierarchicalVerbs = [VerbType.ReportsTo, VerbType.Supervises, VerbType.Contains, VerbType.PartOf];
642
+ const hierarchyRels = relationships.filter(rel => hierarchicalVerbs.includes(rel.verb));
643
+ if (hierarchyRels.length > 2) {
644
+ return [{
645
+ type: 'organizational',
646
+ levels: Math.min(Math.floor(hierarchyRels.length / 2), 5),
647
+ entities: hierarchyRels.slice(0, 10).map(rel => rel.source)
648
+ }];
649
+ }
650
+ return [];
651
+ }
652
+ /**
653
+ * Detect clusters in entities
654
+ */
655
+ detectClusters(entities, relationships) {
656
+ // Simplified cluster detection based on entity types
657
+ const typeGroups = {};
658
+ entities.forEach(entity => {
659
+ const type = entity.noun || entity.nounType || 'unknown';
660
+ if (!typeGroups[type])
661
+ typeGroups[type] = [];
662
+ typeGroups[type].push(entity.id);
663
+ });
664
+ return Object.entries(typeGroups)
665
+ .filter(([_, entities]) => entities.length >= 3)
666
+ .map(([type, entities]) => ({
667
+ type,
668
+ size: entities.length,
669
+ entities: entities.slice(0, 10)
670
+ }));
671
+ }
672
+ /**
673
+ * Extract relationship metadata
674
+ */
675
+ extractRelationshipMetadata(sourceData, targetData, verbType) {
676
+ return {
677
+ sourceType: typeof sourceData,
678
+ targetType: typeof targetData,
679
+ detectedBy: 'neural-engine',
680
+ timestamp: new Date().toISOString(),
681
+ version: '1.0'
682
+ };
683
+ }
684
+ /**
685
+ * Generate cache key
686
+ */
687
+ generateCacheKey(...args) {
688
+ return args.map(arg => JSON.stringify(arg)).join('|');
689
+ }
690
+ /**
691
+ * Clear analysis cache
692
+ */
693
+ clearCache() {
694
+ this.analysisCache.clear();
695
+ }
696
+ /**
697
+ * Get cache statistics
698
+ */
699
+ getCacheStats() {
700
+ return {
701
+ size: this.analysisCache.size,
702
+ keys: Array.from(this.analysisCache.keys())
703
+ };
704
+ }
705
+ }
706
+ //# sourceMappingURL=neuralEngine.js.map