8.0 RC cleanup toward "one place per thing, zero-config, no deprecation":
- Remove the `brain.neural()` clustering namespace (ImprovedNeuralAPI + the dead
legacy NeuralAPI + the neural CLI + neural-only types). Similarity is `find({vector})`
/ `similar({to})`; attribute grouping is the aggregation `GROUP BY` engine. The separate
entity-extraction / smart-import feature (NeuralImport, NeuralEntityExtractor, SmartExtractor,
NaturalLanguageProcessor, `brain.extract()`/`brain.nlp()`) is kept.
- Remove `Db.search()`; `find()` is the one query verb (accepts a bare string or FindParams).
Fix the bundled MCP client, which called a non-existent `brain.search(query, limit)` →
now `find({ query, limit })`.
- Storage config: collapse to one canonical top-level `path` key. The pre-8.0 aliases
(`rootDirectory`, `options.*`, `fileSystemStorage.*`) are removed and now THROW with the
exact rename instead of silently defaulting to `./brainy-data` on upgrade. A single resolver
feeds createStorage, the 7.x→8.0 migration probe, and the plugin-factory handoff, so a native
storage provider resolves the identical root (no split-brain).
- Fix `similar({ threshold })`: the min-similarity filter was silently dropped; it is now
applied as a post-filter on `result.score` (the documented way to bound semantic results).
- Fix `vfs.rename()` on a directory: child path updates spread the entity vector into `update()`
and failed dimension validation; they are metadata-only updates now.
- Fix `vfs.move()`: copy+delete orphaned the content-addressed content blob (the destination
shared the source hash, then unlink removed it). `move()` now delegates to `rename()` — an
in-place path change that preserves the blob and the entity id, for files and directories.
- Fix streaming import: the bulk fast path never flushed mid-import nor signalled queryability.
Entity writes are now chunked by a progressive flush interval (100 → 1000 → 5000); each chunk
flushes and emits `progress.queryable`, so imported data is queryable during the import.
- Sweep all docs, comments, and JSDoc for the removed/changed APIs.
Integration suite: 49 files / 588 passed / 0 failed. Unit: 80 files / 1456 passed, no type errors.
237 lines
8.2 KiB
TypeScript
237 lines
8.2 KiB
TypeScript
/**
|
|
* Directory Import with Entity Extraction Caching Example
|
|
*
|
|
* Demonstrates:
|
|
* - Importing directories with progress tracking
|
|
* - Entity extraction caching for performance
|
|
* - Relationship detection with confidence scores
|
|
* - Cache statistics monitoring
|
|
*/
|
|
|
|
import { Brainy, NounType, VerbType } from '../src/brainy.js'
|
|
import { DirectoryImporter } from '../src/vfs/importers/DirectoryImporter.js'
|
|
import { ProgressTracker, formatProgress } from '../src/types/progress.types.js'
|
|
import { detectRelationshipsWithConfidence } from '../src/neural/relationshipConfidence.js'
|
|
import { NeuralEntityExtractor } from '../src/neural/entityExtractor.js'
|
|
|
|
async function main() {
|
|
console.log('🧠 Brainy 3.21.0 - Directory Import with Caching Example\n')
|
|
|
|
// Initialize Brainy
|
|
const brain = new Brainy({ verbose: false })
|
|
await brain.init()
|
|
|
|
console.log('✅ Brainy initialized\n')
|
|
|
|
// The entity extractor (and its extraction cache) is constructed directly.
|
|
const extractor = new NeuralEntityExtractor(brain)
|
|
|
|
// Example 1: Import directory with entity extraction caching
|
|
console.log('📁 Example 1: Import Directory with Caching\n')
|
|
|
|
const vfs = brain.vfs
|
|
const importer = new DirectoryImporter(vfs, brain)
|
|
|
|
// Progress tracking
|
|
const tracker = ProgressTracker.create(100)
|
|
tracker.start()
|
|
|
|
try {
|
|
// Import with progress (using async generator)
|
|
console.log('Importing directory...')
|
|
|
|
let filesProcessed = 0
|
|
for await (const progress of importer.importStream('./examples', {
|
|
batchSize: 10,
|
|
recursive: true,
|
|
generateEmbeddings: true,
|
|
extractMetadata: true
|
|
})) {
|
|
if (progress.type === 'progress') {
|
|
filesProcessed = progress.processed
|
|
const trackedProgress = tracker.update(progress.processed, progress.current)
|
|
console.log(` ${formatProgress(trackedProgress)}`)
|
|
} else if (progress.type === 'complete') {
|
|
console.log(`\n✅ Import complete! Processed ${progress.processed} files\n`)
|
|
} else if (progress.type === 'error') {
|
|
console.error(`❌ Error: ${progress.error?.message}`)
|
|
}
|
|
}
|
|
|
|
tracker.complete({ filesProcessed })
|
|
|
|
} catch (error) {
|
|
console.error('Import failed:', error)
|
|
}
|
|
|
|
// Example 2: Entity extraction with caching
|
|
console.log('\n📝 Example 2: Entity Extraction with Caching\n')
|
|
|
|
const sampleText = `
|
|
John Smith created the user authentication system for the application.
|
|
The authentication system uses JWT tokens and bcrypt for password hashing.
|
|
Mary Johnson manages the backend team that maintains the system.
|
|
The system was built using Node.js and PostgreSQL database.
|
|
`
|
|
|
|
console.log('First extraction (cache miss):')
|
|
const startTime1 = Date.now()
|
|
const entities1 = await extractor.extract(sampleText, {
|
|
types: [NounType.Person, NounType.Service, NounType.Technology],
|
|
confidence: 0.7,
|
|
cache: {
|
|
enabled: true,
|
|
ttl: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
invalidateOn: 'hash'
|
|
}
|
|
})
|
|
const time1 = Date.now() - startTime1
|
|
console.log(` Extracted ${entities1.length} entities in ${time1}ms`)
|
|
console.log(` Entities: ${entities1.map(e => e.text).join(', ')}\n`)
|
|
|
|
console.log('Second extraction (cache hit):')
|
|
const startTime2 = Date.now()
|
|
const entities2 = await extractor.extract(sampleText, {
|
|
types: [NounType.Person, NounType.Service, NounType.Technology],
|
|
confidence: 0.7,
|
|
cache: {
|
|
enabled: true,
|
|
invalidateOn: 'hash'
|
|
}
|
|
})
|
|
const time2 = Date.now() - startTime2
|
|
console.log(` Extracted ${entities2.length} entities in ${time2}ms`)
|
|
console.log(` Speedup: ${Math.round(time1 / time2)}x faster!\n`)
|
|
|
|
// Show cache statistics
|
|
const cacheStats = extractor.getCacheStats()
|
|
console.log('📊 Cache Statistics:')
|
|
console.log(` Hits: ${cacheStats.hits}`)
|
|
console.log(` Misses: ${cacheStats.misses}`)
|
|
console.log(` Hit Rate: ${(cacheStats.hitRate * 100).toFixed(1)}%`)
|
|
console.log(` Total Entries: ${cacheStats.totalEntries}`)
|
|
console.log(` Avg Entities per Entry: ${cacheStats.averageEntitiesPerEntry}\n`)
|
|
|
|
// Example 3: Relationship detection with confidence
|
|
console.log('🔗 Example 3: Relationship Detection with Confidence\n')
|
|
|
|
const relationships = detectRelationshipsWithConfidence(
|
|
entities1,
|
|
sampleText,
|
|
{
|
|
minConfidence: 0.6,
|
|
maxDistance: 100,
|
|
useProximityBoost: true,
|
|
usePatternMatching: true,
|
|
useStructuralAnalysis: true
|
|
}
|
|
)
|
|
|
|
console.log(`Detected ${relationships.length} relationships:\n`)
|
|
for (const rel of relationships.slice(0, 5)) { // Show top 5
|
|
console.log(` ${rel.sourceEntity.text} --[${rel.verbType}]--> ${rel.targetEntity.text}`)
|
|
console.log(` Confidence: ${(rel.confidence * 100).toFixed(1)}%`)
|
|
console.log(` Evidence: ${rel.evidence.reasoning}`)
|
|
console.log(` Method: ${rel.evidence.method}`)
|
|
console.log(` Source: "${rel.evidence.sourceText?.substring(0, 60)}..."\n`)
|
|
}
|
|
|
|
// Example 4: Create relationships in graph with confidence
|
|
console.log('📊 Example 4: Creating Relationships in Graph\n')
|
|
|
|
const createdRelations = []
|
|
for (const rel of relationships.slice(0, 3)) { // Create top 3
|
|
try {
|
|
// Add entities to brain
|
|
const sourceId = await brain.add({
|
|
data: rel.sourceEntity.text,
|
|
type: rel.sourceEntity.type,
|
|
metadata: {
|
|
confidence: rel.sourceEntity.confidence,
|
|
extractedFrom: 'sample text'
|
|
}
|
|
})
|
|
|
|
const targetId = await brain.add({
|
|
data: rel.targetEntity.text,
|
|
type: rel.targetEntity.type,
|
|
metadata: {
|
|
confidence: rel.targetEntity.confidence,
|
|
extractedFrom: 'sample text'
|
|
}
|
|
})
|
|
|
|
// Create relationship with confidence
|
|
const relationId = await brain.relate({
|
|
from: sourceId,
|
|
to: targetId,
|
|
type: rel.verbType,
|
|
confidence: rel.confidence,
|
|
evidence: rel.evidence,
|
|
metadata: {
|
|
autoDetected: true,
|
|
detectedAt: new Date().toISOString()
|
|
}
|
|
})
|
|
|
|
createdRelations.push(relationId)
|
|
console.log(` ✅ Created: ${rel.sourceEntity.text} → ${rel.targetEntity.text}`)
|
|
} catch (error) {
|
|
console.error(` ❌ Failed to create relationship:`, error)
|
|
}
|
|
}
|
|
|
|
console.log(`\n✅ Created ${createdRelations.length} relationships in knowledge graph`)
|
|
|
|
// Example 5: Query relationships by confidence
|
|
console.log('\n🔍 Example 5: Query High-Confidence Relationships\n')
|
|
|
|
const allRelations = await brain.getRelations({
|
|
limit: 100
|
|
})
|
|
|
|
const highConfidence = allRelations.filter(r => (r.confidence || 0) >= 0.7)
|
|
console.log(`Found ${highConfidence.length} high-confidence relationships (≥70%):\n`)
|
|
|
|
for (const rel of highConfidence.slice(0, 5)) {
|
|
console.log(` ${rel.from} → ${rel.to} (${rel.type})`)
|
|
console.log(` Confidence: ${((rel.confidence || 0) * 100).toFixed(1)}%`)
|
|
if (rel.evidence) {
|
|
console.log(` Method: ${rel.evidence.method}`)
|
|
console.log(` Reasoning: ${rel.evidence.reasoning}\n`)
|
|
}
|
|
}
|
|
|
|
// Example 6: Cache management
|
|
console.log('🧹 Example 6: Cache Management\n')
|
|
|
|
console.log('Cache operations:')
|
|
|
|
// Cleanup expired entries
|
|
const cleaned = extractor.cleanupCache()
|
|
console.log(` Cleaned ${cleaned} expired entries`)
|
|
|
|
// Invalidate specific cache entry
|
|
const invalidated = extractor.invalidateCache('hash:abc123')
|
|
console.log(` Invalidated entry: ${invalidated}`)
|
|
|
|
// Get final stats
|
|
const finalStats = extractor.getCacheStats()
|
|
console.log(` Final cache size: ${finalStats.totalEntries} entries`)
|
|
console.log(` Memory used: ~${Math.round(finalStats.cacheSize / 1024)}KB`)
|
|
|
|
// Clear all cache (optional)
|
|
// extractor.clearCache()
|
|
// console.log(' Cleared entire cache')
|
|
|
|
console.log('\n✨ Example complete!')
|
|
console.log('\n📚 Key Takeaways:')
|
|
console.log(' • Entity extraction caching provides 10-100x speedup on repeated content')
|
|
console.log(' • Progress tracking gives real-time feedback for long operations')
|
|
console.log(' • Relationship confidence helps filter low-quality connections')
|
|
console.log(' • Evidence tracking makes relationships explainable and debuggable')
|
|
console.log(' • All features are opt-in and backward compatible')
|
|
}
|
|
|
|
// Run example
|
|
main().catch(console.error)
|