Tambahkan penyelesaian obrolan OpenAI ke aplikasi desktop WinUI 3 / SDK Aplikasi Windows Anda
Dalam panduan ini, Anda akan mempelajari cara mengintegrasikan API OpenAI ke dalam aplikasi desktop WinUI 3 / SDK Aplikasi Windows Anda. Kami akan membangun antarmuka seperti obrolan yang memungkinkan Anda menghasilkan respons terhadap pesan menggunakan API penyelesaian obrolan OpenAI:
Prasyarat
- Siapkan komputer pengembangan Anda (lihat Mulai menggunakan WinUI).
- Memahami konsep inti dalam Cara membangun aplikasi Halo Dunia menggunakan C# dan WinUI 3 / SDK Aplikasi Windows - kami akan membangun cara tersebut dalam yang satu ini.
- Kunci OPENAI API dari dasbor pengembang OpenAI Anda.
- OpenAI SDK terinstal di proyek Anda. Lihat dokumentasi OpenAI untuk daftar pustaka komunitas. Dalam cara ini, kita akan menggunakan betalgo/openai.
Membuat proyek
- Buka Visual Studio dan buat proyek baru melalui
File
Project
>New
>. - Cari
WinUI
dan pilihBlank App, Packaged (WinUI 3 in Desktop)
templat proyek C#. - Tentukan nama proyek, nama solusi, dan direktori. Dalam contoh ini, proyek kami
ChatGPT_WinUI3
milik solusiChatGPT_WinUI3
, yang akan dibuat diC:\Projects\
.
Setelah membuat proyek, Anda akan melihat struktur file default berikut di Penjelajah Solusi Anda:
Mengatur variabel lingkungan Anda
Untuk menggunakan OpenAI SDK, Anda harus mengatur variabel lingkungan dengan kunci API Anda. Dalam contoh ini, kita akan menggunakan OPENAI_API_KEY
variabel lingkungan. Setelah Anda memiliki kunci API dari dasbor pengembang OpenAI, Anda dapat mengatur variabel lingkungan dari baris perintah sebagai berikut:
setx OPENAI_API_KEY <your-api-key>
Perhatikan bahwa metode ini berfungsi dengan baik untuk pengembangan, tetapi Anda mungkin ingin menggunakan metode yang lebih aman untuk aplikasi produksi (misalnya: Anda dapat menyimpan kunci API Anda dalam brankas kunci aman yang dapat diakses layanan jarak jauh atas nama aplikasi Anda). Lihat Praktik terbaik untuk keamanan kunci OpenAI.
Menginstal OpenAI SDK
Dari menu Visual Studio View
, pilih Terminal
. Anda akan melihat instans Developer Powershell
muncul. Jalankan perintah berikut dari direktori akar proyek Anda untuk menginstal SDK:
dotnet add package Betalgo.OpenAI
Menginisialisasi SDK
Di MainWindow.xaml.cs
, inisialisasi SDK dengan kunci API Anda:
//...
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
});
}
}
}
Membangun UI obrolan
Kita akan menggunakan StackPanel
untuk menampilkan daftar pesan, dan TextBox
untuk memungkinkan pengguna memasukkan pesan baru. Perbarui MainWindow.xaml
sebagai berikut:
<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>
Menerapkan pengiriman, penerimaan, dan tampilan pesan
SendButton_Click
Tambahkan penanganan aktivitas untuk menangani pengiriman, penerimaan, dan tampilan pesan:
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()]);
}
}
Menjalankan aplikasi
Jalankan aplikasi dan coba mengobrol! Anda seharusnya melihat sesuatu seperti berikut:
Meningkatkan antarmuka obrolan
Mari kita lakukan peningkatan berikut pada antarmuka obrolan:
ScrollViewer
Tambahkan keStackPanel
untuk mengaktifkan pengguliran.TextBlock
Tambahkan untuk menampilkan respons GPT dengan cara yang lebih berbeda secara visual dari input pengguna.ProgressBar
Tambahkan untuk menunjukkan kapan aplikasi sedang menunggu respons dari API GPT.- Tengahkan
StackPanel
di jendela, mirip dengan antarmuka web ChatGPT. - Pastikan pesan dibungkus ke baris berikutnya saat mencapai tepi jendela.
- Buat yang
TextBox
lebih besar dan responsif terhadapEnter
kunci.
Mulai dari atas:
Menambahkan ScrollViewer
Bungkus ListView
dalam ScrollViewer
untuk mengaktifkan pengguliran vertikal pada percakapan panjang:
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ListView x:Name="ConversationList" />
</ScrollViewer>
<!-- ... -->
</StackPanel>
Menggunakan TextBlock
AddMessageToConversation
Ubah metode untuk menata input pengguna dan respons GPT secara berbeda:
// ...
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());
}
Menambahkan ProgressBar
Untuk menunjukkan kapan aplikasi menunggu respons, tambahkan ProgressBar
ke 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>
Kemudian, perbarui penanganan SendButton_Click
aktivitas untuk menampilkan ProgressBar
saat menunggu respons:
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!
}
Tengahkan StackPanel
Untuk memerah StackPanel
dan menarik pesan ke bawah ke arah TextBox
, sesuaikan Grid
pengaturan di MainWindow.xaml
:
<Grid VerticalAlignment="Bottom" HorizontalAlignment="Center">
<!-- ... -->
</Grid>
Membungkus pesan
Untuk memastikan bahwa pesan dibungkus ke baris berikutnya saat mencapai tepi jendela, perbarui MainWindow.xaml
untuk menggunakan ItemsControl
.
Ganti ini:
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ListView x:Name="ConversationList" />
</ScrollViewer>
Dengan ini:
<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>
Kami kemudian akan memperkenalkan MessageItem
kelas untuk memfasilitasi pengikatan dan pewarnaan:
// ...
public class MessageItem
{
public string Text { get; set; }
public SolidColorBrush Color { get; set; }
}
// ...
Terakhir, perbarui AddMessageToConversation
metode untuk menggunakan kelas baru MessageItem
:
// ...
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);
}
// ...
Meningkatkan TextBox
Untuk membuat lebih TextBox
besar dan responsif terhadap Enter
kunci, perbarui MainWindow.xaml
sebagai berikut:
<!-- ... -->
<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>
<!-- ... -->
Kemudian, tambahkan penanganan InputTextBox_KeyDown
aktivitas untuk menangani Enter
kunci:
//...
private void InputTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter && !string.IsNullOrWhiteSpace(InputTextBox.Text))
{
SendButton_Click(this, new RoutedEventArgs());
}
}
//...
Menjalankan aplikasi yang ditingkatkan
Antarmuka obrolan baru dan yang ditingkatkan akan terlihat seperti ini:
Rekap
Inilah yang Anda capai dalam cara ini:
- Anda menambahkan kemampuan API OpenAI ke aplikasi desktop WinUI 3 / SDK Aplikasi Windows Anda dengan menginstal SDK komunitas dan menginisialisasinya dengan kunci API Anda.
- Anda membangun antarmuka seperti obrolan yang memungkinkan Anda menghasilkan respons terhadap pesan menggunakan API penyelesaian obrolan OpenAI.
- Anda meningkatkan antarmuka obrolan dengan:
ScrollViewer
menambahkan ,TextBlock
menggunakan untuk menampilkan respons GPT,ProgressBar
menambahkan untuk menunjukkan kapan aplikasi menunggu respons dari API GPT,- tengah di
StackPanel
jendela, - memastikan bahwa pesan dibungkus ke baris berikutnya saat mencapai tepi jendela, dan
- membuat yang
TextBox
lebih besar, dapat diubah ukurannya, dan responsif terhadapEnter
kunci.
File kode lengkap
<?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());
}
}
}
}
Terkait
Windows developer