From 09f15a9cb7ea698b48a6ca8e53f4eb0117aa6a2e Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Fri, 14 Feb 2025 16:58:51 +0100 Subject: [PATCH 01/25] Enhance application structure and functionality - Updated README.md for clarity on application features. - Added using directives and improved service configuration in Program.cs. - Enhanced error handling and status code management in Program.cs. - Changed application URL port in launchSettings.json. - Added package references for Blazor Bootstrap and other libraries. - Created new HTML structure in App.razor and implemented routing in Routes.razor. - Updated MainLayout.razor for Blazor Bootstrap layout and sidebar navigation. - Developed new components: Counter.razor, Documents.razor, Error.razor, Home.razor, and Weather.razor. - Added utility classes: RequestExtensions.cs and StreamExtensions.cs. - Updated app.css for custom styles and added favicon.png. - Created functions.js for local time conversion utility. --- README.md | 2 +- SqlDatabaseVectorSearch/Components/App.razor | 33 ++++ .../Components/Layout/MainLayout.razor | 56 ++++++ .../Components/Layout/MainLayout.razor.css | 20 +++ .../Components/Pages/Counter.razor | 18 ++ .../Components/Pages/Documents.razor | 169 ++++++++++++++++++ .../Components/Pages/Error.razor | 36 ++++ .../Components/Pages/Home.razor | 12 ++ .../Components/Pages/Weather.razor | 63 +++++++ .../Components/Routes.razor | 6 + .../Components/_Imports.razor | 14 ++ .../Extensions/RequestExtensions.cs | 64 +++++++ .../Extensions/StreamExtensions.cs | 16 ++ SqlDatabaseVectorSearch/Program.cs | 45 ++++- .../Properties/launchSettings.json | 3 +- .../SqlDatabaseVectorSearch.csproj | 1 + SqlDatabaseVectorSearch/wwwroot/app.css | 40 +++++ SqlDatabaseVectorSearch/wwwroot/favicon.png | Bin 0 -> 2193 bytes .../wwwroot/js/functions.js | 3 + 19 files changed, 592 insertions(+), 9 deletions(-) create mode 100644 SqlDatabaseVectorSearch/Components/App.razor create mode 100644 SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor create mode 100644 SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css create mode 100644 SqlDatabaseVectorSearch/Components/Pages/Counter.razor create mode 100644 SqlDatabaseVectorSearch/Components/Pages/Documents.razor create mode 100644 SqlDatabaseVectorSearch/Components/Pages/Error.razor create mode 100644 SqlDatabaseVectorSearch/Components/Pages/Home.razor create mode 100644 SqlDatabaseVectorSearch/Components/Pages/Weather.razor create mode 100644 SqlDatabaseVectorSearch/Components/Routes.razor create mode 100644 SqlDatabaseVectorSearch/Components/_Imports.razor create mode 100644 SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs create mode 100644 SqlDatabaseVectorSearch/Extensions/StreamExtensions.cs create mode 100644 SqlDatabaseVectorSearch/wwwroot/app.css create mode 100644 SqlDatabaseVectorSearch/wwwroot/favicon.png create mode 100644 SqlDatabaseVectorSearch/wwwroot/js/functions.js diff --git a/README.md b/README.md index a62f962..ccb1791 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # SQL Database Vector Search Sample A repository that showcases the native VECTOR type in Azure SQL Database to perform embeddings and RAG with Azure OpenAI. -The application is a Minimal API that exposes endpoints to load documents, generate embeddings and save them into the database as Vectors, and perform searches using Vector Search and RAG. Currently, PDF, DOCX, TXT and MD files are supported. Vectors are saved and retrieved with Entity Framework Core using the [EFCore.SqlServer.VectorSearch](https://github.com/efcore/EfCore.SqlServer.VectorSearch) library. Embedding and Chat Completion are integrated with [Semantic Kernel](https://github.com/microsoft/semantic-kernel). +The application is a Minimal API that exposes endpoints to load documents, generate embeddings and save them into the database as Vectors, and perform searches using Vector Search and RAG. Currently, PDF, DOCX, TXT and MD files are supported. Vectors are saved and retrieved with Entity Framework Core using the [EFCore.SqlServer.VectorSearch](https://github.com/efcore/EfCore.SqlServer.VectorSearch) library. Embedding and Chat Completion are integrated with [Semantic Kernel](https://github.com/microsoft/semantic-kernel). > [!NOTE] > If you prefer to use straight SQL, check out the [sql branch](https://github.com/marcominerva/SqlDatabaseVectorSearch/tree/sql). diff --git a/SqlDatabaseVectorSearch/Components/App.razor b/SqlDatabaseVectorSearch/Components/App.razor new file mode 100644 index 0000000..8babb62 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/App.razor @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor new file mode 100644 index 0000000..54a9c59 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor @@ -0,0 +1,56 @@ +@inherits LayoutComponentBase + + + + + + + + + + + + @Body + + + + Footer links... + + + +@code { + private IEnumerable navItems = default!; + + private Task Sidebar2DataProvider(Sidebar2DataProviderRequest request) + { + if (navItems is null) + { + navItems = GetNavItems(); + } + + var result = request.ApplyTo(navItems); + return Task.FromResult(result); + } + + private IEnumerable GetNavItems() + { + navItems = [ + new() { Id = "1", Href = "/", IconName = IconName.HouseDoorFill, Text = "Home", Match = NavLinkMatch.All}, + new() { Id = "2", Href = "/counter", IconName = IconName.PlusSquareFill, Text = "Counter"}, + new() { Id = "3", Href = "/weather", IconName = IconName.Table, Text = "Weather"}, + new() { Id = "4", Href= "/documents", IconName = IconName.FileTypeTxt, Text = "Documents" } + ]; + + return navItems; + } +} + +
+ An unhandled error has occurred. + Reload + 🗙 +
diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css new file mode 100644 index 0000000..a3ae64a --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css @@ -0,0 +1,20 @@ +#blazor-error-ui { + color-scheme: light only; + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + box-sizing: border-box; + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + + #blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; + } \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Components/Pages/Counter.razor b/SqlDatabaseVectorSearch/Components/Pages/Counter.razor new file mode 100644 index 0000000..ef23cb3 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Pages/Counter.razor @@ -0,0 +1,18 @@ +@page "/counter" + +Counter + +

Counter

+ +

Current count: @currentCount

+ + + +@code { + private int currentCount = 0; + + private void IncrementCount() + { + currentCount++; + } +} diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor new file mode 100644 index 0000000..2751635 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -0,0 +1,169 @@ +@page "/documents" +@using MimeMapping + +@inject VectorSearchService vectorSearchService +@inject DocumentService documentService +@inject IJSRuntime JSRuntime + + +Documents + +

Upload new document

+ + +
+
+
+ + + + + + +
+
+
+
+ +
+
+
+
+ +@if (documents.Count > 0) +{ +

Available documents

+ + + + + + + + + + + + @foreach (var document in documents) + { + + + + + + + } + +
NameNumber of chunksCreation Date
+ + @document.Name@document.ChunkCount@document.LocalCreationDateString
+ + +} + +@code { + private Button uploadButton = default!; + private Button deleteButton = default!; + + private IList documents = []; + private List messages = []; + + [SupplyParameterFromForm] + public IBrowserFile? File { get; set; } + + protected override async Task OnInitializedAsync() + { + await LoadDocumentsAsync(); + } + + private async Task LoadDocumentsAsync() + { + var dbDocuments = await documentService.GetAsync(); + + documents.Clear(); + foreach (var dbDocument in dbDocuments) + { + documents.Add(new SelectableDocument(dbDocument.Id, dbDocument.Name, dbDocument.CreationDate, dbDocument.ChunkCount) + { + LocalCreationDateString = await JSRuntime.InvokeAsync("getLocalTime", dbDocument.CreationDate) + }); + } + } + + private void HandleFileSelected(InputFileChangeEventArgs e) + { + File = e.File; + } + + private async Task HandleValidSubmit() + { + if (File is null) + { + return; + } + + uploadButton.ShowLoading(); + + try + { + await using var inputStream = File.OpenReadStream(20 * 1024 * 1024); // 20 MB + await using var stream = await inputStream.GetMemoryStreamAsync(); + + await vectorSearchService.ImportAsync(stream, File.Name, MimeUtility.GetMimeMapping(File.Name), null); + + + CreateToastMessage(ToastType.Success, "Upload document", $"The document {File.Name} has been successfully uploaded and indexed.", DateTime.Now.ToString("g")); + + await LoadDocumentsAsync(); + } + finally + { + uploadButton.HideLoading(); + } + } + + private async Task DeleteSelectedDocuments() + { + var selectedDocuments = documents?.Where(d => d.IsSelected) ?? []; + + try + { + uploadButton.ShowLoading(); + + foreach (var document in selectedDocuments) + { + await documentService.DeleteAsync(document.Id); + } + + await LoadDocumentsAsync(); + CreateToastMessage(ToastType.Info, "Delete documents", "The selected documents have been successfully deleted.", DateTime.Now.ToString("g")); + } + finally + { + uploadButton.HideLoading(); + } + } + + private void CreateToastMessage(ToastType toastType, string title, string message, string? helpText = null) + { + var toastMessage = new ToastMessage + { + Type = toastType, + Title = title, + HelpText = helpText, + Message = message, + AutoHide = true, + }; + + messages.Add(toastMessage); + } + + private record class SelectableDocument(Guid Id, string Name, DateTimeOffset CreationDate, int ChunkCount) : Document(Id, Name, CreationDate, ChunkCount) + { + public bool IsSelected { get; set; } + + public string LocalCreationDateString { get; set; } = string.Empty; + } +} diff --git a/SqlDatabaseVectorSearch/Components/Pages/Error.razor b/SqlDatabaseVectorSearch/Components/Pages/Error.razor new file mode 100644 index 0000000..576cc2d --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Pages/Error.razor @@ -0,0 +1,36 @@ +@page "/Error" +@using System.Diagnostics + +Error + +

Error.

+

An error occurred while processing your request.

+ +@if (ShowRequestId) +{ +

+ Request ID: @RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

+ +@code{ + [CascadingParameter] + private HttpContext? HttpContext { get; set; } + + private string? RequestId { get; set; } + private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + protected override void OnInitialized() => + RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; +} diff --git a/SqlDatabaseVectorSearch/Components/Pages/Home.razor b/SqlDatabaseVectorSearch/Components/Pages/Home.razor new file mode 100644 index 0000000..9773793 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Pages/Home.razor @@ -0,0 +1,12 @@ +@page "/" + +Blazor Bootstrap - Web App (.NET 9) - Starter Template + +

Hello, world!

+ +Welcome to your new Blazor Bootstrap - Web App (.NET 9). +
+
+Interactive render mode: Server +
+Interactivity location: Global \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Components/Pages/Weather.razor b/SqlDatabaseVectorSearch/Components/Pages/Weather.razor new file mode 100644 index 0000000..dd36b18 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Pages/Weather.razor @@ -0,0 +1,63 @@ +@page "/weather" + +Weather + +

Weather

+ +

This component demonstrates showing data.

+ +@if (forecasts == null) +{ +

Loading...

+} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
+} + +@code { + private WeatherForecast[]? forecasts; + + protected override async Task OnInitializedAsync() + { + // Simulate asynchronous loading to demonstrate a loading indicator + await Task.Delay(500); + + var startDate = DateOnly.FromDateTime(DateTime.Now); + var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; + forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = startDate.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }).ToArray(); + } + + private class WeatherForecast + { + public DateOnly Date { get; set; } + public int TemperatureC { get; set; } + public string? Summary { get; set; } + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + } +} diff --git a/SqlDatabaseVectorSearch/Components/Routes.razor b/SqlDatabaseVectorSearch/Components/Routes.razor new file mode 100644 index 0000000..f756e19 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Routes.razor @@ -0,0 +1,6 @@ + + + + + + diff --git a/SqlDatabaseVectorSearch/Components/_Imports.razor b/SqlDatabaseVectorSearch/Components/_Imports.razor new file mode 100644 index 0000000..f24de82 --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/_Imports.razor @@ -0,0 +1,14 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using SqlDatabaseVectorSearch +@using SqlDatabaseVectorSearch.Components +@using SqlDatabaseVectorSearch.Extensions +@using SqlDatabaseVectorSearch.Models +@using SqlDatabaseVectorSearch.Services +@using BlazorBootstrap \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs b/SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs new file mode 100644 index 0000000..0be6602 --- /dev/null +++ b/SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs @@ -0,0 +1,64 @@ +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; + +namespace SqlDatabaseVectorSearch.Extensions; + +public static partial class RequestExtensions +{ + [GeneratedRegex("(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled)] + private static partial Regex MobileBrowserRegex { get; } + + [GeneratedRegex("1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled)] + private static partial Regex MobileBrowserVersionRegex { get; } + + [GeneratedRegex(@"^/(?[a-z]{2})(/|$)", RegexOptions.IgnoreCase | RegexOptions.Compiled)] + private static partial Regex RouteCultureRegex { get; } + + public static bool IsMobileRequest(this HttpContext httpContext) + => httpContext.Request.IsMobile(); + + public static bool IsMobile(this HttpRequest request) + { + var userAgent = request.Headers[HeaderNames.UserAgent].ToString(); + var isMobileBrowser = false; + if (userAgent?.Length > 4 && (MobileBrowserRegex.IsMatch(userAgent) || MobileBrowserVersionRegex.IsMatch(userAgent.AsSpan(0, 4)))) + { + isMobileBrowser = true; + } + + return isMobileBrowser; + } + + public static string GetCultureFromRoute(this HttpContext httpContext) + => RouteCultureRegex.Match(httpContext.Request.Path).Groups["culture"].Value.ToLowerInvariant(); + + public static string GetPathWithCulture(this HttpContext httpContext, string culture) + { + var request = httpContext.Request; + var path = RouteCultureRegex.Replace(request.Path.ToString(), "/"); + var newPath = $"/{culture}{path}{request.QueryString}"; + + return newPath; + } + + public static bool IsApiRequest(this HttpContext httpContext) + => httpContext.Request.Path.StartsWithSegments("/api"); + + public static bool IsSwaggerRequest(this HttpContext httpContext) + => httpContext.Request.Path.StartsWithSegments("/swagger"); + + public static bool IsWebRequest(this HttpContext httpContext) + => !httpContext.IsApiRequest() && !httpContext.IsSwaggerRequest(); + + public static string Content(this IUrlHelper urlHelper, HttpContext httpContext, string contentPath) + => urlHelper.Content(httpContext.Request, contentPath); + + public static string Content(this IUrlHelper urlHelper, HttpRequest request, string contentPath) + { + var path = urlHelper.Content(contentPath); + var url = $"{request.Scheme}://{request.Host}{request.PathBase}{path}"; + + return url; + } +} \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Extensions/StreamExtensions.cs b/SqlDatabaseVectorSearch/Extensions/StreamExtensions.cs new file mode 100644 index 0000000..415eb53 --- /dev/null +++ b/SqlDatabaseVectorSearch/Extensions/StreamExtensions.cs @@ -0,0 +1,16 @@ +namespace SqlDatabaseVectorSearch.Extensions; + +public static class StreamExtensions +{ + public static async Task GetMemoryStreamAsync(this Stream stream) + { + // Use a BufferedStream to read the file in chunks + using var bufferedStream = new BufferedStream(stream); + + var ms = new MemoryStream(); + await bufferedStream.CopyToAsync(ms); + + ms.Position = 0; + return ms; + } +} diff --git a/SqlDatabaseVectorSearch/Program.cs b/SqlDatabaseVectorSearch/Program.cs index 1455b34..7f2c198 100644 --- a/SqlDatabaseVectorSearch/Program.cs +++ b/SqlDatabaseVectorSearch/Program.cs @@ -5,8 +5,10 @@ using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.EntityFrameworkCore; using Microsoft.SemanticKernel; using MimeMapping; +using SqlDatabaseVectorSearch.Components; using SqlDatabaseVectorSearch.ContentDecoders; using SqlDatabaseVectorSearch.DataAccessLayer; +using SqlDatabaseVectorSearch.Extensions; using SqlDatabaseVectorSearch.Models; using SqlDatabaseVectorSearch.Services; using SqlDatabaseVectorSearch.Settings; @@ -21,6 +23,11 @@ builder.Configuration.AddJsonFile("appsettings.local.json", optional: true, relo var aiSettings = builder.Services.ConfigureAndGet(builder.Configuration, "AzureOpenAI")!; var appSettings = builder.Services.ConfigureAndGet(builder.Configuration, nameof(AppSettings))!; +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents(); + +builder.Services.AddBlazorBootstrap(); + builder.Services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); @@ -83,24 +90,50 @@ var app = builder.Build(); // Configure the HTTP request pipeline. app.UseHttpsRedirection(); -app.UseExceptionHandler(new ExceptionHandlerOptions +app.UseWhen(context => context.IsWebRequest(), builder => { - StatusCodeSelector = exception => exception switch + if (!app.Environment.IsDevelopment()) { - NotSupportedException => StatusCodes.Status501NotImplemented, - _ => StatusCodes.Status500InternalServerError + builder.UseExceptionHandler("/error"); + + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + builder.UseHsts(); } + + builder.UseStatusCodePagesWithReExecute("/error"); }); -app.UseStatusCodePages(); +app.UseWhen(context => context.IsApiRequest(), builder => +{ + app.UseExceptionHandler(new ExceptionHandlerOptions + { + StatusCodeSelector = exception => exception switch + { + NotSupportedException => StatusCodes.Status501NotImplemented, + _ => StatusCodes.Status500InternalServerError + } + }); + + builder.UseStatusCodePages(); +}); app.MapOpenApi(); app.UseSwaggerUI(options => { - options.RoutePrefix = string.Empty; options.SwaggerEndpoint("/openapi/v1.json", builder.Environment.ApplicationName); }); +app.UseRouting(); +// app.UseRateLimiter(); +app.UseRequestLocalization(); +// app.UseCors(); + +app.UseAntiforgery(); + +app.MapStaticAssets(); +app.MapRazorComponents() + .AddInteractiveServerRenderMode(); + app.MapPost("/api/ask", async (Question question, VectorSearchService vectorSearchService, CancellationToken cancellationToken, [Description("If true, the question will be reformulated taking into account the context of the chat identified by the given ConversationId.")] bool reformulate = true) => { diff --git a/SqlDatabaseVectorSearch/Properties/launchSettings.json b/SqlDatabaseVectorSearch/Properties/launchSettings.json index f677316..3306ea1 100644 --- a/SqlDatabaseVectorSearch/Properties/launchSettings.json +++ b/SqlDatabaseVectorSearch/Properties/launchSettings.json @@ -5,8 +5,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "launchUrl": "", - "applicationUrl": "https://localhost:7024;http://localhost:5178", + "applicationUrl": "https://localhost:7025;http://localhost:5178", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj index c8e83e5..3a3f57f 100644 --- a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj +++ b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj @@ -8,6 +8,7 @@ + diff --git a/SqlDatabaseVectorSearch/wwwroot/app.css b/SqlDatabaseVectorSearch/wwwroot/app.css new file mode 100644 index 0000000..2839617 --- /dev/null +++ b/SqlDatabaseVectorSearch/wwwroot/app.css @@ -0,0 +1,40 @@ +:root { + --bs-body-bg: #fff; + --bb-sidebar2-top-row-background-color: var(--bb-violet-bg); + --bb-sidebar2-top-row-border-color: var(--bb-violet-bg); + --bb-sidebar2-navbar-toggler-icon-color: var(--bb-violet-bg); + --bb-sidebar2-nav-item-text-active-color-rgb: 112.520718, 44.062154, 249.437846; + --bb-sidebar2-nav-item-text-color: rgba(0,0,0,0.9); + --bb-sidebar2-nav-item-text-hover-color: rgba(var(--bb-sidebar2-nav-item-text-active-color-rgb), 0.9); + --bb-sidebar2-nav-item-text-active-color: rgba(var(--bb-sidebar2-nav-item-text-active-color-rgb), 0.9); + --bb-sidebar2-nav-item-background-hover-color: rgba(var(--bb-sidebar2-nav-item-text-active-color-rgb), 0.08); + --bb-sidebar2-nav-item-group-background-color: rgba(var(--bb-sidebar2-nav-item-text-active-color-rgb), 0.08); +} + +h1:focus { + outline: none; +} + +.bb-sidebar2 nav .nav-item a { + color: var(--bb-sidebar2-nav-item-text-color) !important; +} + + .bb-sidebar2 nav .nav-item a:hover { + background-color: var(--bb-sidebar2-nav-item-background-hover-color) !important; + color: var(--bb-sidebar2-nav-item-text-hover-color) !important; + } + + .bb-sidebar2 nav .nav-item a.active { + background-color: var(--bb-sidebar2-nav-item-background-hover-color) !important; + color: var(--bb-sidebar2-nav-item-text-active-color) !important; + } + +.blazor-error-boundary { + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + + .blazor-error-boundary::after { + content: "An error has occurred." + } \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/wwwroot/favicon.png b/SqlDatabaseVectorSearch/wwwroot/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..4d1b2564caad5b2e021ae65ec36bb8a165686e57 GIT binary patch literal 2193 zcmZ{ldpy&N8^^ycF}K2$$~sQ5QoA#0YHp40K`)OU|WFV=K}`R)Usdv^GE+b#!cZ3@06+@-OF}??0Ym`BiD)M~@j3A$5^^9z zl?UGhL=|m|bo1=$$+;AyFm|{%Zf@wbF`~6mkrU}e5sEO*@qB7Tu$iQw2(oBSKI&j1 z-7UBRGgH_?ce5rVI}iRvt}CHcTg+nLd(cq(j+Im8l?>pfjdXnzE_-7-Akz8BD7W^Z z>KUgGF6Qs^RuJ3tz1_K;;s~*ShqWhc?q1%@No8n^Wo4Teq;>1g^b#1CC zr>)k0e!2qCJ_fqT|3h<+yae^jD$hYk+-*4<6nE%e%$Fa9bG(Aucd4;_5hkNz3d39%Viz{keQ)a7(QY^qFbkB+#wvhKm} zL>W2J->0zC8IZ0Zvh1^Ks#)7-JL{2^EVL%9i26QS6lhOdM)Xvjuf!rqOUH_$grp&0 zgH1w&0i5EK|1q(1IE<1*#?t=uekkDlAtGd7ZiFQDql{h zx#s65%=y8}$a8Ocjjd(p^!uZEp-Fo$V`s(r!jl6Qee(cTbyW$?G zXt{XoiRz{_NsT|SmYwbE!r6FV)+Vk4q#*YKO7X~WpwcJa#{ z`)rYW5Zo%cxWB*O9&+7K;ZZNTa-@cl{09gcm8(2AU>`R-y5UfpQ?zw1fOK_nS~N~~ z8j+i|*~Suz@(Qfnh$NHAE>0xwLm@TChv73_q<-%m!~!)SY~GzR;S%hYO%&^n+=YeEW?(ULE(L(*!sOudNkGj4BPv2Hk>@o+h zYnURw_Tp2lP5@A?GuDB$RQLz(t%eCbq-?DhG5rPX)fZ}q&%_n6yX__5_yHZvVo(AjG*5bm>^ zB2pao(BHbDu-&&~;W+fWqMz;D=b@f??-In~%_El}Yf%NaEsGoUQVxl**=*ebS5W`d zlEU1-Yl!W!o(Ut^88cH1eo-ufe|M^=HjFf?-5hXWxQ%~hyM?T3$V{MS)HB-~{4KID z6F!STwMPxy!eS`T_*w=Q(+TVTL4I0Ud130_tW@LW*45veH-EQ4?5fNx;Ta)U15RF= z^|nkzNi*B#4w?kVrQPGM`Dh=omV4BDaUB088$Ust66|AgIEKze7I_(1zf>d!ec{5` z6D6gGVjD4qc?)`RF_T)S5@l(jJcH zqmDK7>B&kZwg;<4mQ;T{VPj*H4G&09PzUwR+)R-cMJDn6ifZOKPgcWJ4laBxtI?u@ zdmF?dQPEcH!0m801Vhk+{_XYIY=3j`$NuRf5hWdUbA!rHLYCFA1N4;zf#Ni;MT_xCU9? zAGGooZxrzdO==7qW{y|OcCL}F=%Vp(?W2^{NoJkLCv?l#tWgNAUe7@sDH}>lf9{!j zqiGQh#p!QTu@3XMy^2R;?27RhuhZO{yq2e0Nuiku;N#Bo9UUExWz2iCyy(S^Z5-js zTeTl(DpnM!?ojbQKS}(+*@SB0Cs`ORZyklN^Yc0t*s71TtFH(&sDdPQ5Px7b-c^V? zIP;RpWTJ<88G2LEZIWPXn5CunyE$HFie-B`mSGw?{d({go5p|yr>5`O6n-2+L6zw% za|{NV*o5F$`RMCPh|;C O0BAdB+d6BX#Qy-V#`@9# literal 0 HcmV?d00001 diff --git a/SqlDatabaseVectorSearch/wwwroot/js/functions.js b/SqlDatabaseVectorSearch/wwwroot/js/functions.js new file mode 100644 index 0000000..75b35c4 --- /dev/null +++ b/SqlDatabaseVectorSearch/wwwroot/js/functions.js @@ -0,0 +1,3 @@ +function getLocalTime(utcDateTime) { + return new Date(utcDateTime).toLocaleString(); +} From 83e8f8ff23efca34764532fdddd05bf3f281bf99 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Fri, 14 Feb 2025 17:38:03 +0100 Subject: [PATCH 02/25] Update document management UI and functionality - Changed the "Documents" icon in `MainLayout.razor`. - Added a `ConfirmDialog` component in `Documents.razor` for user confirmations. - Adjusted the capitalization of the creation date column header. - Restructured the delete button layout for better responsiveness and changed its icon. - Updated lifecycle method from `OnInitializedAsync` to `OnAfterRenderAsync` for improved document loading. - Introduced a new asynchronous method for obtaining local date strings. - Updated toast messages to use the new date formatting method. - Added a new method for converting UTC dates to local time. - Introduced a `SelectableDocument` record class to enhance document management. --- .../Components/Layout/MainLayout.razor | 2 +- .../Components/Pages/Documents.razor | 51 +++++++++++++++---- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor index 54a9c59..11dbb73 100644 --- a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor @@ -42,7 +42,7 @@ new() { Id = "1", Href = "/", IconName = IconName.HouseDoorFill, Text = "Home", Match = NavLinkMatch.All}, new() { Id = "2", Href = "/counter", IconName = IconName.PlusSquareFill, Text = "Counter"}, new() { Id = "3", Href = "/weather", IconName = IconName.Table, Text = "Weather"}, - new() { Id = "4", Href= "/documents", IconName = IconName.FileTypeTxt, Text = "Documents" } + new() { Id = "4", Href= "/documents", IconName = IconName.FileText, Text = "Documents" } ]; return navItems; diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor index 2751635..19889a3 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -6,6 +6,8 @@ @inject IJSRuntime JSRuntime + + Documents

Upload new document

@@ -40,7 +42,7 @@ Name Number of chunks - Creation Date + Creation date @@ -58,12 +60,19 @@ - +
+
+
+ +
+
+
} @code { + private ConfirmDialog dialog = default!; private Button uploadButton = default!; private Button deleteButton = default!; @@ -73,8 +82,13 @@ [SupplyParameterFromForm] public IBrowserFile? File { get; set; } - protected override async Task OnInitializedAsync() + protected override async Task OnAfterRenderAsync(bool firstRender) { + if (!firstRender) + { + return; + } + await LoadDocumentsAsync(); } @@ -87,9 +101,11 @@ { documents.Add(new SelectableDocument(dbDocument.Id, dbDocument.Name, dbDocument.CreationDate, dbDocument.ChunkCount) { - LocalCreationDateString = await JSRuntime.InvokeAsync("getLocalTime", dbDocument.CreationDate) + LocalCreationDateString = await GetLocalDateTimeStringAsync(dbDocument.CreationDate) }); } + + StateHasChanged(); } private void HandleFileSelected(InputFileChangeEventArgs e) @@ -114,7 +130,7 @@ await vectorSearchService.ImportAsync(stream, File.Name, MimeUtility.GetMimeMapping(File.Name), null); - CreateToastMessage(ToastType.Success, "Upload document", $"The document {File.Name} has been successfully uploaded and indexed.", DateTime.Now.ToString("g")); + CreateToastMessage(ToastType.Success, "Upload document", $"The document {File.Name} has been successfully uploaded and indexed.", await GetLocalDateTimeStringAsync(DateTimeOffset.UtcNow)); await LoadDocumentsAsync(); } @@ -128,9 +144,19 @@ { var selectedDocuments = documents?.Where(d => d.IsSelected) ?? []; + var confirmation = await dialog.ShowAsync( + title: "Delete the selected document?", + message1: "This will delete the documents and all the corresponding embeddings. The operation cannot be undone.", + message2: "Do you want to proceed?"); + + if (!confirmation) + { + return; + } + try { - uploadButton.ShowLoading(); + deleteButton.ShowLoading(); foreach (var document in selectedDocuments) { @@ -138,11 +164,11 @@ } await LoadDocumentsAsync(); - CreateToastMessage(ToastType.Info, "Delete documents", "The selected documents have been successfully deleted.", DateTime.Now.ToString("g")); + CreateToastMessage(ToastType.Info, "Delete documents", "The selected documents have been successfully deleted.", await GetLocalDateTimeStringAsync(DateTimeOffset.UtcNow)); } finally { - uploadButton.HideLoading(); + deleteButton.HideLoading(); } } @@ -160,6 +186,11 @@ messages.Add(toastMessage); } + private async Task GetLocalDateTimeStringAsync(DateTimeOffset dateTime) + { + return await JSRuntime.InvokeAsync("getLocalTime", dateTime); + } + private record class SelectableDocument(Guid Id, string Name, DateTimeOffset CreationDate, int ChunkCount) : Document(Id, Name, CreationDate, ChunkCount) { public bool IsSelected { get; set; } From f9a2bf0bf9aa566e723f23b25e250426e89627ef Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Fri, 14 Feb 2025 18:01:59 +0100 Subject: [PATCH 03/25] Enhance document upload and sidebar functionality - Updated `Sidebar2` in `MainLayout.razor` for SQL Vector Search. - Improved document upload interface in `Documents.razor` with icons and tooltips. - Adjusted layout to include Document ID input and changed checkbox to `CheckboxInput`. - Added `documentId` property for handling document uploads. - Enhanced `SelectableDocument` class with `ContentType` property for better document info. --- .../Components/Layout/MainLayout.razor | 4 +-- .../Components/Pages/Documents.razor | 35 ++++++++++++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor index 11dbb73..b9e8526 100644 --- a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor @@ -7,8 +7,8 @@ diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor index 19889a3..9b42243 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -10,11 +10,14 @@ Documents -

Upload new document

+

+ + Upload new document +

-
+
@@ -24,6 +27,17 @@
+
+
+ + + + + Document ID + + +
+
@@ -34,13 +48,18 @@ @if (documents.Count > 0) { -

Available documents

+

+ + Available documents +

+ + @@ -50,9 +69,11 @@ { + + @@ -82,6 +103,8 @@ [SupplyParameterFromForm] public IBrowserFile? File { get; set; } + public string? documentId { get; set; } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) @@ -127,7 +150,7 @@ await using var inputStream = File.OpenReadStream(20 * 1024 * 1024); // 20 MB await using var stream = await inputStream.GetMemoryStreamAsync(); - await vectorSearchService.ImportAsync(stream, File.Name, MimeUtility.GetMimeMapping(File.Name), null); + await vectorSearchService.ImportAsync(stream, File.Name, MimeUtility.GetMimeMapping(File.Name), Guid.Parse(documentId)); CreateToastMessage(ToastType.Success, "Upload document", $"The document {File.Name} has been successfully uploaded and indexed.", await GetLocalDateTimeStringAsync(DateTimeOffset.UtcNow)); @@ -195,6 +218,8 @@ { public bool IsSelected { get; set; } + public string ContentType => MimeUtility.GetMimeMapping(Name); + public string LocalCreationDateString { get; set; } = string.Empty; } } From be3f0dbf09c826dc243cd5f0f0145b65049796e6 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Mon, 17 Feb 2025 12:32:12 +0100 Subject: [PATCH 04/25] Update document handling and styling improvements - Changed `app.css` path in `App.razor`. - Refactored `Documents.razor` to improve form handling: - Removed `VectorSearchService` injection; added `IServiceProvider` and `IJSRuntime`. - Updated header from `

` to `

`. - Introduced `uploadDocumentRequest` for form state management. - Modified document ID input for optional GUID with validation. - Disabled upload button when no file is selected. - Enhanced document loading logic with scoped service provider. - Updated deletion logic to handle multiple document IDs. - Added method in `DocumentService.cs` for bulk document deletion. - Restructured `app.css` for improved styling and new validation/error message styles. --- SqlDatabaseVectorSearch/Components/App.razor | 2 +- .../Components/Pages/Documents.razor | 82 +++++++++++++------ .../Components/_Imports.razor | 3 +- .../Services/DocumentService.cs | 3 + .../wwwroot/{ => css}/app.css | 12 +++ 5 files changed, 73 insertions(+), 29 deletions(-) rename SqlDatabaseVectorSearch/wwwroot/{ => css}/app.css (95%) diff --git a/SqlDatabaseVectorSearch/Components/App.razor b/SqlDatabaseVectorSearch/Components/App.razor index 8babb62..6b1533a 100644 --- a/SqlDatabaseVectorSearch/Components/App.razor +++ b/SqlDatabaseVectorSearch/Components/App.razor @@ -9,7 +9,7 @@ - + diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor index 9b42243..a9ba723 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -1,8 +1,7 @@ @page "/documents" @using MimeMapping -@inject VectorSearchService vectorSearchService -@inject DocumentService documentService +@inject IServiceProvider ServiceProvider @inject IJSRuntime JSRuntime @@ -10,12 +9,14 @@ Documents -

+

Upload new document -

+

+ + + -
@@ -35,23 +36,30 @@ Document ID - +
+
- +
-@if (documents.Count > 0) +@if (documents.Count == 0) { -

+
+ +
+} +else +{ +

Available documents -

+
Id NameContent type Number of chunks Creation date
- + @document.Id @document.Name@document.ContentType @document.ChunkCount @document.LocalCreationDateString
@@ -100,10 +108,14 @@ private IList documents = []; private List messages = []; - [SupplyParameterFromForm] - public IBrowserFile? File { get; set; } + private UploadDocumentRequest uploadDocumentRequest = new(); + private EditContext? editContext; - public string? documentId { get; set; } + protected override void OnInitialized() + { + editContext = new EditContext(uploadDocumentRequest); + base.OnInitialized(); + } protected override async Task OnAfterRenderAsync(bool firstRender) { @@ -112,11 +124,14 @@ return; } - await LoadDocumentsAsync(); + await Task.Delay(2000); + await using var scope = ServiceProvider.CreateAsyncScope(); + await LoadDocumentsAsync(scope.ServiceProvider); } - private async Task LoadDocumentsAsync() + private async Task LoadDocumentsAsync(IServiceProvider services) { + var documentService = services.GetRequiredService(); var dbDocuments = await documentService.GetAsync(); documents.Clear(); @@ -133,12 +148,12 @@ private void HandleFileSelected(InputFileChangeEventArgs e) { - File = e.File; + uploadDocumentRequest.File = e.File; } private async Task HandleValidSubmit() { - if (File is null) + if (uploadDocumentRequest.File is null) { return; } @@ -147,15 +162,19 @@ try { - await using var inputStream = File.OpenReadStream(20 * 1024 * 1024); // 20 MB + var fileName = uploadDocumentRequest.File.Name; + await using var inputStream = uploadDocumentRequest.File.OpenReadStream(20 * 1024 * 1024); // 20 MB await using var stream = await inputStream.GetMemoryStreamAsync(); - await vectorSearchService.ImportAsync(stream, File.Name, MimeUtility.GetMimeMapping(File.Name), Guid.Parse(documentId)); + await using var scope = ServiceProvider.CreateAsyncScope(); + var vectorSearchService = scope.ServiceProvider.GetRequiredService(); + var documentId = string.IsNullOrWhiteSpace(uploadDocumentRequest.DocumentId) ? null : (Guid?)Guid.Parse(uploadDocumentRequest.DocumentId); + await vectorSearchService.ImportAsync(stream, fileName, MimeUtility.GetMimeMapping(fileName), documentId); - CreateToastMessage(ToastType.Success, "Upload document", $"The document {File.Name} has been successfully uploaded and indexed.", await GetLocalDateTimeStringAsync(DateTimeOffset.UtcNow)); + CreateToastMessage(ToastType.Success, "Upload document", $"The document {fileName} has been successfully uploaded and indexed.", await GetLocalDateTimeStringAsync(DateTimeOffset.UtcNow)); - await LoadDocumentsAsync(); + await LoadDocumentsAsync(scope.ServiceProvider); } finally { @@ -165,7 +184,7 @@ private async Task DeleteSelectedDocuments() { - var selectedDocuments = documents?.Where(d => d.IsSelected) ?? []; + var selectedDocumentIds = documents?.Where(d => d.IsSelected).Select(d => d.Id) ?? []; var confirmation = await dialog.ShowAsync( title: "Delete the selected document?", @@ -181,12 +200,12 @@ { deleteButton.ShowLoading(); - foreach (var document in selectedDocuments) - { - await documentService.DeleteAsync(document.Id); - } + await using var scope = ServiceProvider.CreateAsyncScope(); + var documentService = scope.ServiceProvider.GetRequiredService(); - await LoadDocumentsAsync(); + await documentService.DeleteAsync(selectedDocumentIds); + + await LoadDocumentsAsync(scope.ServiceProvider); CreateToastMessage(ToastType.Info, "Delete documents", "The selected documents have been successfully deleted.", await GetLocalDateTimeStringAsync(DateTimeOffset.UtcNow)); } finally @@ -222,4 +241,13 @@ public string LocalCreationDateString { get; set; } = string.Empty; } + + public class UploadDocumentRequest + { + [SupplyParameterFromForm] + public IBrowserFile? File { get; set; } + + [RegularExpression(@"^(\{|\()?[0-9a-fA-F]{8}(-?)[0-9a-fA-F]{4}(-?)[0-9a-fA-F]{4}(-?)[0-9a-fA-F]{4}(-?)[0-9a-fA-F]{12}(\}|\))?$", ErrorMessage = "Invalid GUID format.")] + public string? DocumentId { get; set; } + } } diff --git a/SqlDatabaseVectorSearch/Components/_Imports.razor b/SqlDatabaseVectorSearch/Components/_Imports.razor index f24de82..06b940f 100644 --- a/SqlDatabaseVectorSearch/Components/_Imports.razor +++ b/SqlDatabaseVectorSearch/Components/_Imports.razor @@ -1,4 +1,5 @@ -@using System.Net.Http +@using System.ComponentModel.DataAnnotations +@using System.Net.Http @using System.Net.Http.Json @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing diff --git a/SqlDatabaseVectorSearch/Services/DocumentService.cs b/SqlDatabaseVectorSearch/Services/DocumentService.cs index 5896ecc..2a6c6ef 100644 --- a/SqlDatabaseVectorSearch/Services/DocumentService.cs +++ b/SqlDatabaseVectorSearch/Services/DocumentService.cs @@ -36,4 +36,7 @@ public class DocumentService(ApplicationDbContext dbContext) public Task DeleteAsync(Guid documentId, CancellationToken cancellationToken = default) => dbContext.Documents.Where(d => d.Id == documentId).ExecuteDeleteAsync(cancellationToken); + + public Task DeleteAsync(IEnumerable documentIds, CancellationToken cancellationToken = default) + => dbContext.Documents.Where(d => documentIds.Contains(d.Id)).ExecuteDeleteAsync(cancellationToken); } \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/wwwroot/app.css b/SqlDatabaseVectorSearch/wwwroot/css/app.css similarity index 95% rename from SqlDatabaseVectorSearch/wwwroot/app.css rename to SqlDatabaseVectorSearch/wwwroot/css/app.css index 2839617..a1da72e 100644 --- a/SqlDatabaseVectorSearch/wwwroot/app.css +++ b/SqlDatabaseVectorSearch/wwwroot/css/app.css @@ -29,6 +29,18 @@ h1:focus { color: var(--bb-sidebar2-nav-item-text-active-color) !important; } +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + .blazor-error-boundary { background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; padding: 1rem 1rem 1rem 3.7rem; From d1ce7111c3285eb1566cdaed527ad4c7ee0ad305 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Mon, 17 Feb 2025 13:02:32 +0100 Subject: [PATCH 05/25] Enhance document loading and update UI in Blazor app - Added `StateHasChanged()` call after loading documents in `Documents.razor`. - Introduced `LoadDocumentsAsync` method for document retrieval. - Updated page title in `Home.razor` and injected `IHttpClientFactory`. - Implemented loading spinner and markdown fetching in `OnAfterRenderAsync`. - Configured HTTP client with resilience handler in `Program.cs`. --- .../Components/Pages/Documents.razor | 4 +- .../Components/Pages/Home.razor | 42 +++++++++++++++---- SqlDatabaseVectorSearch/Program.cs | 1 + 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor index a9ba723..7f8aa6d 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -127,6 +127,8 @@ else await Task.Delay(2000); await using var scope = ServiceProvider.CreateAsyncScope(); await LoadDocumentsAsync(scope.ServiceProvider); + + StateHasChanged(); } private async Task LoadDocumentsAsync(IServiceProvider services) @@ -142,8 +144,6 @@ else LocalCreationDateString = await GetLocalDateTimeStringAsync(dbDocument.CreationDate) }); } - - StateHasChanged(); } private void HandleFileSelected(InputFileChangeEventArgs e) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Home.razor b/SqlDatabaseVectorSearch/Components/Pages/Home.razor index 9773793..8730203 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Home.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Home.razor @@ -1,12 +1,38 @@ @page "/" +@rendermode @(new InteractiveServerRenderMode(prerender: false)) -Blazor Bootstrap - Web App (.NET 9) - Starter Template +@inject IHttpClientFactory HttpClientFactory -

Hello, world!

+SQL Database Vector Search -Welcome to your new Blazor Bootstrap - Web App (.NET 9). -
-
-Interactive render mode: Server -
-Interactivity location: Global \ No newline at end of file +@if (markdown is null) +{ +
+ +
+} +else +{ +
+
+ @markdown +
+
+} + +@code +{ + private string markdown = default!; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (!firstRender) + { + return; + } + + markdown = await HttpClientFactory.CreateClient().GetStringAsync("https://raw.githubusercontent.com/marcominerva/SqlDatabaseVectorSearch/refs/heads/master/README.md"); + + StateHasChanged(); + } +} \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Program.cs b/SqlDatabaseVectorSearch/Program.cs index 7f2c198..fb5b967 100644 --- a/SqlDatabaseVectorSearch/Program.cs +++ b/SqlDatabaseVectorSearch/Program.cs @@ -51,6 +51,7 @@ builder.Services.AddHybridCache(options => }; }); +builder.Services.AddHttpClient(); builder.Services.ConfigureHttpClientDefaults(builder => { builder.AddStandardResilienceHandler(); From f0cccb00b9d9736861a9030cffb8978a75321784 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Tue, 18 Feb 2025 14:41:16 +0100 Subject: [PATCH 06/25] Enhance error handling UI and middleware in ASP.NET Updated `Error.razor` to provide distinct 404 and 500 error messages with a user-friendly layout, including a home button. Conditionally rendered Request ID display and removed development mode information for a cleaner user experience. Modified `Program.cs` to change error handling middleware from re-executing the error page to redirecting with error codes, improving error information passed to the error page. --- .../Components/Pages/Error.razor | 56 ++++++++++++------- SqlDatabaseVectorSearch/Program.cs | 2 +- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Error.razor b/SqlDatabaseVectorSearch/Components/Pages/Error.razor index 576cc2d..2ae9814 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Error.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Error.razor @@ -1,33 +1,49 @@ @page "/Error" @using System.Diagnostics +@rendermode @(new InteractiveServerRenderMode(prerender: false)) -Error +
+
+ @if (Code == 404) + { + Page Not Found -

Error.

-

An error occurred while processing your request.

+

404

+

Ops! Page Not Found.

+

+ The page you're looking for does not exists. +

+ } + else + { + Unexpected Error -@if (ShowRequestId) -{ -

- Request ID: @RequestId -

-} +

500

+

Ops! Unexpected error.

+

+ An unexpected error occurred while loading the page. Please, wait a minute and try again. +

+ } -

Development Mode

-

- Swapping to Development environment will display more detailed information about the error that occurred. -

-

- The Development environment shouldn't be enabled for deployed applications. - It can result in displaying sensitive information from exceptions to end users. - For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development - and restarting the app. -

+ Back to Home -@code{ + @if (ShowRequestId) + { +

+ Request ID: @RequestId +

+ } +
+
+ +@code { [CascadingParameter] private HttpContext? HttpContext { get; set; } + [Parameter] + [SupplyParameterFromQuery(Name = "code")] + public int Code { get; set; } + private string? RequestId { get; set; } private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); diff --git a/SqlDatabaseVectorSearch/Program.cs b/SqlDatabaseVectorSearch/Program.cs index fb5b967..7c20f81 100644 --- a/SqlDatabaseVectorSearch/Program.cs +++ b/SqlDatabaseVectorSearch/Program.cs @@ -101,7 +101,7 @@ app.UseWhen(context => context.IsWebRequest(), builder => builder.UseHsts(); } - builder.UseStatusCodePagesWithReExecute("/error"); + builder.UseStatusCodePagesWithRedirects("/error?code={0}"); }); app.UseWhen(context => context.IsApiRequest(), builder => From 9c19b4ec73cc235eb08d660e8543cf4834d5e0ac Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Tue, 18 Feb 2025 17:54:34 +0100 Subject: [PATCH 07/25] Refactor layout and remove unused components Updated `MainLayout.razor` to include a GitHub link and modified sidebar navigation. Removed `Counter.razor` and integrated its functionality into `Ask.razor`. Enhanced error handling in `Error.razor` and removed request ID display. Deleted `Weather.razor` and its associated content. --- .../Components/Layout/MainLayout.razor | 17 ++--- .../Pages/{Counter.razor => Ask.razor} | 0 .../Components/Pages/Error.razor | 15 +---- .../Components/Pages/Weather.razor | 63 ------------------- 4 files changed, 10 insertions(+), 85 deletions(-) rename SqlDatabaseVectorSearch/Components/Pages/{Counter.razor => Ask.razor} (100%) delete mode 100644 SqlDatabaseVectorSearch/Components/Pages/Weather.razor diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor index b9e8526..ed2879b 100644 --- a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor @@ -2,15 +2,17 @@ - + + + + IconName="IconName.Search" + Title="SQL Vector Search" + DataProvider="Sidebar2DataProvider" + WidthUnit="Unit.Px" /> @@ -40,9 +42,8 @@ { navItems = [ new() { Id = "1", Href = "/", IconName = IconName.HouseDoorFill, Text = "Home", Match = NavLinkMatch.All}, - new() { Id = "2", Href = "/counter", IconName = IconName.PlusSquareFill, Text = "Counter"}, - new() { Id = "3", Href = "/weather", IconName = IconName.Table, Text = "Weather"}, - new() { Id = "4", Href= "/documents", IconName = IconName.FileText, Text = "Documents" } + new() { Id = "2", Href = "/ask", IconName = IconName.ChatDots, Text = "Ask"}, + new() { Id = "3", Href= "/documents", IconName = IconName.FileText, Text = "Documents" } ]; return navItems; diff --git a/SqlDatabaseVectorSearch/Components/Pages/Counter.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor similarity index 100% rename from SqlDatabaseVectorSearch/Components/Pages/Counter.razor rename to SqlDatabaseVectorSearch/Components/Pages/Ask.razor diff --git a/SqlDatabaseVectorSearch/Components/Pages/Error.razor b/SqlDatabaseVectorSearch/Components/Pages/Error.razor index 2ae9814..8f4830b 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Error.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Error.razor @@ -14,7 +14,7 @@ The page you're looking for does not exists.

} - else + else if (Code > 0) { Unexpected Error @@ -26,13 +26,6 @@ } Back to Home - - @if (ShowRequestId) - { -

- Request ID: @RequestId -

- } @@ -43,10 +36,4 @@ [Parameter] [SupplyParameterFromQuery(Name = "code")] public int Code { get; set; } - - private string? RequestId { get; set; } - private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - - protected override void OnInitialized() => - RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; } diff --git a/SqlDatabaseVectorSearch/Components/Pages/Weather.razor b/SqlDatabaseVectorSearch/Components/Pages/Weather.razor deleted file mode 100644 index dd36b18..0000000 --- a/SqlDatabaseVectorSearch/Components/Pages/Weather.razor +++ /dev/null @@ -1,63 +0,0 @@ -@page "/weather" - -Weather - -

Weather

- -

This component demonstrates showing data.

- -@if (forecasts == null) -{ -

Loading...

-} -else -{ -
- - - - - - - - - - @foreach (var forecast in forecasts) - { - - - - - - - } - -
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
-} - -@code { - private WeatherForecast[]? forecasts; - - protected override async Task OnInitializedAsync() - { - // Simulate asynchronous loading to demonstrate a loading indicator - await Task.Delay(500); - - var startDate = DateOnly.FromDateTime(DateTime.Now); - var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; - forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = startDate.AddDays(index), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = summaries[Random.Shared.Next(summaries.Length)] - }).ToArray(); - } - - private class WeatherForecast - { - public DateOnly Date { get; set; } - public int TemperatureC { get; set; } - public string? Summary { get; set; } - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - } -} From ca51b19ea35da29ac9e60f3cca94f9aa47b2d7af Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Tue, 18 Feb 2025 17:56:02 +0100 Subject: [PATCH 08/25] Change page route and update titles in Ask.razor Updated the route from "/counter" to "/ask". Changed the page title from "Counter" to "Chat with your data" and modified the heading accordingly. The functionality for displaying the current count and the increment button remains intact. --- SqlDatabaseVectorSearch/Components/Pages/Ask.razor | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor index ef23cb3..60013c5 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor @@ -1,8 +1,6 @@ -@page "/counter" +@page "/ask" -Counter - -

Counter

+Chat with your data

Current count: @currentCount

From 9f6ac67b26ec59fe9155a25f21bc6e9e02f98ac1 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Wed, 19 Feb 2025 16:48:02 +0100 Subject: [PATCH 09/25] Enhance chat interface and update styles Significantly updated `Ask.razor` to improve the chat interface with a new layout for user and assistant messages, added input area for questions, and buttons for submission and reset. Removed the previous count display and introduced asynchronous message handling and a new `Message` class. Minor change in `Documents.razor` by removing a 2000 ms delay before loading documents. Updated `Ask.razor.css` with new styles for tooltips, avatars, input fields, card bodies, and progress indicators. Added or updated `assistant.png` and `user.png` for new avatar images in the chat interface. --- .../Components/Pages/Ask.razor | 149 +++++++++++++++++- .../Components/Pages/Ask.razor.css | 100 ++++++++++++ .../Components/Pages/Documents.razor | 1 - .../wwwroot/images/assistant.png | Bin 0 -> 2058 bytes .../wwwroot/images/user.png | Bin 0 -> 1010 bytes 5 files changed, 242 insertions(+), 8 deletions(-) create mode 100644 SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css create mode 100644 SqlDatabaseVectorSearch/wwwroot/images/assistant.png create mode 100644 SqlDatabaseVectorSearch/wwwroot/images/user.png diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor index 60013c5..4acc8bf 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor @@ -1,16 +1,151 @@ @page "/ask" +@inject IServiceProvider ServiceProvider +@inject IJSRuntime JSRuntime + Chat with your data -

Current count: @currentCount

+
+
- + @foreach (var message in messages) + { + if (message.Role == "user") + { +
+
+
+
+ @message.Text +
+
+
+
+ +
+
+ } + else if (message.Role == "assistant") + { +
+
+ +
+
+
+ @if (message.Text is null) + { +
+
+
+
+
+
+
+ } + else + { +
+
+ @message.Text +
+ @if (message.IsCompleted) + { +
+ + + +
+ } +
+ } +
+
+
+ } + } +
-@code { - private int currentCount = 0; + +
- private void IncrementCount() +@code +{ + private Button askButton = default!; + private Button resetButton = default!; + + private IList messages = []; + private string? question; + + private Guid conversationId = Guid.NewGuid(); + private bool isAsking = false; + + + private async Task AskQuestion() { - currentCount++; + isAsking = true; + + try + { + var userMessage = new Message { Text = question, Role = "user" }; + messages.Add(userMessage); + + var assistantMessage = new Message { Role = "assistant" }; + messages.Add(assistantMessage); + + await using var scope = ServiceProvider.CreateAsyncScope(); + var vectorSearchService = scope.ServiceProvider.GetRequiredService(); + + var response = await vectorSearchService.AskQuestionAsync(new Question(conversationId, question!)); + + assistantMessage.Text = response.Answer; + assistantMessage.IsCompleted = true; + + question = null; + } + finally + { + isAsking = false; + } } -} + + private void Reset() + { + question = null; + conversationId = Guid.NewGuid(); + messages.Clear(); + } + + private ValueTask CopyToClipboard(string text) + { + return JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", text); + } + + public class Message + { + public string? Text { get; set; } + + public required string Role { get; set; } + + public bool IsCompleted { get; set; } + } +} \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css new file mode 100644 index 0000000..7fa7e3b --- /dev/null +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css @@ -0,0 +1,100 @@ +.tooltip-inner { + text-align: left; +} + +.avatar { + width: 50px; + height: 50px; + border-radius: 50%; + border: 2px solid #ddd; + padding: 2px; + flex: none; +} + +input:focus { + outline: 0px !important; + box-shadow: none !important; +} + +input[type="checkbox"], +input[type="checkbox"] + label { + cursor: pointer; +} + +.card-body { + overflow: auto; + height: 490px; +} + +@media (min-width: 768px) { + .card-body { + height: 595px; + } +} + +@media (min-width: 2560px) { + .card-body { + height: 950px; + } +} + +.card-text { + border: 2px solid #ddd; + border-radius: 8px; +} + +.progress-chat { + width: 200px; + height: 4px; +} + +.progress-bar-chat { + height: 4px; + background-color: rgba(5, 114, 206, 0.2); + width: 100%; + overflow: hidden; +} + +.progress-bar-indeterminate { + width: 100%; + height: 100%; + background-color: rgb(5, 114, 206); + animation: indeterminate-animation 1s infinite linear; + transform-origin: 0% 50%; +} + +@keyframes indeterminate-animation { + 0% { + transform: translateX(0) scaleX(0); + } + + 40% { + transform: translateX(0) scaleX(0.4); + } + + 100% { + transform: translateX(100%) scaleX(0.5); + } +} + +.btn-clipboard { + line-height: 1; + color: var(--bs-body-color); + background-color: var(--bd-pre-bg); + border: 0; + border-radius: .25rem; + margin-right: -.4em +} + + .btn-clipboard:hover { + color: var(--bs-link-hover-color) + } + + .btn-clipboard:focus { + z-index: 3 + } + +.btn-clipboard { + position: relative; + z-index: 2; +} diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor index 7f8aa6d..19ef8f6 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -124,7 +124,6 @@ else return; } - await Task.Delay(2000); await using var scope = ServiceProvider.CreateAsyncScope(); await LoadDocumentsAsync(scope.ServiceProvider); diff --git a/SqlDatabaseVectorSearch/wwwroot/images/assistant.png b/SqlDatabaseVectorSearch/wwwroot/images/assistant.png new file mode 100644 index 0000000000000000000000000000000000000000..64ec75c02d2e4290e4f7c8d7a27d0eb3eebf4ab1 GIT binary patch literal 2058 zcmV+l2=(`gP)xQZGYcXrL8BoCfoRl(1pI+47$XXbKLkXGhJc*GBU~Dg!~{imxx6q62n)Nk-&b8d z^!9Y`^vo_`B`-Z){p!{CRlR!ks&?D8`yZF%6DM{(oXO~XUTG`^mHO)H0f*D+{YTPi z%MrZqJCaKEza$;%dbe8>F;Q(AVsX+CYbpHAx_G?DErr+u&`F0=sV0Cui05Ry_vKT) zH$f(}8Sq3x+#x~h;=E~S76stHC+JoEJl3uv2o)%nr6xM74cqz zPrd{E7JNH%B$MgfYVb*;SHje_-xTQg0dk529TVkJBmptS{)XSsWt*040{mRaxucUN z-IFX652M|$%KmY*e~1J@;yg&qZZ-I%uAPPal><89H+9(t@9{ta>GWCv+|A!;^8tYW z0U~4gGFfc?Pm2aG-A0Zk+(Z{6!V-Y)NVwB}IjWJ!?S8fael@^-YY&oGLEs4^ zGFB2Xv=0@5@31ab7EOTu3=j>;XwL`TK$Av9mm?k122$*)N1aP29xp9nTS%=hfpmJ7 zbP@QtbRp%UB+Yl$L#GisFBJuz(T0l>BQjr-agQ_>8hzCsEh)z;yLId6)=>knfHwT1 zQ++CR7r>pyENrZsKKQdrW-`e` zRaMux3Gkiut?XD^2ZOs?Wu%=Ph&`C4yphD~enl61!_wY^@18*@+|0VeQ>S*qbg#p- zo{~?zd)o!+&<1VMraK}fqtOS;DZi#%RQVVhj1n5Wtwk_H`B>T{{x18NOoQQ>?2*7P-VFVhvrQ0KyC9oQDh!Ft* zf9AUn0bd=*4i>aV+mQKcq?foyI!L4*^~1~re02>v+vV<>K&l-&RwVVzU&Jj1RH7=H(m=co|kDtE^$b=B3S_389|1z zPpb1l#FqeaB`oYMcFq*=yEQvBI^NEx)H@oztr>w3F2pu6>gd|GW;R`^cqk06biHr_ z$jd?E6hM8+6guo8mbz%ewzT24=}E;mgb?Z-XS!Z60hV$@45lA*B-wdBeH*;CjpqQi z_0>_Sco+iibiL?;X&fd=U>7wE06lG$pnvQU|st?XaVyZbsYUGjawGRa*XQUY(i#=n|b{KzkCItUzdX4 zvJT&ryI1^W?Q(1%B4_1Y44_!4Y4YWa9mz)fDTx=W@nt|5EPZ-@dn9CPx zk8NaI+HjF!AMV|~)y3ZKdHsQSuWr?f1s&LjBIDfd$^F3)^IJ_M789LSveks=M|d7+ zixfJj*e5gXfa$zmd*-CdNiK9NW#j6%H{koFVF&PwQV|z*h}3j&YEJr(;o zUZc+M3Papi9@GA<8m2dHSTw-ewR})P!ZuYy^~Um86Hty#Cg~PljYc9$P=$dUtMRj(omwfc#DywAEr?OhJID5CXhtTEyS( zZJ&p4_~Uw~gJ;GkB#4vSMp{+FjElY<)2uZM9+BVnt{CL&|4)yP%kQ+2omJR&u5CR1 zE+VE-;Ca2LcGhX``b3#1RiSN}m%!UES6Y3O5$W6iY#m|EtTE{t)~W3y^SY6nfV!Dz za-Yy7CSZ}60{$4%tTs9JcN((*C>DN=59spc&Y?e4zFB){)lCjA`{V3!eenR?%;zx_0;8 zflg}~y*&!GFmxiPzO3i{%FsA3fi_$NPssKN(LMwFr?W0wEb5@X&0AkyCSvwsTU2@p zI8o?}#dZ|>am~=sQOHdoVTgXVt7t}8T)6~X5vUmfLmN)x@o3L(d}o9RHjSL0~s}mr1}A@{r~^~07*qoM6N<$g8moj=l}o! literal 0 HcmV?d00001 diff --git a/SqlDatabaseVectorSearch/wwwroot/images/user.png b/SqlDatabaseVectorSearch/wwwroot/images/user.png new file mode 100644 index 0000000000000000000000000000000000000000..b4a325df87ef07d2ec501a5f3a9a97fcadde56f8 GIT binary patch literal 1010 zcmV$JM=Qh(q}jdWjU5aN;Mr-Fg^Q3+A_`DGI{ zyn80PjuL@~&FEgwAsN8?W`xMbhNn&F@Lm&XoEyMJn^-fT)88dwz`~XRcu#O{0Kb^N zvStA1`lk)xNAV2j2JjMk$Knzip4XM^%aj)b!*jde+j0TH3o@f@`>UQ=xRV zfws^G`a%vO@DsA6^ugmBe)OkOs4pvFy!xIRl`HO`D^)e9ST09QY1twb%ggb9)vh+s z7WzP6$T1}oad#U1#O&VUl+mh58IA0@aR?wlT?Gd%00yeUs%%uDiUy@ia9!p84`e7f zVDa>`=fxq&<&@HmA200Pyr%H)nZ)=>Dcu7FJ+fv+drkD77T9m8l)tKdV0~4qRQ!B< zR$%wEw`NBp-&~V2(VOW)QQVrqe~<_goHCJhaY46<>;)614F2rv-2K+a@_a{~vhF+R zk^H>Fcy6C<;8^7B0({JpJT6H^!!S^+!jI+c+=!QrVcCLi+4JJjKqlX7WF?t#8%KWp zih0~KVRSMHn^-e|mrecZ1?Pol$h9vlC!&x!gO5z&2$#SZ+=KP*l#2Z3aqBiK@KX$Z z2#@~U9~NazP!pRy91=WYC>|dDL9XGwCZwVPUVpR3r@i!`FDBz)l?8t?|Od zkzfpbAr0=)#6`j9fDMf1#7>h2_sEtLI~A}2lbC0AN)m~~14F-# z_-x}W5^@iYYeH>c=u4&Kfg8xAVz3FPztiPf3mAYUU;_}nX_N>j(cmOA1i+!@{hoA6 g7!-Us!ttNPZ`wVEs12!VEdT%j07*qoM6N<$f)c{ykN^Mx literal 0 HcmV?d00001 From 5382795529f0434f2906fd9d6288e703b35633ab Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Wed, 19 Feb 2025 17:33:30 +0100 Subject: [PATCH 10/25] Enhance Ask.razor UI and functionality Updated clipboard button to use Button component with Icon. Added HandleKeyDown event for submitting questions with Enter key. Modified question handling to support streaming responses. Refactored CopyToClipboard method to be asynchronous. --- .../Components/Pages/Ask.razor | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor index 4acc8bf..7c14e28 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor @@ -51,12 +51,17 @@
@if (message.IsCompleted) { -
- - - +
+ @*
+ + + +
*@ +
+ +
}
@@ -75,7 +80,7 @@ - +
+ + +
} @@ -105,6 +107,9 @@ private Guid conversationId = Guid.NewGuid(); private bool isAsking = false; + [Inject] + protected ToastService ToastService { get; set; } = default!; + private async Task HandleKeyDown(KeyboardEventArgs e) { if (e.Key == "Enter" && !isAsking && !string.IsNullOrWhiteSpace(question)) @@ -117,24 +122,28 @@ { isAsking = true; + var userQuestion = new Question(conversationId, question!); + var userMessage = new Message { Text = userQuestion.Text, Role = "user" }; + messages.Add(userMessage); + + var assistantMessage = new Message { Role = "assistant" }; + messages.Add(assistantMessage); + + question = null; + await Task.Yield(); + try { - var userQuestion = new Question(conversationId, question!); - var userMessage = new Message { Text = userQuestion.Text, Role = "user" }; - messages.Add(userMessage); - - var assistantMessage = new Message { Role = "assistant" }; - messages.Add(assistantMessage); - - question = null; - await Task.Yield(); - await using var scope = ServiceProvider.CreateAsyncScope(); var vectorSearchService = scope.ServiceProvider.GetRequiredService(); var response = vectorSearchService.AskStreamingAsync(userQuestion); await foreach (var delta in response) { + if (delta.StreamState == StreamState.Start) + { + assistantMessage.TokenUsage = FormatTokenUsage(delta.TokenUsage); + } if (delta.StreamState == StreamState.Append) { assistantMessage.Text += delta.Answer; @@ -142,12 +151,18 @@ else if (delta.StreamState == StreamState.End) { assistantMessage.IsCompleted = true; + assistantMessage.TokenUsage += FormatTokenUsage(delta.TokenUsage); } await Task.Yield(); StateHasChanged(); } } + catch (Exception ex) + { + assistantMessage.Text = $"There was an error while processing the question: {ex.Message}"; + assistantMessage.IsCompleted = true; + } finally { isAsking = false; @@ -166,6 +181,40 @@ await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", text); } + private string FormatTokenUsage(TokenUsageResponse? tokenUsageResponse) + { + if (tokenUsageResponse is null) + { + return string.Empty; + } + + var reformulation = tokenUsageResponse.Reformulation is not null + ? $"

Reformulation:
{FormatTokenUsageDetails(tokenUsageResponse.Reformulation)}

" + : string.Empty; + + var embeddingTokenCount = tokenUsageResponse.EmbeddingTokenCount.HasValue + ? $"

Embedding Token Count: {tokenUsageResponse.EmbeddingTokenCount}

" + : string.Empty; + + var question = tokenUsageResponse.Question is not null + ? $"

Question:
{FormatTokenUsageDetails(tokenUsageResponse.Question)}

" + : string.Empty; + + return $"{reformulation}{embeddingTokenCount}{question}"; + } + + private string FormatTokenUsageDetails(TokenUsage? tokenUsage) + { + if (tokenUsage is null) + { + return string.Empty; + } + + return $"Input Token Count: {tokenUsage.InputTokenCount}
" + + $"Output Token Count: {tokenUsage.OutputTokenCount}
" + + $"Total Token Count: {tokenUsage.TotalTokenCount}"; + } + public class Message { public string? Text { get; set; } @@ -173,5 +222,7 @@ public required string Role { get; set; } public bool IsCompleted { get; set; } + + public string? TokenUsage { get; set; } } } \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor index 695ee40..3722858 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -24,7 +24,7 @@ - +
@@ -105,7 +105,6 @@ else private Button deleteButton = default!; private IList documents = []; - private List messages = []; private UploadDocumentRequest uploadDocumentRequest = new(); private EditContext? editContext; @@ -161,9 +160,10 @@ else uploadButton.ShowLoading(); + var fileName = uploadDocumentRequest.File.Name; + try { - var fileName = uploadDocumentRequest.File.Name; await using var inputStream = uploadDocumentRequest.File.OpenReadStream(20 * 1024 * 1024); // 20 MB await using var stream = await inputStream.GetMemoryStreamAsync(); @@ -177,6 +177,10 @@ else await LoadDocumentsAsync(scope.ServiceProvider); } + catch (Exception ex) + { + ToastService.Notify(await CreateToastMessageAsync(ToastType.Danger, "Upload error", $"There was an error while uploading the document {fileName}: {ex.Message}")); + } finally { uploadButton.HideLoading(); @@ -218,6 +222,10 @@ else await LoadDocumentsAsync(scope.ServiceProvider); ToastService.Notify(await CreateToastMessageAsync(ToastType.Info, "Delete documents", "The selected documents have been successfully deleted.")); } + catch (Exception ex) + { + ToastService.Notify(await CreateToastMessageAsync(ToastType.Danger, "Delete error", $"There was an error while deleting the documents: {ex.Message}")); + } finally { deleteButton.HideLoading(); From b7c8cfff764a95cfb910b320758cdf3d62a02dc0 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Thu, 20 Feb 2025 12:19:20 +0100 Subject: [PATCH 14/25] Update button types in Ask.razor and improve CSS focus style - Specified `Type` attributes for buttons in `Ask.razor` to clarify their intended behavior. - Added `h1:focus` style in `app.css` to remove default outline for focused headings. --- SqlDatabaseVectorSearch/Components/Pages/Ask.razor | 6 +++--- SqlDatabaseVectorSearch/wwwroot/css/app.css | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor index f9d4691..b1c282d 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor @@ -59,7 +59,7 @@
- @@ -84,10 +84,10 @@
- -
diff --git a/SqlDatabaseVectorSearch/wwwroot/css/app.css b/SqlDatabaseVectorSearch/wwwroot/css/app.css index a1da72e..947645a 100644 --- a/SqlDatabaseVectorSearch/wwwroot/css/app.css +++ b/SqlDatabaseVectorSearch/wwwroot/css/app.css @@ -11,10 +11,6 @@ --bb-sidebar2-nav-item-group-background-color: rgba(var(--bb-sidebar2-nav-item-text-active-color-rgb), 0.08); } -h1:focus { - outline: none; -} - .bb-sidebar2 nav .nav-item a { color: var(--bb-sidebar2-nav-item-text-color) !important; } @@ -29,6 +25,10 @@ h1:focus { color: var(--bb-sidebar2-nav-item-text-active-color) !important; } +h1:focus { + outline: none; +} + .valid.modified:not([type=checkbox]) { outline: 1px solid #26b050; } From c22b4100fb28f64dd9867b4c376825850ff7d801 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Thu, 20 Feb 2025 15:01:25 +0100 Subject: [PATCH 15/25] Refactor Ask component and improve sidebar styles - Removed clipboard icon reference and added ElementReference for input field in Ask.razor. - Introduced OnAfterRenderAsync method to manage input focus. - Updated app.css with new CSS variables for enhanced sidebar styling. - Added setFocus function in functions.js to manage element focus. --- .../Components/Pages/Ask.razor | 16 +++++++++-- SqlDatabaseVectorSearch/wwwroot/css/app.css | 28 +++++++++++++------ .../wwwroot/js/functions.js | 7 ++++- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor index b1c282d..e02079c 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor @@ -60,7 +60,7 @@
@@ -82,7 +82,7 @@ - +
-@if (documents.Count == 0) +@if (isLoading && documents.Count == 0) {
@@ -104,6 +104,7 @@ else private Button uploadButton = default!; private Button deleteButton = default!; + private bool isLoading = true; private IList documents = []; private UploadDocumentRequest uploadDocumentRequest = new(); @@ -133,16 +134,25 @@ else private async Task LoadDocumentsAsync(IServiceProvider services) { - var documentService = services.GetRequiredService(); - var dbDocuments = await documentService.GetAsync(); + isLoading = true; - documents.Clear(); - foreach (var dbDocument in dbDocuments) + try { - documents.Add(new SelectableDocument(dbDocument.Id, dbDocument.Name, dbDocument.CreationDate, dbDocument.ChunkCount) - { - LocalCreationDateString = await GetLocalDateTimeStringAsync(dbDocument.CreationDate) - }); + var documentService = services.GetRequiredService(); + var dbDocuments = await documentService.GetAsync(); + + documents.Clear(); + foreach (var dbDocument in dbDocuments) + { + documents.Add(new SelectableDocument(dbDocument.Id, dbDocument.Name, dbDocument.CreationDate, dbDocument.ChunkCount) + { + LocalCreationDateString = await GetLocalDateTimeStringAsync(dbDocument.CreationDate) + }); + } + } + finally + { + isLoading = false; } } diff --git a/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.Designer.cs b/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.Designer.cs new file mode 100644 index 0000000..bb1f760 --- /dev/null +++ b/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.Designer.cs @@ -0,0 +1,93 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SqlDatabaseVectorSearch.DataAccessLayer; + +#nullable disable + +namespace SqlDatabaseVectorSearch.DataAccessLayer.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250224102351_Initial")] + partial class Initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("Documents", (string)null); + }); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.DocumentChunk", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DocumentId") + .HasColumnType("uniqueidentifier"); + + b.PrimitiveCollection("Embedding") + .IsRequired() + .HasColumnType("vector(1536)"); + + b.Property("Index") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.ToTable("DocumentChunks", (string)null); + }); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.DocumentChunk", b => + { + b.HasOne("SqlDatabaseVectorSearch.DataAccessLayer.Entities.Document", "Document") + .WithMany("Chunks") + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_DocumentChunks_Documents"); + + b.Navigation("Document"); + }); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.Document", b => + { + b.Navigation("Chunks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.cs b/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.cs new file mode 100644 index 0000000..a44fde0 --- /dev/null +++ b/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.cs @@ -0,0 +1,64 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SqlDatabaseVectorSearch.DataAccessLayer.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Documents", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + CreationDate = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Documents", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "DocumentChunks", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + DocumentId = table.Column(type: "uniqueidentifier", nullable: false), + Index = table.Column(type: "int", nullable: false), + Content = table.Column(type: "nvarchar(max)", nullable: false), + Embedding = table.Column(type: "vector(1536)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DocumentChunks", x => x.Id); + table.ForeignKey( + name: "FK_DocumentChunks_Documents", + column: x => x.DocumentId, + principalTable: "Documents", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_DocumentChunks_DocumentId", + table: "DocumentChunks", + column: "DocumentId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DocumentChunks"); + + migrationBuilder.DropTable( + name: "Documents"); + } + } +} diff --git a/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/ApplicationDbContextModelSnapshot.cs b/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 0000000..8be4784 --- /dev/null +++ b/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,90 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SqlDatabaseVectorSearch.DataAccessLayer; + +#nullable disable + +namespace SqlDatabaseVectorSearch.DataAccessLayer.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("Documents", (string)null); + }); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.DocumentChunk", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DocumentId") + .HasColumnType("uniqueidentifier"); + + b.PrimitiveCollection("Embedding") + .IsRequired() + .HasColumnType("vector(1536)"); + + b.Property("Index") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.ToTable("DocumentChunks", (string)null); + }); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.DocumentChunk", b => + { + b.HasOne("SqlDatabaseVectorSearch.DataAccessLayer.Entities.Document", "Document") + .WithMany("Chunks") + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_DocumentChunks_Documents"); + + b.Navigation("Document"); + }); + + modelBuilder.Entity("SqlDatabaseVectorSearch.DataAccessLayer.Entities.Document", b => + { + b.Navigation("Chunks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SqlDatabaseVectorSearch/Program.cs b/SqlDatabaseVectorSearch/Program.cs index f8d4bb7..f6695ca 100644 --- a/SqlDatabaseVectorSearch/Program.cs +++ b/SqlDatabaseVectorSearch/Program.cs @@ -86,6 +86,7 @@ builder.Services.AddDefaultProblemDetails(); builder.Services.AddDefaultExceptionHandler(); var app = builder.Build(); +await ConfigureDatabaseAsync(app.Services); // Configure the HTTP request pipeline. app.UseHttpsRedirection(); @@ -96,7 +97,7 @@ app.UseWhen(context => context.IsWebRequest(), builder => { builder.UseExceptionHandler("/error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + // The default HSTS value is 30 days. builder.UseHsts(); } @@ -217,4 +218,12 @@ documentsApiGroup.MapDelete("{documentId:guid}", async (Guid documentId, Documen .WithSummary("Deletes a document") .WithDescription("This endpoint deletes the document and all its chunks."); -app.Run(); \ No newline at end of file +app.Run(); + +static async Task ConfigureDatabaseAsync(IServiceProvider serviceProvider) +{ + await using var scope = serviceProvider.CreateAsyncScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + + await dbContext.Database.MigrateAsync(); +} \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj index 3a3f57f..4658723 100644 --- a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj +++ b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj @@ -14,6 +14,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/SqlDatabaseVectorSearch/wwwroot/docs.md b/SqlDatabaseVectorSearch/wwwroot/docs.md index fcf9f37..62df785 100644 --- a/SqlDatabaseVectorSearch/wwwroot/docs.md +++ b/SqlDatabaseVectorSearch/wwwroot/docs.md @@ -2,13 +2,11 @@ ## Setup -- [Create an Azure SQL Database](https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart) on a server that has the Vector Support feature enabled -- Execute the [Scripts.sql](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/Scripts.sql) file to create the tables needed by the application - - You may need to update the size of the [`VECTOR`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/Scripts.sql#L17) column to match the size of the embedding model. Currently, the maximum allowed value is 1998. +- [Create an Azure SQL Database](https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart) - Open the [appsettings.json](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json) file and set the connection string to the database and the other settings required by Azure OpenAI - - If your embedding model supports shortening, like **text-embedding-3-small** and **text-embedding-3-large**, and you want to use this feature, you need to set the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to match the value you have used in the SQL script. If your model doesn't provide this feature, or do you want to use the default size, just leave the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to NULL. Keep in mind that **text-embedding-3-small** has a dimension of 1536, while **text-embedding-3-large** uses vectors with 3072 elements, so with this latter model it is mandatory to specify a value (that, as said, must be less or equal to 1998). -- Run the application and start importing your documents with `/api/documents` endpoint. -- Ask questions using `/api/ask` or `/api/ask-streaming` endpoints. + - If your embedding model supports shortening, like **text-embedding-3-small** and **text-embedding-3-large**, and you want to use this feature, you need to set the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to the corresponding value. If your model doesn't provide this feature, or do you want to use the default size, just leave the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to NULL. Keep in mind that **text-embedding-3-small** has a dimension of 1536, while **text-embedding-3-large** uses vectors with 3072 elements, so with this latter model it is mandatory to specify a value (that, as said, must be less or equal to 1998). +- You may need to update the size of the [`VECTOR`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/ApplicationDbContext.cs?plain=1#L42C1-L42C47) column to match the size of the embedding model. The default value is 1536. Currently, the maximum allowed value is 1998. If you change it, remember to update also the Migration. +- Run the application and start importing your documents ## Supported features From 22522a2d50f0d48142c4b2f35fa8654ca854888e Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Mon, 24 Feb 2025 12:02:17 +0100 Subject: [PATCH 18/25] Update documentation for VECTOR column migration Clarified the need to update the Database Migration when changing the size of the `VECTOR` column to match the embedding model. This replaces the previous mention that lacked a specific link to the Database Migration. --- SqlDatabaseVectorSearch/wwwroot/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SqlDatabaseVectorSearch/wwwroot/docs.md b/SqlDatabaseVectorSearch/wwwroot/docs.md index 62df785..455e935 100644 --- a/SqlDatabaseVectorSearch/wwwroot/docs.md +++ b/SqlDatabaseVectorSearch/wwwroot/docs.md @@ -5,7 +5,7 @@ - [Create an Azure SQL Database](https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart) - Open the [appsettings.json](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json) file and set the connection string to the database and the other settings required by Azure OpenAI - If your embedding model supports shortening, like **text-embedding-3-small** and **text-embedding-3-large**, and you want to use this feature, you need to set the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to the corresponding value. If your model doesn't provide this feature, or do you want to use the default size, just leave the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to NULL. Keep in mind that **text-embedding-3-small** has a dimension of 1536, while **text-embedding-3-large** uses vectors with 3072 elements, so with this latter model it is mandatory to specify a value (that, as said, must be less or equal to 1998). -- You may need to update the size of the [`VECTOR`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/ApplicationDbContext.cs?plain=1#L42C1-L42C47) column to match the size of the embedding model. The default value is 1536. Currently, the maximum allowed value is 1998. If you change it, remember to update also the Migration. +- You may need to update the size of the [`VECTOR`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/ApplicationDbContext.cs?plain=1#L42C1-L42C47) column to match the size of the embedding model. The default value is 1536. Currently, the maximum allowed value is 1998. If you change it, remember to update also the [Database Migration](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.cs?plain=1#L35C1-L35C92). - Run the application and start importing your documents ## Supported features From eb368470e8087a34c7679af44b999e1834a13cb8 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Tue, 25 Feb 2025 14:56:46 +0100 Subject: [PATCH 19/25] Update README and image assets for SQL Database Vector Search - Enhanced README.md with new sections and images for the web app and API. - Clarified setup instructions and reorganized content. - Removed SqlDatabaseVectorSearch.png; modified favicon.png and SqlDatabaseVectorSearch_API.png. - Added new image file: SqlDatabaseVectorSearch_WebApp.png. --- README.md | 19 +++++++++++------- SqlDatabaseVectorSearch/wwwroot/favicon.png | Bin 2193 -> 1799 bytes .../SqlDatabaseVectorSearch_API.png | Bin docs/SqlDatabaseVectorSearch_WebApp.png | Bin 0 -> 82250 bytes 4 files changed, 12 insertions(+), 7 deletions(-) rename SqlDatabaseVectorSearch.png => docs/SqlDatabaseVectorSearch_API.png (100%) create mode 100644 docs/SqlDatabaseVectorSearch_WebApp.png diff --git a/README.md b/README.md index 95720a0..b797f9c 100644 --- a/README.md +++ b/README.md @@ -6,17 +6,22 @@ The application is a Minimal API that exposes endpoints to load documents, gener > [!NOTE] > If you prefer to use straight SQL, check out the [sql branch](https://github.com/marcominerva/SqlDatabaseVectorSearch/tree/sql). -![SQL Database Vector Search](https://raw.githubusercontent.com/marcominerva/SqlDatabaseVectorSearch/refs/heads/master/SqlDatabaseVectorSearch.png) +### Web App +![SQL Database Vector Search Web App](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/docs/SqlDatabaseVectorSearch_API_.png) + +### Web API +![SQL Database Vector Search API](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/docs/SqlDatabaseVectorSearch_API_.png) ## Setup -- [Create an Azure SQL Database](https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart) on a server that has the Vector Support feature enabled -- Execute the [Scripts.sql](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/Scripts.sql) file to create the tables needed by the application - - You may need to update the size of the [`VECTOR`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/Scripts.sql#L17) column to match the size of the embedding model. Currently, the maximum allowed value is 1998. +- [Create an Azure SQL Database](https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart) - Open the [appsettings.json](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json) file and set the connection string to the database and the other settings required by Azure OpenAI - - If your embedding model supports shortening, like **text-embedding-3-small** and **text-embedding-3-large**, and you want to use this feature, you need to set the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to match the value you have used in the SQL script. If your model doesn't provide this feature, or do you want to use the default size, just leave the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to NULL. Keep in mind that **text-embedding-3-small** has a dimension of 1536, while **text-embedding-3-large** uses vectors with 3072 elements, so with this latter model it is mandatory to specify a value (that, as said, must be less or equal to 1998). -- Run the application and start importing your documents with `/api/documents` endpoint. -- Ask questions using `/api/ask` or `/api/ask-streaming` endpoints. + - If your embedding model supports shortening, like **text-embedding-3-small** and **text-embedding-3-large**, and you want to use this feature, you need to set the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to the corresponding value. If your model doesn't provide this feature, or do you want to use the default size, just leave the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to NULL. Keep in mind that **text-embedding-3-small** has a dimension of 1536, while **text-embedding-3-large** uses vectors with 3072 elements, so with this latter model it is mandatory to specify a value (that, as said, must be less or equal to 1998). +- You may need to update the size of the [`VECTOR`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/ApplicationDbContext.cs?plain=1#L42C1-L42C47) column to match the size of the embedding model. The default value is 1536. Currently, the maximum allowed value is 1998. If you change it, remember to update also the [Database Migration](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.cs?plain=1#L35C1-L35C92). +- Run the application and start importing your documents +- If you want to directly use the APIs: + - import your documents with the `/api/documents` endpoint. + - Ask questions using `/api/ask` or `/api/ask-streaming` endpoints. ## Supported features diff --git a/SqlDatabaseVectorSearch/wwwroot/favicon.png b/SqlDatabaseVectorSearch/wwwroot/favicon.png index 4d1b2564caad5b2e021ae65ec36bb8a165686e57..0c3cb7ff00aa51b7218525d4ab9b3b2ddc475ff6 100644 GIT binary patch delta 1766 zcmVsx_Pt(Cr1C9qj!}Gg}F*B?%{F^RadWGDUOei|1~r;bk~Xi z!o$O(6mt1+r(O>&f6dLHQL8|uR02L@CYQ;cGlhIPlY>$rXWwbmYG~FrL90#&w5LQO zF>l(mDbOi^{rmSHnwy(j93LNt{{DW@ceFDgYL(Kq@iQQe%w&yLYhczOl`^ZXse!uM zC8PTqi3F;vsvsyZFw!Z2xVX532w(y40k1GKJq;5R6EHS5e+HwYqcAl!1(TDLKmeaU zeQJAd8W{nT$p}WH5xTm%z|h%=;N;NQ&;ZitgLohfv$U@!T-VSp4e*my=-@Zfh^Ycyt*q?gD!SR!U0eJlQ zF?4ivKwDeef3g551%WH207%^a*2iK2P*y}LdVrEr%7y+LTLVb3#`G5urbV^<e z^`NY*?6ycGO2X8bK0kIWcU4p{WZ?xdfBr#fDXaZF9uLG~F>^|!By!UKva_=jc_qBR zDXlxg!j3%$AUZmFFK#$)Q-P%&n=L6=Qi1bcKme!`78h|@=&|?0SKDnTd!} zL-!PkTQ_eqz(REX%g^VS1Z9mff0p|qlqR>ZkW#XUy&z&$dV#evQZc%np3XX9jid(7 zC;kQ^WIsxc>7V8Sss#iHr{vX}i0DerGqKw>W6>h5pHEB#Arg+}LMlwJJrSV_Vo=wk zV7F*ErLdE8YZ0Y5GPoM&(^m_edR%Rx1QiZ2Vx^Q6;!#FWS+Tx-{^_07G1 z-$ae&OhQ86`t|E0UjEf80-zNd5_0sbFTap_Z`>IDM$U2l3yA{-rgS2ezW@LL07*qo IM6N<$g1#t8MF0Q* delta 2161 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

{M7?MgmD%mibwZ|>?5QS4XpZAwP{g? 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πBBq?2_2s+ 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 literal 0 HcmV?d00001 From 9071e130de01483748207ef1a25804750679c182 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Tue, 25 Feb 2025 15:17:06 +0100 Subject: [PATCH 20/25] Enhance documentation and refactor request handling Updated README.md to clarify functionality and added a link to OpenAPI documentation in MainLayout.razor. Removed unnecessary methods from RequestExtensions.cs for simplification. Streamlined docs.md by removing detailed JSON response examples while retaining key information about response streaming. --- README.md | 4 +- .../Components/Layout/MainLayout.razor | 5 +- .../Extensions/RequestExtensions.cs | 24 ---- SqlDatabaseVectorSearch/wwwroot/docs.md | 123 +----------------- 4 files changed, 8 insertions(+), 148 deletions(-) diff --git a/README.md b/README.md index b797f9c..d647218 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # SQL Database Vector Search Sample A repository that showcases the native VECTOR type in Azure SQL Database to perform embeddings and RAG with Azure OpenAI. -The application is a Minimal API that exposes endpoints to load documents, generate embeddings and save them into the database as Vectors, and perform searches using Vector Search and RAG. Currently, PDF, DOCX, TXT and MD files are supported. Vectors are saved and retrieved with Entity Framework Core using the [EFCore.SqlServer.VectorSearch](https://github.com/efcore/EfCore.SqlServer.VectorSearch) library. Embedding and Chat Completion are integrated with [Semantic Kernel](https://github.com/microsoft/semantic-kernel). +The application allows to load documents, generate embeddings and save them into the database as Vectors, and perform searches using Vector Search and RAG. Currently, PDF, DOCX, TXT and MD files are supported. Vectors are saved and retrieved with Entity Framework Core using the [EFCore.SqlServer.VectorSearch](https://github.com/efcore/EfCore.SqlServer.VectorSearch) library. Embedding and Chat Completion are integrated with [Semantic Kernel](https://github.com/microsoft/semantic-kernel). > [!NOTE] > If you prefer to use straight SQL, check out the [sql branch](https://github.com/marcominerva/SqlDatabaseVectorSearch/tree/sql). +This repository contains a Blazor Web App as well as a Minimal API that allows to programatically interact with embeddings and RAG. + ### Web App ![SQL Database Vector Search Web App](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/docs/SqlDatabaseVectorSearch_API_.png) diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor index 13566ae..87f3437 100644 --- a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor @@ -6,8 +6,11 @@ + + + - + diff --git a/SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs b/SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs index 0be6602..5b32f3e 100644 --- a/SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs +++ b/SqlDatabaseVectorSearch/Extensions/RequestExtensions.cs @@ -1,5 +1,4 @@ using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; namespace SqlDatabaseVectorSearch.Extensions; @@ -30,18 +29,6 @@ public static partial class RequestExtensions return isMobileBrowser; } - public static string GetCultureFromRoute(this HttpContext httpContext) - => RouteCultureRegex.Match(httpContext.Request.Path).Groups["culture"].Value.ToLowerInvariant(); - - public static string GetPathWithCulture(this HttpContext httpContext, string culture) - { - var request = httpContext.Request; - var path = RouteCultureRegex.Replace(request.Path.ToString(), "/"); - var newPath = $"/{culture}{path}{request.QueryString}"; - - return newPath; - } - public static bool IsApiRequest(this HttpContext httpContext) => httpContext.Request.Path.StartsWithSegments("/api"); @@ -50,15 +37,4 @@ public static partial class RequestExtensions public static bool IsWebRequest(this HttpContext httpContext) => !httpContext.IsApiRequest() && !httpContext.IsSwaggerRequest(); - - public static string Content(this IUrlHelper urlHelper, HttpContext httpContext, string contentPath) - => urlHelper.Content(httpContext.Request, contentPath); - - public static string Content(this IUrlHelper urlHelper, HttpRequest request, string contentPath) - { - var path = urlHelper.Content(contentPath); - var url = $"{request.Scheme}://{request.Host}{request.PathBase}{path}"; - - return url; - } } \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/wwwroot/docs.md b/SqlDatabaseVectorSearch/wwwroot/docs.md index 455e935..d67a11a 100644 --- a/SqlDatabaseVectorSearch/wwwroot/docs.md +++ b/SqlDatabaseVectorSearch/wwwroot/docs.md @@ -12,125 +12,4 @@ - Conversation history with question reformulation - Information about token usage -- Response streaming - -```json -{ - "originalQuestion": "why is mars called the red planet?", - "reformulatedQuestion": "Why is Mars referred to as the Red Planet?", - "answer": "Mars is referred to as the Red Planet due to its characteristic reddish color, which is caused by the abundance of iron oxide (rust) on its surface. This distinctive coloration has also been a significant factor in the cultural and mythological associations of Mars across different civilizations.", - "streamState": null, - "tokenUsage": { - "reformulation": { - "inputTokenCount": 107, - "outputTokenCount": 10, - "totalTokenCount": 117 - }, - "embeddingTokenCount": 10, - "question": { - "inputTokenCount": 9142, - "outputTokenCount": 53, - "totalTokenCount": 9195 - } - } -} -``` - -### How response streaming works - -When using the `/api/ask-streaming` endpoint, answers will be streamed as happens with the typical response from OpenAI. The format of the response is the following: - -```json -[ - { - "originalQuestion": "why is mars called the red planet?", - "reformulatedQuestion": "Why is Mars referred to as the Red Planet?", - "answer": null, - "streamState": "Start", - "tokenUsage": { - "reformulation": { - "inputTokenCount": 107, - "outputTokenCount": 10, - "totalTokenCount": 117 - }, - "embeddingTokenCount": 10, - "question": null - } - }, - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": "Mars", - "streamState": "Append", - "tokenUsage": null - }, - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": " is", - "streamState": "Append", - "tokenUsage": null - }, - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": " called", - "streamState": "Append", - "tokenUsage": null - }, - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": " the", - "streamState": "Append", - "tokenUsage": null - }, - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": " Red", - "streamState": "Append", - "tokenUsage": null - }, - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": " Planet", - "streamState": "Append", - "tokenUsage": null - }, - //... - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": ".", - "streamState": "Append", - "tokenUsage": null - }, - { - "originalQuestion": null, - "reformulatedQuestion": null, - "answer": null, - "streamState": "End", - "tokenUsage": { - "reformulation": null, - "embeddingTokenCount": null, - "question": { - "inputTokenCount": 8986, - "outputTokenCount": 31, - "totalTokenCount": 9017 - } - } - } -] -``` - -- The first piece of the response has the following characteristics: - - the *streamState* property is set to `Start`, - - it contains the question and its reformulation (if not requested, *reformulatedQuestion* will be equals to *originalQuestion*) - - the *tokenUsage* section holds information about token used for reformulation (if done) and for the embedding of the question -- Then, there are as many elements for the actual answer as necessary: - - each one contains a token - - The *streamState* property is set to `Append` - - *origianlQuestion*, *reformulatedQuestion* and *tokenUsage* are always `null` -- The stream ends when an element with *streamState* equals to `End` is received. This element contains token usage information for the question and the whole answer. +- Response streaming \ No newline at end of file From e1324115f8794ca646595029192f69f8b9125a3b Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Tue, 25 Feb 2025 15:52:58 +0100 Subject: [PATCH 21/25] Remove footer and update card layout styles - Removed the `FooterSection` from `MainLayout.razor` and its associated styles in `MainLayout.razor.css`. - Added top margin to the card in `Ask.razor` for improved spacing. - Increased height of `.card-body` in both default and media queries for better content display. - Added CSS rules in `app.css` to reset margin and padding for `body` and `html`. - Modified binary file `SqlDatabaseVectorSearch_WebApp.png`. --- .../Components/Layout/MainLayout.razor | 8 +------- .../Components/Layout/MainLayout.razor.css | 17 ----------------- .../Components/Pages/Ask.razor | 2 +- .../Components/Pages/Ask.razor.css | 6 +++--- SqlDatabaseVectorSearch/wwwroot/css/app.css | 6 ++++++ docs/SqlDatabaseVectorSearch_WebApp.png | Bin 82250 -> 86705 bytes 6 files changed, 11 insertions(+), 28 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor index 87f3437..c9c7108 100644 --- a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor @@ -23,15 +23,9 @@ - @Body + @Body - -

- - @code { diff --git a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css index fd8d52c..a3ae64a 100644 --- a/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css +++ b/SqlDatabaseVectorSearch/Components/Layout/MainLayout.razor.css @@ -1,20 +1,3 @@ -.footer-content { - display: flex; - justify-content: space-between; - align-items: center; - background-color: #f8f9fa; - border-top: 1px solid #dee2e6; -} - - .footer-content span { - font-size: 0.9rem; - color: #6c757d; - } - - .footer-content .ms-auto { - margin-left: auto; - } - #blazor-error-ui { color-scheme: light only; background: lightyellow; diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor index 98dd393..2dd519d 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor @@ -5,7 +5,7 @@ Chat with your data -
+
@foreach (var message in messages) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css index 7fa7e3b..0299a21 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor.css @@ -23,18 +23,18 @@ input[type="checkbox"] + label { .card-body { overflow: auto; - height: 490px; + height: 560px; } @media (min-width: 768px) { .card-body { - height: 595px; + height: 665px; } } @media (min-width: 2560px) { .card-body { - height: 950px; + height: 1020px; } } diff --git a/SqlDatabaseVectorSearch/wwwroot/css/app.css b/SqlDatabaseVectorSearch/wwwroot/css/app.css index e2f8887..1f3f172 100644 --- a/SqlDatabaseVectorSearch/wwwroot/css/app.css +++ b/SqlDatabaseVectorSearch/wwwroot/css/app.css @@ -1,3 +1,9 @@ +body, html { + margin: 0; + padding: 0; + height: 100%; +} + :root { --bb-sidebar2-width: 270px; --bb-sidebar2-collapsed-width: 50px; diff --git a/docs/SqlDatabaseVectorSearch_WebApp.png b/docs/SqlDatabaseVectorSearch_WebApp.png index f1ebbb06b1ee2540ea1885780dd273e8d701b7fd..97a75a75516203da3f4cc5d952a222c47544d6f8 100644 GIT binary patch literal 86705 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%0DOvaRn`2ELomFyZZ& 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

{M7?MgmD%mibwZ|>?5QS4XpZAwP{g? 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πBBq?2_2s+ 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 From ec5bf2acb2a44c516019455222dda0a194e7d44c Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Wed, 26 Feb 2025 10:36:50 +0100 Subject: [PATCH 22/25] Update Home.razor and project dependencies Refactor Home.razor to replace markdown loading with static HTML content for the SQL Database Vector Search application, including a main heading and feature list. Remove the IWebHostEnvironment dependency. Upgrade package references in SqlDatabaseVectorSearch.csproj for Microsoft.ML.Tokenizers and Microsoft.SemanticKernel. Revise docs.md to focus on supported features instead of setup instructions. Add new SVG files (openai.svg and sqldatabase.svg) for application icons. --- .../Components/Pages/Home.razor | 46 ++++++------------- .../SqlDatabaseVectorSearch.csproj | 8 ++-- SqlDatabaseVectorSearch/wwwroot/docs.md | 15 ------ .../wwwroot/images/openai.svg | 1 + .../wwwroot/images/sqldatabase.svg | 1 + 5 files changed, 19 insertions(+), 52 deletions(-) delete mode 100644 SqlDatabaseVectorSearch/wwwroot/docs.md create mode 100644 SqlDatabaseVectorSearch/wwwroot/images/openai.svg create mode 100644 SqlDatabaseVectorSearch/wwwroot/images/sqldatabase.svg diff --git a/SqlDatabaseVectorSearch/Components/Pages/Home.razor b/SqlDatabaseVectorSearch/Components/Pages/Home.razor index f7336c8..571e0c4 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Home.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Home.razor @@ -1,39 +1,19 @@ @page "/" @rendermode @(new InteractiveServerRenderMode(prerender: false)) -@inject IWebHostEnvironment WebHostEnvironment - SQL Database Vector Search -@if (markdown is null) -{ -

- -
-} -else -{ -
-
- @markdown -
-
-} +

SQL Database Vector Search

+

+ How to use the native VECTOR type in Azure SQL Database to perform embeddings and RAG with Azure OpenAI. +

+

+ This application allows to load documents, generate embeddings and save them into the database as Vectors, and perform searches using Vector Search and RAG. Currently, PDF, DOCX, TXT and MD files are supported. Vectors are saved and retrieved with Entity Framework Core using the EFCore.SqlServer.VectorSearch library. Embedding and Chat Completion are integrated with Semantic Kernel. +

-@code -{ - private string markdown = default!; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (!firstRender) - { - return; - } - - var filePath = Path.Combine(WebHostEnvironment.WebRootPath, "docs.md"); - markdown = await File.ReadAllTextAsync(filePath); - - StateHasChanged(); - } -} \ No newline at end of file +

Supported features

+
    +
  • Conversation history with question reformulation
  • +
  • Information about token usage
  • +
  • Response streaming
  • +
diff --git a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj index 4658723..a5b04db 100644 --- a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj +++ b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj @@ -20,10 +20,10 @@ - - - - + + + + diff --git a/SqlDatabaseVectorSearch/wwwroot/docs.md b/SqlDatabaseVectorSearch/wwwroot/docs.md deleted file mode 100644 index d67a11a..0000000 --- a/SqlDatabaseVectorSearch/wwwroot/docs.md +++ /dev/null @@ -1,15 +0,0 @@ -# SQL Database Vector Search - -## Setup - -- [Create an Azure SQL Database](https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart) -- Open the [appsettings.json](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json) file and set the connection string to the database and the other settings required by Azure OpenAI - - If your embedding model supports shortening, like **text-embedding-3-small** and **text-embedding-3-large**, and you want to use this feature, you need to set the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to the corresponding value. If your model doesn't provide this feature, or do you want to use the default size, just leave the [`Dimensions`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/appsettings.json#L17) property to NULL. Keep in mind that **text-embedding-3-small** has a dimension of 1536, while **text-embedding-3-large** uses vectors with 3072 elements, so with this latter model it is mandatory to specify a value (that, as said, must be less or equal to 1998). -- You may need to update the size of the [`VECTOR`](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/ApplicationDbContext.cs?plain=1#L42C1-L42C47) column to match the size of the embedding model. The default value is 1536. Currently, the maximum allowed value is 1998. If you change it, remember to update also the [Database Migration](https://github.com/marcominerva/SqlDatabaseVectorSearch/blob/master/SqlDatabaseVectorSearch/DataAccessLayer/Migrations/00000000000000_Initial.cs?plain=1#L35C1-L35C92). -- Run the application and start importing your documents - -## Supported features - -- Conversation history with question reformulation -- Information about token usage -- Response streaming \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/wwwroot/images/openai.svg b/SqlDatabaseVectorSearch/wwwroot/images/openai.svg new file mode 100644 index 0000000..a0e8f8e --- /dev/null +++ b/SqlDatabaseVectorSearch/wwwroot/images/openai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/wwwroot/images/sqldatabase.svg b/SqlDatabaseVectorSearch/wwwroot/images/sqldatabase.svg new file mode 100644 index 0000000..4271bd1 --- /dev/null +++ b/SqlDatabaseVectorSearch/wwwroot/images/sqldatabase.svg @@ -0,0 +1 @@ +Icon-databases-130 \ No newline at end of file From 9d2c4e2e0c6c9a94583caf5d2d86d6eafedc81dc Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Wed, 26 Feb 2025 16:09:04 +0100 Subject: [PATCH 23/25] Update Swashbuckle.AspNetCore.SwaggerUI version Updated the `Swashbuckle.AspNetCore.SwaggerUI` package from version `7.2.0` to `7.3.0` in the `SqlDatabaseVectorSearch.csproj` file. --- SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj index a5b04db..0964ec7 100644 --- a/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj +++ b/SqlDatabaseVectorSearch/SqlDatabaseVectorSearch.csproj @@ -27,7 +27,7 @@ - + From c662d34a2aa90e44184fa0d6642ff14c2e336cb1 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Fri, 28 Feb 2025 11:24:57 +0100 Subject: [PATCH 24/25] Refactor Ask.razor and update dependencies - Renamed `CopyToClipboard` to `CopyToClipboardAsync` in `Ask.razor` for clarity on asynchronous operation. - Added `ElementReference` for `chat` and introduced `EnsureMessageIsVisibleAsync` to improve message visibility. - Modified streaming state handling for better readability. - Made `FormatTokenUsage` and `FormatTokenUsageDetails` methods static and adjusted their implementations. - Enhanced styling in `Home.razor` with a new paragraph class. - Updated `SqlDatabaseVectorSearch.csproj` to upgrade `Microsoft.SemanticKernel` and other package versions. - Added a new `scrollTo` function in `functions.js` to improve user experience by ensuring elements are visible. --- .../Components/Pages/Ask.razor | 40 +++++++++++++------ .../Components/Pages/Home.razor | 2 +- .../SqlDatabaseVectorSearch.csproj | 6 +-- .../wwwroot/js/functions.js | 9 ++++- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor index 2dd519d..a6691ed 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor @@ -59,7 +59,7 @@
- @@ -73,6 +73,8 @@
} } + +