Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Neste tutorial, você aprenderá como integrar a API da OpenAI ao seu aplicativo de desktop WinUI 3 / Windows App SDK. Construiremos uma interface semelhante a um bate-papo que permite gerar respostas a mensagens usando a geração de texto da OpenAI e APIs de solicitação:
Prerequisites
- Configure seu computador de desenvolvimento (consulte Começar a desenvolver aplicativos do Windows).
- Familiaridade com os principais conceitos em Como criar um aplicativo Hello World usando C# e WinUI / Windows App SDK - vamos desenvolver esse tutorial neste.
- Uma chave de API OpenAI do seu painel de desenvolvedor OpenAI.
- Um SDK OpenAI instalado em seu projeto. Consulte a documentação do OpenAI para obter uma lista de bibliotecas comunitárias. Neste tutorial, usaremos a biblioteca oficial da API OpenAI .NET.
Criar um projeto
Você cria um novo projeto WinUI no Visual Studio seguindo as etapas na seção Criar e iniciar seu primeiro aplicativo WinUI do artigo Começar a desenvolver aplicativos do Windows . Para este exemplo, digite ChatGPT_WinUI3 como o nome do projeto e ChatGPT_WinUI3 para o nome da solução ao inserir os detalhes do projeto na caixa de diálogo.
Definir a variável de ambiente
Para usar o OpenAI SDK, você precisará definir uma variável de ambiente com sua chave de API. Neste exemplo, usaremos a OPENAI_API_KEY variável de ambiente. Depois de ter sua chave de API no painel do desenvolvedor OpenAI, você pode definir a variável de ambiente a partir da linha de comando da seguinte maneira:
setx OPENAI_API_KEY <your-api-key>
Observe que esse método funciona bem para desenvolvimento, mas você desejará usar um método mais seguro para aplicativos de produção (por exemplo: você pode armazenar sua chave de API em um cofre de chaves seguro que um serviço remoto pode acessar em nome do seu aplicativo). Consulte Práticas recomendadas para segurança de chaves OpenAI.
Instalar a biblioteca OpenAI
No menu do View Visual Studio, selecione Terminal. Você deve ver uma instância de Developer Powershell aparecer. Execute o seguinte comando a partir do diretório raiz do seu projeto para instalar o pacote OpenAI .NET:
dotnet add package OpenAI
Inicializar a biblioteca
No MainWindow.xaml.cs, inicialize a biblioteca OpenAI com sua chave de API:
//...
using OpenAI;
using OpenAI.Chat;
namespace ChatGPT_WinUI3
{
public sealed partial class MainWindow : Window
{
private OpenAIClient openAiService;
public MainWindow()
{
this.InitializeComponent();
var openAiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
openAiService = new(openAiKey);
}
}
}
Crie a interface do usuário do bate-papo
Usaremos a StackPanel para exibir uma lista de mensagens e a TextBox para permitir que os usuários insiram novas mensagens. Atualize MainWindow.xaml da seguinte forma:
<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>
Implementar o envio, recebimento e exibição de mensagens
Adicione um SendButton_Click manipulador de eventos para lidar com o envio, recebimento e exibição de mensagens:
public sealed partial class MainWindow : Window
{
// ...
private async void SendButton_Click(object sender, RoutedEventArgs e)
{
try
{
string userInput = InputTextBox.Text;
if (!string.IsNullOrEmpty(userInput))
{
AddMessageToConversation($"User: {userInput}");
InputTextBox.Text = string.Empty;
var chatClient = openAiService.GetChatClient("gpt-4o"); // or another model
var chatOptions = new ChatCompletionOptions
{
MaxOutputTokenCount = 300
};
// Assemble the chat prompt with a system message and the user's input
var completionResult = await chatClient.CompleteChatAsync(
[
ChatMessage.CreateSystemMessage("You are a helpful assistant."),
ChatMessage.CreateUserMessage(userInput)
],
chatOptions);
if (completionResult != null && completionResult.Value.Content.Count > 0)
{
AddMessageToConversation($"GPT: {completionResult.Value.Content.First().Text}");
}
else
{
AddMessageToConversation($"GPT: Sorry, something bad happened: {completionResult?.Value.Refusal ?? "Unknown error."}");
}
}
}
catch (Exception ex)
{
AddMessageToConversation($"GPT: Sorry, something bad happened: {ex.Message}");
}
}
private void AddMessageToConversation(string message)
{
ConversationList.Items.Add(message);
ConversationList.ScrollIntoView(ConversationList.Items[ConversationList.Items.Last()]);
}
}
Executar o aplicativo
Execute o aplicativo e tente conversar! Você deve ver algo assim:
Melhorar a interface de chat
Vamos fazer as seguintes melhorias na interface de chat:
- Adicione um
ScrollVieweraoStackPanelpara ativar a rolagem. - Adicione um
TextBlockpara exibir a resposta GPT de uma forma visualmente mais distinta da entrada do usuário. - Adicione um
ProgressBarpara indicar quando o aplicativo está aguardando uma resposta da API GPT. - Centralize o
StackPanelna janela, semelhante à interface web do ChatGPT. - Certifique-se de que as mensagens passem para a linha seguinte quando atingirem a borda da janela.
- Torne o
TextBoxmaior e responsivo à teclaEnter.
Começando pelo topo:
Adicionar ScrollViewer
Envolva o ListView em um ScrollViewer para permitir a rolagem vertical em conversas longas.
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ListView x:Name="ConversationList" />
</ScrollViewer>
<!-- ... -->
</StackPanel>
Utilize TextBlock
Modifique o AddMessageToConversation método para definir o estilo da entrada do usuário e da resposta GPT de forma diferente:
// ...
private void AddMessageToConversation(string message)
{
var messageBlock = new TextBlock
{
Text = message,
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());
}
Adicionar ProgressBar
Para indicar quando o aplicativo está aguardando uma resposta, adicione um ProgressBar ao 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>
Em seguida, atualize o SendButton_Click manipulador de eventos para mostrar o ProgressBar enquanto aguarda uma resposta:
private async void SendButton_Click(object sender, RoutedEventArgs e)
{
ResponseProgressBar.Visibility = Visibility.Visible; // new!
string userInput = InputTextBox.Text;
try
{
if (!string.IsNullOrEmpty(userInput))
{
AddMessageToConversation($"User: {userInput}");
InputTextBox.Text = string.Empty;
var chatClient = openAiService.GetChatClient("gpt-4o"); // or another model
var chatOptions = new ChatCompletionOptions
{
MaxOutputTokenCount = 300
};
// Assemble the chat prompt with a system message and the user's input
var completionResult = await chatClient.CompleteChatAsync(
[
ChatMessage.CreateSystemMessage("You are a helpful assistant."),
ChatMessage.CreateUserMessage(userInput)
],
chatOptions);
if (completionResult != null && completionResult.Value.Content.Count > 0)
{
AddMessageToConversation($"GPT: {completionResult.Value.Content.First().Text}");
}
else
{
AddMessageToConversation($"GPT: Sorry, something bad happened: {completionResult?.Value.Refusal ?? "Unknown error."}");
}
}
}
catch (Exception ex)
{
AddMessageToConversation($"GPT: Sorry, something bad happened: {ex.Message}");
}
finally // new!
{
ResponseProgressBar.Visibility = Visibility.Collapsed; // new!
}
}
Centralizar o StackPanel
Para centralizar o StackPanel e puxar as mensagens para baixo em direção ao TextBox, ajuste as Grid definições em MainWindow.xaml:
<Grid VerticalAlignment="Bottom" HorizontalAlignment="Center">
<!-- ... -->
</Grid>
Encapsular mensagens
Para garantir que as mensagens sejam quebradas para a próxima linha quando chegarem à borda da janela, atualize MainWindow.xaml para usar um ItemsControl.
Substitui isto:
<ScrollViewer x:Name="ConversationScrollViewer" VerticalScrollBarVisibility="Auto" MaxHeight="500">
<ListView x:Name="ConversationList" />
</ScrollViewer>
Com isso:
<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>
Em seguida, apresentaremos uma classe MessageItem para facilitar a ligação e a coloração.
// ...
public class MessageItem
{
public string Text { get; set; }
public SolidColorBrush Color { get; set; }
}
// ...
Finalmente, atualize o AddMessageToConversation método para usar a nova MessageItem classe:
// ...
private void AddMessageToConversation(string message)
{
var messageItem = new MessageItem
{
Text = message,
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);
}
// ...
Melhorar a TextBox
Para tornar o TextBox maior e responsivo à Enter chave, atualize MainWindow.xaml da seguinte maneira:
<!-- ... -->
<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>
<!-- ... -->
Em seguida, adicione o InputTextBox_KeyDown manipulador de eventos para manipular a Enter chave:
//...
private void InputTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter && !string.IsNullOrWhiteSpace(InputTextBox.Text))
{
SendButton_Click(this, new RoutedEventArgs());
}
}
//...
Execute a aplicação melhorada
Sua interface de bate-papo nova e aprimorada deve ter esta aparência:
Recap
Veja o que você realizou neste tutorial:
- Você adicionou os recursos da API do OpenAI ao seu aplicativo de desktop WinUI 3 / Windows App SDK instalando a biblioteca oficial do OpenAI e inicializando-a com sua chave de API.
- Você criou uma interface semelhante a um bate-papo que permite gerar respostas a mensagens usando a geração de texto da OpenAI e APIs de solicitação.
- Você melhorou a interface do bate-papo ao realizar as seguintes ações:
- adicionando um
ScrollViewer, - usando a
TextBlockpara exibir a resposta GPT, - adicionando um
ProgressBarpara indicar quando o aplicativo está aguardando uma resposta da API GPT, - centralizando o
StackPanelna janela, - garantir que as mensagens sejam transferidas para a próxima linha quando chegarem à borda da janela, e
- tornando o
TextBoxmaior, redimensionável e responsivo à teclaEnter.
- adicionando um
Arquivos de código completos
O código a seguir é um exemplo completo do aplicativo de bate-papo com finalizações de bate-papo OpenAI integradas:
<?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.Chat;
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(openAiKey);
}
private async void SendButton_Click(object sender, RoutedEventArgs e)
{
ResponseProgressBar.Visibility = Visibility.Visible;
string userInput = InputTextBox.Text;
try
{
if (!string.IsNullOrEmpty(userInput))
{
AddMessageToConversation($"User: {userInput}");
InputTextBox.Text = string.Empty;
var chatClient = openAiService.GetChatClient("gpt-4o"); // or another model
var chatOptions = new ChatCompletionOptions
{
MaxOutputTokenCount = 300
};
// Assemble the chat prompt with a system message and the user's input
var completionResult = await chatClient.CompleteChatAsync(
[
ChatMessage.CreateSystemMessage("You are a helpful assistant."),
ChatMessage.CreateUserMessage(userInput)
],
chatOptions);
if (completionResult != null && completionResult.Value.Content.Count > 0)
{
AddMessageToConversation($"GPT: {completionResult.Value.Content.First().Text}");
}
else
{
AddMessageToConversation($"GPT: Sorry, something bad happened: {completionResult?.Value.Refusal ?? "Unknown error."}");
}
}
}
catch (Exception ex)
{
AddMessageToConversation($"GPT: Sorry, something bad happened: {ex.Message}");
}
finally
{
ResponseProgressBar.Visibility = Visibility.Collapsed;
}
}
private void AddMessageToConversation(string message)
{
var messageItem = new MessageItem
{
Text = message,
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());
}
}
}
}
Conteúdo relacionado
Windows developer