Skip to content

Commit 011731c

Browse files
committed
feat: Enhance Blazor demo application with advanced components and interactive interface
- Implemented QueryInput component with validation, mode selection, and streaming toggle. - Created ResultsDisplay component for rich result presentation with card and list views. - Developed StreamingDisplay component for real-time response handling and display. - Enhanced NLWebDemo with a tabbed interface for Query, Streaming, and API Test sections. - Added comprehensive API testing interface with request configuration and response display. - Improved UI with Bootstrap and FontAwesome for a modern look and feel. - Integrated mock data generation and simulated streaming responses for demonstration. - Updated documentation to reflect new features and completed phases.
1 parent 17cf1b3 commit 011731c

File tree

8 files changed

+1346
-93
lines changed

8 files changed

+1346
-93
lines changed

demo/Components/Layout/MainLayout.razor

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@
66
<div class="container">
77
<a class="navbar-brand" href="/">NLWebNet Demo</a>
88
<div class="navbar-nav">
9-
<a class="nav-link" href="/">Home</a>
10-
<a class="nav-link" href="/nlweb">NLWeb Demo</a>
11-
<a class="nav-link" href="/openapi/v1.json" target="_blank">OpenAPI Spec</a>
9+
<a class="nav-link" href="/">
10+
<i class="fas fa-home me-1"></i>Home
11+
</a>
12+
<a class="nav-link" href="/nlweb">
13+
<i class="fas fa-search me-1"></i>NLWeb Demo
14+
</a>
15+
<a class="nav-link" href="/api-test">
16+
<i class="fas fa-flask me-1"></i>API Test
17+
</a>
18+
<a class="nav-link" href="/openapi/v1.json" target="_blank">
19+
<i class="fas fa-file-code me-1"></i>OpenAPI Spec
20+
</a>
1221
</div>
1322
</div>
1423
</nav>

demo/Components/Pages/ApiTest.razor

Lines changed: 394 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 225 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,112 @@
11
@page "/nlweb"
22
@rendermode @(new InteractiveServerRenderMode(prerender: false))
33
@inject IJSRuntime JSRuntime
4+
@inject HttpClient HttpClient
5+
@using NLWebNet.Models
6+
@using System.Text.Json
47

58
<PageTitle>NLWebNet Demo</PageTitle>
69

7-
<div class="container mt-4">
10+
<div class="container-fluid mt-4">
811
<div class="row">
912
<div class="col-12">
10-
<h1 class="mb-4">NLWebNet Interactive Demo</h1>
11-
12-
<div class="card">
13-
<div class="card-header">
14-
<h5 class="mb-0">Query Interface</h5>
13+
<div class="d-flex justify-content-between align-items-center mb-4">
14+
<h1 class="mb-0">
15+
<i class="fas fa-globe-americas text-primary me-2"></i>
16+
NLWebNet Interactive Demo
17+
</h1> <div class="btn-group" role="group">
18+
<button type="button" class="btn @(activeTab == "query" ? "btn-primary" : "btn-outline-primary")"
19+
@onclick='() => SetActiveTab("query")'>
20+
<i class="fas fa-search me-1"></i>Query
21+
</button>
22+
<button type="button" class="btn @(activeTab == "streaming" ? "btn-primary" : "btn-outline-primary")"
23+
@onclick='() => SetActiveTab("streaming")'>
24+
<i class="fas fa-stream me-1"></i>Streaming
25+
</button>
26+
<button type="button" class="btn @(activeTab == "api" ? "btn-primary" : "btn-outline-primary")"
27+
@onclick='() => SetActiveTab("api")'>
28+
<i class="fas fa-code me-1"></i>API Test
29+
</button>
1530
</div>
16-
<div class="card-body">
17-
<div class="mb-3">
18-
<label for="queryInput" class="form-label">Enter your query:</label>
19-
<input type="text" class="form-control" id="queryInput" @bind="queryText"
20-
placeholder="Ask a question..." />
21-
</div>
22-
23-
<div class="row mb-3">
24-
<div class="col-md-6">
25-
<label for="modeSelect" class="form-label">Query Mode:</label>
26-
<select class="form-select" id="modeSelect" @bind="selectedMode">
27-
<option value="@QueryMode.List">List</option>
28-
<option value="@QueryMode.Summarize">Summarize</option>
29-
<option value="@QueryMode.Generate">Generate</option>
30-
</select>
31-
</div>
32-
<div class="col-md-6">
33-
<div class="form-check mt-4">
34-
<input class="form-check-input" type="checkbox" id="streamingCheck" @bind="enableStreaming" />
35-
<label class="form-check-label" for="streamingCheck">
36-
Enable Streaming
37-
</label>
38-
</div>
39-
</div>
31+
</div>
32+
33+
@if (activeTab == "query")
34+
{
35+
<div class="row">
36+
<div class="col-lg-6"> <QueryInput OnSubmit="HandleQuerySubmitted"
37+
IsLoading="isLoading"
38+
@ref="queryInputComponent" />
4039
</div>
41-
42-
<button class="btn btn-primary" @onclick="SubmitQuery" disabled="@isLoading">
43-
@if (isLoading)
40+
<div class="col-lg-6">
41+
@if (currentResponse != null)
4442
{
45-
<span class="spinner-border spinner-border-sm me-2" role="status"></span>
43+
<ResultsDisplay Response="currentResponse"
44+
ShowDebugInfo="true"
45+
OnResultClicked="HandleResultClicked" />
4646
}
47-
Submit Query
48-
</button>
47+
else if (!string.IsNullOrEmpty(errorMessage))
48+
{
49+
<div class="card">
50+
<div class="card-body">
51+
<div class="alert alert-danger">
52+
<i class="fas fa-exclamation-triangle me-2"></i>
53+
<strong>Error:</strong> @errorMessage
54+
</div>
55+
</div>
56+
</div>
57+
}
58+
</div>
4959
</div>
50-
</div>
51-
52-
@if (!string.IsNullOrEmpty(responseMessage))
60+
}
61+
else if (activeTab == "streaming")
5362
{
54-
<div class="card mt-4">
55-
<div class="card-header">
56-
<h5 class="mb-0">Response</h5>
63+
<div class="row">
64+
<div class="col-lg-4">
65+
<div class="card">
66+
<div class="card-header">
67+
<h5 class="mb-0">Streaming Query</h5>
68+
</div>
69+
<div class="card-body">
70+
<div class="mb-3">
71+
<label class="form-label">Query</label>
72+
<input type="text" class="form-control" @bind="streamingQuery"
73+
placeholder="Enter streaming query..." />
74+
</div>
75+
<button class="btn btn-primary" @onclick="StartStreamingQuery"
76+
disabled="@(isStreaming || string.IsNullOrWhiteSpace(streamingQuery))">
77+
@if (isStreaming)
78+
{
79+
<span class="spinner-border spinner-border-sm me-2"></span>
80+
}
81+
<i class="fas fa-play me-1"></i>Start Streaming
82+
</button>
83+
</div>
84+
</div>
85+
</div>
86+
<div class="col-lg-8">
87+
<StreamingDisplay IsStreaming="isStreaming"
88+
IsCompleted="streamingCompleted"
89+
QueryId="streamingQueryId"
90+
OnStopStreaming="StopStreaming"
91+
@ref="streamingDisplay" />
5792
</div>
58-
<div class="card-body">
59-
<pre class="bg-light p-3 rounded">@responseMessage</pre>
93+
</div>
94+
}
95+
else if (activeTab == "api")
96+
{
97+
<div class="row">
98+
<div class="col-12">
99+
<div class="card">
100+
<div class="card-header">
101+
<h5 class="mb-0">API Testing Interface</h5>
102+
</div>
103+
<div class="card-body">
104+
<div class="alert alert-info">
105+
<i class="fas fa-info-circle me-2"></i>
106+
Test the NLWebNet API endpoints directly. This will be implemented in the next iteration.
107+
</div>
108+
</div>
109+
</div>
60110
</div>
61111
</div>
62112
}
@@ -65,32 +115,151 @@
65115
</div>
66116

67117
@code {
68-
private string queryText = "";
69-
private QueryMode selectedMode = QueryMode.List;
70-
private bool enableStreaming = true;
118+
private string activeTab = "query";
71119
private bool isLoading = false;
72-
private string responseMessage = "";
120+
private string errorMessage = "";
121+
122+
// Query tab
123+
private QueryInput? queryInputComponent;
124+
private NLWebResponse? currentResponse;
73125

74-
private void SubmitQuery()
126+
// Streaming tab
127+
private string streamingQuery = "";
128+
private bool isStreaming = false;
129+
private bool streamingCompleted = false; private string streamingQueryId = "";
130+
private StreamingDisplay? streamingDisplay;
131+
132+
private void SetActiveTab(string tab)
133+
{
134+
activeTab = tab;
135+
errorMessage = "";
136+
}
137+
138+
private async Task HandleQuerySubmitted(NLWebRequest request)
75139
{
76-
if (string.IsNullOrWhiteSpace(queryText))
77-
return;
78-
79140
isLoading = true;
80-
responseMessage = "";
141+
errorMessage = "";
142+
currentResponse = null;
81143

82144
try
83145
{
84-
// TODO: This will be implemented when the library is complete
85-
responseMessage = $"Query: {queryText}\nMode: {selectedMode}\nStreaming: {enableStreaming}\n\n(NLWebNet library integration coming soon...)";
146+
// Simulate API call for now - will be replaced with actual NLWebNet API calls
147+
await Task.Delay(1000); // Simulate network delay
148+
149+
currentResponse = CreateMockResponse(request);
86150
}
87151
catch (Exception ex)
88152
{
89-
responseMessage = $"Error: {ex.Message}";
153+
errorMessage = ex.Message;
90154
}
91155
finally
92156
{
93157
isLoading = false;
94158
}
95159
}
160+
161+
private NLWebResponse CreateMockResponse(NLWebRequest request)
162+
{ var response = new NLWebResponse
163+
{
164+
QueryId = Guid.NewGuid().ToString(),
165+
Query = request.Query,
166+
Mode = request.Mode,
167+
Summary = $"Mock summary for query: '{request.Query}' in {request.Mode} mode",
168+
GeneratedResponse = request.Mode == QueryMode.Generate
169+
? $"Generated response: Based on your query '{request.Query}', here is a comprehensive answer with relevant information and insights."
170+
: null,
171+
Results = new List<NLWebResult>()
172+
};
173+
174+
// Add mock results
175+
for (int i = 1; i <= 5; i++)
176+
{
177+
response.Results.Add(new NLWebResult
178+
{
179+
Name = $"Result {i}",
180+
Url = $"https://example.com/result{i}",
181+
Description = $"This is a mock description for result {i} related to '{request.Query}'",
182+
Score = 0.9 - (i * 0.1),
183+
Site = "example.com"
184+
});
185+
}
186+
187+
return response;
188+
}
189+
190+
private void HandleResultClicked(NLWebResult result)
191+
{
192+
// Handle result click - could navigate, show details, etc.
193+
JSRuntime.InvokeVoidAsync("open", result.Url, "_blank");
194+
}
195+
196+
private async Task StartStreamingQuery()
197+
{
198+
if (string.IsNullOrWhiteSpace(streamingQuery))
199+
return;
200+
201+
isStreaming = true;
202+
streamingCompleted = false;
203+
streamingQueryId = Guid.NewGuid().ToString();
204+
205+
// Clear previous results
206+
streamingDisplay?.ClearStream();
207+
208+
// Simulate streaming response
209+
await SimulateStreamingResponse();
210+
}
211+
212+
private async Task SimulateStreamingResponse()
213+
{
214+
try
215+
{
216+
streamingDisplay?.AddTextChunk("Starting query processing...");
217+
await Task.Delay(500);
218+
219+
streamingDisplay?.AddTextChunk("Searching web sources...");
220+
await Task.Delay(800);
221+
222+
// Add some mock results
223+
for (int i = 1; i <= 3; i++)
224+
{ var result = new NLWebResult
225+
{
226+
Name = $"Streaming Result {i}",
227+
Url = $"https://example.com/streaming{i}",
228+
Description = $"Streamed result {i} for query: {streamingQuery}",
229+
Score = 0.95 - (i * 0.05),
230+
Site = "example.com"
231+
};
232+
233+
streamingDisplay?.AddResultChunk(result);
234+
await Task.Delay(600);
235+
}
236+
237+
streamingDisplay?.AddTextChunk("Processing results...");
238+
await Task.Delay(400);
239+
240+
streamingDisplay?.AddSummaryChunk($"Found 3 relevant results for '{streamingQuery}'. The results show comprehensive information about the topic.");
241+
await Task.Delay(300);
242+
243+
streamingDisplay?.AddTextChunk("Query completed successfully.");
244+
}
245+
catch (Exception ex)
246+
{
247+
streamingDisplay?.AddErrorChunk($"Streaming error: {ex.Message}");
248+
}
249+
finally
250+
{
251+
isStreaming = false;
252+
streamingCompleted = true;
253+
}
254+
}
255+
private Task StopStreaming()
256+
{
257+
isStreaming = false;
258+
streamingDisplay?.AddTextChunk("Streaming stopped by user.");
259+
return Task.CompletedTask;
260+
}
261+
public void Dispose()
262+
{
263+
// Cleanup if needed
264+
}
96265
}

0 commit comments

Comments
 (0)