diff --git a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor
index 9e07b45..60a2af1 100644
--- a/SqlDatabaseVectorSearch/Components/Pages/Ask.razor
+++ b/SqlDatabaseVectorSearch/Components/Pages/Ask.razor
@@ -1,4 +1,5 @@
@page "/ask"
+@using System.Text.RegularExpressions
@inject IServiceProvider ServiceProvider
@inject IJSRuntime JSRuntime
@@ -72,6 +73,23 @@
+ @if (message.Citations is not null && message.Citations.Count() > 0)
+ {
+
+ @foreach (var citation in message.Citations)
+ {
+
+
+ @citation.FileName @if (!string.IsNullOrEmpty(citation.PageNumber))
+ {
+ pag. @citation.PageNumber
+ }
+
+
@citation.Quote
+
+ }
+
+ }
}
}
@@ -178,10 +196,17 @@
}
else if (delta.StreamState == StreamState.Append)
{
+ // Adds tokens to the assistant message as they are received
assistantMessage.Text += delta.Answer;
}
else if (delta.StreamState == StreamState.End)
{
+ // Extracts citations, if any.
+ var (cleanText, citations) = ExtractCitations(assistantMessage.Text);
+
+ assistantMessage.Text = cleanText;
+ assistantMessage.Citations = citations;
+
assistantMessage.IsCompleted = true;
assistantMessage.TokenUsage += FormatTokenUsage(delta.TokenUsage);
}
@@ -269,6 +294,36 @@
await JSRuntime.InvokeVoidAsync("scrollTo", chat);
}
+ private static (string, IEnumerable) ExtractCitations(string? text)
+ {
+ var citations = new List();
+
+ if (string.IsNullOrEmpty(text))
+ {
+ return (text ?? string.Empty, citations);
+ }
+
+ var pattern = "(.*?)<\\/citation>";
+
+ var matches = Regex.Matches(text, pattern, RegexOptions.Singleline);
+ foreach (Match match in matches)
+ {
+ if (match.Success && match.Groups.Count == 4)
+ {
+ citations.Add(new Citation
+ {
+ FileName = match.Groups[1].Value,
+ PageNumber = match.Groups[2].Value,
+ Quote = match.Groups[3].Value
+ });
+ }
+ }
+
+ // Remove all tags from the text
+ var cleanText = Regex.Replace(text, pattern, string.Empty, RegexOptions.Singleline).TrimEnd();
+ return (cleanText, citations);
+ }
+
public class Message
{
public string? Text { get; set; }
@@ -278,5 +333,17 @@
public bool IsCompleted { get; set; }
public string? TokenUsage { get; set; }
+
+ // List of citations extracted from the answer
+ public IEnumerable? Citations { get; set; }
+ }
+
+ public class Citation
+ {
+ public string FileName { get; set; } = null!;
+
+ public string Quote { get; set; } = null!;
+
+ public string PageNumber { get; set; } = null!;
}
}
\ No newline at end of file
diff --git a/SqlDatabaseVectorSearch/wwwroot/css/app.css b/SqlDatabaseVectorSearch/wwwroot/css/app.css
index 1f3f172..3d4dd04 100644
--- a/SqlDatabaseVectorSearch/wwwroot/css/app.css
+++ b/SqlDatabaseVectorSearch/wwwroot/css/app.css
@@ -62,3 +62,9 @@ h1:focus {
.blazor-error-boundary::after {
content: "An error has occurred."
}
+
+.citation-box {
+ width: fit-content;
+ max-width: 100%;
+ background-color: #f8f9fa;
+}