brainy/dist/distributed/domainDetector.js
David Snelling f8c45f2d8d Initial commit: Brainy - Multi-Dimensional AI Database
Open source vector database with HNSW indexing, graph relationships,
and metadata facets. Features CLI with professional augmentation registry
integration for discovering extensions and capabilities.
2025-08-18 17:35:06 -07:00

307 lines
No EOL
10 KiB
JavaScript

/**
* Domain Detector
* Automatically detects and manages data domains for logical separation
*/
export class DomainDetector {
constructor() {
this.domainPatterns = [
{
domain: 'medical',
patterns: {
fields: ['symptoms', 'diagnosis', 'treatment', 'medication', 'patient'],
keywords: ['medical', 'health', 'disease', 'symptom', 'treatment', 'doctor', 'patient']
},
priority: 1
},
{
domain: 'legal',
patterns: {
fields: ['contract', 'clause', 'litigation', 'statute', 'jurisdiction'],
keywords: ['legal', 'law', 'contract', 'court', 'attorney', 'litigation', 'statute']
},
priority: 1
},
{
domain: 'product',
patterns: {
fields: ['price', 'sku', 'inventory', 'category', 'brand'],
keywords: ['product', 'price', 'sale', 'inventory', 'catalog', 'item', 'sku']
},
priority: 1
},
{
domain: 'customer',
patterns: {
fields: ['customerId', 'email', 'phone', 'address', 'orders'],
keywords: ['customer', 'client', 'user', 'account', 'profile', 'contact']
},
priority: 1
},
{
domain: 'financial',
patterns: {
fields: ['amount', 'currency', 'transaction', 'balance', 'account'],
keywords: ['financial', 'money', 'payment', 'transaction', 'bank', 'credit', 'debit']
},
priority: 1
},
{
domain: 'technical',
patterns: {
fields: ['code', 'function', 'error', 'stack', 'api'],
keywords: ['code', 'software', 'api', 'error', 'debug', 'function', 'class', 'method']
},
priority: 2
}
];
this.customPatterns = [];
this.domainStats = new Map();
}
/**
* Detect domain from data object
* @param data - The data object to analyze
* @returns The detected domain and metadata
*/
detectDomain(data) {
if (!data || typeof data !== 'object') {
return { domain: 'general' };
}
// Check for explicit domain field
if (data.domain && typeof data.domain === 'string') {
this.updateStats(data.domain);
return {
domain: data.domain,
domainMetadata: this.extractDomainMetadata(data, data.domain)
};
}
// Score each domain pattern
const scores = new Map();
// Check custom patterns first (higher priority)
for (const pattern of this.customPatterns) {
const score = this.scorePattern(data, pattern);
if (score > 0) {
scores.set(pattern.domain, score * (pattern.priority || 1));
}
}
// Check default patterns
for (const pattern of this.domainPatterns) {
const score = this.scorePattern(data, pattern);
if (score > 0) {
const currentScore = scores.get(pattern.domain) || 0;
scores.set(pattern.domain, currentScore + score * (pattern.priority || 1));
}
}
// Find highest scoring domain
let bestDomain = 'general';
let bestScore = 0;
for (const [domain, score] of scores.entries()) {
if (score > bestScore) {
bestDomain = domain;
bestScore = score;
}
}
this.updateStats(bestDomain);
return {
domain: bestDomain,
domainMetadata: this.extractDomainMetadata(data, bestDomain)
};
}
/**
* Score a data object against a domain pattern
*/
scorePattern(data, pattern) {
let score = 0;
// Check field matches
if (pattern.patterns.fields) {
const dataKeys = Object.keys(data);
for (const field of pattern.patterns.fields) {
if (dataKeys.some(key => key.toLowerCase().includes(field.toLowerCase()))) {
score += 2; // Field match is strong signal
}
}
}
// Check keyword matches in values
if (pattern.patterns.keywords) {
const dataStr = JSON.stringify(data).toLowerCase();
for (const keyword of pattern.patterns.keywords) {
if (dataStr.includes(keyword.toLowerCase())) {
score += 1;
}
}
}
// Check regex patterns
if (pattern.patterns.regex) {
const dataStr = JSON.stringify(data);
if (pattern.patterns.regex.test(dataStr)) {
score += 3; // Regex match is very specific
}
}
return score;
}
/**
* Extract domain-specific metadata
*/
extractDomainMetadata(data, domain) {
const metadata = {};
switch (domain) {
case 'medical':
if (data.patientId)
metadata.patientId = data.patientId;
if (data.condition)
metadata.condition = data.condition;
if (data.severity)
metadata.severity = data.severity;
break;
case 'legal':
if (data.caseId)
metadata.caseId = data.caseId;
if (data.jurisdiction)
metadata.jurisdiction = data.jurisdiction;
if (data.documentType)
metadata.documentType = data.documentType;
break;
case 'product':
if (data.sku)
metadata.sku = data.sku;
if (data.category)
metadata.category = data.category;
if (data.brand)
metadata.brand = data.brand;
if (data.price)
metadata.priceRange = this.getPriceRange(data.price);
break;
case 'customer':
if (data.customerId)
metadata.customerId = data.customerId;
if (data.segment)
metadata.segment = data.segment;
if (data.lifetime_value)
metadata.valueCategory = this.getValueCategory(data.lifetime_value);
break;
case 'financial':
if (data.accountId)
metadata.accountId = data.accountId;
if (data.transactionType)
metadata.transactionType = data.transactionType;
if (data.amount)
metadata.amountRange = this.getAmountRange(data.amount);
break;
case 'technical':
if (data.service)
metadata.service = data.service;
if (data.environment)
metadata.environment = data.environment;
if (data.severity)
metadata.severity = data.severity;
break;
}
// Add detection confidence
metadata.detectionConfidence = this.calculateConfidence(data, domain);
return metadata;
}
/**
* Calculate detection confidence
*/
calculateConfidence(data, domain) {
// If domain was explicitly specified
if (data.domain === domain)
return 'high';
// Check how many patterns matched
const pattern = [...this.customPatterns, ...this.domainPatterns]
.find(p => p.domain === domain);
if (!pattern)
return 'low';
const score = this.scorePattern(data, pattern);
if (score >= 5)
return 'high';
if (score >= 2)
return 'medium';
return 'low';
}
/**
* Categorize price ranges
*/
getPriceRange(price) {
if (price < 10)
return 'low';
if (price < 100)
return 'medium';
if (price < 1000)
return 'high';
return 'premium';
}
/**
* Categorize customer value
*/
getValueCategory(value) {
if (value < 100)
return 'low';
if (value < 1000)
return 'medium';
if (value < 10000)
return 'high';
return 'vip';
}
/**
* Categorize amount ranges
*/
getAmountRange(amount) {
if (amount < 100)
return 'micro';
if (amount < 1000)
return 'small';
if (amount < 10000)
return 'medium';
if (amount < 100000)
return 'large';
return 'enterprise';
}
/**
* Add custom domain pattern
* @param pattern - Custom domain pattern to add
*/
addCustomPattern(pattern) {
// Remove existing pattern for same domain if exists
this.customPatterns = this.customPatterns.filter(p => p.domain !== pattern.domain);
this.customPatterns.push(pattern);
}
/**
* Remove custom domain pattern
* @param domain - Domain to remove pattern for
*/
removeCustomPattern(domain) {
this.customPatterns = this.customPatterns.filter(p => p.domain !== domain);
}
/**
* Update domain statistics
*/
updateStats(domain) {
const count = this.domainStats.get(domain) || 0;
this.domainStats.set(domain, count + 1);
}
/**
* Get domain statistics
* @returns Map of domain to count
*/
getDomainStats() {
return new Map(this.domainStats);
}
/**
* Clear domain statistics
*/
clearStats() {
this.domainStats.clear();
}
/**
* Get all configured domains
* @returns Array of domain names
*/
getConfiguredDomains() {
const domains = new Set();
for (const pattern of [...this.domainPatterns, ...this.customPatterns]) {
domains.add(pattern.domain);
}
return Array.from(domains).sort();
}
}
//# sourceMappingURL=domainDetector.js.map