@cmdoss/memwal-sdk 0.6.2 → 0.8.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.
- package/ARCHITECTURE.md +547 -547
- package/BENCHMARKS.md +238 -238
- package/README.md +310 -181
- package/dist/ai-sdk/tools.d.ts +2 -2
- package/dist/ai-sdk/tools.js +2 -2
- package/dist/client/ClientMemoryManager.js +2 -2
- package/dist/client/ClientMemoryManager.js.map +1 -1
- package/dist/client/PersonalDataWallet.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +29 -1
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +45 -13
- package/dist/client/SimplePDWClient.js.map +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
- package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
- package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.js +272 -39
- package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
- package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
- package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
- package/dist/config/ConfigurationHelper.js +61 -61
- package/dist/config/defaults.js +2 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/graph/GraphService.js +21 -21
- package/dist/graph/GraphService.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
- package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.js +37 -15
- package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
- package/dist/infrastructure/seal/SealService.d.ts +13 -5
- package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
- package/dist/infrastructure/seal/SealService.js +36 -34
- package/dist/infrastructure/seal/SealService.js.map +1 -1
- package/dist/langchain/createPDWRAG.js +30 -30
- package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
- package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.js +44 -4
- package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
- package/dist/services/CapabilityService.d.ts.map +1 -1
- package/dist/services/CapabilityService.js +30 -14
- package/dist/services/CapabilityService.js.map +1 -1
- package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
- package/dist/services/CrossContextPermissionService.js +9 -7
- package/dist/services/CrossContextPermissionService.js.map +1 -1
- package/dist/services/EmbeddingService.d.ts +28 -1
- package/dist/services/EmbeddingService.d.ts.map +1 -1
- package/dist/services/EmbeddingService.js +54 -0
- package/dist/services/EmbeddingService.js.map +1 -1
- package/dist/services/EncryptionService.d.ts.map +1 -1
- package/dist/services/EncryptionService.js +6 -5
- package/dist/services/EncryptionService.js.map +1 -1
- package/dist/services/GeminiAIService.js +309 -309
- package/dist/services/IndexManager.d.ts +5 -1
- package/dist/services/IndexManager.d.ts.map +1 -1
- package/dist/services/IndexManager.js +17 -40
- package/dist/services/IndexManager.js.map +1 -1
- package/dist/services/QueryService.js +1 -1
- package/dist/services/QueryService.js.map +1 -1
- package/dist/services/StorageService.d.ts +11 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/dist/services/StorageService.js +73 -10
- package/dist/services/StorageService.js.map +1 -1
- package/dist/services/TransactionService.d.ts +20 -0
- package/dist/services/TransactionService.d.ts.map +1 -1
- package/dist/services/TransactionService.js +43 -0
- package/dist/services/TransactionService.js.map +1 -1
- package/dist/services/ViewService.js +2 -2
- package/dist/services/ViewService.js.map +1 -1
- package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +410 -20
- package/dist/services/storage/QuiltBatchManager.js.map +1 -1
- package/dist/services/storage/index.d.ts +1 -1
- package/dist/services/storage/index.d.ts.map +1 -1
- package/dist/services/storage/index.js.map +1 -1
- package/dist/utils/LRUCache.d.ts +106 -0
- package/dist/utils/LRUCache.d.ts.map +1 -0
- package/dist/utils/LRUCache.js +281 -0
- package/dist/utils/LRUCache.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/memoryIndexOnChain.d.ts +212 -0
- package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
- package/dist/utils/memoryIndexOnChain.js +312 -0
- package/dist/utils/memoryIndexOnChain.js.map +1 -0
- package/dist/utils/rebuildIndexNode.d.ts +29 -0
- package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
- package/dist/utils/rebuildIndexNode.js +366 -98
- package/dist/utils/rebuildIndexNode.js.map +1 -1
- package/dist/vector/HnswWasmService.d.ts +20 -5
- package/dist/vector/HnswWasmService.d.ts.map +1 -1
- package/dist/vector/HnswWasmService.js +73 -40
- package/dist/vector/HnswWasmService.js.map +1 -1
- package/dist/vector/IHnswService.d.ts +10 -1
- package/dist/vector/IHnswService.d.ts.map +1 -1
- package/dist/vector/IHnswService.js.map +1 -1
- package/dist/vector/NodeHnswService.d.ts +16 -0
- package/dist/vector/NodeHnswService.d.ts.map +1 -1
- package/dist/vector/NodeHnswService.js +84 -5
- package/dist/vector/NodeHnswService.js.map +1 -1
- package/dist/vector/createHnswService.d.ts +1 -1
- package/dist/vector/createHnswService.js +1 -1
- package/dist/vector/index.d.ts +1 -1
- package/dist/vector/index.js +1 -1
- package/package.json +157 -157
- package/src/access/PermissionService.ts +635 -635
- package/src/aggregation/AggregationService.ts +389 -389
- package/src/ai-sdk/PDWVectorStore.ts +715 -715
- package/src/ai-sdk/index.ts +65 -65
- package/src/ai-sdk/tools.ts +460 -460
- package/src/ai-sdk/types.ts +404 -404
- package/src/batch/BatchManager.ts +597 -597
- package/src/batch/BatchingService.ts +429 -429
- package/src/batch/MemoryProcessingCache.ts +492 -492
- package/src/batch/index.ts +30 -30
- package/src/browser.ts +200 -200
- package/src/client/ClientMemoryManager.ts +987 -987
- package/src/client/PersonalDataWallet.ts +345 -345
- package/src/client/SimplePDWClient.ts +1289 -1222
- package/src/client/factory.ts +154 -154
- package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
- package/src/client/namespaces/BatchNamespace.ts +356 -356
- package/src/client/namespaces/CacheNamespace.ts +123 -123
- package/src/client/namespaces/CapabilityNamespace.ts +217 -217
- package/src/client/namespaces/ClassifyNamespace.ts +169 -169
- package/src/client/namespaces/ContextNamespace.ts +297 -297
- package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
- package/src/client/namespaces/EncryptionNamespace.ts +221 -221
- package/src/client/namespaces/GraphNamespace.ts +468 -468
- package/src/client/namespaces/IndexNamespace.ts +361 -361
- package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
- package/src/client/namespaces/PermissionsNamespace.ts +254 -254
- package/src/client/namespaces/PipelineNamespace.ts +220 -220
- package/src/client/namespaces/SearchNamespace.ts +1049 -1049
- package/src/client/namespaces/StorageNamespace.ts +458 -458
- package/src/client/namespaces/TxNamespace.ts +260 -260
- package/src/client/namespaces/WalletNamespace.ts +243 -243
- package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
- package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
- package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
- package/src/client/namespaces/consolidated/index.ts +39 -39
- package/src/client/signers/KeypairSigner.ts +108 -108
- package/src/client/signers/UnifiedSigner.ts +110 -110
- package/src/client/signers/WalletAdapterSigner.ts +159 -159
- package/src/client/signers/index.ts +26 -26
- package/src/config/ConfigurationHelper.ts +412 -412
- package/src/config/defaults.ts +51 -51
- package/src/config/index.ts +8 -8
- package/src/config/validation.ts +70 -70
- package/src/core/index.ts +14 -14
- package/src/core/interfaces/IService.ts +307 -307
- package/src/core/interfaces/index.ts +8 -8
- package/src/core/types/capability.ts +297 -297
- package/src/core/types/index.ts +870 -870
- package/src/core/types/wallet.ts +270 -270
- package/src/core/types.ts +9 -9
- package/src/core/wallet.ts +222 -222
- package/src/embedding/index.ts +19 -19
- package/src/embedding/types.ts +357 -357
- package/src/errors/index.ts +602 -602
- package/src/errors/recovery.ts +461 -461
- package/src/errors/validation.ts +567 -567
- package/src/generated/pdw/capability.ts +319 -319
- package/src/graph/GraphService.ts +887 -887
- package/src/graph/KnowledgeGraphManager.ts +728 -728
- package/src/graph/index.ts +25 -25
- package/src/index.ts +498 -474
- package/src/infrastructure/index.ts +22 -22
- package/src/infrastructure/seal/EncryptionService.ts +628 -603
- package/src/infrastructure/seal/SealService.ts +613 -615
- package/src/infrastructure/seal/index.ts +9 -9
- package/src/infrastructure/sui/BlockchainManager.ts +627 -627
- package/src/infrastructure/sui/SuiService.ts +888 -888
- package/src/infrastructure/sui/index.ts +9 -9
- package/src/infrastructure/walrus/StorageManager.ts +604 -604
- package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
- package/src/infrastructure/walrus/index.ts +9 -9
- package/src/langchain/PDWEmbeddings.ts +145 -145
- package/src/langchain/PDWVectorStore.ts +456 -456
- package/src/langchain/createPDWRAG.ts +303 -303
- package/src/langchain/index.ts +47 -47
- package/src/permissions/ConsentRepository.browser.ts +249 -249
- package/src/permissions/ConsentRepository.ts +364 -364
- package/src/pipeline/MemoryPipeline.ts +862 -862
- package/src/pipeline/PipelineManager.ts +683 -683
- package/src/pipeline/index.ts +26 -26
- package/src/retrieval/AdvancedSearchService.ts +629 -629
- package/src/retrieval/MemoryAnalyticsService.ts +711 -711
- package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
- package/src/retrieval/MemoryRetrievalService.ts +904 -830
- package/src/retrieval/index.ts +42 -42
- package/src/services/BatchService.ts +352 -352
- package/src/services/CapabilityService.ts +464 -448
- package/src/services/ClassifierService.ts +465 -465
- package/src/services/CrossContextPermissionService.ts +486 -484
- package/src/services/EmbeddingService.ts +771 -706
- package/src/services/EncryptionService.ts +712 -711
- package/src/services/GeminiAIService.ts +753 -753
- package/src/services/IndexManager.ts +977 -1004
- package/src/services/MemoryIndexService.ts +1003 -1003
- package/src/services/MemoryService.ts +369 -369
- package/src/services/QueryService.ts +890 -890
- package/src/services/StorageService.ts +1182 -1111
- package/src/services/TransactionService.ts +838 -790
- package/src/services/VectorService.ts +462 -462
- package/src/services/ViewService.ts +484 -484
- package/src/services/index.ts +25 -25
- package/src/services/storage/BlobAttributesManager.ts +333 -333
- package/src/services/storage/KnowledgeGraphManager.ts +425 -425
- package/src/services/storage/MemorySearchManager.ts +387 -387
- package/src/services/storage/QuiltBatchManager.ts +1130 -660
- package/src/services/storage/WalrusMetadataManager.ts +268 -268
- package/src/services/storage/WalrusStorageManager.ts +287 -287
- package/src/services/storage/index.ts +57 -52
- package/src/types/index.ts +13 -13
- package/src/utils/LRUCache.ts +378 -0
- package/src/utils/index.ts +76 -68
- package/src/utils/memoryIndexOnChain.ts +507 -0
- package/src/utils/rebuildIndex.ts +290 -290
- package/src/utils/rebuildIndexNode.ts +771 -424
- package/src/vector/BrowserHnswIndexService.ts +758 -758
- package/src/vector/HnswWasmService.ts +731 -679
- package/src/vector/IHnswService.ts +233 -224
- package/src/vector/NodeHnswService.ts +833 -735
- package/src/vector/VectorManager.ts +478 -478
- package/src/vector/createHnswService.ts +135 -135
- package/src/vector/index.ts +56 -56
- package/src/wallet/ContextWalletService.ts +656 -656
- package/src/wallet/MainWalletService.ts +317 -317
|
@@ -1,712 +1,712 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MemoryAnalyticsService - Memory Analytics & Insights
|
|
3
|
-
*
|
|
4
|
-
* Provides comprehensive analytics and insights for memory data including:
|
|
5
|
-
* - Usage pattern analysis
|
|
6
|
-
* - Similarity clustering
|
|
7
|
-
* - Trend analysis and forecasting
|
|
8
|
-
* - Knowledge discovery
|
|
9
|
-
* - Content sentiment analysis
|
|
10
|
-
* - Recommendation engines
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { UnifiedMemoryResult } from './MemoryRetrievalService';
|
|
14
|
-
import { KnowledgeGraphManager } from '../graph/KnowledgeGraphManager';
|
|
15
|
-
import { VectorManager } from '../vector/VectorManager';
|
|
16
|
-
|
|
17
|
-
export interface MemoryAnalytics {
|
|
18
|
-
userId: string;
|
|
19
|
-
periodStart: Date;
|
|
20
|
-
periodEnd: Date;
|
|
21
|
-
|
|
22
|
-
// Basic statistics
|
|
23
|
-
totalMemories: number;
|
|
24
|
-
totalSize: number;
|
|
25
|
-
averageImportance: number;
|
|
26
|
-
|
|
27
|
-
// Usage patterns
|
|
28
|
-
usagePatterns: UsagePattern[];
|
|
29
|
-
|
|
30
|
-
// Content analysis
|
|
31
|
-
topCategories: Array<{ category: string; count: number; percentage: number }>;
|
|
32
|
-
topTags: Array<{ tag: string; count: number; coOccurrences: string[] }>;
|
|
33
|
-
contentDistribution: {
|
|
34
|
-
textContent: number;
|
|
35
|
-
multimedia: number;
|
|
36
|
-
documents: number;
|
|
37
|
-
other: number;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// Temporal analysis
|
|
41
|
-
temporalTrends: {
|
|
42
|
-
creationTrend: TrendAnalysis;
|
|
43
|
-
accessTrend: TrendAnalysis;
|
|
44
|
-
sizeTrend: TrendAnalysis;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// Similarity and clustering
|
|
48
|
-
similarityClusters: SimilarityCluster[];
|
|
49
|
-
|
|
50
|
-
// Knowledge insights
|
|
51
|
-
knowledgeInsights: MemoryInsights;
|
|
52
|
-
|
|
53
|
-
// Performance metrics
|
|
54
|
-
retrievalPerformance: {
|
|
55
|
-
averageRetrievalTime: number;
|
|
56
|
-
cacheHitRate: number;
|
|
57
|
-
popularMemories: string[];
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface UsagePattern {
|
|
62
|
-
type: 'creation' | 'access' | 'modification' | 'sharing';
|
|
63
|
-
pattern: 'daily' | 'weekly' | 'monthly' | 'seasonal' | 'irregular';
|
|
64
|
-
peakTimes: Array<{ period: string; intensity: number }>;
|
|
65
|
-
frequency: number;
|
|
66
|
-
trend: 'increasing' | 'decreasing' | 'stable';
|
|
67
|
-
anomalies: Array<{
|
|
68
|
-
date: Date;
|
|
69
|
-
type: 'spike' | 'drop' | 'outlier';
|
|
70
|
-
severity: number;
|
|
71
|
-
possibleCauses?: string[];
|
|
72
|
-
}>;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface SimilarityCluster {
|
|
76
|
-
id: string;
|
|
77
|
-
label: string;
|
|
78
|
-
memories: string[];
|
|
79
|
-
centroid: number[];
|
|
80
|
-
coherence: number;
|
|
81
|
-
size: number;
|
|
82
|
-
characteristics: {
|
|
83
|
-
dominantTopics: string[];
|
|
84
|
-
averageImportance: number;
|
|
85
|
-
timeSpread: { start: Date; end: Date };
|
|
86
|
-
commonTags: string[];
|
|
87
|
-
};
|
|
88
|
-
relationships: Array<{
|
|
89
|
-
clusterId: string;
|
|
90
|
-
similarity: number;
|
|
91
|
-
sharedMemories: number;
|
|
92
|
-
}>;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export interface TrendAnalysis {
|
|
96
|
-
direction: 'up' | 'down' | 'stable' | 'volatile';
|
|
97
|
-
strength: number; // 0-1
|
|
98
|
-
seasonality: {
|
|
99
|
-
detected: boolean;
|
|
100
|
-
period?: 'daily' | 'weekly' | 'monthly' | 'yearly';
|
|
101
|
-
amplitude?: number;
|
|
102
|
-
};
|
|
103
|
-
forecast: Array<{
|
|
104
|
-
date: Date;
|
|
105
|
-
predicted: number;
|
|
106
|
-
confidence: number;
|
|
107
|
-
upper: number;
|
|
108
|
-
lower: number;
|
|
109
|
-
}>;
|
|
110
|
-
changePoints: Array<{
|
|
111
|
-
date: Date;
|
|
112
|
-
significance: number;
|
|
113
|
-
description: string;
|
|
114
|
-
}>;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export interface MemoryInsights {
|
|
118
|
-
knowledgeDomains: Array<{
|
|
119
|
-
domain: string;
|
|
120
|
-
expertise: number;
|
|
121
|
-
memories: string[];
|
|
122
|
-
keyEntities: string[];
|
|
123
|
-
growthRate: number;
|
|
124
|
-
}>;
|
|
125
|
-
|
|
126
|
-
learningProgression: Array<{
|
|
127
|
-
topic: string;
|
|
128
|
-
startDate: Date;
|
|
129
|
-
currentLevel: number;
|
|
130
|
-
progressRate: number;
|
|
131
|
-
milestones: Array<{
|
|
132
|
-
date: Date;
|
|
133
|
-
achievement: string;
|
|
134
|
-
memoryId: string;
|
|
135
|
-
}>;
|
|
136
|
-
}>;
|
|
137
|
-
|
|
138
|
-
conceptualConnections: Array<{
|
|
139
|
-
concept1: string;
|
|
140
|
-
concept2: string;
|
|
141
|
-
connectionStrength: number;
|
|
142
|
-
bridgeMemories: string[];
|
|
143
|
-
evolutionOverTime: Array<{
|
|
144
|
-
date: Date;
|
|
145
|
-
strength: number;
|
|
146
|
-
}>;
|
|
147
|
-
}>;
|
|
148
|
-
|
|
149
|
-
contentQuality: {
|
|
150
|
-
averageSentiment: number;
|
|
151
|
-
clarityScore: number;
|
|
152
|
-
completenessScore: number;
|
|
153
|
-
originalityScore: number;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
recommendations: Array<{
|
|
157
|
-
type: 'explore' | 'review' | 'connect' | 'expand';
|
|
158
|
-
priority: number;
|
|
159
|
-
title: string;
|
|
160
|
-
description: string;
|
|
161
|
-
memoryIds: string[];
|
|
162
|
-
reasoning: string;
|
|
163
|
-
}>;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Memory Analytics Service
|
|
168
|
-
*/
|
|
169
|
-
export class MemoryAnalyticsService {
|
|
170
|
-
private graphManager: KnowledgeGraphManager;
|
|
171
|
-
private vectorManager: VectorManager | null;
|
|
172
|
-
|
|
173
|
-
// Analytics cache
|
|
174
|
-
private analyticsCache = new Map<string, { analytics: MemoryAnalytics; timestamp: number }>();
|
|
175
|
-
private readonly ANALYTICS_CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
|
176
|
-
|
|
177
|
-
constructor(config?: {
|
|
178
|
-
graphManager?: KnowledgeGraphManager;
|
|
179
|
-
vectorManager?: VectorManager;
|
|
180
|
-
}) {
|
|
181
|
-
this.graphManager = config?.graphManager ?? new KnowledgeGraphManager();
|
|
182
|
-
// VectorManager is optional - some analytics work without it
|
|
183
|
-
this.vectorManager = config?.vectorManager ?? null;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ==================== MAIN ANALYTICS METHODS ====================
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Generate comprehensive analytics for a user's memories
|
|
190
|
-
*/
|
|
191
|
-
async generateMemoryAnalytics(
|
|
192
|
-
userId: string,
|
|
193
|
-
memories: UnifiedMemoryResult[],
|
|
194
|
-
options?: {
|
|
195
|
-
includeForecasting?: boolean;
|
|
196
|
-
includeClustering?: boolean;
|
|
197
|
-
includeInsights?: boolean;
|
|
198
|
-
periodStart?: Date;
|
|
199
|
-
periodEnd?: Date;
|
|
200
|
-
}
|
|
201
|
-
): Promise<MemoryAnalytics> {
|
|
202
|
-
const cacheKey = `analytics:${userId}:${JSON.stringify(options)}`;
|
|
203
|
-
|
|
204
|
-
// Check cache
|
|
205
|
-
const cached = this.getCachedAnalytics(cacheKey);
|
|
206
|
-
if (cached) return cached;
|
|
207
|
-
|
|
208
|
-
const startDate = options?.periodStart || new Date(Date.now() - 90 * 24 * 60 * 60 * 1000); // 90 days ago
|
|
209
|
-
const endDate = options?.periodEnd || new Date();
|
|
210
|
-
|
|
211
|
-
// Filter memories by period
|
|
212
|
-
const periodMemories = memories.filter(m =>
|
|
213
|
-
m.created >= startDate && m.created <= endDate
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
try {
|
|
217
|
-
// Basic statistics
|
|
218
|
-
const basicStats = this.calculateBasicStats(periodMemories);
|
|
219
|
-
|
|
220
|
-
// Usage patterns
|
|
221
|
-
const usagePatterns = await this.analyzeUsagePatterns(periodMemories, userId);
|
|
222
|
-
|
|
223
|
-
// Content analysis
|
|
224
|
-
const contentAnalysis = this.analyzeContent(periodMemories);
|
|
225
|
-
|
|
226
|
-
// Temporal trends
|
|
227
|
-
const temporalTrends = await this.analyzeTempralTrends(
|
|
228
|
-
periodMemories,
|
|
229
|
-
options?.includeForecasting ?? true
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
// Similarity clustering
|
|
233
|
-
let similarityClusters: SimilarityCluster[] = [];
|
|
234
|
-
if (options?.includeClustering !== false) {
|
|
235
|
-
similarityClusters = await this.performSimilarityClustering(periodMemories);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Knowledge insights
|
|
239
|
-
let knowledgeInsights: MemoryInsights = {
|
|
240
|
-
knowledgeDomains: [],
|
|
241
|
-
learningProgression: [],
|
|
242
|
-
conceptualConnections: [],
|
|
243
|
-
contentQuality: {
|
|
244
|
-
averageSentiment: 0.5,
|
|
245
|
-
clarityScore: 0.7,
|
|
246
|
-
completenessScore: 0.8,
|
|
247
|
-
originalityScore: 0.6
|
|
248
|
-
},
|
|
249
|
-
recommendations: []
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
if (options?.includeInsights !== false) {
|
|
253
|
-
knowledgeInsights = await this.generateKnowledgeInsights(periodMemories, userId);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Performance metrics
|
|
257
|
-
const performanceMetrics = this.calculatePerformanceMetrics(periodMemories);
|
|
258
|
-
|
|
259
|
-
const analytics: MemoryAnalytics = {
|
|
260
|
-
userId,
|
|
261
|
-
periodStart: startDate,
|
|
262
|
-
periodEnd: endDate,
|
|
263
|
-
...basicStats,
|
|
264
|
-
usagePatterns,
|
|
265
|
-
...contentAnalysis,
|
|
266
|
-
temporalTrends,
|
|
267
|
-
similarityClusters,
|
|
268
|
-
knowledgeInsights,
|
|
269
|
-
retrievalPerformance: performanceMetrics
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
// Cache results
|
|
273
|
-
this.cacheAnalytics(cacheKey, analytics);
|
|
274
|
-
|
|
275
|
-
return analytics;
|
|
276
|
-
|
|
277
|
-
} catch (error) {
|
|
278
|
-
throw new Error(`Analytics generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Analyze usage patterns over time
|
|
284
|
-
*/
|
|
285
|
-
async analyzeUsagePatterns(
|
|
286
|
-
memories: UnifiedMemoryResult[],
|
|
287
|
-
userId: string
|
|
288
|
-
): Promise<UsagePattern[]> {
|
|
289
|
-
const patterns: UsagePattern[] = [];
|
|
290
|
-
|
|
291
|
-
// Creation pattern
|
|
292
|
-
const creationPattern = this.analyzeCreationPattern(memories);
|
|
293
|
-
patterns.push(creationPattern);
|
|
294
|
-
|
|
295
|
-
// Access pattern (if analytics data is available)
|
|
296
|
-
const accessPattern = this.analyzeAccessPattern(memories);
|
|
297
|
-
patterns.push(accessPattern);
|
|
298
|
-
|
|
299
|
-
return patterns;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Perform similarity-based clustering
|
|
304
|
-
*/
|
|
305
|
-
async performSimilarityClustering(
|
|
306
|
-
memories: UnifiedMemoryResult[],
|
|
307
|
-
options?: {
|
|
308
|
-
numberOfClusters?: number;
|
|
309
|
-
similarityThreshold?: number;
|
|
310
|
-
algorithm?: 'kmeans' | 'hierarchical' | 'dbscan';
|
|
311
|
-
}
|
|
312
|
-
): Promise<SimilarityCluster[]> {
|
|
313
|
-
const clusters: SimilarityCluster[] = [];
|
|
314
|
-
|
|
315
|
-
// Extract embeddings from memories (if available)
|
|
316
|
-
const embeddings = await this.extractEmbeddings(memories);
|
|
317
|
-
|
|
318
|
-
// Perform clustering
|
|
319
|
-
const clusterAssignments = await this.performClustering(
|
|
320
|
-
embeddings,
|
|
321
|
-
options?.algorithm || 'kmeans',
|
|
322
|
-
options?.numberOfClusters || Math.min(10, Math.floor(memories.length / 5))
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
// Build cluster objects
|
|
326
|
-
for (let i = 0; i < clusterAssignments.length; i++) {
|
|
327
|
-
const clusterMemories = memories.filter((_, idx) => clusterAssignments[idx] === i);
|
|
328
|
-
|
|
329
|
-
if (clusterMemories.length > 0) {
|
|
330
|
-
const cluster = await this.buildCluster(clusterMemories, i);
|
|
331
|
-
clusters.push(cluster);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Calculate inter-cluster relationships
|
|
336
|
-
this.calculateClusterRelationships(clusters);
|
|
337
|
-
|
|
338
|
-
return clusters;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Generate knowledge insights from memories
|
|
343
|
-
*/
|
|
344
|
-
async generateKnowledgeInsights(
|
|
345
|
-
memories: UnifiedMemoryResult[],
|
|
346
|
-
userId: string
|
|
347
|
-
): Promise<MemoryInsights> {
|
|
348
|
-
// Analyze knowledge domains
|
|
349
|
-
const knowledgeDomains = await this.identifyKnowledgeDomains(memories);
|
|
350
|
-
|
|
351
|
-
// Track learning progression
|
|
352
|
-
const learningProgression = await this.analyzeLearningProgression(memories);
|
|
353
|
-
|
|
354
|
-
// Find conceptual connections
|
|
355
|
-
const conceptualConnections = await this.findConceptualConnections(memories, userId);
|
|
356
|
-
|
|
357
|
-
// Analyze content quality
|
|
358
|
-
const contentQuality = await this.analyzeContentQuality(memories);
|
|
359
|
-
|
|
360
|
-
// Generate recommendations
|
|
361
|
-
const recommendations = await this.generateRecommendations(
|
|
362
|
-
memories,
|
|
363
|
-
knowledgeDomains,
|
|
364
|
-
learningProgression,
|
|
365
|
-
conceptualConnections
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
return {
|
|
369
|
-
knowledgeDomains,
|
|
370
|
-
learningProgression,
|
|
371
|
-
conceptualConnections,
|
|
372
|
-
contentQuality,
|
|
373
|
-
recommendations
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// ==================== HELPER METHODS ====================
|
|
378
|
-
|
|
379
|
-
private calculateBasicStats(memories: UnifiedMemoryResult[]): {
|
|
380
|
-
totalMemories: number;
|
|
381
|
-
totalSize: number;
|
|
382
|
-
averageImportance: number;
|
|
383
|
-
} {
|
|
384
|
-
const totalMemories = memories.length;
|
|
385
|
-
const totalSize = memories.reduce((sum, m) => sum + m.metadata.size, 0);
|
|
386
|
-
const averageImportance = memories.reduce((sum, m) => sum + m.metadata.importance, 0) / totalMemories || 0;
|
|
387
|
-
|
|
388
|
-
return {
|
|
389
|
-
totalMemories,
|
|
390
|
-
totalSize,
|
|
391
|
-
averageImportance
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
private analyzeContent(memories: UnifiedMemoryResult[]): {
|
|
396
|
-
topCategories: Array<{ category: string; count: number; percentage: number }>;
|
|
397
|
-
topTags: Array<{ tag: string; count: number; coOccurrences: string[] }>;
|
|
398
|
-
contentDistribution: {
|
|
399
|
-
textContent: number;
|
|
400
|
-
multimedia: number;
|
|
401
|
-
documents: number;
|
|
402
|
-
other: number;
|
|
403
|
-
};
|
|
404
|
-
} {
|
|
405
|
-
// Category analysis
|
|
406
|
-
const categoryMap = new Map<string, number>();
|
|
407
|
-
memories.forEach(m => {
|
|
408
|
-
categoryMap.set(m.category, (categoryMap.get(m.category) || 0) + 1);
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
const topCategories = Array.from(categoryMap.entries())
|
|
412
|
-
.map(([category, count]) => ({
|
|
413
|
-
category,
|
|
414
|
-
count,
|
|
415
|
-
percentage: (count / memories.length) * 100
|
|
416
|
-
}))
|
|
417
|
-
.sort((a, b) => b.count - a.count)
|
|
418
|
-
.slice(0, 10);
|
|
419
|
-
|
|
420
|
-
// Tag analysis
|
|
421
|
-
const tagMap = new Map<string, { count: number; coOccurrences: Set<string> }>();
|
|
422
|
-
memories.forEach(m => {
|
|
423
|
-
m.metadata.tags.forEach(tag => {
|
|
424
|
-
if (!tagMap.has(tag)) {
|
|
425
|
-
tagMap.set(tag, { count: 0, coOccurrences: new Set() });
|
|
426
|
-
}
|
|
427
|
-
tagMap.get(tag)!.count++;
|
|
428
|
-
|
|
429
|
-
// Track co-occurrences
|
|
430
|
-
m.metadata.tags.forEach(otherTag => {
|
|
431
|
-
if (otherTag !== tag) {
|
|
432
|
-
tagMap.get(tag)!.coOccurrences.add(otherTag);
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
const topTags = Array.from(tagMap.entries())
|
|
439
|
-
.map(([tag, data]) => ({
|
|
440
|
-
tag,
|
|
441
|
-
count: data.count,
|
|
442
|
-
coOccurrences: Array.from(data.coOccurrences).slice(0, 5)
|
|
443
|
-
}))
|
|
444
|
-
.sort((a, b) => b.count - a.count)
|
|
445
|
-
.slice(0, 20);
|
|
446
|
-
|
|
447
|
-
// Content type distribution
|
|
448
|
-
const contentDistribution = {
|
|
449
|
-
textContent: memories.filter(m => m.metadata.contentType === 'text').length,
|
|
450
|
-
multimedia: memories.filter(m => ['image', 'video', 'audio'].includes(m.metadata.contentType)).length,
|
|
451
|
-
documents: memories.filter(m => ['pdf', 'doc', 'docx'].includes(m.metadata.contentType)).length,
|
|
452
|
-
other: 0
|
|
453
|
-
};
|
|
454
|
-
contentDistribution.other = memories.length -
|
|
455
|
-
contentDistribution.textContent -
|
|
456
|
-
contentDistribution.multimedia -
|
|
457
|
-
contentDistribution.documents;
|
|
458
|
-
|
|
459
|
-
return {
|
|
460
|
-
topCategories,
|
|
461
|
-
topTags,
|
|
462
|
-
contentDistribution
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
private analyzeCreationPattern(memories: UnifiedMemoryResult[]): UsagePattern {
|
|
467
|
-
// Analyze when memories are created
|
|
468
|
-
const hourlyDistribution = new Array(24).fill(0);
|
|
469
|
-
const dailyDistribution = new Array(7).fill(0);
|
|
470
|
-
|
|
471
|
-
memories.forEach(memory => {
|
|
472
|
-
const hour = memory.created.getHours();
|
|
473
|
-
const day = memory.created.getDay();
|
|
474
|
-
hourlyDistribution[hour]++;
|
|
475
|
-
dailyDistribution[day]++;
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
// Find peak times
|
|
479
|
-
const peakHours = hourlyDistribution
|
|
480
|
-
.map((count, hour) => ({ period: `${hour}:00`, intensity: count }))
|
|
481
|
-
.sort((a, b) => b.intensity - a.intensity)
|
|
482
|
-
.slice(0, 3);
|
|
483
|
-
|
|
484
|
-
// Determine pattern type
|
|
485
|
-
const pattern = this.determinePattern(memories.map(m => m.created));
|
|
486
|
-
|
|
487
|
-
return {
|
|
488
|
-
type: 'creation',
|
|
489
|
-
pattern,
|
|
490
|
-
peakTimes: peakHours,
|
|
491
|
-
frequency: memories.length,
|
|
492
|
-
trend: 'stable', // Would need time series analysis
|
|
493
|
-
anomalies: [] // Would detect using statistical methods
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
private analyzeAccessPattern(memories: UnifiedMemoryResult[]): UsagePattern {
|
|
498
|
-
// Placeholder - would analyze access patterns if data available
|
|
499
|
-
return {
|
|
500
|
-
type: 'access',
|
|
501
|
-
pattern: 'irregular',
|
|
502
|
-
peakTimes: [],
|
|
503
|
-
frequency: 0,
|
|
504
|
-
trend: 'stable',
|
|
505
|
-
anomalies: []
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
private determinePattern(dates: Date[]): UsagePattern['pattern'] {
|
|
510
|
-
// Simple pattern detection - could be enhanced with statistical analysis
|
|
511
|
-
if (dates.length < 7) return 'irregular';
|
|
512
|
-
|
|
513
|
-
// Check for daily pattern (consistent creation times)
|
|
514
|
-
const hours = dates.map(d => d.getHours());
|
|
515
|
-
const hourVariance = this.calculateVariance(hours);
|
|
516
|
-
if (hourVariance < 4) return 'daily';
|
|
517
|
-
|
|
518
|
-
// Check for weekly pattern
|
|
519
|
-
const days = dates.map(d => d.getDay());
|
|
520
|
-
const dayVariance = this.calculateVariance(days);
|
|
521
|
-
if (dayVariance < 2) return 'weekly';
|
|
522
|
-
|
|
523
|
-
return 'irregular';
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
private calculateVariance(numbers: number[]): number {
|
|
527
|
-
const mean = numbers.reduce((a, b) => a + b, 0) / numbers.length;
|
|
528
|
-
const variance = numbers.reduce((sum, num) => sum + Math.pow(num - mean, 2), 0) / numbers.length;
|
|
529
|
-
return variance;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Placeholder implementations for complex analytics methods
|
|
533
|
-
private async analyzeTempralTrends(
|
|
534
|
-
memories: UnifiedMemoryResult[],
|
|
535
|
-
includeForecasting: boolean
|
|
536
|
-
): Promise<MemoryAnalytics['temporalTrends']> {
|
|
537
|
-
return {
|
|
538
|
-
creationTrend: {
|
|
539
|
-
direction: 'stable',
|
|
540
|
-
strength: 0.5,
|
|
541
|
-
seasonality: { detected: false },
|
|
542
|
-
forecast: [],
|
|
543
|
-
changePoints: []
|
|
544
|
-
},
|
|
545
|
-
accessTrend: {
|
|
546
|
-
direction: 'stable',
|
|
547
|
-
strength: 0.5,
|
|
548
|
-
seasonality: { detected: false },
|
|
549
|
-
forecast: [],
|
|
550
|
-
changePoints: []
|
|
551
|
-
},
|
|
552
|
-
sizeTrend: {
|
|
553
|
-
direction: 'up',
|
|
554
|
-
strength: 0.3,
|
|
555
|
-
seasonality: { detected: false },
|
|
556
|
-
forecast: [],
|
|
557
|
-
changePoints: []
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
private calculatePerformanceMetrics(memories: UnifiedMemoryResult[]): MemoryAnalytics['retrievalPerformance'] {
|
|
563
|
-
return {
|
|
564
|
-
averageRetrievalTime: 150, // ms
|
|
565
|
-
cacheHitRate: 0.85,
|
|
566
|
-
popularMemories: memories
|
|
567
|
-
.sort((a, b) => (b.analytics?.viewCount || 0) - (a.analytics?.viewCount || 0))
|
|
568
|
-
.slice(0, 10)
|
|
569
|
-
.map(m => m.id)
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
private async extractEmbeddings(memories: UnifiedMemoryResult[]): Promise<number[][]> {
|
|
574
|
-
// Extract or generate embeddings for clustering
|
|
575
|
-
return memories.map(() => new Array(384).fill(0).map(() => Math.random()));
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
private async performClustering(
|
|
579
|
-
embeddings: number[][],
|
|
580
|
-
algorithm: string,
|
|
581
|
-
clusters: number
|
|
582
|
-
): Promise<number[]> {
|
|
583
|
-
// Perform clustering algorithm - simplified k-means
|
|
584
|
-
return embeddings.map((_, i) => i % clusters);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
private async buildCluster(memories: UnifiedMemoryResult[], clusterId: number): Promise<SimilarityCluster> {
|
|
588
|
-
const centroid = new Array(384).fill(0).map(() => Math.random());
|
|
589
|
-
|
|
590
|
-
return {
|
|
591
|
-
id: `cluster_${clusterId}`,
|
|
592
|
-
label: `Memory Cluster ${clusterId + 1}`,
|
|
593
|
-
memories: memories.map(m => m.id),
|
|
594
|
-
centroid,
|
|
595
|
-
coherence: 0.75,
|
|
596
|
-
size: memories.length,
|
|
597
|
-
characteristics: {
|
|
598
|
-
dominantTopics: memories.slice(0, 3).map(m => m.category),
|
|
599
|
-
averageImportance: memories.reduce((sum, m) => sum + m.metadata.importance, 0) / memories.length,
|
|
600
|
-
timeSpread: {
|
|
601
|
-
start: new Date(Math.min(...memories.map(m => m.created.getTime()))),
|
|
602
|
-
end: new Date(Math.max(...memories.map(m => m.created.getTime())))
|
|
603
|
-
},
|
|
604
|
-
commonTags: this.findCommonTags(memories)
|
|
605
|
-
},
|
|
606
|
-
relationships: []
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
private findCommonTags(memories: UnifiedMemoryResult[]): string[] {
|
|
611
|
-
const tagCounts = new Map<string, number>();
|
|
612
|
-
memories.forEach(m => {
|
|
613
|
-
m.metadata.tags.forEach(tag => {
|
|
614
|
-
tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
|
|
615
|
-
});
|
|
616
|
-
});
|
|
617
|
-
|
|
618
|
-
return Array.from(tagCounts.entries())
|
|
619
|
-
.filter(([_, count]) => count >= memories.length * 0.3) // At least 30% of memories
|
|
620
|
-
.map(([tag]) => tag)
|
|
621
|
-
.slice(0, 5);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
private calculateClusterRelationships(clusters: SimilarityCluster[]): void {
|
|
625
|
-
clusters.forEach(cluster => {
|
|
626
|
-
cluster.relationships = clusters
|
|
627
|
-
.filter(other => other.id !== cluster.id)
|
|
628
|
-
.map(other => ({
|
|
629
|
-
clusterId: other.id,
|
|
630
|
-
similarity: this.calculateClusterSimilarity(cluster, other),
|
|
631
|
-
sharedMemories: this.countSharedMemories(cluster, other)
|
|
632
|
-
}))
|
|
633
|
-
.sort((a, b) => b.similarity - a.similarity)
|
|
634
|
-
.slice(0, 3);
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
private calculateClusterSimilarity(cluster1: SimilarityCluster, cluster2: SimilarityCluster): number {
|
|
639
|
-
// Calculate cosine similarity between centroids
|
|
640
|
-
return Math.random() * 0.5 + 0.25; // Placeholder
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
private countSharedMemories(cluster1: SimilarityCluster, cluster2: SimilarityCluster): number {
|
|
644
|
-
return cluster1.memories.filter(id => cluster2.memories.includes(id)).length;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// Knowledge analysis placeholders
|
|
648
|
-
private async identifyKnowledgeDomains(memories: UnifiedMemoryResult[]): Promise<MemoryInsights['knowledgeDomains']> {
|
|
649
|
-
return [];
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
private async analyzeLearningProgression(memories: UnifiedMemoryResult[]): Promise<MemoryInsights['learningProgression']> {
|
|
653
|
-
return [];
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
private async findConceptualConnections(
|
|
657
|
-
memories: UnifiedMemoryResult[],
|
|
658
|
-
userId: string
|
|
659
|
-
): Promise<MemoryInsights['conceptualConnections']> {
|
|
660
|
-
return [];
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
private async analyzeContentQuality(memories: UnifiedMemoryResult[]): Promise<MemoryInsights['contentQuality']> {
|
|
664
|
-
return {
|
|
665
|
-
averageSentiment: 0.65,
|
|
666
|
-
clarityScore: 0.75,
|
|
667
|
-
completenessScore: 0.80,
|
|
668
|
-
originalityScore: 0.70
|
|
669
|
-
};
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
private async generateRecommendations(
|
|
673
|
-
memories: UnifiedMemoryResult[],
|
|
674
|
-
domains: MemoryInsights['knowledgeDomains'],
|
|
675
|
-
progression: MemoryInsights['learningProgression'],
|
|
676
|
-
connections: MemoryInsights['conceptualConnections']
|
|
677
|
-
): Promise<MemoryInsights['recommendations']> {
|
|
678
|
-
return [];
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// ==================== CACHE MANAGEMENT ====================
|
|
682
|
-
|
|
683
|
-
private getCachedAnalytics(key: string): MemoryAnalytics | null {
|
|
684
|
-
const cached = this.analyticsCache.get(key);
|
|
685
|
-
if (cached && Date.now() - cached.timestamp < this.ANALYTICS_CACHE_TTL) {
|
|
686
|
-
return cached.analytics;
|
|
687
|
-
}
|
|
688
|
-
this.analyticsCache.delete(key);
|
|
689
|
-
return null;
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
private cacheAnalytics(key: string, analytics: MemoryAnalytics): void {
|
|
693
|
-
this.analyticsCache.set(key, { analytics, timestamp: Date.now() });
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* Clear analytics cache
|
|
698
|
-
*/
|
|
699
|
-
clearCache(): void {
|
|
700
|
-
this.analyticsCache.clear();
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
/**
|
|
704
|
-
* Get cache statistics
|
|
705
|
-
*/
|
|
706
|
-
getCacheStats(): { entries: number; totalSize: number } {
|
|
707
|
-
return {
|
|
708
|
-
entries: this.analyticsCache.size,
|
|
709
|
-
totalSize: JSON.stringify(Array.from(this.analyticsCache.values())).length
|
|
710
|
-
};
|
|
711
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* MemoryAnalyticsService - Memory Analytics & Insights
|
|
3
|
+
*
|
|
4
|
+
* Provides comprehensive analytics and insights for memory data including:
|
|
5
|
+
* - Usage pattern analysis
|
|
6
|
+
* - Similarity clustering
|
|
7
|
+
* - Trend analysis and forecasting
|
|
8
|
+
* - Knowledge discovery
|
|
9
|
+
* - Content sentiment analysis
|
|
10
|
+
* - Recommendation engines
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { UnifiedMemoryResult } from './MemoryRetrievalService';
|
|
14
|
+
import { KnowledgeGraphManager } from '../graph/KnowledgeGraphManager';
|
|
15
|
+
import { VectorManager } from '../vector/VectorManager';
|
|
16
|
+
|
|
17
|
+
export interface MemoryAnalytics {
|
|
18
|
+
userId: string;
|
|
19
|
+
periodStart: Date;
|
|
20
|
+
periodEnd: Date;
|
|
21
|
+
|
|
22
|
+
// Basic statistics
|
|
23
|
+
totalMemories: number;
|
|
24
|
+
totalSize: number;
|
|
25
|
+
averageImportance: number;
|
|
26
|
+
|
|
27
|
+
// Usage patterns
|
|
28
|
+
usagePatterns: UsagePattern[];
|
|
29
|
+
|
|
30
|
+
// Content analysis
|
|
31
|
+
topCategories: Array<{ category: string; count: number; percentage: number }>;
|
|
32
|
+
topTags: Array<{ tag: string; count: number; coOccurrences: string[] }>;
|
|
33
|
+
contentDistribution: {
|
|
34
|
+
textContent: number;
|
|
35
|
+
multimedia: number;
|
|
36
|
+
documents: number;
|
|
37
|
+
other: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Temporal analysis
|
|
41
|
+
temporalTrends: {
|
|
42
|
+
creationTrend: TrendAnalysis;
|
|
43
|
+
accessTrend: TrendAnalysis;
|
|
44
|
+
sizeTrend: TrendAnalysis;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Similarity and clustering
|
|
48
|
+
similarityClusters: SimilarityCluster[];
|
|
49
|
+
|
|
50
|
+
// Knowledge insights
|
|
51
|
+
knowledgeInsights: MemoryInsights;
|
|
52
|
+
|
|
53
|
+
// Performance metrics
|
|
54
|
+
retrievalPerformance: {
|
|
55
|
+
averageRetrievalTime: number;
|
|
56
|
+
cacheHitRate: number;
|
|
57
|
+
popularMemories: string[];
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface UsagePattern {
|
|
62
|
+
type: 'creation' | 'access' | 'modification' | 'sharing';
|
|
63
|
+
pattern: 'daily' | 'weekly' | 'monthly' | 'seasonal' | 'irregular';
|
|
64
|
+
peakTimes: Array<{ period: string; intensity: number }>;
|
|
65
|
+
frequency: number;
|
|
66
|
+
trend: 'increasing' | 'decreasing' | 'stable';
|
|
67
|
+
anomalies: Array<{
|
|
68
|
+
date: Date;
|
|
69
|
+
type: 'spike' | 'drop' | 'outlier';
|
|
70
|
+
severity: number;
|
|
71
|
+
possibleCauses?: string[];
|
|
72
|
+
}>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface SimilarityCluster {
|
|
76
|
+
id: string;
|
|
77
|
+
label: string;
|
|
78
|
+
memories: string[];
|
|
79
|
+
centroid: number[];
|
|
80
|
+
coherence: number;
|
|
81
|
+
size: number;
|
|
82
|
+
characteristics: {
|
|
83
|
+
dominantTopics: string[];
|
|
84
|
+
averageImportance: number;
|
|
85
|
+
timeSpread: { start: Date; end: Date };
|
|
86
|
+
commonTags: string[];
|
|
87
|
+
};
|
|
88
|
+
relationships: Array<{
|
|
89
|
+
clusterId: string;
|
|
90
|
+
similarity: number;
|
|
91
|
+
sharedMemories: number;
|
|
92
|
+
}>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface TrendAnalysis {
|
|
96
|
+
direction: 'up' | 'down' | 'stable' | 'volatile';
|
|
97
|
+
strength: number; // 0-1
|
|
98
|
+
seasonality: {
|
|
99
|
+
detected: boolean;
|
|
100
|
+
period?: 'daily' | 'weekly' | 'monthly' | 'yearly';
|
|
101
|
+
amplitude?: number;
|
|
102
|
+
};
|
|
103
|
+
forecast: Array<{
|
|
104
|
+
date: Date;
|
|
105
|
+
predicted: number;
|
|
106
|
+
confidence: number;
|
|
107
|
+
upper: number;
|
|
108
|
+
lower: number;
|
|
109
|
+
}>;
|
|
110
|
+
changePoints: Array<{
|
|
111
|
+
date: Date;
|
|
112
|
+
significance: number;
|
|
113
|
+
description: string;
|
|
114
|
+
}>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface MemoryInsights {
|
|
118
|
+
knowledgeDomains: Array<{
|
|
119
|
+
domain: string;
|
|
120
|
+
expertise: number;
|
|
121
|
+
memories: string[];
|
|
122
|
+
keyEntities: string[];
|
|
123
|
+
growthRate: number;
|
|
124
|
+
}>;
|
|
125
|
+
|
|
126
|
+
learningProgression: Array<{
|
|
127
|
+
topic: string;
|
|
128
|
+
startDate: Date;
|
|
129
|
+
currentLevel: number;
|
|
130
|
+
progressRate: number;
|
|
131
|
+
milestones: Array<{
|
|
132
|
+
date: Date;
|
|
133
|
+
achievement: string;
|
|
134
|
+
memoryId: string;
|
|
135
|
+
}>;
|
|
136
|
+
}>;
|
|
137
|
+
|
|
138
|
+
conceptualConnections: Array<{
|
|
139
|
+
concept1: string;
|
|
140
|
+
concept2: string;
|
|
141
|
+
connectionStrength: number;
|
|
142
|
+
bridgeMemories: string[];
|
|
143
|
+
evolutionOverTime: Array<{
|
|
144
|
+
date: Date;
|
|
145
|
+
strength: number;
|
|
146
|
+
}>;
|
|
147
|
+
}>;
|
|
148
|
+
|
|
149
|
+
contentQuality: {
|
|
150
|
+
averageSentiment: number;
|
|
151
|
+
clarityScore: number;
|
|
152
|
+
completenessScore: number;
|
|
153
|
+
originalityScore: number;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
recommendations: Array<{
|
|
157
|
+
type: 'explore' | 'review' | 'connect' | 'expand';
|
|
158
|
+
priority: number;
|
|
159
|
+
title: string;
|
|
160
|
+
description: string;
|
|
161
|
+
memoryIds: string[];
|
|
162
|
+
reasoning: string;
|
|
163
|
+
}>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Memory Analytics Service
|
|
168
|
+
*/
|
|
169
|
+
export class MemoryAnalyticsService {
|
|
170
|
+
private graphManager: KnowledgeGraphManager;
|
|
171
|
+
private vectorManager: VectorManager | null;
|
|
172
|
+
|
|
173
|
+
// Analytics cache
|
|
174
|
+
private analyticsCache = new Map<string, { analytics: MemoryAnalytics; timestamp: number }>();
|
|
175
|
+
private readonly ANALYTICS_CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
|
176
|
+
|
|
177
|
+
constructor(config?: {
|
|
178
|
+
graphManager?: KnowledgeGraphManager;
|
|
179
|
+
vectorManager?: VectorManager;
|
|
180
|
+
}) {
|
|
181
|
+
this.graphManager = config?.graphManager ?? new KnowledgeGraphManager();
|
|
182
|
+
// VectorManager is optional - some analytics work without it
|
|
183
|
+
this.vectorManager = config?.vectorManager ?? null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ==================== MAIN ANALYTICS METHODS ====================
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Generate comprehensive analytics for a user's memories
|
|
190
|
+
*/
|
|
191
|
+
async generateMemoryAnalytics(
|
|
192
|
+
userId: string,
|
|
193
|
+
memories: UnifiedMemoryResult[],
|
|
194
|
+
options?: {
|
|
195
|
+
includeForecasting?: boolean;
|
|
196
|
+
includeClustering?: boolean;
|
|
197
|
+
includeInsights?: boolean;
|
|
198
|
+
periodStart?: Date;
|
|
199
|
+
periodEnd?: Date;
|
|
200
|
+
}
|
|
201
|
+
): Promise<MemoryAnalytics> {
|
|
202
|
+
const cacheKey = `analytics:${userId}:${JSON.stringify(options)}`;
|
|
203
|
+
|
|
204
|
+
// Check cache
|
|
205
|
+
const cached = this.getCachedAnalytics(cacheKey);
|
|
206
|
+
if (cached) return cached;
|
|
207
|
+
|
|
208
|
+
const startDate = options?.periodStart || new Date(Date.now() - 90 * 24 * 60 * 60 * 1000); // 90 days ago
|
|
209
|
+
const endDate = options?.periodEnd || new Date();
|
|
210
|
+
|
|
211
|
+
// Filter memories by period
|
|
212
|
+
const periodMemories = memories.filter(m =>
|
|
213
|
+
m.created >= startDate && m.created <= endDate
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
// Basic statistics
|
|
218
|
+
const basicStats = this.calculateBasicStats(periodMemories);
|
|
219
|
+
|
|
220
|
+
// Usage patterns
|
|
221
|
+
const usagePatterns = await this.analyzeUsagePatterns(periodMemories, userId);
|
|
222
|
+
|
|
223
|
+
// Content analysis
|
|
224
|
+
const contentAnalysis = this.analyzeContent(periodMemories);
|
|
225
|
+
|
|
226
|
+
// Temporal trends
|
|
227
|
+
const temporalTrends = await this.analyzeTempralTrends(
|
|
228
|
+
periodMemories,
|
|
229
|
+
options?.includeForecasting ?? true
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// Similarity clustering
|
|
233
|
+
let similarityClusters: SimilarityCluster[] = [];
|
|
234
|
+
if (options?.includeClustering !== false) {
|
|
235
|
+
similarityClusters = await this.performSimilarityClustering(periodMemories);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Knowledge insights
|
|
239
|
+
let knowledgeInsights: MemoryInsights = {
|
|
240
|
+
knowledgeDomains: [],
|
|
241
|
+
learningProgression: [],
|
|
242
|
+
conceptualConnections: [],
|
|
243
|
+
contentQuality: {
|
|
244
|
+
averageSentiment: 0.5,
|
|
245
|
+
clarityScore: 0.7,
|
|
246
|
+
completenessScore: 0.8,
|
|
247
|
+
originalityScore: 0.6
|
|
248
|
+
},
|
|
249
|
+
recommendations: []
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
if (options?.includeInsights !== false) {
|
|
253
|
+
knowledgeInsights = await this.generateKnowledgeInsights(periodMemories, userId);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Performance metrics
|
|
257
|
+
const performanceMetrics = this.calculatePerformanceMetrics(periodMemories);
|
|
258
|
+
|
|
259
|
+
const analytics: MemoryAnalytics = {
|
|
260
|
+
userId,
|
|
261
|
+
periodStart: startDate,
|
|
262
|
+
periodEnd: endDate,
|
|
263
|
+
...basicStats,
|
|
264
|
+
usagePatterns,
|
|
265
|
+
...contentAnalysis,
|
|
266
|
+
temporalTrends,
|
|
267
|
+
similarityClusters,
|
|
268
|
+
knowledgeInsights,
|
|
269
|
+
retrievalPerformance: performanceMetrics
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Cache results
|
|
273
|
+
this.cacheAnalytics(cacheKey, analytics);
|
|
274
|
+
|
|
275
|
+
return analytics;
|
|
276
|
+
|
|
277
|
+
} catch (error) {
|
|
278
|
+
throw new Error(`Analytics generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Analyze usage patterns over time
|
|
284
|
+
*/
|
|
285
|
+
async analyzeUsagePatterns(
|
|
286
|
+
memories: UnifiedMemoryResult[],
|
|
287
|
+
userId: string
|
|
288
|
+
): Promise<UsagePattern[]> {
|
|
289
|
+
const patterns: UsagePattern[] = [];
|
|
290
|
+
|
|
291
|
+
// Creation pattern
|
|
292
|
+
const creationPattern = this.analyzeCreationPattern(memories);
|
|
293
|
+
patterns.push(creationPattern);
|
|
294
|
+
|
|
295
|
+
// Access pattern (if analytics data is available)
|
|
296
|
+
const accessPattern = this.analyzeAccessPattern(memories);
|
|
297
|
+
patterns.push(accessPattern);
|
|
298
|
+
|
|
299
|
+
return patterns;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Perform similarity-based clustering
|
|
304
|
+
*/
|
|
305
|
+
async performSimilarityClustering(
|
|
306
|
+
memories: UnifiedMemoryResult[],
|
|
307
|
+
options?: {
|
|
308
|
+
numberOfClusters?: number;
|
|
309
|
+
similarityThreshold?: number;
|
|
310
|
+
algorithm?: 'kmeans' | 'hierarchical' | 'dbscan';
|
|
311
|
+
}
|
|
312
|
+
): Promise<SimilarityCluster[]> {
|
|
313
|
+
const clusters: SimilarityCluster[] = [];
|
|
314
|
+
|
|
315
|
+
// Extract embeddings from memories (if available)
|
|
316
|
+
const embeddings = await this.extractEmbeddings(memories);
|
|
317
|
+
|
|
318
|
+
// Perform clustering
|
|
319
|
+
const clusterAssignments = await this.performClustering(
|
|
320
|
+
embeddings,
|
|
321
|
+
options?.algorithm || 'kmeans',
|
|
322
|
+
options?.numberOfClusters || Math.min(10, Math.floor(memories.length / 5))
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// Build cluster objects
|
|
326
|
+
for (let i = 0; i < clusterAssignments.length; i++) {
|
|
327
|
+
const clusterMemories = memories.filter((_, idx) => clusterAssignments[idx] === i);
|
|
328
|
+
|
|
329
|
+
if (clusterMemories.length > 0) {
|
|
330
|
+
const cluster = await this.buildCluster(clusterMemories, i);
|
|
331
|
+
clusters.push(cluster);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Calculate inter-cluster relationships
|
|
336
|
+
this.calculateClusterRelationships(clusters);
|
|
337
|
+
|
|
338
|
+
return clusters;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Generate knowledge insights from memories
|
|
343
|
+
*/
|
|
344
|
+
async generateKnowledgeInsights(
|
|
345
|
+
memories: UnifiedMemoryResult[],
|
|
346
|
+
userId: string
|
|
347
|
+
): Promise<MemoryInsights> {
|
|
348
|
+
// Analyze knowledge domains
|
|
349
|
+
const knowledgeDomains = await this.identifyKnowledgeDomains(memories);
|
|
350
|
+
|
|
351
|
+
// Track learning progression
|
|
352
|
+
const learningProgression = await this.analyzeLearningProgression(memories);
|
|
353
|
+
|
|
354
|
+
// Find conceptual connections
|
|
355
|
+
const conceptualConnections = await this.findConceptualConnections(memories, userId);
|
|
356
|
+
|
|
357
|
+
// Analyze content quality
|
|
358
|
+
const contentQuality = await this.analyzeContentQuality(memories);
|
|
359
|
+
|
|
360
|
+
// Generate recommendations
|
|
361
|
+
const recommendations = await this.generateRecommendations(
|
|
362
|
+
memories,
|
|
363
|
+
knowledgeDomains,
|
|
364
|
+
learningProgression,
|
|
365
|
+
conceptualConnections
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
knowledgeDomains,
|
|
370
|
+
learningProgression,
|
|
371
|
+
conceptualConnections,
|
|
372
|
+
contentQuality,
|
|
373
|
+
recommendations
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ==================== HELPER METHODS ====================
|
|
378
|
+
|
|
379
|
+
private calculateBasicStats(memories: UnifiedMemoryResult[]): {
|
|
380
|
+
totalMemories: number;
|
|
381
|
+
totalSize: number;
|
|
382
|
+
averageImportance: number;
|
|
383
|
+
} {
|
|
384
|
+
const totalMemories = memories.length;
|
|
385
|
+
const totalSize = memories.reduce((sum, m) => sum + m.metadata.size, 0);
|
|
386
|
+
const averageImportance = memories.reduce((sum, m) => sum + m.metadata.importance, 0) / totalMemories || 0;
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
totalMemories,
|
|
390
|
+
totalSize,
|
|
391
|
+
averageImportance
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private analyzeContent(memories: UnifiedMemoryResult[]): {
|
|
396
|
+
topCategories: Array<{ category: string; count: number; percentage: number }>;
|
|
397
|
+
topTags: Array<{ tag: string; count: number; coOccurrences: string[] }>;
|
|
398
|
+
contentDistribution: {
|
|
399
|
+
textContent: number;
|
|
400
|
+
multimedia: number;
|
|
401
|
+
documents: number;
|
|
402
|
+
other: number;
|
|
403
|
+
};
|
|
404
|
+
} {
|
|
405
|
+
// Category analysis
|
|
406
|
+
const categoryMap = new Map<string, number>();
|
|
407
|
+
memories.forEach(m => {
|
|
408
|
+
categoryMap.set(m.category, (categoryMap.get(m.category) || 0) + 1);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
const topCategories = Array.from(categoryMap.entries())
|
|
412
|
+
.map(([category, count]) => ({
|
|
413
|
+
category,
|
|
414
|
+
count,
|
|
415
|
+
percentage: (count / memories.length) * 100
|
|
416
|
+
}))
|
|
417
|
+
.sort((a, b) => b.count - a.count)
|
|
418
|
+
.slice(0, 10);
|
|
419
|
+
|
|
420
|
+
// Tag analysis
|
|
421
|
+
const tagMap = new Map<string, { count: number; coOccurrences: Set<string> }>();
|
|
422
|
+
memories.forEach(m => {
|
|
423
|
+
m.metadata.tags.forEach(tag => {
|
|
424
|
+
if (!tagMap.has(tag)) {
|
|
425
|
+
tagMap.set(tag, { count: 0, coOccurrences: new Set() });
|
|
426
|
+
}
|
|
427
|
+
tagMap.get(tag)!.count++;
|
|
428
|
+
|
|
429
|
+
// Track co-occurrences
|
|
430
|
+
m.metadata.tags.forEach(otherTag => {
|
|
431
|
+
if (otherTag !== tag) {
|
|
432
|
+
tagMap.get(tag)!.coOccurrences.add(otherTag);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
const topTags = Array.from(tagMap.entries())
|
|
439
|
+
.map(([tag, data]) => ({
|
|
440
|
+
tag,
|
|
441
|
+
count: data.count,
|
|
442
|
+
coOccurrences: Array.from(data.coOccurrences).slice(0, 5)
|
|
443
|
+
}))
|
|
444
|
+
.sort((a, b) => b.count - a.count)
|
|
445
|
+
.slice(0, 20);
|
|
446
|
+
|
|
447
|
+
// Content type distribution
|
|
448
|
+
const contentDistribution = {
|
|
449
|
+
textContent: memories.filter(m => m.metadata.contentType === 'text').length,
|
|
450
|
+
multimedia: memories.filter(m => ['image', 'video', 'audio'].includes(m.metadata.contentType)).length,
|
|
451
|
+
documents: memories.filter(m => ['pdf', 'doc', 'docx'].includes(m.metadata.contentType)).length,
|
|
452
|
+
other: 0
|
|
453
|
+
};
|
|
454
|
+
contentDistribution.other = memories.length -
|
|
455
|
+
contentDistribution.textContent -
|
|
456
|
+
contentDistribution.multimedia -
|
|
457
|
+
contentDistribution.documents;
|
|
458
|
+
|
|
459
|
+
return {
|
|
460
|
+
topCategories,
|
|
461
|
+
topTags,
|
|
462
|
+
contentDistribution
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
private analyzeCreationPattern(memories: UnifiedMemoryResult[]): UsagePattern {
|
|
467
|
+
// Analyze when memories are created
|
|
468
|
+
const hourlyDistribution = new Array(24).fill(0);
|
|
469
|
+
const dailyDistribution = new Array(7).fill(0);
|
|
470
|
+
|
|
471
|
+
memories.forEach(memory => {
|
|
472
|
+
const hour = memory.created.getHours();
|
|
473
|
+
const day = memory.created.getDay();
|
|
474
|
+
hourlyDistribution[hour]++;
|
|
475
|
+
dailyDistribution[day]++;
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// Find peak times
|
|
479
|
+
const peakHours = hourlyDistribution
|
|
480
|
+
.map((count, hour) => ({ period: `${hour}:00`, intensity: count }))
|
|
481
|
+
.sort((a, b) => b.intensity - a.intensity)
|
|
482
|
+
.slice(0, 3);
|
|
483
|
+
|
|
484
|
+
// Determine pattern type
|
|
485
|
+
const pattern = this.determinePattern(memories.map(m => m.created));
|
|
486
|
+
|
|
487
|
+
return {
|
|
488
|
+
type: 'creation',
|
|
489
|
+
pattern,
|
|
490
|
+
peakTimes: peakHours,
|
|
491
|
+
frequency: memories.length,
|
|
492
|
+
trend: 'stable', // Would need time series analysis
|
|
493
|
+
anomalies: [] // Would detect using statistical methods
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
private analyzeAccessPattern(memories: UnifiedMemoryResult[]): UsagePattern {
|
|
498
|
+
// Placeholder - would analyze access patterns if data available
|
|
499
|
+
return {
|
|
500
|
+
type: 'access',
|
|
501
|
+
pattern: 'irregular',
|
|
502
|
+
peakTimes: [],
|
|
503
|
+
frequency: 0,
|
|
504
|
+
trend: 'stable',
|
|
505
|
+
anomalies: []
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
private determinePattern(dates: Date[]): UsagePattern['pattern'] {
|
|
510
|
+
// Simple pattern detection - could be enhanced with statistical analysis
|
|
511
|
+
if (dates.length < 7) return 'irregular';
|
|
512
|
+
|
|
513
|
+
// Check for daily pattern (consistent creation times)
|
|
514
|
+
const hours = dates.map(d => d.getHours());
|
|
515
|
+
const hourVariance = this.calculateVariance(hours);
|
|
516
|
+
if (hourVariance < 4) return 'daily';
|
|
517
|
+
|
|
518
|
+
// Check for weekly pattern
|
|
519
|
+
const days = dates.map(d => d.getDay());
|
|
520
|
+
const dayVariance = this.calculateVariance(days);
|
|
521
|
+
if (dayVariance < 2) return 'weekly';
|
|
522
|
+
|
|
523
|
+
return 'irregular';
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
private calculateVariance(numbers: number[]): number {
|
|
527
|
+
const mean = numbers.reduce((a, b) => a + b, 0) / numbers.length;
|
|
528
|
+
const variance = numbers.reduce((sum, num) => sum + Math.pow(num - mean, 2), 0) / numbers.length;
|
|
529
|
+
return variance;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Placeholder implementations for complex analytics methods
|
|
533
|
+
private async analyzeTempralTrends(
|
|
534
|
+
memories: UnifiedMemoryResult[],
|
|
535
|
+
includeForecasting: boolean
|
|
536
|
+
): Promise<MemoryAnalytics['temporalTrends']> {
|
|
537
|
+
return {
|
|
538
|
+
creationTrend: {
|
|
539
|
+
direction: 'stable',
|
|
540
|
+
strength: 0.5,
|
|
541
|
+
seasonality: { detected: false },
|
|
542
|
+
forecast: [],
|
|
543
|
+
changePoints: []
|
|
544
|
+
},
|
|
545
|
+
accessTrend: {
|
|
546
|
+
direction: 'stable',
|
|
547
|
+
strength: 0.5,
|
|
548
|
+
seasonality: { detected: false },
|
|
549
|
+
forecast: [],
|
|
550
|
+
changePoints: []
|
|
551
|
+
},
|
|
552
|
+
sizeTrend: {
|
|
553
|
+
direction: 'up',
|
|
554
|
+
strength: 0.3,
|
|
555
|
+
seasonality: { detected: false },
|
|
556
|
+
forecast: [],
|
|
557
|
+
changePoints: []
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private calculatePerformanceMetrics(memories: UnifiedMemoryResult[]): MemoryAnalytics['retrievalPerformance'] {
|
|
563
|
+
return {
|
|
564
|
+
averageRetrievalTime: 150, // ms
|
|
565
|
+
cacheHitRate: 0.85,
|
|
566
|
+
popularMemories: memories
|
|
567
|
+
.sort((a, b) => (b.analytics?.viewCount || 0) - (a.analytics?.viewCount || 0))
|
|
568
|
+
.slice(0, 10)
|
|
569
|
+
.map(m => m.id)
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private async extractEmbeddings(memories: UnifiedMemoryResult[]): Promise<number[][]> {
|
|
574
|
+
// Extract or generate embeddings for clustering
|
|
575
|
+
return memories.map(() => new Array(384).fill(0).map(() => Math.random()));
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
private async performClustering(
|
|
579
|
+
embeddings: number[][],
|
|
580
|
+
algorithm: string,
|
|
581
|
+
clusters: number
|
|
582
|
+
): Promise<number[]> {
|
|
583
|
+
// Perform clustering algorithm - simplified k-means
|
|
584
|
+
return embeddings.map((_, i) => i % clusters);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
private async buildCluster(memories: UnifiedMemoryResult[], clusterId: number): Promise<SimilarityCluster> {
|
|
588
|
+
const centroid = new Array(384).fill(0).map(() => Math.random());
|
|
589
|
+
|
|
590
|
+
return {
|
|
591
|
+
id: `cluster_${clusterId}`,
|
|
592
|
+
label: `Memory Cluster ${clusterId + 1}`,
|
|
593
|
+
memories: memories.map(m => m.id),
|
|
594
|
+
centroid,
|
|
595
|
+
coherence: 0.75,
|
|
596
|
+
size: memories.length,
|
|
597
|
+
characteristics: {
|
|
598
|
+
dominantTopics: memories.slice(0, 3).map(m => m.category),
|
|
599
|
+
averageImportance: memories.reduce((sum, m) => sum + m.metadata.importance, 0) / memories.length,
|
|
600
|
+
timeSpread: {
|
|
601
|
+
start: new Date(Math.min(...memories.map(m => m.created.getTime()))),
|
|
602
|
+
end: new Date(Math.max(...memories.map(m => m.created.getTime())))
|
|
603
|
+
},
|
|
604
|
+
commonTags: this.findCommonTags(memories)
|
|
605
|
+
},
|
|
606
|
+
relationships: []
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private findCommonTags(memories: UnifiedMemoryResult[]): string[] {
|
|
611
|
+
const tagCounts = new Map<string, number>();
|
|
612
|
+
memories.forEach(m => {
|
|
613
|
+
m.metadata.tags.forEach(tag => {
|
|
614
|
+
tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
return Array.from(tagCounts.entries())
|
|
619
|
+
.filter(([_, count]) => count >= memories.length * 0.3) // At least 30% of memories
|
|
620
|
+
.map(([tag]) => tag)
|
|
621
|
+
.slice(0, 5);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private calculateClusterRelationships(clusters: SimilarityCluster[]): void {
|
|
625
|
+
clusters.forEach(cluster => {
|
|
626
|
+
cluster.relationships = clusters
|
|
627
|
+
.filter(other => other.id !== cluster.id)
|
|
628
|
+
.map(other => ({
|
|
629
|
+
clusterId: other.id,
|
|
630
|
+
similarity: this.calculateClusterSimilarity(cluster, other),
|
|
631
|
+
sharedMemories: this.countSharedMemories(cluster, other)
|
|
632
|
+
}))
|
|
633
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
634
|
+
.slice(0, 3);
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
private calculateClusterSimilarity(cluster1: SimilarityCluster, cluster2: SimilarityCluster): number {
|
|
639
|
+
// Calculate cosine similarity between centroids
|
|
640
|
+
return Math.random() * 0.5 + 0.25; // Placeholder
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
private countSharedMemories(cluster1: SimilarityCluster, cluster2: SimilarityCluster): number {
|
|
644
|
+
return cluster1.memories.filter(id => cluster2.memories.includes(id)).length;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Knowledge analysis placeholders
|
|
648
|
+
private async identifyKnowledgeDomains(memories: UnifiedMemoryResult[]): Promise<MemoryInsights['knowledgeDomains']> {
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
private async analyzeLearningProgression(memories: UnifiedMemoryResult[]): Promise<MemoryInsights['learningProgression']> {
|
|
653
|
+
return [];
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
private async findConceptualConnections(
|
|
657
|
+
memories: UnifiedMemoryResult[],
|
|
658
|
+
userId: string
|
|
659
|
+
): Promise<MemoryInsights['conceptualConnections']> {
|
|
660
|
+
return [];
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
private async analyzeContentQuality(memories: UnifiedMemoryResult[]): Promise<MemoryInsights['contentQuality']> {
|
|
664
|
+
return {
|
|
665
|
+
averageSentiment: 0.65,
|
|
666
|
+
clarityScore: 0.75,
|
|
667
|
+
completenessScore: 0.80,
|
|
668
|
+
originalityScore: 0.70
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
private async generateRecommendations(
|
|
673
|
+
memories: UnifiedMemoryResult[],
|
|
674
|
+
domains: MemoryInsights['knowledgeDomains'],
|
|
675
|
+
progression: MemoryInsights['learningProgression'],
|
|
676
|
+
connections: MemoryInsights['conceptualConnections']
|
|
677
|
+
): Promise<MemoryInsights['recommendations']> {
|
|
678
|
+
return [];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// ==================== CACHE MANAGEMENT ====================
|
|
682
|
+
|
|
683
|
+
private getCachedAnalytics(key: string): MemoryAnalytics | null {
|
|
684
|
+
const cached = this.analyticsCache.get(key);
|
|
685
|
+
if (cached && Date.now() - cached.timestamp < this.ANALYTICS_CACHE_TTL) {
|
|
686
|
+
return cached.analytics;
|
|
687
|
+
}
|
|
688
|
+
this.analyticsCache.delete(key);
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
private cacheAnalytics(key: string, analytics: MemoryAnalytics): void {
|
|
693
|
+
this.analyticsCache.set(key, { analytics, timestamp: Date.now() });
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Clear analytics cache
|
|
698
|
+
*/
|
|
699
|
+
clearCache(): void {
|
|
700
|
+
this.analyticsCache.clear();
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Get cache statistics
|
|
705
|
+
*/
|
|
706
|
+
getCacheStats(): { entries: number; totalSize: number } {
|
|
707
|
+
return {
|
|
708
|
+
entries: this.analyticsCache.size,
|
|
709
|
+
totalSize: JSON.stringify(Array.from(this.analyticsCache.values())).length
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
712
|
}
|