Integrálás ügyfélalkalmazással a Speech SDK használatával

Fontos

Az egyéni parancsok 2026. április 30-án megszűnnek. 2023. október 30-ától nem hozhat létre új Egyéni parancsokat a Speech Studióban. A módosítással kapcsolatban a LUIS 2025. október 1-jén megszűnik. 2023. április 1-től nem hozhat létre új LUIS-erőforrásokat.

Ebből a cikkből megtudhatja, hogyan kérheti le a közzétett Egyéni parancsok alkalmazást az UWP-alkalmazásban futó Speech SDK-ból. Az Egyéni parancsok alkalmazással való kapcsolat létrehozásához a következőkre van szükség:

  • Egyéni parancsok közzététele és alkalmazásazonosító (alkalmazásazonosító) lekérése
  • Hozzon létre egy Univerzális Windows-platform (UWP) ügyfélalkalmazást a Speech SDK használatával, amely lehetővé teszi az egyéni parancsok alkalmazással való beszélgetést

Előfeltételek

A cikk elvégzéséhez egyéni parancsok alkalmazásra van szükség. Próbálkozzon egy gyorsútmutatóval egy egyéni parancsalkalmazás létrehozásához:

Emellett a következőkre van szükség:

1. lépés: Egyéni parancsok közzététele alkalmazás

  1. Nyissa meg a korábban létrehozott Egyéni parancsok alkalmazást.

  2. Nyissa meg a Gépház, és válassza a LUIS-erőforrást.

  3. Ha az előrejelzési erőforrás nincs hozzárendelve, válasszon ki egy lekérdezés-előrejelzési kulcsot, vagy hozzon létre egy újat.

    Az alkalmazás közzététele előtt mindig szükség van a lekérdezés-előrejelzési kulcsra. A LUIS-erőforrásokról további információt a LUIS-erőforrás létrehozása című témakörben talál .

  4. Lépjen vissza a Parancsok szerkesztéséhez, válassza a Közzététel lehetőséget.

    Publish application

  5. Másolja ki az alkalmazásazonosítót a "közzététel" értesítésből későbbi használatra.

  6. Másolja a Speech Erőforráskulcsot későbbi használatra.

2. lépés: Visual Studio-projekt létrehozása

Hozzon létre egy Visual Studio-projektet az UWP fejlesztéséhez, és telepítse a Speech SDK-t.

3. lépés: Mintakód hozzáadása

Ebben a lépésben hozzáadjuk az alkalmazás felhasználói felületét meghatározó XAML-kódot, és hozzáadjuk a C#-kód mögötti implementációt.

XAML-kód

Hozza létre az alkalmazás felhasználói felületét az XAML-kód hozzáadásával.

  1. Nyissa meg a MegoldáskezelőMainPage.xaml

  2. A tervező XAML nézetében cserélje le a teljes tartalmat a következő kódrészletre:

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

A Tervező nézet frissül az alkalmazás felhasználói felületének megjelenítéséhez.

C# kód mögötti forrás

Adja hozzá a kód mögötti forrást, hogy az alkalmazás a várt módon működjön. A kód mögötti forrás a következőket tartalmazza:

  • Kötelező using utasítások a névterekhez és Speech.Dialog a Speech névterekhez.
  • Egyszerű implementáció a mikrofonhoz való hozzáférés biztosításához, egy gombkezelőhöz kapcsolva.
  • Egyszerű felhasználói felületi segédek az alkalmazás üzeneteinek és hibáinak megjelenítéséhez.
  • Az inicializálási kód elérési útjának kezdőpontja.
  • Segéd a szöveg visszajátszásához a beszédhez (streamelés támogatása nélkül).
  • Egy üres gombkezelő a figyelés megkezdéséhez.

Adja hozzá a kód mögötti forrást az alábbiak szerint:

  1. A Megoldáskezelő nyissa meg a kód mögötti forrásfájlt MainPage.xaml.csMainPage.xaml(a )

  2. Cserélje le a fájl tartalmát a következő kódra:

    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
            }
        }
    }
    

    Feljegyzés

    Ha a következő hibaüzenet jelenik meg: "Az "Objektum" típus egy nem hivatkozott szerelvényben van definiálva"

    1. A megoldás jobb ügyfélalkalmazása.
    2. Válassza a Megoldáshoz készült NuGet-csomagok kezelése lehetőséget, válassza a Frissítések
    3. Ha megjelenik a Microsoft.NETCore.UniversalWindowsPlatform a frissítési listában, frissítse a Microsoft.NETCore.UniversalWindowsPlatformot a legújabb verzióra
  3. Adja hozzá a következő kódot a metódus törzséhez: 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. Cserélje le a sztringeket YourApplicationId, YourSpeechSubscriptionKeyvalamint az alkalmazás, a beszédkulcs és YourServiceRegiona régió saját értékeit

  5. Fűzze hozzá a következő kódrészletet a következő metódustörzs végéhez: 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. Adja hozzá a következő kódrészletet a ListenButton_ButtonClicked metódus törzséhez az MainPage osztályban

    // 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. A menüsávon válassza az Összes fájl>mentése lehetőséget a módosítások mentéséhez

Próba

  1. A menüsávon válassza a Build Solution (Build Solution)>lehetőséget az alkalmazás létrehozásához. A kód fordításának hiba nélkül kell végbe mennie.

  2. Az alkalmazás elindításához válassza a Hibakeresés indítása hibakeresés>(vagy az F5 billentyű lenyomása) lehetőséget. Megjelenik a helloworld ablak.

    Sample UWP virtual assistant application in C# - quickstart

  3. Válassza a Mikrofon engedélyezése lehetőséget. Ha megjelenik a hozzáférési engedélykérés, válassza az Igen lehetőséget.

    Microphone access permission request

  4. Válassza a Talk lehetőséget, és beszéljen egy angol kifejezéssel vagy mondattal az eszköz mikrofonjába. A beszéd a Direct Line Speech csatornára kerül, és át lesz írva a szövegre, amely megjelenik az ablakban.

Következő lépések