Fermer

octobre 24, 2024

Premiers pas avec le contrôle d’invite .NET MAUI AI

Premiers pas avec le contrôle d’invite .NET MAUI AI


Découvrez le contrôle .NET MAUI AIPrompt, ses propriétés personnalisables disponibles et certaines choses que vous pouvez accomplir avec lui lors de l’association avec un service LLM.

Le .NET MAUI AIPrompt le contrôle de Progress Telerik nous permet, en tant que développeurs, d’intégrer des modèles d’intelligence artificielle LLM (Large Language Model) à nos applications .NET MAUI, afin que les utilisateurs puissent interagir avec elles grâce à une bonne expérience utilisateur. C’est un contrôle esthétique et que nous pouvons implémenter en quelques lignes de code seulement. Explorons-le !

Ajout des packages NuGet nécessaires à notre projet

Pour installer l’interface utilisateur Progress Telerik pour les contrôles .NET MAUI, vous avez à votre disposition le guide d’installation avec différentes approches. Dans mon cas, j’ai opté pour l’installation des packages NuGet, je vais donc ajouter le package appelé Telerik.UI.pour.Maui au projet comme vous pouvez le voir ci-dessous :

Installation du package Nuget Telerik pour Maui

Les autres packages NuGet que vous devez installer pour suivre ce guide sont :

  • Betalgo.OpenAI
  • CommunityToolkit.Mvvm

J’ai choisi le package Betalgo.OpenAI car il offre la flexibilité de travailler avec les modèles OpenAI et Azure OpenAI, et ils fonctionnent à partir d’un projet .NET MAUI (bien qu’il serait conseillé de communiquer avec une API pour consommer des modèles d’IA).

Configuration du projet pour qu’il fonctionne avec .NET MAUI AIPrompt

Une fois que nous avons installé les packages NuGet correspondants, l’étape suivante consiste à configurer le projet pour pouvoir travailler avec le contrôle AIPrompt.

Commençons par aller au MauiProgram.cs fichier pour ajouter l’invocation de la méthode UseTelerik comme indiqué ci-dessous :

public static class MauiProgram
{
  public static MauiApp CreateMauiApp()
  {            
    var builder = MauiApp.CreateBuilder();
    builder
      .UseMauiApp<App>()
      .UseTelerik ()                
      ...
  }
}

Ensuite, nous irons à la page XAML où nous travaillerons avec le contrôle (dans mon cas, le MainPage.xaml fichier) et ajoutez cet espace de noms :

<ContentPage ...
    xmlns:telerik="http://schemas.telerik.com/2022/xaml/maui"    
    ..>
</ContentPage>

Avec cet espace de noms ajouté, nous pouvons maintenant utiliser le contrôle, que, dans sa structure la plus simple, nous pouvons utiliser comme suit :

<Grid>
    <telerik:RadAIPrompt
        x:Name="aiPrompt"
        InputText="{Binding InputText}"
        OutputItems="{Binding OutputItems}"
        PromptRequestCommand="{Binding ExecutePromptRequestCommand}" />
    <Grid
        Background="Black"
        IsVisible="{Binding ShowLoader}"
        Opacity="0.9">
        <telerik:RadBusyIndicator
            AnimationContentColor="Blue"
            HorizontalOptions="Center"
            IsBusy="{Binding ShowLoader}"
            VerticalOptions="Center" />
    </Grid>
</Grid>

Les principales propriétés du contrôle AIPrompt, selon le code ci-dessus, sont les suivantes :

  • Texte d’entrée: C’est la propriété liée qui définit l’invite de l’utilisateur sur l’IA.
  • Éléments de sortie: C’est une collection liée qui permet de garder une trace de toutes les réponses générées par l’IA.
  • Commande PromptRequests: C’est la commande qui va exécuter la requête au service LLM.

Dans le code ci-dessus, nous pouvons également voir une Grid avec un ActivityIndicator qui fait office de superposition pour montrer à l’utilisateur que sa demande est en cours de traitement.

Création du ViewModel

Parce que nous utilisons des liaisons dans le code XAML, nous allons créer un ViewModel pour avoir une bonne séparation des fonctionnalités. J’ai créé un ViewModel.cs fichier avec la structure suivante :

public partial class ViewModel : ObservableObject
{
    [ObservableProperty]
    private string inputText = string.Empty;
 
    [ObservableProperty]
    private IList<AIPromptOutputItem> outputItems = new ObservableCollection<AIPromptOutputItem>();
 
    [ObservableProperty]
    private bool showLoader;
}

Comme nous utilisons la boîte à outils MVVM, nous devons définir la classe comme partial et hériter de ObservableObject. De même, les propriétés doivent être créées comme s’il s’agissait de champs en ajoutant le [ObservableProperty] attribut.

Création de la classe d’assistance pour interroger le LLM

L’avantage que nous offre le contrôle AIPrompt est qu’il nous permet de nous connecter au service LLM que nous souhaitons, que ce soit OpenAI, Azure OpenAI, Llama, Groq, entre autres. Pour que cela fonctionne correctement, nous devons créer les classes qui nous permettent de gérer une connexion à ces services.

Dans mon cas, je vais utiliser le service Azure OpenAI, bien que vous puissiez également utiliser le service OpenAI en suivant l’exemple de code du Documentation du package Betalgo.

La classe que j’ai créée pour communiquer avec Azure OpenAI s’appelle AzureOpenAIService et est le suivant :

public class AzureOpenAIService
{
    OpenAIService azureClient;
    public AzureOpenAIService()
    {
        azureClient = new OpenAIService(new OpenAiOptions()
        {
            ProviderType = ProviderType.Azure,
            ApiKey = Constants.AzureKey,
            BaseDomain = Constants.AzureEndpoint,
            DeploymentId = "gpt4o_std"
        });
    }
 
    public async Task<string> GetResponse(string prompt)
    {
        var completionResult = await azureClient.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest
        {
            Messages = new List<ChatMessage>
            {
                ChatMessage.FromSystem("You are a helpful assistant that talks like a .NET MAUI robot."),
                ChatMessage.FromUser("Hi, can you help me?"),
                ChatMessage.FromAssistant("Beep boop! Affirmative, user! My circuits are primed and ready to assist. What task shall we execute today?"),
                ChatMessage.FromUser($"{prompt}"),
            },
            Model = Models.Gpt_4o,
        });
        if (completionResult.Successful)
        {
            Console.WriteLine(completionResult.Choices.First().Message.Content);
            return completionResult.Choices.First().Message.Content;
        }
        return string.Empty;
    }
}

Dans la classe ci-dessus, le AzureOpenAIService Le constructeur est responsable de l’initialisation de l’instance avec les informations nécessaires pour se connecter à Azure OpenAI. Vous pouvez voir qu’il utilise une classe appelée Constants qui est une classe définie dans le Constants.cs fichier et a la structure suivante :

public static class Constants
{
    public static string AzureKey = "YOUR_AZURE_KEY";
    public static string AzureEndpoint = "YOUR_AZURE_ENDPOINT";
}

D’un autre côté, le GetResponse La méthode prend l’invite comme paramètre et exécute le CreateCompletion méthode. Cette méthode permet de paramétrer un ensemble de messages pour donner un format et un ton aux conversations avec le LLM.

Connecter l’application au LLM

Une fois que la classe de type de service est prête à se connecter à Azure OpenAI, l’étape suivante consiste à l’enregistrer depuis MauiProgram.csdans le but de pouvoir l’injecter dans les pages de la manière suivante :

    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            ...        
            builder.Services.AddSingleton<AzureOpenAIService>();
            builder.Services.AddTransient<MainPage>();
            builder.Services.AddTransient<ViewModel>();
 
            return builder.Build();
        }
    }

Maintenant que le service a été enregistré, nous pouvons l’injecter et conserver une référence dans le ViewModel, comme dans l’exemple suivant :

public partial class ViewModel : ObservableObject
{
    ...
    AzureOpenAIService azureAIService;
    public ViewModel(AzureOpenAIService azureOpenAIService)
    {
        this.azureAIService = azureOpenAIService;
    }
}

Enfin, dans le ViewModel nous ajoutons la commande qui nous permettra de faire la requête au LLM, en utilisant le service ajouté comme suit :

public partial class ViewModel : ObservableObject
{
...
    [RelayCommand]
    private async Task ExecutePromptRequest(object arg)
    {
        ShowLoader = true;
        var response = await this.azureAIService.GetResponse(arg?.ToString());
        AIPromptOutputItem outputItem = new AIPromptOutputItem
        {
            Title = "Generated with AI:",
            InputText = arg?.ToString(),
            ResponseText = $"{response}"
        };
 
        this.OutputItems.Insert(0, outputItem);
        this.InputText = string.Empty;
        ShowLoader = false;
    }
...    

A partir du code ci-dessus, nous pouvons souligner qu’un nouvel objet de type AIPromptOutputItem est créé et contient les propriétés suivantes :

  • Titre: Le titre de la carte qui sera montrée à l’utilisateur, qui peut être le texte que nous choisissons
  • Texte d’entrée: invite d’origine de l’utilisateur
  • Texte de réponse: La réponse du LLM

Ces propriétés seront présentées à l’utilisateur dans chaque réponse générée par le LLM. De même, la réponse est ajoutée à la collection de réponses et nous effaçons la zone de texte d’invite.

Tester l’application

Une fois que nous avons configuré ViewModel pour qu’il fonctionne avec le service LLM, la dernière chose que nous ferons est de modifier le flux de l’application pour qu’il fonctionne avec l’injection de dépendances. Tout d’abord, allons à App.xaml.cs et modifiez le constructeur de l’application comme suit :

public App(MainPage mainPage)
{
    InitializeComponent();
 
    MainPage = mainPage;
}

Dans MainPage.xaml.csnous allons modifier le constructeur pour recevoir une dépendance comme celle-ci :

public MainPage(ViewModel viewModel)
{
    InitializeComponent();
    this.BindingContext = viewModel;
}

Une fois ces modifications apportées, vous pouvez maintenant démarrer l’application. Cela montrera le contrôle AIPrompt avec lequel nous pouvons interagir pour faire des requêtes au LLM et qui a l’air fabuleux :

Le contrôle .NET MAUI AIPrompt déployé

Si vous appuyez sur le Générer bouton, le service LLM sera consulté pour vous donner une réponse à la question demandée :

Le contrôle .NET MAUI AIPrompt affichant l’onglet Sortie avec la réponse à l’invite

Dans l’image ci-dessus, vous pouvez voir que le LLM a répondu correctement à l’invite saisie et que le contrôle affiche un ensemble de boutons sous la réponse générée. Ces boutons ont des fonctions prédéfinies : le bouton « Copier » est utilisé pour la copie, et les boutons d’évaluation permettent aux utilisateurs de voter pour ou de supprimer un vote d’une réponse générée. Cependant, si nous souhaitons modifier le comportement par défaut de ces boutons, nous pouvons le faire en ajoutant une commande au ViewModel, déterminant quelle action sera exécutée lorsque nous appuierons dessus.

Ajout de fonctionnalités aux boutons d’évaluation et de copie

Pour lier la fonctionnalité des boutons Notation et Copier, il est nécessaire d’utiliser certaines propriétés supplémentaires dans le contrôle, qui sont les suivantes :

<telerik:RadAIPrompt
    ...
    OutputItemCopyCommand="{Binding CopyCommand}"
    OutputItemRatingChangedCommand="{Binding OutputItemRatingChangedCommand}"
    OutputItemRetryCommand="{Binding RetryCommand}" />

D’après le code ci-dessus, les propriétés fonctionnent pour les éléments suivants :

  • OutputItemCopyCommand: Permet de lier une commande lorsque le Copie le bouton est enfoncé
  • OutputItemRatingChangedCommand: Permet d’associer une commande lorsque l’on appuie sur l’un des boutons de notation, en obtenant l’élément de réponse sur lequel il a été appuyé ainsi que la valeur positive ou négative.
  • OutputItemRetryCommand: Permet de lier une commande lorsque le bouton de régénération est enfoncé.

Une fois les nouvelles propriétés et leurs liaisons ajoutées, l’étape suivante consiste à créer les commandes pour exécuter les actions. Nous allons faire cela dans le ViewModel, qui ressemblera à ceci :

public partial class ViewModel : ObservableObject
{
    ...
    [RelayCommand]
    public async Task Copy(object arg)
    {
        AIPromptOutputItem outputItem = (AIPromptOutputItem)arg;
        await Clipboard.Default.SetTextAsync(outputItem.ResponseText);
        await Application.Current.MainPage.DisplayAlert("Copied to clipboard:", outputItem.ResponseText, "Ok");
    }
 
    [RelayCommand]
    private async Task Retry(object arg)
    {
        AIPromptOutputItem outputItem = (AIPromptOutputItem)arg;
        await this.ExecutePromptRequest(outputItem.InputText);
        this.InputText = string.Empty;
    }
 
    [RelayCommand]
    private void OutputItemRatingChanged(object arg)
    {
        AIPromptOutputItem outputItem = (AIPromptOutputItem)arg;
        Application.Current.MainPage.DisplayAlert("Response rating changed:", $"The rating of response {outputItems.IndexOf(outputItem)} has changed with rating {outputItem.Rating}.", "Ok");
    }
}

Dans la section de code ci-dessus, vous pouvez voir chacune des commandes recevoir un argument qui permet d’obtenir la valeur de l’action demandée, à la fois pour copier la réponse dans le presse-papiers, régénérer une réponse et obtenir la nouvelle valeur dans l’évaluation d’une réponse.

Affichage des suggestions d’invite initiales

Lorsque les utilisateurs utilisent votre application, il peut arriver qu’ils ne sachent pas quel type d’invites ils peuvent utiliser pour obtenir des réponses du LLM. Heureusement, le contrôle AIPrompt nous permet de définir le Suggestions propriété pour le lier à une liste de suggestions rapides. Cette propriété ressemble à ceci :

<telerik:RadAIPrompt 
    ...
    Suggestions="{Binding Suggestions}" />

Dans le ViewModel, nous nous lions à une collection de chaînes qui seront les suggestions initialisées à notre convenance, comme dans l’exemple suivant :

public partial class ViewModel : ObservableObject
{
    [ObservableProperty]
    private IList<string> suggestions;    
    public ViewModel(AzureOpenAIService azureOpenAIService)
    {
        Suggestions = new List<string>
            {
                "Create a happy tweet about .NET MAUI",
                "Create a quote that Gerald Versluis never said",
                "Tell me the daily horoscope for .NET developers today",
            };
    }
    ...
}

Lors de l’exécution de l’application avec les modifications ci-dessus, nous pouvons voir les suggestions d’invite initiales extraites de la liste des chaînes :

Contrôle .NET MAUI AIPrompt affichant une liste de suggestions d'invites

Voyons maintenant comment effectuer le post-traitement d’une réponse générée par le LLM.

Post-traitement d’une réponse générée par le LLM

Le contrôle .NET MAUI AIPrompt nous permet également d’ajouter des boutons pour effectuer des actions ultérieures sur l’une des réponses générées par le LLM. Par exemple, nous pourrions traduire la réponse dans une autre langue, résumer la réponse, créer un tweet et le publier sur les réseaux sociaux, etc.

Pour activer ces nouveaux boutons, nous devons ajouter les propriétés suivantes au contrôle :

<telerik:RadAIPrompt
...
    CommandTappedCommand="{Binding CommandTappedCommand}"
    Commands="{Binding Commands}"
/>

Les propriétés ci-dessus effectuent les opérations suivantes :

  • Commandes: Permet de se lier à une liste de nouvelles commandes, en pouvant définir des caractéristiques telles que du texte, une icône, entre autres.
  • CommandeTappedCommand: Permet de se lier à une Commande qui sera exécutée dès que l’une des nouvelles commandes sera enfoncée.

D’autre part, dans le ViewModel nous devons créer la propriété et la commande qui seront liées comme suit :

public partial class ViewModel : ObservableObject
{
    [ObservableProperty]
    private IList<AIPromptCommandBase> commands;
    public ViewModel(AzureOpenAIService azureOpenAIService)
    {
       ...
       this.commands = new List<AIPromptCommandBase>();
       this.commands.Add(new AIPromptCommand { ImageSource = new FontImageSource() { FontFamily = TelerikFont.Name, Size = 12, Glyph = TelerikFont.IconSparkle }, Text = "Translate to Spanish", });      
    }
    ...
    [RelayCommand]
    private async Task CommandTapped(object arg)
    {
            ShowLoader = true;
            AIPromptCommandBase command = (AIPromptCommandBase)arg;
            var currentCommand = command.Text;
            var lastAnswer = OutputItems.FirstOrDefault();
            var response = await this.azureAIService.GetResponse($"Translate the following text to Spanish: {lastAnswer.ResponseText}");
            lastAnswer.ResponseText = response;
            ShowLoader = false;
    }
}

Dans le code ci-dessus, j’ai défini une collection de type IList<AIPrompt> qui est initialisé dans le constructeur. Dans cet exemple spécifique, la commande permettra à l’utilisateur de traduire la dernière réponse générée en espagnol, bien que vous puissiez ajouter autant de commandes que nécessaire. La nouvelle commande apparaît dans le contrôle comme suit :

La commande personnalisée pour traduire un texte en espagnol dans le contrôle .NET MAUI AIPrompt

D’un autre côté, j’ai également défini le CommandTapped méthode qui permettra à l’utilisateur d’exécuter l’action sélectionnée. Cette action est obtenue dans le currentCommand variable; dans mon cas, comme je n’ai défini qu’une seule commande, je ne fais aucune comparaison pour savoir quelle est l’action sélectionnée. Enfin, j’exécute l’action sur le premier élément de la liste (la dernière réponse obtenue du LLM), obtenant le résultat suivant :

La réponse traduite en anglais une fois que nous avons appuyé sur la commande personnalisée

Nous voyons que ces propriétés nous permettent d’étendre le contrôle et d’effectuer pratiquement n’importe quelle action souhaitée.

Ajout du contrôle AIPrompt en tant que fenêtre flottante

Jusqu’à présent, nous avons vu le contrôle utilisé sur une page entière ; cependant, cela n’est peut-être pas la solution la plus pratique si vous souhaitez que l’utilisateur consulte le LLM tout en utilisant des sections de votre application.

Heureusement, placer le contrôle AIPrompt sous forme de bouton flottant est extrêmement simple. Il ne vous reste plus qu’à emboîter le RadAIPrompt contrôle à l’intérieur d’un RadAIPromptButton comme suit:

<Grid>
    <Label VerticalOptions="Center" HorizontalOptions="Center" Text="Application content" FontSize="25"/>
    <telerik:RadAIPromptButton
        Margin="20"
        Content="AI"
        FontFamily="TelerikFontExamples"
        HorizontalOptions="End"
        VerticalOptions="End">
        <telerik:RadAIPrompt .../>
    </telerik:RadAIPromptButton>            
</Grid>
...

De cette façon, nous afficherons un bouton flottant qui permettra d’ouvrir le contrôle lorsque nous en aurons besoin :

Le contrôle AIPrompt étant affiché sous forme de bouton flottant dans l'application

En appuyant sur le bouton, nous verrons le contrôle AIPrompt sous la forme d’une fenêtre pop-up avec la même configuration :

Contrôle AIPrompt affiché sous forme de fenêtre contextuelle

Conclusion

Grâce à cet article, vous avez découvert ce qu’est le contrôle .NET MAUI AIPrompt ainsi que plusieurs de ses propriétés disponibles pour le personnaliser. Vous avez appris à utiliser un service LLM pour répondre aux invites des utilisateurs, créer une liste de suggestions d’invites, ajouter des commandes personnalisées au contrôle et le positionner sous forme de bouton flottant. Sans aucun doute, ce contrôle puissant vous permettra d’ajouter de l’intelligence à vos applications rapidement et facilement. À bientôt!

N’oubliez pas : vous pouvez essayer ce contrôle et tous les autres dans Telerik UI pour .NET MAUI gratuitement pendant 30 jours !

Essayez maintenant




Source link