diff --git a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor index 2eca5f6..64bd2b4 100644 --- a/SqlDatabaseVectorSearch/Components/Pages/Documents.razor +++ b/SqlDatabaseVectorSearch/Components/Pages/Documents.razor @@ -1,7 +1,7 @@ @page "/documents" @using MimeMapping -@inject IServiceProvider ServiceProvider +@inject IServiceScopeFactory ServiceScopeFactory @inject IJSRuntime JSRuntime @@ -127,7 +127,7 @@ else return; } - await using var scope = ServiceProvider.CreateAsyncScope(); + await using var scope = ServiceScopeFactory.CreateAsyncScope(); await LoadDocumentsAsync(scope.ServiceProvider); StateHasChanged(); @@ -173,7 +173,7 @@ else await using var inputStream = Model.File.OpenReadStream(20 * 1024 * 1024); // 20 MB await using var stream = await inputStream.GetMemoryStreamAsync(); - await using var scope = ServiceProvider.CreateAsyncScope(); + await using var scope = ServiceScopeFactory.CreateAsyncScope(); var vectorSearchService = scope.ServiceProvider.GetRequiredService(); var documentId = string.IsNullOrWhiteSpace(Model.DocumentId) ? null : (Guid?)Guid.Parse(Model.DocumentId); @@ -223,7 +223,7 @@ else { deleteButton.ShowLoading(); - await using var scope = ServiceProvider.CreateAsyncScope(); + await using var scope = ServiceScopeFactory.CreateAsyncScope(); var documentService = scope.ServiceProvider.GetRequiredService(); await documentService.DeleteAsync(selectedDocumentIds); diff --git a/SqlDatabaseVectorSearch/Program.cs b/SqlDatabaseVectorSearch/Program.cs index 7217fe8..4b09813 100644 --- a/SqlDatabaseVectorSearch/Program.cs +++ b/SqlDatabaseVectorSearch/Program.cs @@ -159,24 +159,23 @@ var textSearchOptions = new TextSearchProviderOptions() sb.AppendLine("Use the excerpts below to answer the user."); sb.AppendLine("Citation rules:"); sb.AppendLine("- Do NOT add inline citations."); - sb.AppendLine("- At the END of your answer, add a single line exactly like:"); - sb.AppendLine(" Sources: [SourceName](SourceLink), [SourceName](SourceLink)"); + sb.AppendLine("- At the END of your answer, add a sources label translated in the same language as the user's question."); + sb.AppendLine("- The sources label MUST be standard-size italic Markdown text, not a heading and not bold. For example: *Sources* or *Fonti*."); + sb.AppendLine("- The citation list MUST be a numbered Markdown list."); + sb.AppendLine("- Format each citation with the source name and the localized page label, followed by a Markdown block quote of about 20-30 words from the excerpt that supports the answer."); + sb.AppendLine("- The block quote MUST start on a new line with the '>' Markdown character."); + sb.AppendLine("- Format each source exactly like:"); + sb.AppendLine(" *Sources*"); + sb.AppendLine(" 1. SourceName, localized-page-label PageNumber"); + sb.AppendLine(" > Supporting excerpt quote of about 20-30 words."); + sb.AppendLine("- Do NOT format source names as links."); sb.AppendLine("- Include ONLY sources you actually used. No duplicates."); sb.AppendLine(); sb.AppendLine("### Sources (copy/paste-ready)"); foreach (var (i, r) in results.Index()) { - var name = string.IsNullOrWhiteSpace(r.SourceName) ? $"Source {i + 1}" : r.SourceName; - - if (!string.IsNullOrWhiteSpace(r.SourceLink)) - { - sb.AppendLine($"- [{name}]({r.SourceLink})"); - } - else - { - sb.AppendLine($"- {name}"); - } + sb.AppendLine($"- {GetSourceName(r, i)}"); } sb.AppendLine(); @@ -184,14 +183,21 @@ var textSearchOptions = new TextSearchProviderOptions() sb.AppendLine("### Excerpts"); foreach (var (i, r) in results.Index()) { - var name = string.IsNullOrWhiteSpace(r.SourceName) ? $"Source {i + 1}" : r.SourceName; - - sb.AppendLine($"[{i + 1}] {name}"); + sb.AppendLine($"[{i + 1}] {GetSourceName(r, i)}"); sb.AppendLine(r.Text); - sb.AppendLine(); + sb.AppendLine("---"); } return sb.ToString(); + + static string GetSourceName(TextSearchProvider.TextSearchResult result, int index) + { + var name = string.IsNullOrWhiteSpace(result.SourceName) ? $"Source {index + 1}" : result.SourceName; + var pageNumber = result.RawRepresentation is int number ? number : (int?)null; + var pageText = pageNumber.HasValue ? $", page {pageNumber}" : string.Empty; + + return $"{name}{pageText}"; + } } }; diff --git a/SqlDatabaseVectorSearch/Services/VectorSearchService.cs b/SqlDatabaseVectorSearch/Services/VectorSearchService.cs index 2c19f40..9333f45 100644 --- a/SqlDatabaseVectorSearch/Services/VectorSearchService.cs +++ b/SqlDatabaseVectorSearch/Services/VectorSearchService.cs @@ -105,7 +105,7 @@ public class ContextProvider(ApplicationDbContext dbContext, IEmbeddingGenerator SourceLink = c.Id.ToString().ToLowerInvariant(), SourceName = c.Document.Name, Text = c.Content, - RawRepresentation = new { c.Id, c.DocumentId, c.PageNumber, c.IndexOnPage, c.Content } + RawRepresentation = c.PageNumber }) .ToListAsync(cancellationToken);