Integracja z aplikacją kliencką przy użyciu zestawu Speech SDK

Ważne

Polecenia niestandardowe zostaną wycofane 30 kwietnia 2026 r. Od 30 października 2023 r. nie można tworzyć nowych aplikacji poleceń niestandardowych w programie Speech Studio. W związku z tą zmianą usługa LUIS zostanie wycofana 1 października 2025 r. Od 1 kwietnia 2023 r. nie można tworzyć nowych zasobów usługi LUIS.

Z tego artykułu dowiesz się, jak wysyłać żądania do opublikowanej aplikacji poleceń niestandardowych z zestawu Speech SDK działającego w aplikacji platformy UWP. Aby nawiązać połączenie z aplikacją Polecenia niestandardowe, potrzebne są następujące elementy:

  • Publikowanie aplikacji poleceń niestandardowych i uzyskiwanie identyfikatora aplikacji (identyfikator aplikacji)
  • Tworzenie aplikacji klienckiej platformy platforma uniwersalna systemu Windows (UWP) przy użyciu zestawu SPEECH SDK w celu umożliwienia komunikacji z aplikacją Poleceń niestandardowych

Wymagania wstępne

Do ukończenia tego artykułu jest wymagana aplikacja Poleceń niestandardowych. Wypróbuj przewodnik Szybki start, aby utworzyć aplikację poleceń niestandardowych:

Wymagane są również:

Krok 1. Publikowanie aplikacji poleceń niestandardowych

  1. Otwórz wcześniej utworzoną aplikację Poleceń niestandardowych.

  2. Przejdź do Ustawienia, wybierz pozycję Zasób usługi LUIS.

  3. Jeśli zasób przewidywania nie jest przypisany, wybierz klucz przewidywania zapytania lub utwórz nowy.

    Klucz przewidywania zapytań jest zawsze wymagany przed opublikowaniem aplikacji. Aby uzyskać więcej informacji na temat zasobów usługi LUIS, zapoznaj się z tematem Tworzenie zasobu usługi LUIS

  4. Wróć do edytowania poleceń, wybierz pozycję Publikuj.

    Publish application

  5. Skopiuj identyfikator aplikacji z powiadomienia "publish" do późniejszego użycia.

  6. Skopiuj klucz zasobu mowy do późniejszego użycia.

Krok 2. Tworzenie projektu programu Visual Studio

Utwórz projekt programu Visual Studio na potrzeby programowania platformy UWP i zainstaluj zestaw Speech SDK.

Krok 3. Dodawanie przykładowego kodu

W tym kroku dodamy kod XAML definiujący interfejs użytkownika aplikacji i dodając implementację kodu w języku C#.

Kod XAML

Utwórz interfejs użytkownika aplikacji, dodając kod XAML.

  1. W Eksplorator rozwiązań otwórzMainPage.xaml

  2. W widoku XAML projektanta zastąp całą zawartość następującym fragmentem kodu:

    <Page
        x:Class="helloworld.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:helloworld"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    
        <Grid>
            <StackPanel Orientation="Vertical" HorizontalAlignment="Center"
                        Margin="20,50,0,0" VerticalAlignment="Center" Width="800">
                <Button x:Name="EnableMicrophoneButton" Content="Enable Microphone"
                        Margin="0,10,10,0" Click="EnableMicrophone_ButtonClicked"
                        Height="35"/>
                <Button x:Name="ListenButton" Content="Talk"
                        Margin="0,10,10,0" Click="ListenButton_ButtonClicked"
                        Height="35"/>
                <StackPanel x:Name="StatusPanel" Orientation="Vertical"
                            RelativePanel.AlignBottomWithPanel="True"
                            RelativePanel.AlignRightWithPanel="True"
                            RelativePanel.AlignLeftWithPanel="True">
                    <TextBlock x:Name="StatusLabel" Margin="0,10,10,0"
                               TextWrapping="Wrap" Text="Status:" FontSize="20"/>
                    <Border x:Name="StatusBorder" Margin="0,0,0,0">
                        <ScrollViewer VerticalScrollMode="Auto"
                                      VerticalScrollBarVisibility="Auto" MaxHeight="200">
                            <!-- Use LiveSetting to enable screen readers to announce
                                 the status update. -->
                            <TextBlock
                                x:Name="StatusBlock" FontWeight="Bold"
                                AutomationProperties.LiveSetting="Assertive"
                                MaxWidth="{Binding ElementName=Splitter, Path=ActualWidth}"
                                Margin="10,10,10,20" TextWrapping="Wrap"  />
                        </ScrollViewer>
                    </Border>
                </StackPanel>
            </StackPanel>
            <MediaElement x:Name="mediaElement"/>
        </Grid>
    </Page>
    

Widok Projekt jest aktualizowany w celu wyświetlenia interfejsu użytkownika aplikacji.

Źródło kodu w języku C#

Dodaj źródło kodu, aby aplikacja działała zgodnie z oczekiwaniami. Źródło kodu zawiera następujące elementy:

  • Wymagane using instrukcje dla Speech przestrzeni nazw i Speech.Dialog .
  • Prosta implementacja zapewniająca dostęp do mikrofonu, przewodową do procedury obsługi przycisków.
  • Podstawowe pomocniki interfejsu użytkownika do prezentowania komunikatów i błędów w aplikacji.
  • Punkt docelowy ścieżki kodu inicjowania.
  • Pomocnik do odtwarzania tekstu na mowę (bez obsługi przesyłania strumieniowego).
  • Pusta procedura obsługi przycisków do rozpoczęcia nasłuchiwania.

Dodaj źródło kodu w następujący sposób:

  1. W Eksplorator rozwiązań otwórz plik MainPage.xaml.cs źródłowy za kodem (pogrupowany w obszarze MainPage.xaml)

  2. Zastąp zawartość pliku następującym kodem:

    using Microsoft.CognitiveServices.Speech;
    using Microsoft.CognitiveServices.Speech.Audio;
    using Microsoft.CognitiveServices.Speech.Dialog;
    using System;
    using System.IO;
    using System.Text;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    
    namespace helloworld
    {
        public sealed partial class MainPage : Page
        {
            private DialogServiceConnector connector;
    
            private enum NotifyType
            {
                StatusMessage,
                ErrorMessage
            };
    
            public MainPage()
            {
                this.InitializeComponent();
            }
    
            private async void EnableMicrophone_ButtonClicked(
                object sender, RoutedEventArgs e)
            {
                bool isMicAvailable = true;
                try
                {
                    var mediaCapture = new Windows.Media.Capture.MediaCapture();
                    var settings =
                        new Windows.Media.Capture.MediaCaptureInitializationSettings();
                    settings.StreamingCaptureMode =
                        Windows.Media.Capture.StreamingCaptureMode.Audio;
                    await mediaCapture.InitializeAsync(settings);
                }
                catch (Exception)
                {
                    isMicAvailable = false;
                }
                if (!isMicAvailable)
                {
                    await Windows.System.Launcher.LaunchUriAsync(
                        new Uri("ms-settings:privacy-microphone"));
                }
                else
                {
                    NotifyUser("Microphone was enabled", NotifyType.StatusMessage);
                }
            }
    
            private void NotifyUser(
                string strMessage, NotifyType type = NotifyType.StatusMessage)
            {
                // If called from the UI thread, then update immediately.
                // Otherwise, schedule a task on the UI thread to perform the update.
                if (Dispatcher.HasThreadAccess)
                {
                    UpdateStatus(strMessage, type);
                }
                else
                {
                    var task = Dispatcher.RunAsync(
                        Windows.UI.Core.CoreDispatcherPriority.Normal,
                        () => UpdateStatus(strMessage, type));
                }
            }
    
            private void UpdateStatus(string strMessage, NotifyType type)
            {
                switch (type)
                {
                    case NotifyType.StatusMessage:
                        StatusBorder.Background = new SolidColorBrush(
                            Windows.UI.Colors.Green);
                        break;
                    case NotifyType.ErrorMessage:
                        StatusBorder.Background = new SolidColorBrush(
                            Windows.UI.Colors.Red);
                        break;
                }
                StatusBlock.Text += string.IsNullOrEmpty(StatusBlock.Text)
                    ? strMessage : "\n" + strMessage;
    
                if (!string.IsNullOrEmpty(StatusBlock.Text))
                {
                    StatusBorder.Visibility = Visibility.Visible;
                    StatusPanel.Visibility = Visibility.Visible;
                }
                else
                {
                    StatusBorder.Visibility = Visibility.Collapsed;
                    StatusPanel.Visibility = Visibility.Collapsed;
                }
                // Raise an event if necessary to enable a screen reader
                // to announce the status update.
                var peer = Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer.FromElement(StatusBlock);
                if (peer != null)
                {
                    peer.RaiseAutomationEvent(
                        Windows.UI.Xaml.Automation.Peers.AutomationEvents.LiveRegionChanged);
                }
            }
    
            // Waits for and accumulates all audio associated with a given
            // PullAudioOutputStream and then plays it to the MediaElement. Long spoken
            // audio will create extra latency and a streaming playback solution
            // (that plays audio while it continues to be received) should be used --
            // see the samples for examples of this.
            private void SynchronouslyPlayActivityAudio(
                PullAudioOutputStream activityAudio)
            {
                var playbackStreamWithHeader = new MemoryStream();
                playbackStreamWithHeader.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4); // ChunkID
                playbackStreamWithHeader.Write(BitConverter.GetBytes(UInt32.MaxValue), 0, 4); // ChunkSize: max
                playbackStreamWithHeader.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4); // Format
                playbackStreamWithHeader.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4); // Subchunk1ID
                playbackStreamWithHeader.Write(BitConverter.GetBytes(16), 0, 4); // Subchunk1Size: PCM
                playbackStreamWithHeader.Write(BitConverter.GetBytes(1), 0, 2); // AudioFormat: PCM
                playbackStreamWithHeader.Write(BitConverter.GetBytes(1), 0, 2); // NumChannels: mono
                playbackStreamWithHeader.Write(BitConverter.GetBytes(16000), 0, 4); // SampleRate: 16kHz
                playbackStreamWithHeader.Write(BitConverter.GetBytes(32000), 0, 4); // ByteRate
                playbackStreamWithHeader.Write(BitConverter.GetBytes(2), 0, 2); // BlockAlign
                playbackStreamWithHeader.Write(BitConverter.GetBytes(16), 0, 2); // BitsPerSample: 16-bit
                playbackStreamWithHeader.Write(Encoding.ASCII.GetBytes("data"), 0, 4); // Subchunk2ID
                playbackStreamWithHeader.Write(BitConverter.GetBytes(UInt32.MaxValue), 0, 4); // Subchunk2Size
    
                byte[] pullBuffer = new byte[2056];
    
                uint lastRead = 0;
                do
                {
                    lastRead = activityAudio.Read(pullBuffer);
                    playbackStreamWithHeader.Write(pullBuffer, 0, (int)lastRead);
                }
                while (lastRead == pullBuffer.Length);
    
                var task = Dispatcher.RunAsync(
                    Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    mediaElement.SetSource(
                        playbackStreamWithHeader.AsRandomAccessStream(), "audio/wav");
                    mediaElement.Play();
                });
            }
    
            private void InitializeDialogServiceConnector()
            {
                // New code will go here
            }
    
            private async void ListenButton_ButtonClicked(
                object sender, RoutedEventArgs e)
            {
                // New code will go here
            }
        }
    }
    

    Uwaga

    Jeśli zostanie wyświetlony błąd: "Typ "Object" jest zdefiniowany w zestawie, do którego nie odwołuje się odwołanie"

    1. Odpowiedni klient twojego rozwiązania.
    2. Wybierz pozycję Zarządzaj pakietami NuGet dla rozwiązania, wybierz pozycję Aktualizacje
    3. Jeśli na liście aktualizacji zostanie wyświetlony element Microsoft.NETCore.UniversalWindowsPlatform , zaktualizuj element Microsoft.NETCore.UniversalWindowsPlatform do najnowszej wersji
  3. Dodaj następujący kod do treści metody InitializeDialogServiceConnector

    // This code creates the `DialogServiceConnector` with your resource information.
    // create a DialogServiceConfig by providing a Custom Commands application id and Speech resource key
    // The RecoLanguage property is optional (default en-US); note that only en-US is supported in Preview
    const string speechCommandsApplicationId = "YourApplicationId"; // Your application id
    const string speechSubscriptionKey = "YourSpeechSubscriptionKey"; // Your Speech resource key
    const string region = "YourServiceRegion"; // The Speech resource region. 
    
    var speechCommandsConfig = CustomCommandsConfig.FromSubscription(speechCommandsApplicationId, speechSubscriptionKey, region);
    speechCommandsConfig.SetProperty(PropertyId.SpeechServiceConnection_RecoLanguage, "en-us");
    connector = new DialogServiceConnector(speechCommandsConfig);
    
  4. Zastąp ciągi YourApplicationId, YourSpeechSubscriptionKeyi YourServiceRegion własnymi wartościami dla aplikacji, klucza mowy i regionu

  5. Dołącz poniższy fragment kodu na końcu treści metody InitializeDialogServiceConnector

    //
    // This code sets up handlers for events relied on by `DialogServiceConnector` to communicate its activities,
    // speech recognition results, and other information.
    //
    // ActivityReceived is the main way your client will receive messages, audio, and events
    connector.ActivityReceived += (sender, activityReceivedEventArgs) =>
    {
        NotifyUser(
            $"Activity received, hasAudio={activityReceivedEventArgs.HasAudio} activity={activityReceivedEventArgs.Activity}");
    
        if (activityReceivedEventArgs.HasAudio)
        {
            SynchronouslyPlayActivityAudio(activityReceivedEventArgs.Audio);
        }
    };
    
    // Canceled will be signaled when a turn is aborted or experiences an error condition
    connector.Canceled += (sender, canceledEventArgs) =>
    {
        NotifyUser($"Canceled, reason={canceledEventArgs.Reason}");
        if (canceledEventArgs.Reason == CancellationReason.Error)
        {
            NotifyUser(
                $"Error: code={canceledEventArgs.ErrorCode}, details={canceledEventArgs.ErrorDetails}");
        }
    };
    
    // Recognizing (not 'Recognized') will provide the intermediate recognized text
    // while an audio stream is being processed
    connector.Recognizing += (sender, recognitionEventArgs) =>
    {
        NotifyUser($"Recognizing! in-progress text={recognitionEventArgs.Result.Text}");
    };
    
    // Recognized (not 'Recognizing') will provide the final recognized text
    // once audio capture is completed
    connector.Recognized += (sender, recognitionEventArgs) =>
    {
        NotifyUser($"Final speech to text result: '{recognitionEventArgs.Result.Text}'");
    };
    
    // SessionStarted will notify when audio begins flowing to the service for a turn
    connector.SessionStarted += (sender, sessionEventArgs) =>
    {
        NotifyUser($"Now Listening! Session started, id={sessionEventArgs.SessionId}");
    };
    
    // SessionStopped will notify when a turn is complete and
    // it's safe to begin listening again
    connector.SessionStopped += (sender, sessionEventArgs) =>
    {
        NotifyUser($"Listening complete. Session ended, id={sessionEventArgs.SessionId}");
    };
    
  6. Dodaj następujący fragment kodu do treści ListenButton_ButtonClicked metody w MainPage klasie

    // This code sets up `DialogServiceConnector` to listen, since you already established the configuration and
    // registered the event handlers.
    if (connector == null)
    {
        InitializeDialogServiceConnector();
        // Optional step to speed up first interaction: if not called,
        // connection happens automatically on first use
        var connectTask = connector.ConnectAsync();
    }
    
    try
    {
        // Start sending audio
        await connector.ListenOnceAsync();
    }
    catch (Exception ex)
    {
        NotifyUser($"Exception: {ex.ToString()}", NotifyType.ErrorMessage);
    }
    
  7. Na pasku menu wybierz pozycję Plik>Zapisz wszystko, aby zapisać zmiany

Czas to wypróbować

  1. Na pasku menu wybierz pozycję Kompiluj>rozwiązanie kompilacji, aby skompilować aplikację. Kod powinien zostać skompilowany bez błędów.

  2. Wybierz pozycję Debuguj>Rozpocznij debugowanie (lub naciśnij klawisz F5), aby uruchomić aplikację. Zostanie wyświetlone okno helloworld .

    Sample UWP virtual assistant application in C# - quickstart

  3. Wybierz pozycję Włącz mikrofon. Jeśli zostanie wyświetlone żądanie uprawnień dostępu, wybierz pozycję Tak.

    Microphone access permission request

  4. Wybierz pozycję Porozmawiaj i powiedz frazę lub zdanie w języku angielskim do mikrofonu urządzenia. Twoja mowa jest przesyłana do kanału mowy direct line i transkrybowana do tekstu, który pojawia się w oknie.

Następne kroki