Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 4 additions & 18 deletions NLWebNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLWebNet", "src\NLWebNet\NLWebNet.csproj", "{1E458E72-D542-44BB-9F84-1EDE008FBB1D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{A39C23D2-F2C0-258D-165A-CF1E7FEE6E7B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLWebNet.Demo", "samples\Demo\NLWebNet.Demo.csproj", "{6F25FD99-AF67-4509-A46C-FCD450F6A775}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLWebNet.AspireHost", "samples\AspireHost\NLWebNet.AspireHost.csproj", "{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLWebNet.Tests", "tests\NLWebNet.Tests\NLWebNet.Tests.csproj", "{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}"
Expand Down Expand Up @@ -63,25 +59,15 @@ Global
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}.Release|x64.Build.0 = Release|Any CPU
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}.Release|x86.ActiveCfg = Release|Any CPU
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}.Release|x86.Build.0 = Release|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Debug|x64.ActiveCfg = Debug|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Debug|x64.Build.0 = Debug|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Debug|x86.ActiveCfg = Debug|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Debug|x86.Build.0 = Debug|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Release|Any CPU.Build.0 = Release|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Release|x64.ActiveCfg = Release|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Release|x64.Build.0 = Release|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Release|x86.ActiveCfg = Release|Any CPU
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution {1E458E72-D542-44BB-9F84-1EDE008FBB1D} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
GlobalSection(NestedProjects) = preSolution
{6F25FD99-AF67-4509-A46C-FCD450F6A775} = {A39C23D2-F2C0-258D-165A-CF1E7FEE6E7B}
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{B8A5E1C0-9E2F-4A2D-8C3D-1234567890AB} = {A39C23D2-F2C0-258D-165A-CF1E7FEE6E7B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8983833A-ABDD-4E53-BEA3-64BCDF1169A5}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Aspire.Hosting;
using Aspire.Hosting.Qdrant;

namespace NLWebNet.Extensions;

Expand All @@ -18,7 +19,7 @@ public static IResourceBuilder<ProjectResource> AddNLWebNetApp(
this IDistributedApplicationBuilder builder,
string name)
{
return builder.AddProject<Projects.NLWebNet_Demo>(name)
return builder.AddProject<Projects.NLWebNet_AspireApp>(name)
.WithEnvironment("ASPNETCORE_ENVIRONMENT", builder.Environment.EnvironmentName)
.WithEnvironment("OTEL_SERVICE_NAME", name)
.WithEnvironment("OTEL_SERVICE_VERSION", "1.0.0");
Expand Down Expand Up @@ -56,4 +57,20 @@ public static IResourceBuilder<ProjectResource> AddNLWebNetAppWithDataBackend(
return builder.AddNLWebNetApp(name)
.WithReference(dataBackend);
}

/// <summary>
/// Adds an NLWebNet application with Qdrant vector database reference
/// </summary>
/// <param name="builder">The distributed application builder</param>
/// <param name="name">The name of the application</param>
/// <param name="qdrant">The Qdrant vector database resource to reference</param>
/// <returns>A resource builder for the NLWebNet application</returns>
public static IResourceBuilder<ProjectResource> AddNLWebNetAppWithQdrant(
this IDistributedApplicationBuilder builder,
string name,
IResourceBuilder<QdrantServerResource> qdrant)
{
return builder.AddNLWebNetApp(name)
.WithReference(qdrant);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.1.0" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.1.0" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.1.0" />
<PackageReference Include="Aspire.Hosting.Azure.PostgreSQL" Version="9.1.0" />
<PackageReference Include="Aspire.Hosting.Azure.Redis" Version="9.1.0" />
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.Qdrant" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.Azure.PostgreSQL" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.Azure.Redis" Version="9.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NLWebNet\NLWebNet.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\Demo\NLWebNet.Demo.csproj" />
<ProjectReference Include="..\NLWebNet.AspireApp\NLWebNet.AspireApp.csproj" />
<ProjectReference Include="..\NLWebNet.Frontend\NLWebNet.Frontend.csproj" />
<ProjectReference Include="..\ServiceDefaults\ServiceDefaults.csproj" IsAspireProjectResource="false" />
</ItemGroup>

</Project>
59 changes: 59 additions & 0 deletions samples/AspireDemo/AspireHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using NLWebNet.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;

var builder = DistributedApplication.CreateBuilder(args);

// Configure logging to reduce telemetry noise while keeping important startup messages
builder.Services.Configure<LoggerFilterOptions>(options =>
{
// Keep important Aspire startup messages but filter telemetry
options.AddFilter("Aspire.Hosting.ApplicationModel", LogLevel.Information);
options.AddFilter("Aspire.Hosting", LogLevel.Information);
options.AddFilter("Aspire", LogLevel.Warning);

// Reduce OpenTelemetry noise
options.AddFilter("OpenTelemetry", LogLevel.Warning);

// Keep basic hosting messages
options.AddFilter("Microsoft.Extensions.Hosting.Internal.Host", LogLevel.Information);
options.AddFilter("Microsoft.Extensions.Hosting", LogLevel.Warning);

// Reduce ASP.NET Core noise but keep startup messages
options.AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", LogLevel.Information);
options.AddFilter("Microsoft.AspNetCore", LogLevel.Warning);

// Reduce DI and HTTP noise
options.AddFilter("Microsoft.Extensions.DependencyInjection", LogLevel.Warning);
options.AddFilter("System.Net.Http", LogLevel.Warning);
});

// Add Qdrant vector database for storing ingested data
var qdrant = builder.AddQdrant("qdrant")
.WithDataVolume(); // Persist data between container restarts

// Add external dependencies (optional - could be databases, message queues, etc.)
// var postgres = builder.AddPostgres("postgres")
// .WithEnvironment("POSTGRES_DB", "nlwebnet")
// .PublishAsAzurePostgresFlexibleServer();

// var redis = builder.AddRedis("redis")
// .PublishAsAzureRedis();

// Add the NLWebNet Aspire application with Qdrant integration
var nlwebapp = builder.AddProject<Projects.NLWebNet_AspireApp>("nlwebnet-aspire-api")
.WithEnvironment("ASPNETCORE_ENVIRONMENT", builder.Environment.EnvironmentName)
.WithEnvironment("NLWebNet__RateLimiting__RequestsPerWindow", "1000")
.WithEnvironment("NLWebNet__RateLimiting__WindowSizeInMinutes", "1")
.WithEnvironment("NLWebNet__EnableStreaming", "true")
.WithReference(qdrant) // Connect to Qdrant for vector storage
.WithReplicas(1); // Single replica for demo purposes

// Add the frontend web application
var frontend = builder.AddProject<Projects.NLWebNet_Frontend>("nlwebnet-frontend")
.WithReference(nlwebapp) // Connect to the API
.WithReplicas(1);

var app = builder.Build();

await app.RunAsync();
218 changes: 218 additions & 0 deletions samples/AspireDemo/FRONTEND_INTEGRATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Frontend Integration Summary

## Overview
Successfully integrated GitHub Models AI embeddings with a user-friendly frontend UI for the AspireDemo application. Users can now configure GitHub tokens via the web interface and experience true semantic search.

## Implementation Details

### 1. Configuration Service (`EmbeddingConfigurationService`)
- **Purpose**: Manages GitHub token configuration in the frontend
- **Features**:
- Token validation and storage
- Configuration change events
- Runtime token management

### 2. GitHub Token Input Component (`GitHubTokenInput.razor`)
- **Purpose**: User interface for configuring GitHub Models API access
- **Features**:
- Token input with validation
- Connection testing
- Visual feedback for configuration status
- Help links and instructions

### 3. Configuration Page (`Configuration.razor`)
- **Purpose**: Dedicated page for application configuration
- **Features**:
- GitHub token configuration
- Information about semantic search modes
- Help and documentation links

### 4. API Service (`ApiService`)
- **Purpose**: Frontend service for communicating with the backend API
- **Features**:
- Search requests with optional GitHub token headers
- Health check endpoint calls
- Error handling and logging

### 5. Backend API Updates
- **Enhanced Search Endpoint**: `/api/search`
- Accepts `X-GitHub-Token` header for runtime token configuration
- Uses provided token for GitHub Models API calls
- Falls back to simple embeddings when no token provided
- Returns results compatible with frontend expectations

- **Health Check Endpoint**: `/api/health`
- Simple endpoint for testing API connectivity
- Used by frontend for connection validation

### 6. Embedding Service Extensions
- **Dynamic Token Support**:
- Added overload methods to support runtime GitHub token configuration
- `GenerateEmbeddingAsync(string text, string? githubToken, CancellationToken cancellationToken)`
- Maintains backward compatibility with existing code

## User Experience Flow

### 1. Initial State (No Configuration)
- User sees warning banner on Vector Search page
- Search uses simple fallback embeddings
- Configuration page shows setup instructions

### 2. Token Configuration
- User navigates to Configuration page
- Enters GitHub Personal Access Token
- System validates token format
- Optional connection test verifies API access

### 3. Enhanced Search (With GitHub Models)
- Success banner appears on Vector Search page
- All searches use GitHub Models AI embeddings
- Improved semantic search quality and relevance

### 4. Dynamic Switching
- Users can clear configuration to test differences
- Real-time switching between embedding modes
- Clear visual indicators of current mode

## Technical Architecture

### Frontend (NLWebNet.Frontend)
```
Components/
├── GitHubTokenInput.razor # Token configuration UI
├── Pages/
│ ├── Configuration.razor # Configuration page
│ └── VectorSearch.razor # Updated search with status
└── Services/
├── EmbeddingConfigurationService.cs # Token management
└── ApiService.cs # API communication
```

### Backend (NLWebNet.AspireApp)
```
Services/
├── IEmbeddingService.cs # Extended interface
├── GitHubModelsEmbeddingService.cs # Dynamic token support
└── EmbeddingService.cs # Updated fallback service

Program.cs # Enhanced API endpoints
```

## Configuration Instructions

### For Users
1. Navigate to the **Configuration** page in the app
2. Click the link to create a GitHub Personal Access Token
3. Generate a token with appropriate scopes (public repos require no scopes)
4. Paste the token in the configuration form
5. Test the connection (optional)
6. Navigate to **Vector Search** to use enhanced semantic search

### For Developers
1. Set `GITHUB_TOKEN` environment variable for server-wide configuration
2. Or use the frontend UI for per-session configuration
3. Tokens provided via frontend take precedence over environment variables

## Key Features Demonstrated

### 1. Real Semantic Search
- **GitHub Models**: Uses AI embeddings for true semantic understanding
- **Simple Fallback**: Basic hash-based embeddings for demo purposes
- **Clear Differentiation**: Users can experience the quality difference

### 2. Dynamic Configuration
- **Runtime Token Management**: No need to restart the application
- **Per-Request Tokens**: Frontend can send different tokens per search
- **Fallback Gracefully**: Switches modes seamlessly

### 3. Production-Ready UI
- **Professional Design**: Modern Bootstrap-based interface
- **Comprehensive Help**: Step-by-step configuration guides
- **Visual Feedback**: Clear status indicators and progress feedback
- **Error Handling**: Graceful error messages and recovery

### 4. Developer Experience
- **Clean Abstractions**: Well-defined interfaces and services
- **Extensible Design**: Easy to add new embedding providers
- **Comprehensive Logging**: Detailed logging for debugging
- **Type Safety**: Strong typing throughout the application

## Testing Results

### Build Status
✅ **Solution builds successfully**
- All projects compile without errors
- Dependencies properly resolved
- Type conflicts resolved

### Functional Testing
✅ **Configuration UI works**
- Token input validation functions correctly
- Connection testing validates GitHub API access
- Configuration persistence across page reloads

✅ **API Integration**
- Health check endpoint responds correctly
- Search endpoint accepts token headers
- Embedding service switches modes dynamically

### Expected Behavior
When a user:
1. **Configures GitHub token** → Search quality improves dramatically
2. **Clears configuration** → Falls back to simple embeddings
3. **Tests connection** → Validates API access before searching
4. **Searches with different modes** → Can observe quality differences

## Performance Characteristics

### With GitHub Models
- **Higher Quality**: True semantic understanding
- **Network Dependency**: Requires internet access to GitHub Models API
- **Rate Limits**: Subject to GitHub API rate limiting
- **Latency**: Additional network call for embedding generation

### With Simple Embeddings
- **Lower Quality**: Basic hash-based similarity
- **Local Processing**: No external dependencies
- **Unlimited**: No rate limits or network dependencies
- **Fast Response**: Local computation only

## Security Considerations

### Token Handling
- **Frontend Storage**: Tokens stored in browser session only
- **Header Transmission**: Sent via HTTPS headers to backend
- **No Persistence**: Not stored in databases or logs
- **Scope Minimization**: Recommend minimal GitHub token scopes

### API Security
- **HTTPS Only**: All communication over encrypted channels
- **Header-Based**: Tokens passed in headers, not query parameters
- **Validation**: Token format validation before API calls
- **Error Handling**: No token leakage in error messages

## Future Enhancements

### Potential Improvements
1. **Token Persistence**: Optional browser storage for convenience
2. **Multiple Providers**: Support for OpenAI, Azure OpenAI, etc.
3. **Advanced Configuration**: Model selection, temperature settings
4. **Analytics**: Search quality metrics and usage analytics
5. **Caching**: Embedding caching for improved performance

### Integration Opportunities
1. **User Authentication**: Integrate with GitHub OAuth
2. **Team Management**: Shared token management for organizations
3. **Usage Monitoring**: Track API usage and costs
4. **A/B Testing**: Compare different embedding providers

## Conclusion

The integration successfully demonstrates:
- **Real semantic search** using GitHub Models AI embeddings
- **Professional user interface** for configuration and search
- **Production-ready architecture** with proper error handling
- **Flexible design** supporting multiple embedding providers
- **Clear value proposition** showing the difference between AI and simple embeddings

Users can now experience the full power of semantic vector search with an intuitive interface, while developers have a clean, extensible foundation for further enhancements.
Loading