Integrera med ett klientprogram med Hjälp av Speech SDK
Viktigt!
Anpassade kommandon dras tillbaka den 30 april 2026. Från och med den 30 oktober 2023 kan du inte skapa nya program för anpassade kommandon i Speech Studio. I samband med den här ändringen dras LUIS tillbaka den 1 oktober 2025. Från och med den 1 april 2023 kan du inte skapa nya LUIS-resurser.
I den här artikeln får du lära dig hur du gör begäranden till ett publicerat program för anpassade kommandon från Speech SDK som körs i ett UWP-program. För att upprätta en anslutning till programmet Anpassade kommandon behöver du:
- Publicera ett program för anpassade kommandon och hämta en programidentifierare (app-ID)
- Skapa en Universell Windows-plattform -klientapp (UWP) med hjälp av Speech SDK så att du kan prata med ditt program för anpassade kommandon
Förutsättningar
Ett program för anpassade kommandon krävs för att slutföra den här artikeln. Prova en snabbstart för att skapa ett program för anpassade kommandon:
Du behöver också:
- Visual Studio 2019 eller senare. Den här guiden baseras på Visual Studio 2019.
- En Azure AI Speech-resursnyckel och -region: Skapa en Speech-resurs på Azure-portalen. Mer information finns i Skapa en resurs med flera tjänster.
- Aktivera enheten för utveckling
Steg 1: Publicera program för anpassade kommandon
Öppna ditt tidigare skapade program för anpassade kommandon.
Gå till Inställningar och välj LUIS-resurs.
Om förutsägelseresursen inte har tilldelats väljer du en frågeförutsägelsenyckel eller skapar en ny.
Frågeförutsägelsenyckel krävs alltid innan du publicerar ett program. Mer information om LUIS-resurser finns i Skapa LUIS-resurs
Gå tillbaka till redigeringskommandon och välj Publicera.
Kopiera app-ID:t från meddelandet "publicera" för senare användning.
Kopiera talresursnyckeln för senare användning.
Steg 2: Skapa ett Visual Studio-projekt
Skapa ett Visual Studio-projekt för UWP-utveckling och installera Speech SDK.
Steg 3: Lägg till exempelkod
I det här steget lägger vi till XAML-koden som definierar programmets användargränssnitt och lägger till C#-kod bakom implementeringen.
XAML-kod
Skapa programmets användargränssnitt genom att lägga till XAML-koden.
Öppna i Solution Explorer
MainPage.xaml
I designerns XAML-vy ersätter du hela innehållet med följande kodfragment:
<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>
Designvyn uppdateras för att visa programmets användargränssnitt.
C#-kod bakom källa
Lägg till källan bakom koden så att programmet fungerar som förväntat. Den bakomliggande källan innehåller:
- Obligatoriska
using
instruktioner förSpeech
namnrymderna ochSpeech.Dialog
. - En enkel implementering för att säkerställa mikrofonåtkomst, kabelansluten till en knapphanterare.
- Grundläggande användargränssnittshjälpare för att presentera meddelanden och fel i programmet.
- En landningsplats för initieringskodsökvägen.
- En hjälp för att spela upp text till tal (utan stöd för direktuppspelning).
- En tom knapphanterare för att börja lyssna.
Lägg till källan bakom koden enligt följande:
I Solution Explorer öppnar du källfilen
MainPage.xaml.cs
bakom koden (grupperad underMainPage.xaml
)Ersätt filens innehåll med följande kod:
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 } } }
Kommentar
Om du ser ett fel: "Typen "Objekt" definieras i en sammansättning som inte refereras till
- Rätt klient för din lösning.
- Välj Hantera NuGet-paket för lösning, välj Uppdateringar
- Om du ser Microsoft.NETCore.UniversalWindowsPlatform i uppdateringslistan uppdaterar du Microsoft.NETCore.UniversalWindowsPlatform till den senaste versionen
Lägg till följande kod i metodtexten i
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);
Ersätt strängarna
YourApplicationId
,YourSpeechSubscriptionKey
ochYourServiceRegion
med dina egna värden för din app, talnyckel och regionLägg till följande kodfragment i slutet av metodtexten i
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}"); };
Lägg till följande kodfragment i brödtexten för
ListenButton_ButtonClicked
metoden iMainPage
klassen// 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); }
I menyraden väljer du Spara alla filer>för att spara ändringarna
Prova nu
I menyraden väljer du Skapa>bygglösning för att skapa programmet. Koden ska kompileras utan fel.
Välj Felsök>Starta felsökning (eller tryck på F5) för att starta programmet. Fönstret helloworld visas.
Välj Aktivera mikrofon. Om begäran om åtkomstbehörighet visas väljer du Ja.
Välj Prata och tala en engelsk fras eller mening i enhetens mikrofon. Ditt tal överförs till direct line speech-kanalen och transkriberas till text, som visas i fönstret.