diff --git a/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.metadata.v8.bin b/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.metadata.v8.bin new file mode 100644 index 0000000..e1608cd Binary files /dev/null and b/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.metadata.v8.bin differ diff --git a/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.projects.v8.bin b/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.projects.v8.bin new file mode 100644 index 0000000..26bf5a0 Binary files /dev/null and b/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.projects.v8.bin differ diff --git a/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.strings.v8.bin b/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.strings.v8.bin new file mode 100644 index 0000000..aeca895 Binary files /dev/null and b/AI Demos/Summarizer/.vs/ProjectEvaluation/summarizer.strings.v8.bin differ diff --git a/AI Demos/Summarizer/.vs/Summarizer/DesignTimeBuild/.dtbcache.v2 b/AI Demos/Summarizer/.vs/Summarizer/DesignTimeBuild/.dtbcache.v2 new file mode 100644 index 0000000..21f69d0 Binary files /dev/null and b/AI Demos/Summarizer/.vs/Summarizer/DesignTimeBuild/.dtbcache.v2 differ diff --git a/AI Demos/Summarizer/.vs/Summarizer/v17/.futdcache.v2 b/AI Demos/Summarizer/.vs/Summarizer/v17/.futdcache.v2 new file mode 100644 index 0000000..38fc972 Binary files /dev/null and b/AI Demos/Summarizer/.vs/Summarizer/v17/.futdcache.v2 differ diff --git a/AI Demos/Summarizer/.vs/Summarizer/v17/.suo b/AI Demos/Summarizer/.vs/Summarizer/v17/.suo new file mode 100644 index 0000000..8bd26a9 Binary files /dev/null and b/AI Demos/Summarizer/.vs/Summarizer/v17/.suo differ diff --git a/AI Demos/Summarizer/.vs/Summarizer/v17/DocumentLayout.json b/AI Demos/Summarizer/.vs/Summarizer/v17/DocumentLayout.json new file mode 100644 index 0000000..7f58684 --- /dev/null +++ b/AI Demos/Summarizer/.vs/Summarizer/v17/DocumentLayout.json @@ -0,0 +1,142 @@ +{ + "Version": 1, + "WorkspaceRootPath": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\", + "Documents": [ + { + "AbsoluteMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|d:\\forgithub\\maui-pdf-viewer-examples\\ai demos\\summarizer\\summarizer\\mainpage.xaml.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|solutionrelative:summarizer\\mainpage.xaml.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|d:\\forgithub\\maui-pdf-viewer-examples\\ai demos\\summarizer\\summarizer\\mauiprogram.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|solutionrelative:summarizer\\mauiprogram.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|d:\\forgithub\\maui-pdf-viewer-examples\\ai demos\\summarizer\\summarizer\\mainpage.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}", + "RelativeMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|solutionrelative:summarizer\\mainpage.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}" + }, + { + "AbsoluteMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|d:\\forgithub\\maui-pdf-viewer-examples\\ai demos\\summarizer\\summarizer\\viewmodel\\pdfviewerviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|solutionrelative:summarizer\\viewmodel\\pdfviewerviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|d:\\forgithub\\maui-pdf-viewer-examples\\ai demos\\summarizer\\summarizer\\assistservices.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|solutionrelative:summarizer\\assistservices.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|d:\\forgithub\\maui-pdf-viewer-examples\\ai demos\\summarizer\\summarizer\\summarizer.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|", + "RelativeMoniker": "D:0:0:{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}|Summarizer\\Summarizer.csproj|solutionrelative:summarizer\\summarizer.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|" + } + ], + "DocumentGroupContainers": [ + { + "Orientation": 0, + "VerticalTabListWidth": 256, + "DocumentGroups": [ + { + "DockedWidth": 200, + "SelectedChildIndex": 6, + "Children": [ + { + "$type": "Bookmark", + "Name": "ST:0:0:{34e76e81-ee4a-11d0-ae2e-00a0c90fffc3}" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{0ad07096-bba9-4900-a651-0598d26f6d24}" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{eefa5220-e298-11d0-8f78-00a0c9110057}" + }, + { + "$type": "Bookmark", + "Name": "ST:1:0:{d212f56b-c48a-434c-a121-1c5d80b59b9f}" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{d78612c7-9962-4b83-95d9-268046dad23a}" + }, + { + "$type": "Document", + "DocumentIndex": 1, + "Title": "MauiProgram.cs", + "DocumentMoniker": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\MauiProgram.cs", + "RelativeDocumentMoniker": "Summarizer\\MauiProgram.cs", + "ToolTip": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\MauiProgram.cs", + "RelativeToolTip": "Summarizer\\MauiProgram.cs", + "ViewState": "AQIAAAAAAAAAAAAAAAAAABYAAAAwAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2024-09-18T12:16:48.383Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 0, + "Title": "MainPage.xaml.cs", + "DocumentMoniker": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\MainPage.xaml.cs", + "RelativeDocumentMoniker": "Summarizer\\MainPage.xaml.cs", + "ToolTip": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\MainPage.xaml.cs", + "RelativeToolTip": "Summarizer\\MainPage.xaml.cs", + "ViewState": "AQIAABIAAAAAAAAAAAAYwDMAAAAAAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2024-09-18T12:16:05.93Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 2, + "Title": "MainPage.xaml", + "DocumentMoniker": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\MainPage.xaml", + "RelativeDocumentMoniker": "Summarizer\\MainPage.xaml", + "ToolTip": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\MainPage.xaml", + "RelativeToolTip": "Summarizer\\MainPage.xaml", + "ViewState": "AQIAAAAAAAAAAAAAAAAAAIwAAAAAAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003549|", + "WhenOpened": "2024-09-18T12:15:30.33Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 3, + "Title": "PdfViewerViewModel.cs", + "DocumentMoniker": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\ViewModel\\PdfViewerViewModel.cs", + "RelativeDocumentMoniker": "Summarizer\\ViewModel\\PdfViewerViewModel.cs", + "ToolTip": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\ViewModel\\PdfViewerViewModel.cs", + "RelativeToolTip": "Summarizer\\ViewModel\\PdfViewerViewModel.cs", + "ViewState": "AQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2024-09-18T12:15:20.014Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 4, + "Title": "AssistServices.cs", + "DocumentMoniker": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\AssistServices.cs", + "RelativeDocumentMoniker": "Summarizer\\AssistServices.cs", + "ToolTip": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\AssistServices.cs", + "RelativeToolTip": "Summarizer\\AssistServices.cs", + "ViewState": "AQIAABMAAAAAAAAAAAAQwAAAAAAAAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2024-09-18T12:15:07.799Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 5, + "Title": "Summarizer", + "DocumentMoniker": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\Summarizer.csproj", + "RelativeDocumentMoniker": "Summarizer\\Summarizer.csproj", + "ToolTip": "D:\\ForGitHub\\maui-pdf-viewer-examples\\AI Demos\\Summarizer\\Summarizer\\Summarizer.csproj", + "RelativeToolTip": "Summarizer\\Summarizer.csproj", + "ViewState": "AQIAACQAAAAAAAAAAAAAAE8AAAAEAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|", + "WhenOpened": "2024-09-18T12:14:31.732Z", + "EditorCaption": "" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer.sln b/AI Demos/Summarizer/Summarizer.sln new file mode 100644 index 0000000..d04bc54 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer.sln @@ -0,0 +1,27 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35122.118 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Summarizer", "Summarizer\Summarizer.csproj", "{CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}.Release|Any CPU.Build.0 = Release|Any CPU + {CD42BBF8-9F64-4E6F-BB42-F00ED07A35C1}.Release|Any CPU.Deploy.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A2477ADB-5676-475F-A831-8327EC2C8B92} + EndGlobalSection +EndGlobal diff --git a/AI Demos/Summarizer/Summarizer/App.xaml b/AI Demos/Summarizer/Summarizer/App.xaml new file mode 100644 index 0000000..ab49df0 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/AI Demos/Summarizer/Summarizer/App.xaml.cs b/AI Demos/Summarizer/Summarizer/App.xaml.cs new file mode 100644 index 0000000..164482b --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/App.xaml.cs @@ -0,0 +1,12 @@ +namespace Summarizer +{ + public partial class App : Application + { + public App() + { + InitializeComponent(); + + MainPage = new AppShell(); + } + } +} diff --git a/AI Demos/Summarizer/Summarizer/AppShell.xaml b/AI Demos/Summarizer/Summarizer/AppShell.xaml new file mode 100644 index 0000000..110b6fd --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/AppShell.xaml @@ -0,0 +1,15 @@ + + + + + + diff --git a/AI Demos/Summarizer/Summarizer/AppShell.xaml.cs b/AI Demos/Summarizer/Summarizer/AppShell.xaml.cs new file mode 100644 index 0000000..dc03246 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/AppShell.xaml.cs @@ -0,0 +1,10 @@ +namespace Summarizer +{ + public partial class AppShell : Shell + { + public AppShell() + { + InitializeComponent(); + } + } +} diff --git a/AI Demos/Summarizer/Summarizer/Assets/summarizeDoc.pdf b/AI Demos/Summarizer/Summarizer/Assets/summarizeDoc.pdf new file mode 100644 index 0000000..c66f17a Binary files /dev/null and b/AI Demos/Summarizer/Summarizer/Assets/summarizeDoc.pdf differ diff --git a/AI Demos/Summarizer/Summarizer/AssistServices.cs b/AI Demos/Summarizer/Summarizer/AssistServices.cs new file mode 100644 index 0000000..1fe3c15 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/AssistServices.cs @@ -0,0 +1,162 @@ +using Syncfusion.Maui.AIAssistView; +using System.Collections.ObjectModel; +using Azure.AI.OpenAI; +using Azure; + +namespace Summarizer +{ + /// + /// Represents a class providing AI assistance services for text extraction, + /// prompt generation, and chat completion functionalities using OpenAI's GPT model. + /// + internal class AssistServices + { + + /// + /// Gets or sets the extracted text from a document. + /// + internal string? ExtractedText { get; set; } + + /// + /// The EndPoint + /// + private const string endpoint = "https://blazorpdf-ai.openai.azure.com/"; + + /// + /// The Deployment name + /// + internal string deploymentName = "gpt-4-0"; + + /// + /// The API key + /// + private const string key = "7f164d6ba53e4df784ecddabbf73d5a8"; + + /// + /// The AzureOpenAI client + /// + internal OpenAIClient? client; + + /// + /// The ChatCompletion option + /// + private ChatCompletionsOptions? chatCompletions; + + internal AssistServices() + { + chatCompletions = new ChatCompletionsOptions + { + DeploymentName = deploymentName, + Temperature = (float)1.2f, + NucleusSamplingFactor = (float)0.9, + FrequencyPenalty = 0.8f, + PresencePenalty = 0.8f + }; + client = new OpenAIClient(new Uri(endpoint), new AzureKeyCredential(key)); + } + + /// + /// Generates a static prompt message. + /// + /// The input prompt string. + /// A predefined message requesting OpenAI connection for real-time queries. + internal async Task GetPrompt(string prompt) + { + if (client != null && chatCompletions != null && key!= "AI_KEY") + { + chatCompletions.Messages.Clear(); + chatCompletions.Messages.Add(new ChatRequestSystemMessage("Please provide the prompt for responce" + prompt)); + chatCompletions.Messages.Add(new ChatRequestUserMessage(prompt)); + var response = await client.GetChatCompletionsAsync(chatCompletions); + return response.Value.Choices[0].Message.Content; + } + else + { + return "Please connect OpenAI for real time queries"; + } + } + + /// + /// Gets a solution to a given prompt by using either local embeddings or extracted text, + /// depending on the platform. + /// + /// The user's question to be processed. + /// A task representing the asynchronous operation, with a solution string as the result. + internal async Task GetSolutionToPrompt(string question) + { + try + { + // Use extracted text + if (ExtractedText != null && client != null && chatCompletions != null && key != "AI_KEY") + { + string message = ExtractedText; + var systemPrompt = "You are a helpful assistant. Use the provided PDF document pages and pick a precise page to answer the user question,Ignore about iTextSharp related points in the details, Strictly don't bold any text all text need to plain text. Pages: " + message; + chatCompletions.Messages.Clear(); + chatCompletions.Messages.Add(new ChatRequestSystemMessage(systemPrompt)); + chatCompletions.Messages.Add(new ChatRequestUserMessage(question)); + var response = await client.GetChatCompletionsAsync(chatCompletions); + return response.Value.Choices[0].Message.Content; + } + return "Please connect OpenAI for real time queries"; + } + catch + { + return "Please connect OpenAI for real time queries"; + } + } + + /// + /// Generates suggestions based on a given prompt. + /// + /// The input prompt string. + /// A task representing the asynchronous operation, with an object as the result. + internal async Task GetSuggestion(string prompt) + { + var chatSuggestions = new AssistItemSuggestion(); + + var suggestions = new ObservableCollection(); + var suggestion = await GetAnswerFromGPT("You are a helpful assistant. Your task is to analyze the provided text and generate 3 short diverse questions and each question should not exceed 10 words."); + if (suggestion != "Please connect OpenAI for real time queries") + { + string[] parts = suggestion.Split(new string[] { "1. ", "2. ", "3. " }, StringSplitOptions.RemoveEmptyEntries); + // Store the parts in separate variables + string question1 = parts.Length > 0 ? parts[0].Trim() : string.Empty; + string question2 = parts.Length > 1 ? parts[1].Trim() : string.Empty; + string question3 = parts.Length > 2 ? parts[2].Trim() : string.Empty; + suggestions.Add(new AssistSuggestion() { Text = question1 }); + suggestions.Add(new AssistSuggestion() { Text = question2 }); + suggestions.Add(new AssistSuggestion() { Text = question3 }); + chatSuggestions.Items = suggestions; + } + return chatSuggestions; + } + + /// + /// Gets an answer from the GPT model using only a system prompt. + /// + /// The system prompt to guide the AI. + /// A task representing the asynchronous operation, with the answer string as the result. + internal async Task GetAnswerFromGPT(string systemPrompt) + { + try + { + if (ExtractedText != null && chatCompletions != null && client != null && key != "AI_KEY") + { + chatCompletions.Messages.Clear(); + chatCompletions.Messages.Add(new ChatRequestSystemMessage(systemPrompt)); + chatCompletions.Messages.Add(new ChatRequestUserMessage(ExtractedText)); + var response = await client.GetChatCompletionsAsync(chatCompletions); + return response.Value.Choices[0].Message.Content; + } + else + { + return "Please connect OpenAI for real time queries"; + } + } + catch + { + return "Please connect OpenAI for real time queries"; + } + } + } +} \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/MainPage.xaml b/AI Demos/Summarizer/Summarizer/MainPage.xaml new file mode 100644 index 0000000..64c5dcf --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/MainPage.xaml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AI Demos/Summarizer/Summarizer/MainPage.xaml.cs b/AI Demos/Summarizer/Summarizer/MainPage.xaml.cs new file mode 100644 index 0000000..84e8047 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/MainPage.xaml.cs @@ -0,0 +1,182 @@ +using Azure.Core; +using Syncfusion.Maui.AIAssistView; +using Syncfusion.Pdf.Parsing; + +namespace Summarizer; + +public partial class MainPage : ContentPage +{ + private bool tapped; + Animation animation; + public MainPage() + { + InitializeComponent(); + animation = new Animation(); + PdfViewer.DocumentLoaded += PdfViewer_DocumentLoaded; + } + + private async void PdfViewer_DocumentLoaded(object? sender, EventArgs? e) + { + AssistServices AI = new AssistServices(); + if (AI.deploymentName == "DEPLOYMENT_NAME") + { + Application.Current?.MainPage?.DisplayAlert("Alert", "The Azure API key or endpoint is missing or incorrect. Please verify your credentials", "OK"); + } + await LoadPDFDataAsync(); + var reply = await viewModel.assistService.GetAnswerFromGPT("Read the PDF document contents and understand the concept. Provide summary for this in 3 to 4 simple sentences. Ignore about iTextSharp related points in the details"); + var suggestion = await viewModel.assistService.GetSuggestion("Provide short Summary for the document"); + AssistItem botMessage = new AssistItem() { Text = reply, Suggestion = suggestion }; + viewModel.Messages.Add(botMessage); + viewModel.ShowLoading = false; + } + + private void AIAssistant_Clicked(object? sender, EventArgs e) + { + AILayout.IsVisible = !AILayout.IsVisible; + if (AILayout.IsVisible) + { + tapped = true; + StopBubbleAnimation(); + } + else + { + StartBubbleAnimation(); + } + } + + internal async Task LoadPDFDataAsync() + { + await Task.Delay(1000); + var documentSource = PdfViewer.DocumentSource; + List extractedText = new List(); + + if (documentSource != null) + { + + Stream stream = (Stream)documentSource; + PdfLoadedDocument loadedDocument = new PdfLoadedDocument(stream); + // Loading page collections + PdfLoadedPageCollection loadedPages = loadedDocument.Pages; + await Task.Run(() => + { + + // Extract annotations to a memory stream and convert to string + using (MemoryStream annotationStream = new MemoryStream()) + { + loadedDocument.ExportAnnotations(annotationStream, AnnotationDataFormat.Json); + string annotations = ConvertToString(annotationStream); + if (!String.IsNullOrEmpty(annotations)) + { + extractedText.Add("Annotations: " + annotations); + } + } + + // Extract form fields to a memory stream and convert to string + using (MemoryStream formStream = new MemoryStream()) + { + if (loadedDocument.Form != null) + { + loadedDocument.Form.ExportData(formStream, DataFormat.Json, "form"); + string formFields = ConvertToString(formStream); + if (!String.IsNullOrEmpty(formFields)) + { + extractedText.Add("Form fields: " + formFields); + } + } + } + + // Extract text from existing PDF document pages + for (int i = 0; i < loadedPages.Count; i++) + { + string text = $"... Page {i + 1} ...\n"; + text += loadedPages[i].ExtractText(); + extractedText.Add(text); + } + string result = string.Join(Environment.NewLine, extractedText); + viewModel.assistService.ExtractedText = result; + }); + } + } + + private string ConvertToString(MemoryStream memoryStream) + { + // Reset the position of the MemoryStream to the beginning + memoryStream.Position = 0; + var reader = new StreamReader(memoryStream, System.Text.Encoding.UTF8); + return reader.ReadToEnd(); + } + private void PreviousPage(object? sender, EventArgs e) + { + PdfViewer.GoToPreviousPage(); + if (PdfViewer.PageNumber == 1) + { + goToPreviousPageButton.IsEnabled = false; + goToNextPageButton.IsEnabled = true; + } + else + { + goToPreviousPageButton.IsEnabled = true; + goToNextPageButton.IsEnabled = true; + } + } + private void NextPage(object? sender, EventArgs e) + { + PdfViewer.GoToNextPage(); + if (PdfViewer.PageNumber == PdfViewer.PageCount) + { + goToNextPageButton.IsEnabled = false; + goToPreviousPageButton.IsEnabled = true; + } + else + { + goToNextPageButton.IsEnabled = true; + goToPreviousPageButton.IsEnabled = true; + } + } + + private void pageNumberEntry_TextChanged(object sender, TextChangedEventArgs e) + { + int pageNumber; + bool check = int.TryParse(e.NewTextValue, out pageNumber); + if (pageNumber != 0) + PdfViewer.GoToPage(pageNumber); + + } + + private void pageNumberEntry_Focused(object sender, FocusEventArgs e) + { + if (!string.IsNullOrEmpty(pageNumberEntry.Text)) + { + // Select all text in the Editor + pageNumberEntry.CursorPosition = 0; + pageNumberEntry.SelectionLength = pageNumberEntry.Text.Length; + } + } + + private void image_Loaded(object sender, EventArgs e) + { + StartBubbleAnimation(); + } + private void StartBubbleAnimation() + { + if (!tapped) + { + var bubbleEffect = new Animation(v => AIButton.Scale = v, 1, 1.15, Easing.CubicInOut); + var fadeEffect = new Animation(v => AIButton.Opacity = v, 1, 0.5, Easing.CubicInOut); + + animation.Add(0, 0.5, bubbleEffect); + animation.Add(0, 0.5, fadeEffect); + animation.Add(0.5, 1, new Animation(v => AIButton.Scale = v, 1.15, 1, Easing.CubicInOut)); + animation.Add(0.5, 1, new Animation(v => AIButton.Opacity = v, 0.5, 1, Easing.CubicInOut)); + + animation.Commit(this, "BubbleEffect", length: 1500, easing: Easing.CubicInOut, repeat: () => true); + + } + } + + private void StopBubbleAnimation() + { + this.AbortAnimation("BubbleEffect"); + tapped = false; + } +} \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/MauiProgram.cs b/AI Demos/Summarizer/Summarizer/MauiProgram.cs new file mode 100644 index 0000000..6e22b3b --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/MauiProgram.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.Logging; +using Syncfusion.Maui.Core.Hosting; + +namespace Summarizer +{ + public static class MauiProgram + { + public static MauiApp CreateMauiApp() + { + var builder = MauiApp.CreateBuilder(); + builder + .UseMauiApp() + .ConfigureFonts(fonts => + { + fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); + fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); + }); + +#if DEBUG + builder.Logging.AddDebug(); +#endif + + builder.ConfigureSyncfusionCore(); + return builder.Build(); + } + } +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Android/AndroidManifest.xml b/AI Demos/Summarizer/Summarizer/Platforms/Android/AndroidManifest.xml new file mode 100644 index 0000000..e9937ad --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Android/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Android/MainActivity.cs b/AI Demos/Summarizer/Summarizer/Platforms/Android/MainActivity.cs new file mode 100644 index 0000000..8b1e44a --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Android/MainActivity.cs @@ -0,0 +1,11 @@ +using Android.App; +using Android.Content.PM; +using Android.OS; + +namespace Summarizer +{ + [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] + public class MainActivity : MauiAppCompatActivity + { + } +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Android/MainApplication.cs b/AI Demos/Summarizer/Summarizer/Platforms/Android/MainApplication.cs new file mode 100644 index 0000000..1b12eff --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Android/MainApplication.cs @@ -0,0 +1,16 @@ +using Android.App; +using Android.Runtime; + +namespace Summarizer +{ + [Application] + public class MainApplication : MauiApplication + { + public MainApplication(IntPtr handle, JniHandleOwnership ownership) + : base(handle, ownership) + { + } + + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + } +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Android/Resources/values/colors.xml b/AI Demos/Summarizer/Summarizer/Platforms/Android/Resources/values/colors.xml new file mode 100644 index 0000000..c04d749 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Android/Resources/values/colors.xml @@ -0,0 +1,6 @@ + + + #512BD4 + #2B0B98 + #2B0B98 + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/AppDelegate.cs b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/AppDelegate.cs new file mode 100644 index 0000000..ff3643b --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/AppDelegate.cs @@ -0,0 +1,10 @@ +using Foundation; + +namespace Summarizer +{ + [Register("AppDelegate")] + public class AppDelegate : MauiUIApplicationDelegate + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + } +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Entitlements.plist b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Entitlements.plist new file mode 100644 index 0000000..de4adc9 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Entitlements.plist @@ -0,0 +1,14 @@ + + + + + + + com.apple.security.app-sandbox + + + com.apple.security.network.client + + + + diff --git a/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Info.plist b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Info.plist new file mode 100644 index 0000000..7268977 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Info.plist @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + UIDeviceFamily + + 2 + + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/appicon.appiconset + + diff --git a/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Program.cs b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Program.cs new file mode 100644 index 0000000..5f4e645 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/MacCatalyst/Program.cs @@ -0,0 +1,16 @@ +using ObjCRuntime; +using UIKit; + +namespace Summarizer +{ + public class Program + { + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, typeof(AppDelegate)); + } + } +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Tizen/Main.cs b/AI Demos/Summarizer/Summarizer/Platforms/Tizen/Main.cs new file mode 100644 index 0000000..488249d --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Tizen/Main.cs @@ -0,0 +1,17 @@ +using Microsoft.Maui; +using Microsoft.Maui.Hosting; +using System; + +namespace Summarizer +{ + internal class Program : MauiApplication + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Tizen/tizen-manifest.xml b/AI Demos/Summarizer/Summarizer/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 0000000..1489b8b --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + maui-appicon-placeholder + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Windows/App.xaml b/AI Demos/Summarizer/Summarizer/Platforms/Windows/App.xaml new file mode 100644 index 0000000..4cfbfdf --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Windows/App.xaml @@ -0,0 +1,8 @@ + + + diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Windows/App.xaml.cs b/AI Demos/Summarizer/Summarizer/Platforms/Windows/App.xaml.cs new file mode 100644 index 0000000..d959684 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Windows/App.xaml.cs @@ -0,0 +1,25 @@ +using Microsoft.UI.Xaml; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Summarizer.WinUI +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + public partial class App : MauiWinUIApplication + { + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + } + + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + } + +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Windows/Package.appxmanifest b/AI Demos/Summarizer/Summarizer/Platforms/Windows/Package.appxmanifest new file mode 100644 index 0000000..f6342b8 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Windows/Package.appxmanifest @@ -0,0 +1,46 @@ + + + + + + + + + $placeholder$ + User Name + $placeholder$.png + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AI Demos/Summarizer/Summarizer/Platforms/Windows/app.manifest b/AI Demos/Summarizer/Summarizer/Platforms/Windows/app.manifest new file mode 100644 index 0000000..690e8b4 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/Windows/app.manifest @@ -0,0 +1,15 @@ + + + + + + + + true/PM + PerMonitorV2, PerMonitor + + + diff --git a/AI Demos/Summarizer/Summarizer/Platforms/iOS/AppDelegate.cs b/AI Demos/Summarizer/Summarizer/Platforms/iOS/AppDelegate.cs new file mode 100644 index 0000000..ff3643b --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/iOS/AppDelegate.cs @@ -0,0 +1,10 @@ +using Foundation; + +namespace Summarizer +{ + [Register("AppDelegate")] + public class AppDelegate : MauiUIApplicationDelegate + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + } +} diff --git a/AI Demos/Summarizer/Summarizer/Platforms/iOS/Info.plist b/AI Demos/Summarizer/Summarizer/Platforms/iOS/Info.plist new file mode 100644 index 0000000..0004a4f --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/iOS/Info.plist @@ -0,0 +1,32 @@ + + + + + LSRequiresIPhoneOS + + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/appicon.appiconset + + diff --git a/AI Demos/Summarizer/Summarizer/Platforms/iOS/Program.cs b/AI Demos/Summarizer/Summarizer/Platforms/iOS/Program.cs new file mode 100644 index 0000000..5f4e645 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Platforms/iOS/Program.cs @@ -0,0 +1,16 @@ +using ObjCRuntime; +using UIKit; + +namespace Summarizer +{ + public class Program + { + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, typeof(AppDelegate)); + } + } +} diff --git a/AI Demos/Summarizer/Summarizer/Properties/launchSettings.json b/AI Demos/Summarizer/Summarizer/Properties/launchSettings.json new file mode 100644 index 0000000..edf8aad --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Windows Machine": { + "commandName": "MsixPackage", + "nativeDebugging": false + } + } +} \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Resources/AppIcon/appicon.svg b/AI Demos/Summarizer/Summarizer/Resources/AppIcon/appicon.svg new file mode 100644 index 0000000..9d63b65 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Resources/AppIcon/appicon.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Resources/AppIcon/appiconfg.svg b/AI Demos/Summarizer/Summarizer/Resources/AppIcon/appiconfg.svg new file mode 100644 index 0000000..21dfb25 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Resources/AppIcon/appiconfg.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Resources/Fonts/OpenSans-Regular.ttf b/AI Demos/Summarizer/Summarizer/Resources/Fonts/OpenSans-Regular.ttf new file mode 100644 index 0000000..d2887c8 Binary files /dev/null and b/AI Demos/Summarizer/Summarizer/Resources/Fonts/OpenSans-Regular.ttf differ diff --git a/AI Demos/Summarizer/Summarizer/Resources/Fonts/OpenSans-Semibold.ttf b/AI Demos/Summarizer/Summarizer/Resources/Fonts/OpenSans-Semibold.ttf new file mode 100644 index 0000000..20060c4 Binary files /dev/null and b/AI Demos/Summarizer/Summarizer/Resources/Fonts/OpenSans-Semibold.ttf differ diff --git a/AI Demos/Summarizer/Summarizer/Resources/Images/dotnet_bot.png b/AI Demos/Summarizer/Summarizer/Resources/Images/dotnet_bot.png new file mode 100644 index 0000000..f93ce02 Binary files /dev/null and b/AI Demos/Summarizer/Summarizer/Resources/Images/dotnet_bot.png differ diff --git a/AI Demos/Summarizer/Summarizer/Resources/Raw/AboutAssets.txt b/AI Demos/Summarizer/Summarizer/Resources/Raw/AboutAssets.txt new file mode 100644 index 0000000..89dc758 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Resources/Raw/AboutAssets.txt @@ -0,0 +1,15 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories). Deployment of the asset to your application +is automatically handled by the following `MauiAsset` Build Action within your `.csproj`. + + + +These files will be deployed with your package and will be accessible using Essentials: + + async Task LoadMauiAsset() + { + using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt"); + using var reader = new StreamReader(stream); + + var contents = reader.ReadToEnd(); + } diff --git a/AI Demos/Summarizer/Summarizer/Resources/Splash/splash.svg b/AI Demos/Summarizer/Summarizer/Resources/Splash/splash.svg new file mode 100644 index 0000000..21dfb25 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Resources/Splash/splash.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Resources/Styles/Colors.xaml b/AI Demos/Summarizer/Summarizer/Resources/Styles/Colors.xaml new file mode 100644 index 0000000..30307a5 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Resources/Styles/Colors.xaml @@ -0,0 +1,45 @@ + + + + + + + #512BD4 + #ac99ea + #242424 + #DFD8F7 + #9880e5 + #2B0B98 + + White + Black + #D600AA + #190649 + #1f1f1f + + #E1E1E1 + #C8C8C8 + #ACACAC + #919191 + #6E6E6E + #404040 + #212121 + #141414 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/Resources/Styles/Styles.xaml b/AI Demos/Summarizer/Summarizer/Resources/Styles/Styles.xaml new file mode 100644 index 0000000..6641e3a --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Resources/Styles/Styles.xaml @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AI Demos/Summarizer/Summarizer/Summarizer.csproj b/AI Demos/Summarizer/Summarizer/Summarizer.csproj new file mode 100644 index 0000000..0b02a74 --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Summarizer.csproj @@ -0,0 +1,94 @@ + + + + net8.0-android;net8.0-ios;net8.0-maccatalyst + $(TargetFrameworks);net8.0-windows10.0.19041.0 + + + + + + + Exe + Summarizer + true + true + enable + enable + + + Summarizer + + + com.companyname.summarizer + + + 1.0 + 1 + + 11.0 + 13.1 + 21.0 + 10.0.17763.0 + 10.0.17763.0 + 6.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AI Demos/Summarizer/Summarizer/Summarizer.csproj.user b/AI Demos/Summarizer/Summarizer/Summarizer.csproj.user new file mode 100644 index 0000000..891593c --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/Summarizer.csproj.user @@ -0,0 +1,31 @@ + + + + False + net8.0-windows10.0.19041.0 + Windows Machine + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + \ No newline at end of file diff --git a/AI Demos/Summarizer/Summarizer/ViewModel/PdfViewerViewModel.cs b/AI Demos/Summarizer/Summarizer/ViewModel/PdfViewerViewModel.cs new file mode 100644 index 0000000..a6257cd --- /dev/null +++ b/AI Demos/Summarizer/Summarizer/ViewModel/PdfViewerViewModel.cs @@ -0,0 +1,127 @@ +using Syncfusion.Maui.AIAssistView; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Windows.Input; +namespace Summarizer +{ + public class PdfViewerViewModel : INotifyPropertyChanged + { + private ObservableCollection messages; + + private bool showLoading = false; + public ICommand CopyCommand { get; set; } + public ICommand RetryCommand { get; set; } + public ICommand AssistViewRequestCommand { get; set; } + + private Stream? _pdfFile; + public Stream? PdfFile + { + get => _pdfFile; + set + { + if (_pdfFile != value) + { + _pdfFile = value; + OnPropertyChanged(nameof(PdfFile)); + } + } + } + + + public ObservableCollection Messages + { + get + { + return this.messages; + } + + set + { + this.messages = value; + RaisePropertyChanged("Messages"); + } + } + + public bool ShowLoading + { + get { return this.showLoading; } + set { this.showLoading = value; RaisePropertyChanged("ShowLoading"); } + } + + internal AssistServices assistService = new AssistServices(); + public PdfViewerViewModel() + { + string basePath = "Summarizer.Assets"; + _pdfFile = typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream($"{basePath}.summarizeDoc.pdf"); + this.messages = new ObservableCollection(); + this.CopyCommand = new Command(ExecuteCopyCommand); + this.RetryCommand = new Command(ExecuteRetryCommand); + this.AssistViewRequestCommand = new Command(ExecuteRequestCommand); + messages.Add(new AssistItem { Text = "Summarize this document", IsRequested = true }); + } + + private async void ExecuteRequestCommand(object obj) + { + this.ShowLoading = true; + var requests = ((RequestEventArgs)obj); + if (requests.RequestItem != null) + { + var request = requests.RequestItem.Text; + await this.GetResult(request); + } + this.ShowLoading = false; + } + + public async Task GetResult(string query) + { + await Task.Delay(1); + var reply = await assistService.GetSolutionToPrompt(query); + var suggestion = await assistService.GetSuggestion(query); + AssistItem botMessage = new AssistItem() { Text = reply, Suggestion = suggestion }; + this.Messages.Add(botMessage); + } + + private void ExecuteCopyCommand(object obj) + { + string text = ((AssistItem)obj).Text; + text = Regex.Replace(text, "<.*?>| ", string.Empty); + Clipboard.SetTextAsync(text); + } + + private async void ExecuteRetryCommand(object obj) + { + this.ShowLoading = true; + var response = ((AssistItem)obj).Text; + var query = await assistService.GetPrompt(response); + await this.GetResult(query).ConfigureAwait(true); + this.ShowLoading = false; + } + + #region PropertyChanged + + /// + /// Property changed handler. + /// + public event PropertyChangedEventHandler? PropertyChanged; + + /// + /// Occurs when property is changed. + /// + /// changed property name + public void RaisePropertyChanged(string propName) + { + if (this.PropertyChanged != null) + { + this.PropertyChanged(this, new PropertyChangedEventArgs(propName)); + } + } + + private void OnPropertyChanged(string propertyName) => + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + #endregion + } + +} \ No newline at end of file