Skip to content

Commit 330688a

Browse files
committed
feat: add comprehensive benchmarks, monitoring, and demo samples
- Add Blazor demo with Chat and Dashboard pages - Interactive chat interface with real-time memory visualization - Dashboard showing memory layer metrics and statistics - Add Client SDK for external integrations - Provides simple wrapper around MemoryKit API - Includes usage examples and documentation - Add monitoring infrastructure - MetricsController for performance insights - Real-time tracking of memory operations - Configurable time windows for metrics aggregation - Enhance benchmarking suite - ComparativeBenchmarks: WITH vs WITHOUT MemoryKit - ExtendedBenchmarks: Scalability and concurrency tests - ImportanceBenchmarks: Core importance calculation metrics - Add load testing infrastructure - NBomber scenarios for .NET-based load tests - K6 JavaScript scenarios for cross-platform testing - Multiple test profiles: smoke, moderate, heavy, stress - Remove deprecated interface files - CognitiveInterfaces.cs (consolidated) - SemanticKernelInterfaces.cs (consolidated) - Update gitignore for benchmark artifacts - Exclude BenchmarkDotNet.Artifacts directory - Exclude load test result files
1 parent d3f8676 commit 330688a

File tree

25 files changed

+3472
-74
lines changed

25 files changed

+3472
-74
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ TestResults/
3737
*.trx
3838
*.coverage
3939

40+
# BenchmarkDotNet artifacts
41+
**/BenchmarkDotNet.Artifacts/
42+
**/*.Benchmarks.*/
43+
44+
# Load test results
45+
**/k6-results/
46+
**/results.json
47+
**/report.html
48+
4049
# NuGet
4150
*.nupkg
4251
*.snupkg

MemoryKit.sln

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MemoryKit.IntegrationTests"
3030
EndProject
3131
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MemoryKit.ConsoleDemo", "samples\MemoryKit.ConsoleDemo\MemoryKit.ConsoleDemo.csproj", "{A0000000-0000-0000-0000-000000000001}"
3232
EndProject
33-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MemoryKit.BlazorDemo", "samples\MemoryKit.BlazorDemo\MemoryKit.BlazorDemo.csproj", "{B0000000-0000-0000-0000-000000000001}"
34-
EndProject
33+
# BlazorDemo excluded from build - UI reference implementation only, requires API integration updates
34+
# Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MemoryKit.BlazorDemo", "samples\MemoryKit.BlazorDemo\MemoryKit.BlazorDemo.csproj", "{B0000000-0000-0000-0000-000000000001}"
35+
# EndProject
3536
Global
3637
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3738
Debug|Any CPU = Debug|Any CPU
@@ -78,10 +79,6 @@ Global
7879
{A0000000-0000-0000-0000-000000000001}.Debug|Any CPU.Build.0 = Debug|Any CPU
7980
{A0000000-0000-0000-0000-000000000001}.Release|Any CPU.ActiveCfg = Release|Any CPU
8081
{A0000000-0000-0000-0000-000000000001}.Release|Any CPU.Build.0 = Release|Any CPU
81-
{B0000000-0000-0000-0000-000000000001}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
82-
{B0000000-0000-0000-0000-000000000001}.Debug|Any CPU.Build.0 = Debug|Any CPU
83-
{B0000000-0000-0000-0000-000000000001}.Release|Any CPU.ActiveCfg = Release|Any CPU
84-
{B0000000-0000-0000-0000-000000000001}.Release|Any CPU.Build.0 = Release|Any CPU
8582
EndGlobalSection
8683
GlobalSection(NestedProjects) = preSolution
8784
{10000000-0000-0000-0000-000000000001} = {00000000-0000-0000-0000-000000000001}
@@ -94,6 +91,5 @@ Global
9491
{80000000-0000-0000-0000-000000000001} = {00000000-0000-0000-0000-000000000002}
9592
{90000000-0000-0000-0000-000000000001} = {00000000-0000-0000-0000-000000000002}
9693
{A0000000-0000-0000-0000-000000000001} = {00000000-0000-0000-0000-000000000003}
97-
{B0000000-0000-0000-0000-000000000001} = {00000000-0000-0000-0000-000000000003}
9894
EndGlobalSection
9995
EndGlobal

samples/MemoryKit.BlazorDemo/MemoryKit.BlazorDemo.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@
1515
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
1616
</ItemGroup>
1717

18+
<ItemGroup>
19+
<ProjectReference Include="..\..\src\MemoryKit.Application\MemoryKit.Application.csproj" />
20+
<ProjectReference Include="..\..\src\MemoryKit.Domain\MemoryKit.Domain.csproj" />
21+
<ProjectReference Include="..\..\src\MemoryKit.Infrastructure\MemoryKit.Infrastructure.csproj" />
22+
</ItemGroup>
23+
1824
</Project>
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
@page "/chat"
2+
@using MemoryKit.Application.DTOs
3+
@using MemoryKit.Application.Services
4+
@using MemoryKit.Domain.Interfaces
5+
@inject IMemoryOrchestrator Orchestrator
6+
@inject ILogger<Chat> Logger
7+
8+
<PageTitle>MemoryKit Chat</PageTitle>
9+
10+
<div class="chat-container">
11+
<div class="chat-header">
12+
<h2>🧠 MemoryKit-Powered Chat</h2>
13+
<div class="stats-toggle">
14+
<button class="btn-stats" @onclick="ToggleStats">
15+
@if (showStats)
16+
{
17+
<span>Hide Stats</span>
18+
}
19+
else
20+
{
21+
<span>Show Stats</span>
22+
}
23+
</button>
24+
</div>
25+
</div>
26+
27+
@if (showStats)
28+
{
29+
<div class="memory-stats">
30+
<div class="stat-card">
31+
<div class="stat-label">Total Messages</div>
32+
<div class="stat-value">@totalMessages</div>
33+
</div>
34+
<div class="stat-card">
35+
<div class="stat-label">Active Memories</div>
36+
<div class="stat-value">@activeMemories</div>
37+
</div>
38+
<div class="stat-card">
39+
<div class="stat-label">Avg Importance</div>
40+
<div class="stat-value">@avgImportance.ToString("F2")</div>
41+
</div>
42+
<div class="stat-card">
43+
<div class="stat-label">High Priority</div>
44+
<div class="stat-value">@highPriorityCount</div>
45+
</div>
46+
</div>
47+
}
48+
49+
<div class="chat-messages" @ref="messagesContainer">
50+
@foreach (var msg in messages)
51+
{
52+
<div class="message @msg.Role">
53+
<div class="message-header">
54+
<span class="message-role">@msg.Role</span>
55+
@if (msg.Role == "User" && msg.Importance > 0)
56+
{
57+
<span class="importance-badge" style="background-color: @GetImportanceColor(msg.Importance)">
58+
@msg.Importance.ToString("F1")
59+
</span>
60+
}
61+
<span class="message-time">@msg.Timestamp.ToString("HH:mm:ss")</span>
62+
</div>
63+
<div class="message-content">@msg.Content</div>
64+
@if (msg.Role == "User" && !string.IsNullOrEmpty(msg.Context))
65+
{
66+
<div class="message-context">
67+
<details>
68+
<summary>🧠 Context Used (@msg.ContextCount items)</summary>
69+
<pre>@msg.Context</pre>
70+
</details>
71+
</div>
72+
}
73+
</div>
74+
}
75+
@if (isProcessing)
76+
{
77+
<div class="message Assistant processing">
78+
<div class="message-header">
79+
<span class="message-role">Assistant</span>
80+
</div>
81+
<div class="message-content">
82+
<span class="typing-indicator">
83+
<span></span>
84+
<span></span>
85+
<span></span>
86+
</span>
87+
</div>
88+
</div>
89+
}
90+
</div>
91+
92+
<div class="chat-input">
93+
<input
94+
type="text"
95+
@bind="currentMessage"
96+
@bind:event="oninput"
97+
@onkeypress="HandleKeyPress"
98+
placeholder="Type your message... (Press Enter to send)"
99+
disabled="@isProcessing" />
100+
<button class="btn-send" @onclick="SendMessage" disabled="@isProcessing">
101+
@if (isProcessing)
102+
{
103+
<span>⏳</span>
104+
}
105+
else
106+
{
107+
<span>Send</span>
108+
}
109+
</button>
110+
</div>
111+
</div>
112+
113+
@code {
114+
private List<ChatMessageViewModel> messages = new();
115+
private string currentMessage = string.Empty;
116+
private bool isProcessing = false;
117+
private bool showStats = true;
118+
private ElementReference messagesContainer;
119+
120+
private string userId = "blazor-user-" + Guid.NewGuid().ToString("N")[..8];
121+
private string conversationId = Guid.NewGuid().ToString();
122+
123+
private int totalMessages = 0;
124+
private int activeMemories = 0;
125+
private double avgImportance = 0.0;
126+
private int highPriorityCount = 0;
127+
128+
protected override async Task OnInitializedAsync()
129+
{
130+
await InitializeConversation();
131+
await RefreshStats();
132+
}
133+
134+
private async Task InitializeConversation()
135+
{
136+
try
137+
{
138+
await Orchestrator.CreateConversationAsync(conversationId, userId, "Blazor Chat Demo");
139+
140+
// Add welcome message
141+
messages.Add(new ChatMessageViewModel
142+
{
143+
Role = "Assistant",
144+
Content = "👋 Welcome! I'm powered by MemoryKit. I can remember our conversation context and provide relevant responses. Try asking me something!",
145+
Timestamp = DateTime.Now
146+
});
147+
}
148+
catch (Exception ex)
149+
{
150+
Logger.LogError(ex, "Failed to initialize conversation");
151+
}
152+
}
153+
154+
private async Task SendMessage()
155+
{
156+
if (string.IsNullOrWhiteSpace(currentMessage) || isProcessing)
157+
return;
158+
159+
var userMessage = currentMessage;
160+
currentMessage = string.Empty;
161+
isProcessing = true;
162+
163+
try
164+
{
165+
// Add user message to UI
166+
var userMsg = new ChatMessageViewModel
167+
{
168+
Role = "User",
169+
Content = userMessage,
170+
Timestamp = DateTime.Now
171+
};
172+
messages.Add(userMsg);
173+
await InvokeAsync(StateHasChanged);
174+
175+
// Process through MemoryKit
176+
var result = await Orchestrator.ProcessConversationAsync(conversationId, userId, userMessage);
177+
178+
// Get context for display
179+
var context = await Orchestrator.GetConversationContextAsync(conversationId, userId, userMessage);
180+
181+
// Update user message with importance and context
182+
userMsg.Importance = result.CalculatedImportance;
183+
userMsg.Context = string.Join("\n", context.RelevantMemories.Select(m => $"[{m.Timestamp:HH:mm}] {m.Content}"));
184+
userMsg.ContextCount = context.RelevantMemories.Count;
185+
186+
// Simulate AI response (in real app, call your LLM service here)
187+
var assistantContent = GenerateAIResponse(userMessage, context.RelevantMemories.Count);
188+
189+
// Store assistant response
190+
await Orchestrator.ProcessConversationAsync(conversationId, userId, assistantContent, isUserMessage: false);
191+
192+
messages.Add(new ChatMessageViewModel
193+
{
194+
Role = "Assistant",
195+
Content = assistantContent,
196+
Timestamp = DateTime.Now
197+
});
198+
199+
await RefreshStats();
200+
}
201+
catch (Exception ex)
202+
{
203+
Logger.LogError(ex, "Error processing message");
204+
messages.Add(new ChatMessageViewModel
205+
{
206+
Role = "System",
207+
Content = $"Error: {ex.Message}",
208+
Timestamp = DateTime.Now
209+
});
210+
}
211+
finally
212+
{
213+
isProcessing = false;
214+
await InvokeAsync(StateHasChanged);
215+
}
216+
}
217+
218+
private string GenerateAIResponse(string userMessage, int contextCount)
219+
{
220+
// This is a mock response. In production, integrate with your LLM service
221+
var responses = new[]
222+
{
223+
$"I understand. Based on {contextCount} relevant memories from our conversation, here's my response: {userMessage}",
224+
$"That's interesting! I recall {contextCount} related points from our earlier discussion.",
225+
$"Got it! MemoryKit helped me find {contextCount} relevant context items to inform my response.",
226+
$"Thanks for sharing! Drawing from {contextCount} memories, I can help with that."
227+
};
228+
return responses[new Random().Next(responses.Length)];
229+
}
230+
231+
private async Task RefreshStats()
232+
{
233+
try
234+
{
235+
totalMessages = messages.Count;
236+
activeMemories = messages.Count(m => m.Role == "User");
237+
238+
var userMessages = messages.Where(m => m.Role == "User" && m.Importance > 0).ToList();
239+
avgImportance = userMessages.Any() ? userMessages.Average(m => m.Importance) : 0.0;
240+
highPriorityCount = userMessages.Count(m => m.Importance >= 0.7);
241+
242+
await InvokeAsync(StateHasChanged);
243+
}
244+
catch (Exception ex)
245+
{
246+
Logger.LogError(ex, "Error refreshing stats");
247+
}
248+
}
249+
250+
private void ToggleStats()
251+
{
252+
showStats = !showStats;
253+
}
254+
255+
private async Task HandleKeyPress(KeyboardEventArgs e)
256+
{
257+
if (e.Key == "Enter" && !e.ShiftKey)
258+
{
259+
await SendMessage();
260+
}
261+
}
262+
263+
private string GetImportanceColor(double importance)
264+
{
265+
if (importance >= 0.8) return "#dc3545"; // High - Red
266+
if (importance >= 0.6) return "#fd7e14"; // Medium-High - Orange
267+
if (importance >= 0.4) return "#ffc107"; // Medium - Yellow
268+
return "#28a745"; // Low - Green
269+
}
270+
271+
private class ChatMessageViewModel
272+
{
273+
public string Role { get; set; } = string.Empty;
274+
public string Content { get; set; } = string.Empty;
275+
public DateTime Timestamp { get; set; }
276+
public double Importance { get; set; }
277+
public string Context { get; set; } = string.Empty;
278+
public int ContextCount { get; set; }
279+
}
280+
}

0 commit comments

Comments
 (0)