Delen via


DALL-E toevoegen aan uw WinUI 3-/Windows App SDK-bureaublad-app

In deze handleiding integreren we de beeldgeneratiemogelijkheden van DALL-E in uw WinUI 3-/Windows App SDK-desktopapp.

Prerequisites

De OpenAI SDK installeren en initialiseren

Zorg ervoor dat de OpenAI .NET-bibliotheek is geïnstalleerd in uw project door uit te voeren dotnet add package OpenAI vanuit het terminalvenster van Visual Studio. Initialiseer de SDK als volgt met uw OpenAI API-sleutel:

//...
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);
        }
    }
}

De gebruikersinterface van uw app wijzigen

Wijzig uw bestaande DateTemplate in MainWindow.xaml om een Image besturingselement op te nemen waarin afbeeldingen in het gesprek worden weergegeven:

<!-- ... 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 ... -->

Houd er rekening mee dat u een chatinterface hebt met een TextBox en Button; zie Hoe u OpenAI-chatvoltooiingen toevoegt aan uw WinUI 3/Windows App SDK-bureaublad-app.

Implementatie van DALL-E-afbeeldingsgeneratie

In uw MainWindow.xaml.cs, voeg de volgende methoden toe om het genereren en weergeven van afbeeldingen te verwerken:

// ... 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);
}

De imageClient.GenerateImageAsync() methode is verantwoordelijk voor het aanroepen van de DALL-E API van OpenAI. Raadpleeg de OpenAI .NET-voorbeelden op GitHub voor meer gebruiksvoorbeelden.

Tip

Vraag Microsoft Copilot om suggesties voor verschillende manieren om de DALL-E en chat-API's in uw app te gebruiken.

Let op de aanwezigheid van ImageUrl in de MessageItem klas. Dit is een nieuwe eigenschap:

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

Uitvoeren en testen

Voer uw app uit, voer een prompt in en klik op de knop Verzenden. U zou iets moeten zien dat er ongeveer zo uitziet:

Een schermopname van de demo-app voor het genereren van WinUI-installatiekopieën.

De gebruikersinterface zelf aanpassen

Probeer een aantal keuzerondjes aan de gebruikersinterface toe te voegen om te bepalen of een afbeelding in het gesprek moet worden opgenomen. Vervolgens kunt u de SendButton_Click methode wijzigen om de methode voor het genereren van afbeeldingen voorwaardelijk aan te roepen op basis van de keuzerondjeselectie.

Recap

In deze handleiding hebt u het volgende geleerd:

  1. Accepteer afbeeldingsprompts van gebruikers binnen een <TextBox>.
  2. Afbeeldingen genereren met behulp van de OpenAI DALL-E-API.
  3. De afbeelding weergeven in een <Image>.

Volledige codebestanden

Hier volgen de volledige codebestanden voor de chatinterface met DALL-E generatie van afbeeldingen. De code is bijgewerkt om radioknoppen te gebruiken om chats of het genereren van afbeeldingen voorwaardelijk aan te roepen, zoals voorgesteld wordt in de gebruikersinterface aanpassen op eigen gelegenheid sectie hierboven.

<?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());
            }
        }
    }
}