From 9f6ac67b26ec59fe9155a25f21bc6e9e02f98ac1 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Wed, 19 Feb 2025 16:48:02 +0100 Subject: [PATCH] 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