Creating a .NET MAUI Smart PDF Viewer App with Auto-Summary Generation Using OpenAI’s ChatGPT

Jollen Moyani - Sep 22 '23 - - Dev Community

Managing and digesting vast amounts of information efficiently is crucial in today’s fast-paced world. In the context of PDF documents, especially lengthy reports, research papers, or technical documentation, reading the entire document to grasp the main points can be time-consuming. That is where a smart PDF viewer app comes in handy.

This blog will explore how to develop a cross-platform smart PDF viewer app using Syncfusion .NET MAUI controls. Our app will enable users to load and view PDF files seamlessly, and it will provide an incredible time-saving feature: automatic summarization of the loaded documents.

To achieve this summary generation functionality, we will leverage the power of OpenAI’s ChatGPT, a cutting-edge natural language processing model. By integrating ChatGPT into our app, we can extract key information and generate concise summaries of PDF documents. This enables users to easily understand a document’s main points without having to read all the content.

The benefits of having a summary of a PDF file upfront are many. Users can save valuable time by quickly assessing the document’s relevance and importance, determining whether it warrants further investment in reading the complete text. Additionally, summaries aid in organizing and categorizing documents, enabling users to manage their digital libraries efficiently.

So, let us dive into the world of .NET MAUI and OpenAI’s ChatGPT to create a smart PDF viewer app that will revolutionize how we interact with and consume PDF documents. Get ready to save time, increase productivity, and unlock the power of intelligent document summarization!

How to get an OpenAPI key

Follow these steps to obtain an OpenAI API key:

  1. Sign in to your OpenAI account : Visit the OpenAI website and sign in using your account credentials.
  2. Navigate to the API section : Once logged in, navigate to the API section of the OpenAI platform. This can usually be found in the account settings or developer dashboard.
  3. Create a new API key : Look for an option to create a new secret API key. Click on it to initiate the key generation process. You will need to complete the purchase process, too.

Create a .NET MAUI app with ChatGPT

Create a .NET MAUI app and follow the instructions within the project.

Configuring ChatGPT APIs

After creating the .NET MAUI app, we need to integrate the ChatGPT library and call the ChatGPT APIs in our project. To do so, follow these steps:

1.Add the ChatGptNet library: Start by referencing and bootstrapping the ChatGptNet library, which provides a convenient interface for interacting with the OpenAI API in .NET. Open the Package Manager Console from the Tools menu in Visual Studio and run the following command to install the ChatGptNet library:

Install-Package ChatGptNet
Enter fullscreen mode Exit fullscreen mode

2.Configure the ChatGptNet library : In the MauiProgram.cs file, locate the CreateMauiApp method and add the following code:

builder.Services.AddChatGpt(options =>
{
    options.ApiKey = ""; // Your API key here;
    options.Organization = null; // Optional
    options.DefaultModel = ChatGptModels.Gpt35Turbo; // Default: ChatGptModels.Gpt35Turbo
    options.MessageLimit = 10; // Default: 10
    options.MessageExpiration = TimeSpan.FromMinutes(5); // Default: 1 hour
});
Enter fullscreen mode Exit fullscreen mode

We’ve created a .NET MAUI app and configured the ChatGPT APIs in it.

Key controls involved in the smart PDF viewer app

Building our smart PDF Viewer app involves leveraging the power of the Syncfusion PDF Library and the following three .NET MAUI controls:

These controls play vital roles in different aspects of our app, ensuring a seamless and user-friendly experience.

The .NET MAUI PDF Viewer takes center stage, enabling us to load and view PDF files within our app. With its rich features, the PDF Viewer provides a smooth and intuitive interface for navigating PDF documents. Users can zoom in and out, scroll through pages, and interact with the document content seamlessly. This control is the foundation of our PDF viewing functionality.

To enhance the user experience and provide quick access to document summaries, we incorporate the .NET MAUI Popup control. When a user wants an overview of a loaded PDF file, the Popup control allows us to display the summary content elegantly and non-intrusively. Presenting the summary as a popup will enable users to conveniently view the key information without disrupting their reading flow or navigating away from the main document view. The Popup control provides a polished and visually appealing way to present the summary, enhancing the overall aesthetics of our app.

Since our app relies on the power of OpenAI’s ChatGPT for summarizing PDF documents, providing a responsive and interactive user experience is crucial during the summary generation process. This is where the Syncfusion Busy Indicator comes into play. While the app communicates with the OpenAI API to generate the summary, the Busy Indicator ensures that users know the process is ongoing. It displays a visually engaging, animated indicator, explaining that the app is working behind the scenes. The Busy Indicator adds a touch of professionalism and reassures users that the app is actively processing their requests.

We’ll also leverage the power of the Syncfusion PDF Library to extract the text from the PDF file. This library provides a comprehensive set of APIs and functionalities to work with PDF documents programmatically. We can extract the necessary content from the loaded PDF file, allowing OpenAI’s ChatGPT to analyze and generate the summary based on the extracted text. It can be seamlessly integrated with our app, enabling efficient text extraction and facilitating summary generation.

Steps to create .NET MAUI smart PDF Viewer app with auto-summary generation powered by OpenAI’s ChatGPT

Configuring the project

Step 1: Add the necessary NuGet packages

Add the Syncfusion.Maui.Core, Syncfusion.Maui.PdfViewer, and Syncfusion.Maui.Popup NuGet packages as references to your project from the NuGet Gallery.

Step 2: Register the handler

Syncfusion.Maui.Core is a dependent package for all Syncfusion .NET MAUI controls. In the MauiProgram.cs file, register the handler for Syncfusion core.

using ChatGptNet;
using ChatGptNet.Models;
using ChatGptNet.ServiceConfigurations;
using Microsoft.Extensions.Logging;
using Syncfusion.Maui.Core.Hosting;

namespace SmartPDFViewer;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
    var builder = MauiApp.CreateBuilder();
    builder
       .UseMauiApp<App>()
       .ConfigureFonts(fonts =>
       {
        fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
       });

       builder.ConfigureSyncfusionCore();

        builder.Services.AddChatGpt(options =>
        {

        options.UseOpenAI("",null);
            options.DefaultModel = OpenAIChatGptModels.Gpt35Turbo; // Default: ChatGptModels.Gpt35Turbo
            options.MessageLimit = 10; // Default: 10
            options.MessageExpiration = TimeSpan.FromMinutes(5); // Default: 1 hour
        });

        builder.Logging.AddDebug();
        return builder.Build();
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Adding resources

Add a new folder to the project named Assets and add the PDF document you need to display in the PDF Viewer. In this demonstration, a PDF file named pdfexample.pdf has been used. You can also use a file browser to choose files dynamically from the device.

Process the PDF document with OpenAI APIs

Follow these steps to process the PDF document with OpenAI APIs:

Step 1: Class, interfaces, and property declarations

Refer to the following code example. In it, the code defines a class called PdfViewerViewModel that implements the INotifyPropertyChanged interface. This interface enables the class to notify subscribers when the value of a property changes.

class PdfViewerViewModel : INotifyPropertyChanged
{
    private Stream? m_pdfDocumentStream;

    public event PropertyChangedEventHandler? PropertyChanged;

    private Guid _sessionGuid = Guid.Empty;

    public Stream PdfDocumentStream
    {
        get
        {
            return m_pdfDocumentStream;
        }
        set
        {
            m_pdfDocumentStream = value;
            OnPropertyChanged("PdfDocumentStream");
        }
    }

    private bool isBusy = false;

    public bool IsBusy
    {
        get
        {
            return isBusy;
        }
        set
        {
            isBusy = value;
            OnPropertyChanged("IsBusy");
        }
    }

    private String processedText = String.Empty;

    public String ProcessedText
    {
        get
        {
            return processedText;
        }
        set
        {
            processedText = value;
            OnPropertyChanged("ProcessedText");
        }
    }

    private int summaryIntensity = 50;

    public int SummaryIntensity
    {
        get
        {
            return summaryIntensity;
        }
        set
        {
            summaryIntensity = value;
            OnPropertyChanged("SummaryIntensity");
        }
    }

    public PdfViewerViewModel()
    {
        m_pdfDocumentStream = typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream("SmartPDFViewer.Assets.pdfexample.pdf");
    }

}
Enter fullscreen mode Exit fullscreen mode

The class declares several properties, including:

  • PdfDocumentStream: This represents a PDF document stream that will be loaded and displayed in the PDF Viewer.
  • IsBusy: Indicates whether the app is currently busy operating.
  • ProcessedText: Stores the processed text or summary generated from the PDF document.
  • SummaryIntensity: This represents the intensity, or length, of the summary.

Step 2: Add the constructor

The PdfViewerViewModel class includes a constructor that initializes the PdfDocumentStream property with a PDF file stream obtained from the app’s assembly resources.

Refer to the following code example.

class PdfViewerViewModel : INotifyPropertyChanged
{
    private Stream? m_pdfDocumentStream;

    public event PropertyChangedEventHandler? PropertyChanged;

    private Guid _sessionGuid = Guid.Empty;

    public Stream PdfDocumentStream
    {
        get
        {
            return m_pdfDocumentStream;
        }
        set
        {
            m_pdfDocumentStream = value;
            OnPropertyChanged("PdfDocumentStream");
        }
    }

    private bool isBusy = false;

    public bool IsBusy
    {
        get
        {
            return isBusy;
        }
        set
        {
            isBusy = value;
            OnPropertyChanged("IsBusy");
        }
    }

    private String processedText = String.Empty;

    public String ProcessedText
    {
        get
        {
            return processedText;
        }
        set
        {
            processedText = value;
            OnPropertyChanged("ProcessedText");
        }
    }

    private int summaryIntensity = 50;

    public int SummaryIntensity
    {
        get
        {
            return summaryIntensity;
        }
        set
        {
            summaryIntensity = value;
            OnPropertyChanged("SummaryIntensity");
        }
    }

    public PdfViewerViewModel()
    {
        m_pdfDocumentStream = typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream("SmartPDFViewer.Assets.pdfexample.pdf");
    }

}
Enter fullscreen mode Exit fullscreen mode

Step 3: Add the OnPropertyChanged method

Refer to the following code example. In it, the OnPropertyChanged method is called to raise the PropertyChanged event. It is used to notify subscribers when the value of a specific property has changed.

class PdfViewerViewModel : INotifyPropertyChanged
{
    private Stream? m_pdfDocumentStream;

    public event PropertyChangedEventHandler? PropertyChanged;

    private Guid _sessionGuid = Guid.Empty;

    public Stream PdfDocumentStream
    {
        get
        {
            return m_pdfDocumentStream;
        }
        set
        {
            m_pdfDocumentStream = value;
            OnPropertyChanged("PdfDocumentStream");
        }
    }

    private bool isBusy = false;

    public bool IsBusy
    {
        get
        {
            return isBusy;
        }
        set
        {
            isBusy = value;
            OnPropertyChanged("IsBusy");
        }
    }

    private String processedText = String.Empty;

    public String ProcessedText
    {
        get
        {
            return processedText;
        }
        set
        {
            processedText = value;
            OnPropertyChanged("ProcessedText");
        }
    }

    private int summaryIntensity = 50;

    public int SummaryIntensity
    {
        get
        {
            return summaryIntensity;
        }
        set
        {
            summaryIntensity = value;
            OnPropertyChanged("SummaryIntensity");
        }
    }

    public PdfViewerViewModel()
    {
        m_pdfDocumentStream = typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream("SmartPDFViewer.Assets.pdfexample.pdf");
    }

    public void OnPropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

}
Enter fullscreen mode Exit fullscreen mode

Step 4: Implement the LoadFile method

In the following code example, the LoadFile method is used to load the PDF document and extract its text content. It uses Syncfusion’s PdfLoadedDocument class to load the document, iterates through its pages, and extracts text using the ExtractText method. After that, the extracted text is stored in the extractedText variable.

Refer to the following code example.

class PdfViewerViewModel : INotifyPropertyChanged
{
    private Stream? m_pdfDocumentStream;

    public event PropertyChangedEventHandler? PropertyChanged;

    private Guid _sessionGuid = Guid.Empty;

    public Stream PdfDocumentStream
    {
        get
        {
            return m_pdfDocumentStream;
        }
        set
        {
            m_pdfDocumentStream = value;
            OnPropertyChanged("PdfDocumentStream");
        }
    }

    private bool isBusy = false;

    public bool IsBusy
    {
        get
        {
            return isBusy;
        }
        set
        {
            isBusy = value;
            OnPropertyChanged("IsBusy");
        }
    }

    private String processedText = String.Empty;

    public String ProcessedText
    {
        get
        {
            return processedText;
        }
        set
        {
            processedText = value;
            OnPropertyChanged("ProcessedText");
        }
    }

    private int summaryIntensity = 50;

    public int SummaryIntensity
    {
        get
        {
            return summaryIntensity;
        }
        set
        {
            summaryIntensity = value;
            OnPropertyChanged("SummaryIntensity");
        }
    }

    public PdfViewerViewModel()
    {
        m_pdfDocumentStream = typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream("SmartPDFViewer.Assets.pdfexample.pdf");
    }

    public void OnPropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
    string extractedText = string.Empty;

    public void LoadFile()
    {
        PdfLoadedDocument loadedDocument = new PdfLoadedDocument(PdfDocumentStream);
        PdfLoadedPageCollection loadedPages = loadedDocument.Pages;
        TextLineCollection lineCollection = new TextLineCollection();
        foreach (PdfLoadedPage loadedPage in loadedPages)
        {
            extractedText += loadedPage.ExtractText(out lineCollection);
        }
        loadedDocument.Close(true);
    }

}
Enter fullscreen mode Exit fullscreen mode

Step 5: Implement the GenerateSummary method

The GenerateSummary method is used to generate a summary of the PDF content using the ChatGPT API. If the PDF file is not loaded, it calls the LoadFile method. It then sets the IsBusy property to true to indicate that the app is performing the summary generation. It obtains a response from the ChatGPT API by invoking the AskAsync method and passing the session ID and a prompt with the extracted text. The generated summary is then assigned to the ProcessedText property. Finally, the GenerateSummary method sets the IsBusy property to false to indicate that the task is complete.

The PdfViewerViewModel class encapsulates the logic and properties required to load a PDF document, extract its text, and generate a summary using the ChatGPT API. It leverages event notifications and property changes to ensure proper communication and updates to the UI.

class PdfViewerViewModel : INotifyPropertyChanged
{
    private Stream? m_pdfDocumentStream;

    public event PropertyChangedEventHandler? PropertyChanged;

    private Guid _sessionGuid = Guid.Empty;

    public Stream PdfDocumentStream
    {
        get
        {
            return m_pdfDocumentStream;
        }
        set
        {
            m_pdfDocumentStream = value;
            OnPropertyChanged("PdfDocumentStream");
        }
    }

    private bool isBusy = false;

    public bool IsBusy
    {
        get
        {
            return isBusy;
        }
        set
        {
            isBusy = value;
            OnPropertyChanged("IsBusy");
        }
    }

    private String processedText = String.Empty;

    public String ProcessedText
    {
        get
        {
            return processedText;
        }
        set
        {
            processedText = value;
            OnPropertyChanged("ProcessedText");
        }
    }

    private int summaryIntensity = 50;

    public int SummaryIntensity
    {
        get
        {
            return summaryIntensity;
        }
        set
        {
            summaryIntensity = value;
            OnPropertyChanged("SummaryIntensity");
        }
    }

    public PdfViewerViewModel()
    {
        m_pdfDocumentStream = typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream("SmartPDFViewer.Assets.pdfexample.pdf");
    }

    public void OnPropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
    string extractedText = string.Empty;

    public void LoadFile()
    {
        PdfLoadedDocument loadedDocument = new PdfLoadedDocument(PdfDocumentStream);
        PdfLoadedPageCollection loadedPages = loadedDocument.Pages;
        TextLineCollection lineCollection = new TextLineCollection();
        foreach (PdfLoadedPage loadedPage in loadedPages)
        {
            extractedText += loadedPage.ExtractText(out lineCollection);
        }
        loadedDocument.Close(true);
    }

    internal async void GenerateSummary(IChatGptClient _chatGptClient, bool isFileLoaded = false)
    {
        if (!isFileLoaded)
        {
            LoadFile();
        }

        this.IsBusy = true;

        if (_sessionGuid == Guid.Empty)
        {
            _sessionGuid = Guid.NewGuid();
        }
        ChatGptResponse response = await _chatGptClient.AskAsync(_sessionGuid,
        "Please provide a summary("+ this.SummaryIntensity +" words) of the content in the PDF file below :" + extractedText);

        this.ProcessedText = response.GetMessage(); ;
        this.IsBusy = false;
    }
}
Enter fullscreen mode Exit fullscreen mode

Implementing the UI design

Follow these steps to implement the UI design:

Step 1: XAML namespace and resource declarations

The code begins with the declaration of XML namespaces used in the XAML file. These namespaces include several custom namespaces for the smart PDF Viewer app, Syncfusion controls, and converters.

  • xmlns:viewer=”clr-namespace:Syncfusion.Maui.PdfViewer;assembly=Syncfusion.Maui.PdfViewer” : The viewer namespace declaration references the Syncfusion PDF Viewer control. It provides access to the PDF viewing capabilities and features of the Syncfusion.Maui.PdfViewer assembly.
  • xmlns:core=”clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core” : The core namespace declaration refers to the Syncfusion.Maui.Core assembly. It provides access to core Syncfusion controls and utilities used in the app, such as the Busy Indicator control.
  • xmlns:popup=”clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup” : The popup namespace declaration points to the Syncfusion.Maui.Popup assembly. It enables the Popup control, which displays the summary content in a popup window.
  • xmlns:syncfusionConverters=”clr-namespace:Syncfusion.Maui.Core.Converters;assembly=Syncfusion.Maui.Core” : The syncfusionConverters namespace declaration refers to the Syncfusion.Maui.Core.Converters assembly. It provides access to the converter classes, such as InvertedBoolConverter, which is used in the XAML file to invert Boolean values for data-binding purposes.

Refer to the following code example. In it, within the ContentPage, the Resources section is defined to declare resources used within the XAML file. In this case, an instance of the InvertedBoolConverter class from the Syncfusion.Maui.Core.Converters namespace is created and assigned a key.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SmartPDFViewer"
             xmlns:viewer="clr-namespace:Syncfusion.Maui.PdfViewer;assembly=Syncfusion.Maui.PdfViewer"
             xmlns:core="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
             xmlns:popup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
             xmlns:syncfusionConverters="clr-namespace:Syncfusion.Maui.Core.Converters;assembly=Syncfusion.Maui.Core"
             x:Class="SmartPDFViewer.MainPage">
 <ContentPage.Resources>
  <syncfusionConverters:InvertedBoolConverter x:Key="invertedBoolConverter"/>
 </ContentPage.Resources>
</ContentPage>
Enter fullscreen mode Exit fullscreen mode

Step 2: Add a Grid layout

Inside the ContentPage, let’s define a Grid element. The Grid layout allows arranging elements in rows and columns. It serves as the container for other controls in the XAML file.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SmartPDFViewer"
             xmlns:viewer="clr-namespace:Syncfusion.Maui.PdfViewer;assembly=Syncfusion.Maui.PdfViewer"
             xmlns:core="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
             xmlns:popup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
             xmlns:syncfusionConverters="clr-namespace:Syncfusion.Maui.Core.Converters;assembly=Syncfusion.Maui.Core"
             x:Class="SmartPDFViewer.MainPage">
 <ContentPage.Resources>
  <syncfusionConverters:InvertedBoolConverter x:Key="invertedBoolConverter"/>
 </ContentPage.Resources>
 <Grid>
 </Grid>
</ContentPage>
Enter fullscreen mode Exit fullscreen mode

Step 3: Add the PDF Viewer control

Within the Grid , add the SfPdfViewer control from Syncfusion.Maui.PdfViewer namespace. This control is responsible for loading and displaying the PDF document. Then, bind the DocumentSource property to the PdfDocumentStream property, which determines the source of the PDF document to be displayed.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SmartPDFViewer"
             xmlns:viewer="clr-namespace:Syncfusion.Maui.PdfViewer;assembly=Syncfusion.Maui.PdfViewer"
             xmlns:core="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
             xmlns:popup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
             xmlns:syncfusionConverters="clr-namespace:Syncfusion.Maui.Core.Converters;assembly=Syncfusion.Maui.Core"
             x:Class="SmartPDFViewer.MainPage">
 <ContentPage.Resources>
  <syncfusionConverters:InvertedBoolConverter x:Key="invertedBoolConverter"/>
 </ContentPage.Resources>
 <Grid>
  <viewer:SfPdfViewer DocumentSource="{Binding PdfDocumentStream}">
  </viewer:SfPdfViewer>
 </Grid>
</ContentPage>
Enter fullscreen mode Exit fullscreen mode

Step 4: Designing the summary button and popup

Next, add an Image control to serve as a button for displaying the summary. It is accompanied by a TapGestureRecognizer to handle the tap event. When the button is tapped, the SfPopup control will be invoked to show the summary content as a popup. It includes a ContentTemplate that defines the layout of the popup, including a SfBusyIndicator to display a loading animation while the summary is being processed. The summary text is displayed in a Label within a ScrollView.

Refer to the following code example.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SmartPDFViewer"
             xmlns:viewer="clr-namespace:Syncfusion.Maui.PdfViewer;assembly=Syncfusion.Maui.PdfViewer"
             xmlns:core="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
             xmlns:popup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
             xmlns:syncfusionConverters="clr-namespace:Syncfusion.Maui.Core.Converters;assembly=Syncfusion.Maui.Core"
             x:Class="SmartPDFViewer.MainPage">
 <ContentPage.Resources>
  <syncfusionConverters:InvertedBoolConverter x:Key="invertedBoolConverter"/>
 </ContentPage.Resources>
 <Grid>
  <viewer:SfPdfViewer DocumentSource="{Binding PdfDocumentStream}">
  </viewer:SfPdfViewer>
   <Image Source="summary.png" WidthRequest="50" HeightRequest="50" Margin="50" HorizontalOptions="End" VerticalOptions="End">
    <Image.GestureRecognizers>
     <TapGestureRecognizer Tapped="ShowSummary_Tapped"/>
    </Image.GestureRecognizers>
   </Image>
   <popup:SfPopup x:Name="popupDisplay" ShowHeader="True" HeaderHeight="50" HeightRequest="500" WidthRequest="400">
   </popup:SfPopup>
 </Grid>
</ContentPage>
Enter fullscreen mode Exit fullscreen mode

Step 5: Designing the summary header and controls

The SfPopup control also includes a HeaderTemplate that defines the layout of the header section. In this case, we’ll display a Label with the text “Summary.”

Following the summary content is a second Grid element containing controls related to the summary. It includes a Label , a Slider , and an Image. These controls allow users to adjust the summary intensity, refresh the summary, and control the visibility of the Busy Indicator.

Refer to the following code example.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SmartPDFViewer"
             xmlns:viewer="clr-namespace:Syncfusion.Maui.PdfViewer;assembly=Syncfusion.Maui.PdfViewer"
             xmlns:core="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
             xmlns:popup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
             xmlns:syncfusionConverters="clr-namespace:Syncfusion.Maui.Core.Converters;assembly=Syncfusion.Maui.Core"
             x:Class="SmartPDFViewer.MainPage">
 <ContentPage.Resources>
  <syncfusionConverters:InvertedBoolConverter x:Key="invertedBoolConverter"/>
 </ContentPage.Resources>
 <Grid>
  <viewer:SfPdfViewer DocumentSource="{Binding PdfDocumentStream}">
  </viewer:SfPdfViewer>
   <Image Source="summary.png" WidthRequest="50" HeightRequest="50" Margin="50" HorizontalOptions="End" VerticalOptions="End">
    <Image.GestureRecognizers>
     <TapGestureRecognizer Tapped="ShowSummary_Tapped"/>
    </Image.GestureRecognizers>
   </Image>
   <popup:SfPopup x:Name="popupDisplay" ShowHeader="True" HeaderHeight="50" HeightRequest="500" WidthRequest="400">
    <popup:SfPopup.ContentTemplate>
     <DataTemplate>
      <Grid RowDefinitions="*,50">
       <core:SfBusyIndicator IsRunning="{Binding IsBusy}" OverlayFill="#FFFFFF">
        <Grid Background="White" Padding="5">
         <ScrollView>
          <Label Text="{Binding ProcessedText}"/>
         </ScrollView>
        </Grid>
       </core:SfBusyIndicator>
       <Grid Grid.Row="1" ColumnDefinitions="*,40" IsVisible="{Binding IsBusy, Converter={StaticResource invertedBoolConverter}}">
        <Label VerticalOptions="Start" Margin="0,2" HorizontalOptions="Start" Text="Conciseness" FontSize="10" FontAttributes="Bold"/>
        <Slider Margin="0,10,10,5" VerticalOptions="Center" Value="{Binding SummaryIntensity, Mode=TwoWay}" Minimum="50" Maximum="500"/>
        <Image Source="refresh.png" WidthRequest="30" HeightRequest="30" Grid.Column="1">
         <Image.GestureRecognizers>
          <TapGestureRecognizer Tapped="RefreshSummary_Tapped"/>
         </Image.GestureRecognizers>
        </Image>
       </Grid>
      </Grid>
     </DataTemplate>
    </popup:SfPopup.ContentTemplate>
    <popup:SfPopup.HeaderTemplate>
     <DataTemplate>
      <Label Text="Summary" FontSize="14" FontAttributes="Bold" Margin="10,0,10,0"/>
     </DataTemplate>
    </popup:SfPopup.HeaderTemplate>
   </popup:SfPopup>
 </Grid>
</ContentPage>
Enter fullscreen mode Exit fullscreen mode

Implementing the code for the UI

Follow these steps to implement the code for the UI:

Step 1: Namespace and class declarations

Declare the Syncfusion.Pdf.Parsing, Syncfusion.Pdf, System.ComponentModel, System.Reflection, ChatGptNet , and ChatGptNet.Models namespaces. These namespaces provide access to the required classes and functionalities.

Then, declare a class named MainPage that extends the ContentPage. This class is used to represent the main page of the smart PDF Viewer app.

using Syncfusion.Pdf.Parsing;
using Syncfusion.Pdf;
using System.ComponentModel;
using System.Reflection;
using ChatGptNet;
using ChatGptNet.Models;

namespace SmartPDFViewer;

public partial class MainPage : ContentPage
{
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Initialization and event handling

Initialize an instance of the PdfViewerViewModel class named viewModel. This view model manages the data and logic associated with the PDF Viewer.

Then, declare a private variable _chatGptClient of type IChatGptClient to communicate with the ChatGPT API.

Define the constructor MainPage(), initialize the page’s components, and set the BindingContext property to the viewModel instance. Also, attach an event handler, MainPage_Loaded , to the Loaded event of the page.

public partial class MainPage : ContentPage
{

    PdfViewerViewModel viewModel = new PdfViewerViewModel();

    private IChatGptClient _chatGptClient;

    public MainPage()
    {
    InitializeComponent();
        this.BindingContext = viewModel;
        this.Loaded += MainPage_Loaded;
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Hook the MainPage_Loaded event handler

The MainPage_Loaded event handler is called when the page is loaded. It retrieves the IChatGptClient instance from the MauiContext services and assigns it to the _chatGptClient variable. This allows the page to access the ChatGPT API for generating summaries.

Refer to the following code example.

public partial class MainPage : ContentPage
{

    PdfViewerViewModel viewModel = new PdfViewerViewModel();

    private IChatGptClient _chatGptClient;

    public MainPage()
    {
    InitializeComponent();
        this.BindingContext = viewModel;
        this.Loaded += MainPage_Loaded;
    }

    private void MainPage_Loaded(object sender, EventArgs e)
    {
        _chatGptClient = Handler.MauiContext.Services.GetService<IChatGptClient>();
    }

}
Enter fullscreen mode Exit fullscreen mode

Step 4: Hook the ShowSummary_Tapped event handler

The ShowSummary_Tapped event handler is called when the user taps on an element, triggering the display of the summary. It shows the popup display by calling the Show method on the popupDisplay instance. After that, it invokes the GenerateSummary method on the viewModel instance, passing the _chatGptClient as an argument. This triggers the generation of a summary using the ChatGPT API.

Refer to the following code example.

public partial class MainPage : ContentPage
{

    PdfViewerViewModel viewModel = new PdfViewerViewModel();

    private IChatGptClient _chatGptClient;

    public MainPage()
    {
    InitializeComponent();
        this.BindingContext = viewModel;
        this.Loaded += MainPage_Loaded;
    }

    private void MainPage_Loaded(object sender, EventArgs e)
    {
        _chatGptClient = Handler.MauiContext.Services.GetService<IChatGptClient>();
    }

    private void ShowSummary_Tapped(object sender, TappedEventArgs e)
    {
        this.popupDisplay.Show();
        viewModel.GenerateSummary(_chatGptClient);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Hook the RefreshSummary_Tapped event handler

The RefreshSummary_Tapped event handler is called when the user taps an element to refresh the summary. It directly invokes the GenerateSummary method on the viewModel instance, passing the _chatGptClient and true as arguments. The second argument indicates that the file is already loaded, and a new summary should be generated.

Refer to the following code example.

public partial class MainPage : ContentPage
{

    PdfViewerViewModel viewModel = new PdfViewerViewModel();

    private IChatGptClient _chatGptClient;

    public MainPage()
    {
    InitializeComponent();
        this.BindingContext = viewModel;
        this.Loaded += MainPage_Loaded;
    }

    private void MainPage_Loaded(object sender, EventArgs e)
    {
        _chatGptClient = Handler.MauiContext.Services.GetService<IChatGptClient>();
    }

    private void ShowSummary_Tapped(object sender, TappedEventArgs e)
    {
        this.popupDisplay.Show();
        viewModel.GenerateSummary(_chatGptClient);
    }

    private void RefreshSummary_Tapped(object sender, TappedEventArgs e)
    {
        viewModel.GenerateSummary(_chatGptClient, true);
    }
}
Enter fullscreen mode Exit fullscreen mode

All the code provided in this blog sets up the main page of the smart PDF Viewer app, initializes the necessary components, handles events for displaying and refreshing the summary, and connects with the ChatGPT API for generating the summaries. If you follow along, you will have a fully functional app that allows seamless PDF viewing and provides invaluable document summaries at your fingertips.

Refer to the following output GIF image to see the smart PDF Viewer app in action.

.NET MAUI Smart PDF Viewer App with Auto-Summary Generation Using OpenAI’s ChatGPT
.NET MAUI Smart PDF Viewer App with Auto-Summary Generation Using OpenAI’s ChatGPT

GitHub reference

Also, check out the .NET MAUI Smart PDF Viewer using OpenAI’s ChatGPT GitHub demo.

Conclusion

Thanks for reading! In this blog, we’ve seen how to create a smart PDF Viewer app using Syncfusion .NET MAUI controls and OpenAI’s ChatGPT API. The app generates summaries for loaded PDFs and gives users the ability to experiment with different ChatGPT models for improved results. By combining the OpenAI ChatGPT API with Syncfusion’s controls, developers can create sophisticated and user-friendly PDF viewing experiences.

Syncfusion’s .NET MAUI controls provide developers with a wide range of tools for building powerful and feature-rich apps. They offer extensive customization options and easy-to-use APIs, allowing seamless integration with the .NET MAUI framework. As a result, developers can easily create cross-platform apps with enhanced functionality using Syncfusion’s controls.

Existing customers can access the latest version of Essential Studio from the License and Downloads page. Developers who are new to Syncfusion can explore Essential Studio’s features with a 30-day free trial.

You can also contact us through our support forums, support portal, or feedback portal. We are always happy to assist you.

*Disclaimer: * You will need to use professional skill and judgment when doing any implementation. This provides only a sample. Syncfusion is not affiliated with ChatGPT and is not responsible for any results.

Related blogs

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .