Skip to content

Commit bada87f

Browse files
committed
Enhance logging and error handling in AskEndpoints and NLWebService
- Added detailed entry and exit logs for /ask endpoints to track request flow. - Improved logging for request processing, including query details and result counts. - Enhanced error logging to include QueryId for better traceability. - Updated NLWebService to log start and end of request processing with QueryId. - Added debug logs for internal processing steps in NLWebService. - Improved validation error handling with specific logs for streaming requests. - Refactored ResultGenerator to include logging for AI client usage and summary generation.
1 parent 40b8289 commit bada87f

File tree

15 files changed

+48168
-170
lines changed

15 files changed

+48168
-170
lines changed

doc/todo.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,20 @@ The NLWebNet library is now successfully deployed as a production-ready NuGet pa
570570
- [x] Deployment automation scripts
571571
- [x] **DEPLOYMENT INFRASTRUCTURE COMPLETED**: Comprehensive deployment strategy implemented with Docker, Kubernetes, and Azure support
572572

573+
### Phase 11.5: GitHub Models Demo Integration ✅
574+
575+
#### Status: **COMPLETED SUCCESSFULLY**
576+
577+
Enhanced the demo application to provide seamless GitHub Models integration for users without AI provider setup:
578+
579+
- [x] **AI Provider Detection**: Created `AIConfigurationService` to detect when no AI provider is configured
580+
- [x] **GitHub Models Client**: Implemented `GitHubModelsChatClient` with Microsoft.Extensions.AI compatibility
581+
- [x] **Token Input UI**: Built `GitHubTokenInput.razor` component with secure session-based token storage
582+
- [x] **Demo Integration**: Updated `NLWebDemo.razor` to show GitHub token input when no AI is configured
583+
- [x] **User Experience**: Added model selection, token validation, and comprehensive help documentation
584+
585+
**Key Benefits**: Users can instantly test real AI responses using GitHub Models without complex configuration setup, providing an excellent out-of-the-box demo experience.
586+
573587
### Open Questions to Resolve
574588

575589
**✅ RESOLVED Questions:**

log.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Couldn't find a project to run. Ensure a project exists in D:\Users\Jon\Documents\GitHub\NLWebNet, or pass the path to the project using --project.
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
@rendermode @(new InteractiveServerRenderMode(prerender: false))
2+
@inject IJSRuntime JSRuntime
3+
@using System.ComponentModel.DataAnnotations
4+
5+
<div class="card border-warning">
6+
<div class="card-header bg-warning text-dark">
7+
<h5 class="card-title mb-0">
8+
<i class="fab fa-github me-2"></i>
9+
Quick AI Setup with GitHub Models
10+
</h5>
11+
</div>
12+
<div class="card-body">
13+
<div class="alert alert-info">
14+
<i class="fas fa-info-circle me-2"></i>
15+
<strong>No AI provider configured!</strong> Enter a GitHub Personal Access Token below to test with GitHub Models instantly.
16+
</div>
17+
18+
<div class="mb-3">
19+
<label for="githubToken" class="form-label">
20+
<i class="fab fa-github me-1"></i>GitHub Personal Access Token
21+
</label>
22+
<div class="input-group">
23+
<input type="@(showToken ? "text" : "password")"
24+
class="form-control @(IsValidToken ? "is-valid" : "")"
25+
id="githubToken"
26+
@bind="GitHubToken"
27+
placeholder="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
28+
disabled="@IsLoading" />
29+
<button type="button"
30+
class="btn btn-outline-secondary"
31+
@onclick="ToggleTokenVisibility"
32+
disabled="@IsLoading">
33+
<i class="fas @(showToken ? "fa-eye-slash" : "fa-eye")"></i>
34+
</button>
35+
</div>
36+
@if (!string.IsNullOrEmpty(validationMessage))
37+
{
38+
<div class="form-text text-danger">
39+
<i class="fas fa-exclamation-triangle me-1"></i>@validationMessage
40+
</div>
41+
}
42+
</div>
43+
44+
<div class="mb-3">
45+
<label for="modelSelect" class="form-label">
46+
<i class="fas fa-robot me-1"></i>AI Model
47+
</label>
48+
<select class="form-select" id="modelSelect" @bind="SelectedModel" disabled="@(IsLoading || string.IsNullOrEmpty(GitHubToken))">
49+
<option value="gpt-4o">GPT-4o (Recommended)</option>
50+
<option value="gpt-4o-mini">GPT-4o Mini (Faster)</option>
51+
<option value="Phi-3.5-mini-instruct">Phi-3.5 Mini</option>
52+
<option value="Llama-3.1-8B-Instruct">Llama 3.1 8B</option>
53+
</select>
54+
</div>
55+
56+
<div class="d-flex gap-2">
57+
<button type="button"
58+
class="btn btn-success"
59+
@onclick="ConfigureGitHubModels"
60+
disabled="@(IsLoading || string.IsNullOrEmpty(GitHubToken))">
61+
@if (IsLoading)
62+
{
63+
<span class="spinner-border spinner-border-sm me-2" role="status"></span>
64+
}
65+
<i class="fas fa-check me-1"></i>Configure AI
66+
</button>
67+
68+
@if (IsValidToken)
69+
{
70+
<button type="button"
71+
class="btn btn-outline-danger"
72+
@onclick="ClearConfiguration">
73+
<i class="fas fa-times me-1"></i>Clear
74+
</button>
75+
}
76+
</div>
77+
78+
<div class="mt-3">
79+
<div class="accordion" id="gitHubTokenHelp">
80+
<div class="accordion-item">
81+
<h2 class="accordion-header">
82+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseHelp">
83+
<i class="fas fa-question-circle me-2"></i>How to get a GitHub Personal Access Token
84+
</button>
85+
</h2>
86+
<div id="collapseHelp" class="accordion-collapse collapse" data-bs-parent="#gitHubTokenHelp">
87+
<div class="accordion-body">
88+
<ol>
89+
<li>Go to <a href="https://github.com/settings/tokens" target="_blank" class="text-decoration-none">GitHub Settings → Personal Access Tokens</a></li>
90+
<li>Click "Generate new token" → "Fine-grained personal access token"</li>
91+
<li>Set expiration and select "All repositories" or specific ones</li>
92+
<li>Under "Account permissions", enable: <code>Model access</code></li>
93+
<li>Generate and copy the token (starts with <code>ghp_</code>)</li>
94+
</ol>
95+
<div class="alert alert-warning mt-2">
96+
<i class="fas fa-exclamation-triangle me-2"></i>
97+
<strong>Security Note:</strong> This token is only stored in your browser session and never sent to our servers.
98+
</div>
99+
</div>
100+
</div>
101+
</div>
102+
</div>
103+
</div>
104+
</div>
105+
</div>
106+
107+
@code {
108+
[Parameter] public EventCallback<string> OnTokenConfigured { get; set; }
109+
[Parameter] public bool IsLoading { get; set; }
110+
111+
private string gitHubToken = string.Empty;
112+
private string selectedModel = "gpt-4o";
113+
private bool showToken = false;
114+
private string validationMessage = string.Empty;
115+
private bool isValidToken = false;
116+
117+
public string GitHubToken
118+
{
119+
get => gitHubToken;
120+
set
121+
{
122+
if (gitHubToken != value)
123+
{
124+
gitHubToken = value;
125+
ValidateToken();
126+
StateHasChanged();
127+
}
128+
}
129+
}
130+
131+
public string SelectedModel
132+
{
133+
get => selectedModel;
134+
set => selectedModel = value;
135+
}
136+
137+
public bool IsValidToken => isValidToken;
138+
139+
protected override async Task OnAfterRenderAsync(bool firstRender)
140+
{
141+
if (firstRender)
142+
{
143+
// Try to restore token from session storage
144+
try
145+
{
146+
var storedToken = await JSRuntime.InvokeAsync<string>("sessionStorage.getItem", "github-token");
147+
var storedModel = await JSRuntime.InvokeAsync<string>("sessionStorage.getItem", "github-model");
148+
149+
if (!string.IsNullOrEmpty(storedToken))
150+
{
151+
GitHubToken = storedToken;
152+
SelectedModel = storedModel ?? "gpt-4o";
153+
StateHasChanged();
154+
}
155+
}
156+
catch
157+
{
158+
// Session storage not available or error - ignore
159+
}
160+
}
161+
}
162+
163+
private void ToggleTokenVisibility()
164+
{
165+
showToken = !showToken;
166+
}
167+
168+
private void ValidateToken()
169+
{
170+
validationMessage = string.Empty;
171+
isValidToken = false;
172+
173+
if (string.IsNullOrEmpty(gitHubToken))
174+
{
175+
return;
176+
}
177+
178+
if (!gitHubToken.StartsWith("ghp_"))
179+
{
180+
validationMessage = "GitHub Personal Access Token should start with 'ghp_'";
181+
return;
182+
}
183+
184+
if (gitHubToken.Length < 40)
185+
{
186+
validationMessage = "Token appears to be too short";
187+
return;
188+
}
189+
190+
isValidToken = true;
191+
}
192+
193+
private async Task ConfigureGitHubModels()
194+
{
195+
if (!IsValidToken)
196+
{
197+
validationMessage = "Please enter a valid GitHub Personal Access Token";
198+
return;
199+
}
200+
201+
try
202+
{
203+
// Store in session storage for this session only
204+
await JSRuntime.InvokeVoidAsync("sessionStorage.setItem", "github-token", GitHubToken);
205+
await JSRuntime.InvokeVoidAsync("sessionStorage.setItem", "github-model", SelectedModel);
206+
207+
// Notify parent component
208+
if (OnTokenConfigured.HasDelegate)
209+
{
210+
await OnTokenConfigured.InvokeAsync(GitHubToken);
211+
}
212+
}
213+
catch (Exception ex)
214+
{
215+
validationMessage = $"Error configuring GitHub Models: {ex.Message}";
216+
}
217+
}
218+
219+
private async Task ClearConfiguration()
220+
{
221+
try
222+
{
223+
await JSRuntime.InvokeVoidAsync("sessionStorage.removeItem", "github-token");
224+
await JSRuntime.InvokeVoidAsync("sessionStorage.removeItem", "github-model");
225+
226+
GitHubToken = string.Empty;
227+
SelectedModel = "gpt-4o";
228+
isValidToken = false;
229+
validationMessage = string.Empty;
230+
231+
// Notify parent component
232+
if (OnTokenConfigured.HasDelegate)
233+
{
234+
await OnTokenConfigured.InvokeAsync(string.Empty);
235+
}
236+
}
237+
catch (Exception ex)
238+
{
239+
validationMessage = $"Error clearing configuration: {ex.Message}";
240+
}
241+
}
242+
}

0 commit comments

Comments
 (0)