Ajouter des achèvements de conversation OpenAI à votre application bureautique WinUI 3 / SDK d'application Windows
Dans ce guide pratique, vous allez apprendre à intégrer l’API d’OpenAI à votre application de bureau WinUI 3 /Windows App SDK. Nous allons créer une interface de type conversation qui vous permet de générer des réponses aux messages à l’aide de l’API de saisie semi-automatique de conversation d’OpenAI :
Prérequis
- Configurez votre ordinateur de développement (consultez Prise en main de WinUI).
- Familiarité avec les concepts fondamentaux de la création d’une application Hello World à l’aide de C# et WinUI 3 / Kit de développement logiciel (SDK) d’application Windows, nous allons nous appuyer sur ce guide pratique dans celui-ci.
- Clé API OpenAI à partir de votre tableau de bord du développeur OpenAI.
- Kit de développement logiciel (SDK) OpenAI installé dans votre projet. Reportez-vous à la documentation OpenAI pour obtenir la liste des bibliothèques communautaires. Dans ce guide pratique, nous allons utiliser betalgo/openai.
Créer un projet
- Ouvrez Visual Studio et créez un projet via
File
>New
>Project
: - Recherchez et sélectionnez le modèle de projet
WinUI
Projet de test codé de l’interface utilisateurBlank App, Packaged (WinUI 3 in Desktop)
. - Spécifiez le nom du projet, le nom de la solution et l’annuaire. Dans cet exemple, notre
ChatGPT_WinUI3
projet appartient à uneChatGPT_WinUI3
solution qui sera créée dansC:\Projects\
.
La structure de fichiers par défaut présentée ci-dessous doit alors s’afficher dans votre Explorateur de solutions :
Définir vos variables d’environnement
Pour utiliser le Kit de développement logiciel (SDK) OpenAI, vous devez définir une variable d’environnement avec votre clé API. Dans cet exemple, nous allons utiliser la variable d'environnement OPENAI_API_KEY
. Une fois que vous avez votre clé API à partir du tableau de bord du développeur OpenAI, vous pouvez définir la variable d’environnement à partir de la ligne de commande comme suit :
setx OPENAI_API_KEY <your-api-key>
Notez que cette méthode fonctionne bien pour le développement, mais vous souhaitez utiliser une méthode plus sécurisée pour les applications de production (par exemple, vous pouvez stocker votre clé API dans un coffre de clés sécurisé auquel un service distant peut accéder pour le compte de votre application). Consultez la page Best practices for OpenAI key safety (Bonnes pratiques pour la sécurité des clés OpenAI).
Installer le SDK .NET OpenAI
Dans le menu de View
Visual Studio, sélectionnez Terminal
. Une instance d’affichage doit s’afficher Developer Powershell
. Exécutez la commande suivante dans le répertoire racine de votre projet pour installer le Kit de développement logiciel (SDK).
dotnet add package Betalgo.OpenAI
Initialiser le SDK
Dans MainWindow.xaml.cs
, initialisez le Kit de développement logiciel (SDK) avec votre clé API :
//...
using OpenAI;
using OpenAI.Managers;
using OpenAI.ObjectModels.RequestModels;
using OpenAI.ObjectModels;
namespace ChatGPT_WinUI3
{
public sealed partial class MainWindow : Window
{
private OpenAIService openAiService;
public MainWindow()
{
this.InitializeComponent();
var openAiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
openAiService = new OpenAIService(new OpenAiOptions(){
ApiKey = openAiKey
});
}
}
}
Créer l’interface utilisateur de conversation
Nous allons utiliser un StackPanel
pour afficher une liste de messages et permettre TextBox
aux utilisateurs d’entrer de nouveaux messages. Mettez à jour MainWindow.xaml
comme suit :
<Window
x:Class="ChatGPT_WinUI3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ChatGPT_WinUI3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<ListView x:Name="ConversationList" />
<StackPanel Orientation="Horizontal">
<TextBox x:Name="InputTextBox" HorizontalAlignment="Stretch"/>
<Button x:Name="SendButton" Content="Send" Click="SendButton_Click"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
Implémenter l’envoi, la réception et l’affichage des messages
Ajoutez un gestionnaire d’événements SendButton_Click
pour gérer l’envoi, la réception et l’affichage des messages :
public sealed partial class MainWindow : Window
{
// ...
private async void SendButton_Click(object sender, RoutedEventArgs e)
{
string userInput = InputTextBox.Text;
if (!string.IsNullOrEmpty(userInput))
{
AddMessageToConversation($"User: {userInput}");
InputTextBox.Text = string.Empty;
var completionResult = await openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest()
{
Messages = new List<ChatMessage>
{
ChatMessage.FromSystem("You are a helpful assistant."),
ChatMessage.FromUser(userInput)
},
Model = Models.Gpt_4_1106_preview,
MaxTokens = 300
});
if (completionResult != null && completionResult.Successful) {
AddMessageToConversation("GPT: " + completionResult.Choices.First().Message.Content);
} else {
AddMessageToConversation("GPT: Sorry, something bad happened: " + completionResult.Error?.Message);
}
}
}
private void AddMessageToConversation(string message)
{
ConversationList.Items.Add(message);
ConversationList.ScrollIntoView(ConversationList.Items[ConversationList.Items.Last()]);
}
}
Exécuter l’application
Exécutez l’application et essayez de discuter ! Un résultat semblable à celui-ci doit s’afficher :
Améliorer l’interface de conversation
Nous allons apporter les améliorations suivantes à l’interface de conversation :
- Ajoutez un
ScrollViewer
àStackPanel
permettant d’activer le défilement. - Ajoutez un
TextBlock
pour afficher la réponse GPT d’une manière plus visuellement distincte de l’entrée de l’utilisateur. - Ajoutez un
ProgressBar
permettant d’indiquer quand l’application attend une réponse de l’API GPT. - Centrez la
StackPanel
fenêtre, comme l’interface web de ChatGPT. - Assurez-vous que les messages sont encapsulés à la ligne suivante lorsqu’ils atteignent le bord de la fenêtre.
- Augmentez la
TextBox
taille et la réactivité de laEnter
clé.
À partir du haut :
Ajouter ScrollViewer
Encapsulez l’élément ListView
dans un ScrollViewer
pour activer le défilement vertical sur de longues conversations :
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ListView x:Name="ConversationList" />
</ScrollViewer>
<!-- ... -->
</StackPanel>
Utilisez TextBlock
.
Modifiez la méthode pour styler l’entrée AddMessageToConversation
de l’utilisateur et la réponse GPT différemment :
// ...
private void AddMessageToConversation(string message)
{
var messageBlock = new TextBlock();
messageBlock.Text = message;
messageBlock.Margin = new Thickness(5);
if (message.StartsWith("User:"))
{
messageBlock.Foreground = new SolidColorBrush(Colors.LightBlue);
}
else
{
messageBlock.Foreground = new SolidColorBrush(Colors.LightGreen);
}
ConversationList.Items.Add(messageBlock);
ConversationList.ScrollIntoView(ConversationList.Items.Last());
}
Ajouter ProgressBar
Pour indiquer quand l’application attend une réponse, ajoutez un ProgressBar
au StackPanel
:
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ListView x:Name="ConversationList" />
</ScrollViewer>
<ProgressBar x:Name="ResponseProgressBar" Height="5" IsIndeterminate="True" Visibility="Collapsed"/> <!-- new! -->
</StackPanel>
Ensuite, mettez à jour le SendButton_Click
gestionnaire d’événements pour afficher le ProgressBar
temps d’attente d’une réponse :
private async void SendButton_Click(object sender, RoutedEventArgs e)
{
ResponseProgressBar.Visibility = Visibility.Visible; // new!
string userInput = InputTextBox.Text;
if (!string.IsNullOrEmpty(userInput))
{
AddMessageToConversation("User: " + userInput);
InputTextBox.Text = string.Empty;
var completionResult = await openAiService.Completions.CreateCompletion(new CompletionCreateRequest()
{
Prompt = userInput,
Model = Models.TextDavinciV3
});
if (completionResult != null && completionResult.Successful) {
AddMessageToConversation("GPT: " + completionResult.Choices.First().Text);
} else {
AddMessageToConversation("GPT: Sorry, something bad happened: " + completionResult.Error?.Message);
}
}
ResponseProgressBar.Visibility = Visibility.Collapsed; // new!
}
Centrer le StackPanel
Pour centrer StackPanel
et extraire les messages vers le bas du TextBox
, ajustez les Grid
paramètres dans MainWindow.xaml
:
<Grid VerticalAlignment="Bottom" HorizontalAlignment="Center">
<!-- ... -->
</Grid>
Encapsuler les messages
Pour vous assurer que les messages sont encapsulés à la ligne suivante lorsqu’ils atteignent le bord de la fenêtre, mettez à jour MainWindow.xaml
pour utiliser un ItemsControl
.
Remplacez ceci :
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ListView x:Name="ConversationList" />
</ScrollViewer>
Par ceci :
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ItemsControl x:Name="ConversationList" Width="300">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" Margin="5" Foreground="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Nous allons ensuite introduire une MessageItem
classe pour faciliter la liaison et la coloration :
// ...
public class MessageItem
{
public string Text { get; set; }
public SolidColorBrush Color { get; set; }
}
// ...
Enfin, mettez à jour la AddMessageToConversation
méthode pour utiliser la nouvelle MessageItem
classe :
// ...
private void AddMessageToConversation(string message)
{
var messageItem = new MessageItem();
messageItem.Text = message;
messageItem.Color = message.StartsWith("User:") ? new SolidColorBrush(Colors.LightBlue) : new SolidColorBrush(Colors.LightGreen);
ConversationList.Items.Add(messageItem);
// handle scrolling
ConversationScrollViewer.UpdateLayout();
ConversationScrollViewer.ChangeView(null, ConversationScrollViewer.ScrollableHeight, null);
}
// ...
Améliorer le TextBox
Pour rendre la TextBox
clé plus grande et réactive Enter
, mettez à jour MainWindow.xaml
comme suit :
<!-- ... -->
<StackPanel Orientation="Vertical" Width="300">
<TextBox x:Name="InputTextBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" KeyDown="InputTextBox_KeyDown" TextWrapping="Wrap" MinHeight="100" MaxWidth="300"/>
<Button x:Name="SendButton" Content="Send" Click="SendButton_Click" HorizontalAlignment="Right"/>
</StackPanel>
<!-- ... -->
Ensuite, ajoutez le InputTextBox_KeyDown
gestionnaire d’événements pour gérer la Enter
clé :
//...
private void InputTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter && !string.IsNullOrWhiteSpace(InputTextBox.Text))
{
SendButton_Click(this, new RoutedEventArgs());
}
}
//...
Exécuter l’application améliorée
Votre interface de conversation nouvelle et améliorée doit ressembler à ceci :
Récapitulatif
Voici les tâches que vous avez accomplies dans ce tutoriel :
- Vous avez ajouté les fonctionnalités d’API d’OpenAI à votre application de bureau WinUI 3 /Windows App SDK en installant un SDK de communauté et en l’initialisant avec votre clé API.
- Vous avez créé une interface de type conversation qui vous permet de générer des réponses aux messages à l’aide de l’API de saisie semi-automatique de conversation d’OpenAI.
- Vous avez amélioré l’interface de conversation par :
- ajout de
ScrollViewer
, - à l’aide d’un
TextBlock
pour afficher la réponse GPT, - ajout d’un
ProgressBar
élément permettant d’indiquer quand l’application attend une réponse de l’API GPT, - centrer la
StackPanel
fenêtre, - s’assurer que les messages sont encapsulés à la ligne suivante lorsqu’ils atteignent le bord de la fenêtre, et
- rendre le
TextBox
plus grand, redimensionnable et réactif à laEnter
clé.
- ajout de
Exemple de code complet :
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="ChatGPT_WinUI3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ChatGPT_WinUI3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid VerticalAlignment="Bottom" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ItemsControl x:Name="ConversationList" Width="300">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" Margin="5" Foreground="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<ProgressBar x:Name="ResponseProgressBar" Height="5" IsIndeterminate="True" Visibility="Collapsed"/>
<StackPanel Orientation="Vertical" Width="300">
<TextBox x:Name="InputTextBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" KeyDown="InputTextBox_KeyDown" TextWrapping="Wrap" MinHeight="100" MaxWidth="300"/>
<Button x:Name="SendButton" Content="Send" Click="SendButton_Click" HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using System;
using System.Collections.Generic;
using System.Linq;
using OpenAI;
using OpenAI.Managers;
using OpenAI.ObjectModels.RequestModels;
using OpenAI.ObjectModels;
namespace ChatGPT_WinUI3
{
public class MessageItem
{
public string Text { get; set; }
public SolidColorBrush Color { get; set; }
}
public sealed partial class MainWindow : Window
{
private OpenAIService openAiService;
public MainWindow()
{
this.InitializeComponent();
var openAiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
openAiService = new OpenAIService(new OpenAiOptions(){
ApiKey = openAiKey
});
}
private async void SendButton_Click(object sender, RoutedEventArgs e)
{
ResponseProgressBar.Visibility = Visibility.Visible;
string userInput = InputTextBox.Text;
if (!string.IsNullOrEmpty(userInput))
{
AddMessageToConversation("User: " + userInput);
InputTextBox.Text = string.Empty;
var completionResult = await openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest()
{
Messages = new List<ChatMessage>
{
ChatMessage.FromSystem("You are a helpful assistant."),
ChatMessage.FromUser(userInput)
},
Model = Models.Gpt_4_1106_preview,
MaxTokens = 300
});
Console.WriteLine(completionResult.ToString());
if (completionResult != null && completionResult.Successful)
{
AddMessageToConversation("GPT: " + completionResult.Choices.First().Message.Content);
}
else
{
AddMessageToConversation("GPT: Sorry, something bad happened: " + completionResult.Error?.Message);
}
}
ResponseProgressBar.Visibility = Visibility.Collapsed;
}
private void AddMessageToConversation(string message)
{
var messageItem = new MessageItem();
messageItem.Text = message;
messageItem.Color = message.StartsWith("User:") ? new SolidColorBrush(Colors.LightBlue) : new SolidColorBrush(Colors.LightGreen);
ConversationList.Items.Add(messageItem);
// handle scrolling
ConversationScrollViewer.UpdateLayout();
ConversationScrollViewer.ChangeView(null, ConversationScrollViewer.ScrollableHeight, null);
}
private void InputTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter && !string.IsNullOrWhiteSpace(InputTextBox.Text))
{
SendButton_Click(this, new RoutedEventArgs());
}
}
}
}
Rubriques connexes
Windows developer