Konuşma SDK'sı kullanarak istemci uygulamasıyla tümleştirme

Önemli

Özel Komutlar 30 Nisan 2026'da kullanımdan kaldırılacaktır. 30 Ekim 2023 itibarıyla Speech Studio'da yeni Özel Komutlar uygulaması oluşturamazsınız. Bu değişiklikle ilgili olarak LUIS, 1 Ekim 2025'te kullanımdan kaldırılacaktır. 1 Nisan 2023 itibarıyla yeni LUIS kaynakları oluşturamazsınız.

Bu makalede, bir UWP uygulamasında çalışan Konuşma SDK'sından yayımlanmış bir Özel Komutlar uygulamasına nasıl istekte bulunacağınızı öğreneceksiniz. Özel Komutlar uygulamasına bağlantı kurmak için şunları yapmanız gerekir:

  • Özel Komutlar uygulaması yayımlama ve uygulama tanımlayıcısı alma (Uygulama Kimliği)
  • Özel Komutlar uygulamanızla konuşmanıza olanak sağlamak için Konuşma SDK'sını kullanarak bir Evrensel Windows Platformu (UWP) istemci uygulaması oluşturma

Önkoşullar

Bu makaleyi tamamlamak için özel komutlar uygulaması gerekir. Özel komutlar uygulaması oluşturmak için hızlı başlangıcı deneyin:

Şunları da yapmanız gerekir:

1. Adım: Özel Komutlar uygulaması yayımlama

  1. Daha önce oluşturduğunuz Özel Komutlar uygulamanızı açın.

  2. Ayarlar gidin, LUIS kaynağı'na tıklayın.

  3. Tahmin kaynağı atanmamışsa bir sorgu tahmin anahtarı seçin veya yeni bir tane oluşturun.

    Bir uygulamayı yayımlamadan önce her zaman sorgu tahmin anahtarı gereklidir. LUIS kaynakları hakkında daha fazla bilgi için bkz . LUIS Kaynağı Oluşturma

  4. Komutları düzenlemeye geri dönün ve Yayımla'yı seçin.

    Publish application

  5. Daha sonra kullanmak üzere "yayımla" bildiriminden Uygulama Kimliğini kopyalayın.

  6. Konuşma Kaynak Anahtarı'nı daha sonra kullanmak üzere kopyalayın.

2. Adım: Visual Studio projesi oluşturma

UWP geliştirmesi için bir Visual Studio projesi oluşturun ve Konuşma SDK'sını yükleyin.

3. Adım: Örnek kod ekleme

Bu adımda, uygulamanın kullanıcı arabirimini tanımlayan XAML kodunu ve C# arka planda kod uygulamasını ekleyeceğiz.

XAML kodu

XAML kodunu ekleyerek uygulamanın kullanıcı arabirimini oluşturun.

  1. Çözüm Gezgini'da MainPage.xaml

  2. Tasarımcının XAML görünümünde tüm içeriği aşağıdaki kod parçacığıyla değiştirin:

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

Tasarım görünümü, uygulamanın kullanıcı arabirimini gösterecek şekilde güncelleştirilir.

C# arka planda kod kaynağı

Uygulamanın beklendiği gibi çalışması için arka planda kod kaynağını ekleyin. Arka planda kod kaynağı şunları içerir:

  • ve Speech.Dialog ad alanları için Speech gerekli using deyimler.
  • Mikrofon erişimini sağlamak için bir düğme işleyiciye kablolu basit bir uygulama.
  • Uygulamada iletileri ve hataları sunmak için temel kullanıcı arabirimi yardımcıları.
  • Başlatma kodu yolu için bir giriş noktası.
  • Metni konuşmaya geri oynatmak için bir yardımcı (akış desteği olmadan).
  • Dinlemeye başlamak için boş bir düğme işleyicisi.

Arka planda kod kaynağını aşağıdaki gibi ekleyin:

  1. Çözüm Gezgini'da arka planda kod kaynak dosyasını MainPage.xaml.cs açın (altında MainPage.xamlgruplandırılmış)

  2. Dosyanın içeriğini aşağıdaki kodla değiştirin:

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

    Not

    Şu hatayı görürseniz: "'Object' türü başvurulmayan bir derlemede tanımlandı"

    1. Çözümünüzü doğru istemciye ekleyin.
    2. Çözüm için NuGet Paketlerini Yönet'i ve Güncelleştirmeler Seç'i seçin
    3. Güncelleştirme listesinde Microsoft.NETCore.UniversalWindowsPlatform görürseniz, Microsoft.NETCore.UniversalWindowsPlatform'u en yeni sürüme güncelleştirin
  3. Yönteminin gövdesine aşağıdaki kodu ekleyin: 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. , ve dizelerini YourApplicationIduygulamanız, konuşma anahtarınız ve bölgeniz için kendi değerlerinizle değiştirin YourServiceRegionYourSpeechSubscriptionKey

  5. Aşağıdaki kod parçacığını yönteminin gövdesinin sonuna ekleyin: 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. Sınıfındaki yönteminin gövdesine ListenButton_ButtonClicked aşağıdaki kod parçacığını MainPage ekleyin

    // 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. Değişikliklerinizi kaydetmek için menü çubuğundan Dosya>Tümünü Kaydet'i seçin

Deneyin

  1. Uygulamayı oluşturmak için menü çubuğunda Derleme Çözümü Oluştur'u>seçin. Kodun hatasız derlenmesi gerekir.

  2. Uygulamayı başlatmak için Hata AyıklamaYı>Başlat Hata Ayıklama'yı seçin (veya F5 tuşuna basın). Helloworld penceresi görüntülenir.

    Sample UWP virtual assistant application in C# - quickstart

  3. Mikrofonu Etkinleştir'i seçin. Erişim izni isteği açılırsa Evet'i seçin.

    Microphone access permission request

  4. Konuş'a tıklayın ve cihazınızın mikrofonuna İngilizce bir tümcecik veya cümle söyleyin. Konuşmanız Doğrudan Çizgi Konuşma kanalına iletilir ve pencerede görünen metne dönüştürülür.

Sonraki adımlar