Back in school, I dreamed of a magic pen that could fix all my mistakes and come up with creative ways to describe fictional characters. With AI, the magic pen is finally here.
As you know, developers are discovering numerous ways to add AI to their solutions (and it’s often easier than you’d think) thanks to easy-to-use cloud-based AI services and flexible control APIs. In this blog post, I'll use OpenAI to extend the capabilities of the DevExpress .NET MAUI HTML Edit. Specifically, I'll show you how easy it is to add AI-related capabilities to our HTML Edit Control and tweak its UI for the best possible user experience.
Configure OpenAI
Until recently, only companies with dedicated machine learning experts were in position to add advanced AI features to their products. Today, thanks to powerful pretrained models with billions of parameters, leveraging AI requires minimal effort. Cloud services like OpenAI now make it easy to tackle complex business requirements, such as:
- Text generation: The core feature of ChatGPT, which we'll use in this post.
- Image analysis: Detect objects in images, identify boundaries, and more
- Image generation: Create images from text descriptions—ideal for apps with design features or data visualization needs
- Text-to-speech and speech-to-text: Seamlessly convert between spoken and written languages.
The process is even more straightforward with the OpenAI .NET library since it provides cloud APIs without directly handling HTTP requests. To get started with OpenAI, you will need to:
- Sign up for OpenAI if you don't already have an account.
- Visit the API Keys page to obtain your API key. Remember, OpenAI uses a credit system to monetize the service—the more powerful the model, the higher the cost. New accounts typically receive free credits unless you've created one previously.
- Open your .NET MAUI project and reference the OpenAI NuGet package.
Create a ChatClient instance and pass your API key to the constructor:
ChatClient aiClient = new(model: "gpt-3.5-turbo", "YOUR API TOKEN");
We'll use the GPT 3.5 Turbo model as it's less resource-intensive, but you can always switch to a more powerful model for more complex requirements.
Configure DevExpress Components
To fully leverage AI, it's essential to create an intuitive user interface. When handling large text messages, it's helpful to support rich text formatting (lists, bold, headings) to visually separate text blocks. Accordingly, we'll use our .NET MAUI HTML Editor. Its APIs allow you to load documents from various sources and retrieve current HTML content (to send to OpenAI). We'll also incorporate buttons to trigger AI actions, using the Toolbar control (which is designed to work seamlessly with components like the DevExpress .NET MAUI HTML Editor).
Display a Document in the HTML Edit Control
With our .NET MAUI HTML Editor, you can load content from various sources like files, streams, strings, or URIs. For this example, we'll load HTML from a document stored in the application's bundle (in the Resources\Raw folder). To display the HTML, simply read the file and pass it to the HTML Editor's SetHtmlSourceAsync method:
async void OnPageAppearing(object sender, EventArgs e) {
using Stream stream = await FileSystem.Current.OpenAppPackageFileAsync("mail.html");
using StreamReader reader = new StreamReader(stream);
await htmledit.SetHtmlSourceAsync(await reader.ReadToEndAsync());
}
Add a Custom Toolbar
On smaller mobile screens, incorporating multiple action buttons without compromising usability can be challenging. It's crucial to strike a balance between the number of actionable elements and their size. Additionally, you need to decide which elements to display since in many instances, you don’t need to display all actions simultaneously (as this can clutter the UI).
Our Toolbar control can help address these realities:
- It automatically adjusts elements based on Material Design 3 standards, so you don’t have to worry about padding or sizing.
- It allows you to group elements into pages. Said differently, you can display all AI-related actions on a separate page, displayed only when needed.
The HTML Editor includes a built-in toolbar, but we’ll hide it in favor of our custom toolbar. To do this, set the HTML Editor’s ShowToolbar property to false and create a Toolbar control with appropriate custom buttons:
<dx:SafeKeyboardAreaView>
<Grid RowDefinitions="*,Auto">
<dx:HtmlEdit x:Name="htmledit" ShowToolbar="false" dx:DXDockLayout.Dock="Top"/>
<dx:DXToolbar Grid.Row="1">
<dx:ToolbarNavigationButton Content="🪄" PageName="AIAssistant"/>
<dx:ToolbarPage Name="AIAssistant" ShowBackButton="true">
<dx:ToolbarButton Content="Fix Grammar ✨" Clicked="OnFixGrammarClick"/>
<dx:ToolbarButton Content="Translate to German 🇩🇪" Clicked="OnToGermanClick"/>
<dx:ToolbarButton Content="Enhance 🪄" Clicked="OnEnhanceClick"/>
</dx:ToolbarPage>
</dx:DXToolbar>
</Grid>
</dx:SafeKeyboardAreaView>
As you'll notice, we've placed the HTML Editor and Toolbar inside the SafeKeyboardAreaView container to prevent overlap when the keyboard is opened.
Obtain an AI Response and Display it within our .NET MAUI HTML Editor
Once your custom toolbar buttons are set up, you can handle associated click events. When a button is clicked, we’ll retrieve content from the HTML Editor, send it to OpenAI, and display the response back in the DevExpress .NET MAUI HTML Editor.
To obtain HTML content, we’ll use the GetHtmlAsync method. We'll then call the CompleteChatAsync method from the OpenAI client class we configured earlier. Finally, we’ll assign the response from OpenAI to the HTML Editor:
async void OnFixGrammarClick(System.Object sender, System.EventArgs e) {
await ExecuteChatRequest($"Fix grammar errors:{await htmledit.GetHtmlAsync()}");
}
async Task ExecuteChatRequest(string prompt) {
try {
ChatCompletion completion = await aiClient.CompleteChatAsync(new List<ChatMessage> {
new SystemChatMessage($"You are an assistant correcting HTML text. Use only those tag types that you can find in the source document"),
new UserChatMessage(prompt)
});
await htmledit.SetHtmlSourceAsync(completion.Content[0].Text);
}
catch (Exception ex) {
await Shell.Current.DisplayAlert("Error", ex.Message, "OK");
}
}
The CompleteChatAsync method accepts a list of chat messages, which can be one of the following:
- System: A general instruction for the model. You can define only one system message.
- User: The user’s prompt, which can include additional instructions and content for the model to process.
- Assistant: The model's reply. You can combine multiple user and assistant messages to build a chat history, ensuring the latest request includes all previous context.
Summary
As user/business expectations continue to rise, integrating AI capabilities will become a more and more critical. Fortunately, you don’t need to be a machine learning expert to take advantage of AI. In this post, I followed these simple steps to incorporate intelligent text enhancements into my .NET MAUI project:
- Sign up for OpenAI and obtain an API key.
- Add a library to your client that connects to OpenAI services.
- Retrieve content from the DevExpress .NET MAUI HTML Editor using GetHtmlAsync
- Add toolbar buttons to invoke AI functions.
These easy-to-follow steps can address a variety of requirements - making the dream of a "magic pen" a reality.