共用方式為


將 DALL-E 新增至 WinUI 3/Windows 應用程式 SDK 傳統型應用程式

在此操作說明中,我們會將 DALL-E 的影像產生功能整合到您的 WinUI 3/Windows 應用程式 SDK 傳統型應用程式。

Prerequisites

安裝並初始化 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

修改現有的 DateTemplateMainWindow.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 ... -->

請注意,此操作說明假設您有 TextBoxButton 的聊天介面;請參閱如何將 OpenAI 聊天完成新增至 WinUI 3/Windows 應用程式 SDK 傳統型應用程式

實作 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

請嘗試詢問 Microsoft Copilot,以取得在應用程式中使用 DALL-E 和聊天 API 的不同方式的一些建議。

請注意 ImageUrl 類別中是否存在 MessageItem。 這是新的屬性:

public class MessageItem
{
    public string Text { get; set; }
    public SolidColorBrush Color { get; set; }
    public string ImageUrl { get; set; } // new
}

執行及測試

執行您的應用程式,輸入提示,然後按下 [傳送] 按鈕。 您應該會看到類似這樣的畫面︰

WinUI 映像產生示範應用程式的螢幕快照。

自行自定義UI

請嘗試將一些單選按鈕新增到使用者介面,以選擇是否在對話中包含圖片。 然後,您可以修改 SendButton_Click 方法,根據單選按鈕的選擇,有條件地呼叫影像生成方法。

Recap

在此指南中,您已了解如何:

  1. <TextBox> 內接受來自使用者的影像提示。
  2. 使用 OpenAI DALL-E API 產生影像。
  3. <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());
            }
        }
    }
}