이 방법에서는 WinUI 3/Windows 앱 SDK 데스크톱 앱에 DALL-E의 이미지 생성 기능을 통합합니다.
Prerequisites
- 개발 컴퓨터 설정( Windows 앱 개발 시작 참조).
- 이 기능을 통합할 기능 채팅 인터페이스입니다. WinUI/Windows 앱 SDK 데스크톱 앱에 OpenAI 채팅 기능을 추가하는 방법에 대해 알아보세요. 이 설명서에서는 DALL-E를 채팅 인터페이스에 통합하는 방법을 시연합니다.
-
OpenAI 개발자 대시보드의 OpenAI API 키(
OPENAI_API_KEY환경 변수에 할당됨)입니다. - 프로젝트에 설치된 OpenAI SDK입니다. OpenAI 설명서에서 커뮤니티 라이브러리 목록을 참조하세요. 이 방법에서는 공식 OpenAI .NET API 라이브러리를 사용합니다.
OpenAI SDK 설치 및 초기화
Visual Studio의 터미널 창에서 실행 dotnet add package OpenAI 하여 프로젝트에 OpenAI .NET 라이브러리가 설치되어 있는지 확인합니다. 다음과 같이 OpenAI API 키로 SDK 초기화:
//...
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);
}
}
}
앱의 UI 수정
기존 DateTemplate을 MainWindow.xaml 내에서 대화 중 이미지를 표시하는 Image 컨트롤을 포함하도록 수정하세요.
<!-- ... existing XAML ... -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" Margin="5" Foreground="{Binding Color}"/>
<Image Source="{Binding ImageUrl}" Margin="5" Stretch="UniformToFill"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!-- ... existing XAML ... -->
이 방법은 TextBox 및 Button이 있는 채팅 인터페이스가 있다고 가정합니다. WinUI 3/Windows 앱 SDK 데스크톱 앱에 OpenAI 채팅 완성 기능을 추가하는 방법을 참고하세요.
DALL-E 이미지 생성 구현
MainWindow.xaml.cs에 이미지 생성 및 표시를 처리하는 다음 메서드를 추가합니다.
// ... existing using statements ...
private async void SendButton_Click(object sender, RoutedEventArgs e)
{
ResponseProgressBar.Visibility = Visibility.Visible;
string userInput = InputTextBox.Text;
if (!string.IsNullOrEmpty(userInput))
{
InputTextBox.Text = string.Empty;
// Use the DALL-E 3 model for image generation.
ImageClient imageClient = openAiService.GetImageClient("dall-e-3");
ClientResult<GeneratedImage> imageResult = await imageClient.GenerateImageAsync(userInput,
new ImageGenerationOptions
{
Size = GeneratedImageSize.W1024xH1024,
ResponseFormat = GeneratedImageFormat.Uri,
EndUserId = "TestUser"
});
if (imageResult.Value != null)
{
AddImageMessageToConversation(imageResult.Value.ImageUri);
}
else
{
AddMessageToConversation("GPT: Sorry, something bad happened.");
}
}
ResponseProgressBar.Visibility = Visibility.Collapsed;
}
private void AddImageMessageToConversation(Uri imageUrl)
{
var imageMessage = new MessageItem
{
ImageUrl = imageUrl.ToString()
};
ConversationList.Items.Add(imageMessage);
// handle scrolling
ConversationScrollViewer.UpdateLayout();
ConversationScrollViewer.ChangeView(null, ConversationScrollViewer.ScrollableHeight, null);
}
이 imageClient.GenerateImageAsync() 메서드는 OpenAI의 DALL-E API를 호출합니다. 자세한 사용 예제는 GitHub의 OpenAI .NET 예제를 참조하세요.
Tip
앱에서 DALL-E 및 채팅 API를 사용하는 다양한 방법에 대한 몇 가지 제안 사항을 Microsoft Copilot에 요청해 보세요.
ImageUrl이(가) MessageItem 클래스에 있는지 확인합니다. 이는 새 속성입니다.
public class MessageItem
{
public string Text { get; set; }
public SolidColorBrush Color { get; set; }
public string ImageUrl { get; set; } // new
}
실행 및 테스트
앱을 실행하고 프롬프트를 입력한 다음 "보내기" 단추를 클릭합니다. 다음과 비슷한 결과가 표시됩니다.
사용자 고유의 UI 사용자 지정
UI에 일부 라디오 단추를 추가하여 대화에 이미지를 포함할지 여부를 선택합니다. 그런 다음 라디오 단추 선택에 따라 이미지 생성 메서드를 조건부로 호출하도록 메서드를 수정 SendButton_Click 할 수 있습니다.
Recap
이본 가이드에서 학습한 내용은 다음과 같습니다.
-
<TextBox>에서 사용자의 이미지 프롬프트를 수락합니다. - OpenAI DALL-E API를 사용하여 이미지를 생성합니다.
-
<Image>에 이미지를 표시합니다.
전체 코드 파일
다음은 DALL-E 이미지 생성을 사용하여 채팅 인터페이스에 대한 전체 코드 파일입니다. 위의 사용자 고유 섹션에서 UI 사용자 지정 에 제안된 대로 라디오 단추를 사용하여 조건부로 채팅 또는 이미지 생성을 호출하도록 코드가 업데이트되었습니다.
<?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>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" Margin="5" Foreground="{Binding Color}"/>
<Image Source="{Binding ImageUrl}" Margin="5" Stretch="UniformToFill"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<ProgressBar x:Name="ResponseProgressBar" Height="5" IsIndeterminate="True" Visibility="Collapsed"/>
<StackPanel Orientation="Vertical" Width="300">
<RadioButtons Header="Query type:">
<RadioButton x:Name="chatRadioButton" Content="Chat" IsChecked="True"/>
<RadioButton x:Name="imageRadioButton" Content="Image"/>
</RadioButtons>
<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 System.Threading.Tasks;
using OpenAI;
using OpenAI.Chat;
using OpenAI.Images;
namespace ChatGPT_WinUI3
{
public class MessageItem
{
public string Text { get; set; }
public SolidColorBrush Color { get; set; }
public string ImageUrl { 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 (imageRadioButton.IsChecked == true)
{
await ProcessImageRequestAsync(userInput);
}
else
{
await ProcessChatRequestAsync(userInput);
}
}
catch (Exception ex)
{
AddMessageToConversation($"GPT: Sorry, something bad happened: {ex.Message}");
}
finally
{
ResponseProgressBar.Visibility = Visibility.Collapsed;
}
}
private async Task ProcessImageRequestAsync(string userInput)
{
if (!string.IsNullOrEmpty(userInput))
{
InputTextBox.Text = string.Empty;
// Use the DALL-E 3 model for image generation.
ImageClient imageClient = openAiService.GetImageClient("dall-e-3");
ClientResult<GeneratedImage> imageResult = await imageClient.GenerateImageAsync(userInput,
new ImageGenerationOptions
{
Size = GeneratedImageSize.W1024xH1024,
ResponseFormat = GeneratedImageFormat.Uri,
EndUserId = "TestUser"
});
if (imageResult.Value != null)
{
AddImageMessageToConversation(imageResult.Value.ImageUri);
}
else
{
AddMessageToConversation("GPT: Sorry, something bad happened.");
}
}
}
private async Task ProcessChatRequestAsync(string userInput)
{
if (!string.IsNullOrEmpty(userInput))
{
AddMessageToConversation($"User: {userInput}");
InputTextBox.Text = string.Empty;
var chatClient = openAiService.GetChatClient("gpt-4o");
var chatOptions = new ChatCompletionOptions
{
MaxOutputTokenCount = 300
};
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."}");
}
}
}
private void AddImageMessageToConversation(Uri imageUrl)
{
var imageMessage = new MessageItem
{
ImageUrl = imageUrl.ToString()
};
ConversationList.Items.Add(imageMessage);
// handle scrolling
ConversationScrollViewer.UpdateLayout();
ConversationScrollViewer.ChangeView(null, ConversationScrollViewer.ScrollableHeight, null);
}
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());
}
}
}
}
관련 콘텐츠
Windows developer