This example adds AI-powered summarize/translate capabilities to the DevExpress JavaScript-based Document Viewer. These enterprise-ready features are available within the user interface via two buttons designed to access the document and process report content as follows:
- Summarize: Uses generative AI to summarize report content and displays core insights associated with this report.
- Translate: Uses AI services to translate report content to a different language.
These actions are also available in context menu when you select report content. Note the AI Operations icon that floats next to the report page. Users can click it to invoke the context menu.
The following is an image of the application interface. As you can see, users can process the entire document, individual pages, or selected content.
Implementation Details
Add NuGet Packages
Add the following NuGet packages:
DevExpress.AIIntegration.Blazor.Reporting.Viewer
DevExpress.Drawing.Skia
(if you use a non-Windows environment)Microsoft.Extensions.AI.OpenAI
,Azure.AI.OpenAI
,Azure.Identity
orMicrosoft.Extensions.AI.Ollama
based on your AI service preferences. This project uses Azure OpenAI. The remainder of this document describes steps related to this package.
For the list of supported AI services and the corresponding prerequisites, refer to Supported AI Services in the following help topic: AI-powered Extensions for DevExpress Reporting.
Add Personal Keys
[!NOTE]
DevExpress AI-powered extensions follow the "bring your own key" principle. DevExpress does not offer a REST API and does not ship any built-in LLMs/SLMs. You need an active Azure/Open AI subscription to obtain the REST API endpoint, key, and model deployment name. These variables must be specified at application startup to register AI clients and enable DevExpress AI-powered Extensions in your application.
To use AI-based Summarize and Translate functionality in your application, you must create an Azure OpenAI resource in the Azure portal. Refer to the following help topic for additional information/guidance: Microsoft - Create and deploy an Azure OpenAI Service resource.
Once you obtain a private endpoint and an API key, open appsettings.json and specify appropriate DeploymentName
, AzureOpenAIKey
, and AzureOpenAIEndpoint
values. Note that DeploymentName
is set to GPT4o
, but you can specify a different model:
JSON"AISettings": {
"DeploymentName": "GPT4o",
"AzureOpenAIKey": "",
"AzureOpenAIEndpoint": ""
}
Create a class to read these settings:
C#public class AISettings {
public string DeploymentName { get; set; }
public string AzureOpenAIKey { get; set; }
public string AzureOpenAIEndpoint { get; set; }
}
Register AI Services on the Server
Call the AddDevExpressAI
method at the application startup to register AI services in your application:
C#using DevExpress.AIIntegration;
using DevExpress.AIIntegration.Reporting;
using DevExpress.AIIntegration.Blazor.Reporting.Viewer.Models;
using Azure.AI.OpenAI;
using Azure;
using Microsoft.Extensions.AI;
// ...
var builder = WebApplication.CreateBuilder(args);
var settings = builder.Configuration.GetSection("AISettings").Get<AISettings>();
//To use Ollama
//IChatClient client = new OllamaChatClient(new Uri("http://localhost:11434/api/chat", "phi3.5:latest"));
IChatClient chatClient = new AzureOpenAIClient(
new Uri(settings.AzureOpenAIEndpoint),
new System.ClientModel.ApiKeyCredential(settings.AzureOpenAIKey)).AsChatClient(settings.DeploymentName);
builder.Services.AddChatClient(config => config.Use(chatClient));
builder.Services.AddDevExpressAI((config) => {
config.AddWebReportingAIIntegration(cfg =>
cfg.SummarizationMode = SummarizationMode.Abstractive);
});
var app = builder.Build();
Enable the DevExpress AI-powered Extension on the Client
Open DocumentViewer.cshtml
and create a JavaScript function that enables AI services and populates a language list. Call this function on the Document Viewer's OnInitializing event:
JavaScript<script>
function OnInitializing(e, s) {
DevExpress.Reporting.Viewer.Settings.AIServicesEnabled(true);
DevExpress.Reporting.Viewer.Settings.AILanguages([
{ key: 'en', text: 'English' },
{ key: 'es', text: 'Spanish' },
{ key: 'de', text: 'German' }
]);
}
</script>
@{
var viewerRender = Html.DevExpress().WebDocumentViewer("DocumentViewer")
.ClientSideEvents((configure) => { configure.OnInitializing("OnInitializing"); })
.Height("100%")
.Bind(Model);
@viewerRender.RenderHtml()
}
Files to Review
Documentation
- AI-powered Extensions for DevExpress Reporting
- Summarize and Translate Reports in the Web Document Viewer
More Examples
- Reporting for Blazor - Integrate AI-powered Summarize and Translate Features based on Azure OpenAI
- Reporting for ASP.NET Core - Integrate AI Assistant based on Azure OpenAI
- Rich Text Editor and HTML Editor for Blazor - How to integrate AI-powered extensions
- AI Chat for Blazor - How to add DxAIChat component in Blazor, MAUI, WPF, and WinForms applications
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
JSON{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"NWindConnectionString": "XpoProvider=SQLite;Data Source=|DataDirectory|Data/nwind.db",
"ReportsDataConnectionString": "Filename=Data/reportsData.db"
},
"AISettings": {
"DeploymentName": "GPT4o",
"AzureOpenAIKey": "",
"AzureOpenAIEndpoint": ""
}
}
C#using Azure;
using Azure.AI.OpenAI;
using DevExpress.AIIntegration;
using DevExpress.AspNetCore;
using DevExpress.AspNetCore.Reporting;
using DevExpress.Security.Resources;
using DevExpress.XtraReports.Web.Extensions;
using JSDocumentViewer.Data;
using JSDocumentViewer.Models;
using JSDocumentViewer.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.IO;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDevExpressControls();
builder.Services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>();
builder.Services.AddMvc();
builder.Services.ConfigureReportingServices(configurator => {
if(builder.Environment.IsDevelopment()) {
configurator.UseDevelopmentMode();
}
configurator.ConfigureReportDesigner(designerConfigurator => {
});
configurator.ConfigureWebDocumentViewer(viewerConfigurator => {
viewerConfigurator.UseCachedReportSourceBuilder();
viewerConfigurator.RegisterConnectionProviderFactory<CustomSqlDataConnectionProviderFactory>();
});
});
var settings = builder.Configuration.GetSection("AISettings").Get<AISettings>();
//To use Ollama
//IChatClient client = new OllamaChatClient(new Uri("http://localhost:11434/api/chat", "phi3.5:latest"));
IChatClient chatClient = new AzureOpenAIClient(
new Uri(settings.AzureOpenAIEndpoint),
new System.ClientModel.ApiKeyCredential(settings.AzureOpenAIKey)).AsChatClient(settings.DeploymentName);
builder.Services.AddChatClient(config => config.Use(chatClient));
builder.Services.AddDevExpressAI((config) => {
config.AddWebReportingAIIntegration(cfg =>
cfg.SummarizationMode = SummarizationMode.Abstractive);
});
builder.Services.AddDbContext<ReportDbContext>(options => options.UseSqlite(builder.Configuration.GetConnectionString("ReportsDataConnectionString")));
var app = builder.Build();
using(var scope = app.Services.CreateScope()) {
var services = scope.ServiceProvider;
services.GetService<ReportDbContext>().InitializeDatabase();
}
var contentDirectoryAllowRule = DirectoryAccessRule.Allow(new DirectoryInfo(Path.Combine(builder.Environment.ContentRootPath, "Content")).FullName);
AccessSettings.ReportingSpecificResources.TrySetRules(contentDirectoryAllowRule, UrlAccessRule.Allow());
app.UseDevExpressControls();
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
if(app.Environment.IsDevelopment()) {
app.UseDeveloperExceptionPage();
} else {
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
string contentPath = app.Environment.ContentRootPath;
AppDomain.CurrentDomain.SetData("DataDirectory", contentPath);
//AppDomain.CurrentDomain.SetData("DXResourceDirectory", contentPath);
app.Run();
C#namespace JSDocumentViewer.Models {
public class AISettings {
public string AzureOpenAIKey { get; set; }
public string DeploymentName { get; set; }
public string AzureOpenAIEndpoint { get; set; }
}
}
Razor@model DevExpress.XtraReports.Web.WebDocumentViewer.WebDocumentViewerModel
<script>
function OnInitializing(e, s) {
DevExpress.Reporting.Viewer.Settings.AIServicesEnabled(true);
DevExpress.Reporting.Viewer.Settings.AILanguages([
{ key: 'en', text: 'English' },
{ key: 'es', text: 'Spanish' },
{ key: 'de', text: 'German' }
]);
}
</script>
@{
var viewerRender = Html.DevExpress().WebDocumentViewer("DocumentViewer")
.ClientSideEvents((configure) => { configure.OnInitializing("OnInitializing"); })
.Height("100%")
.Bind(Model);
@viewerRender.RenderHtml()
}
@section Scripts {
<link href="~/css/dx-reporting-skeleton-screen.css" rel="stylesheet" />
<link rel="stylesheet" href="~/css/viewer.part.bundle.css" />
<link rel="stylesheet" href="~/css/dx.material.blue.light.bundle.css" />
<script src="~/js/reporting.thirdparty.bundle.js"></script>
<script src="~/js/viewer.part.bundle.js"></script>
@viewerRender.RenderScripts()
}