Краткое руководство. Создание пользовательского голосового помощника

В этом кратком руководстве вы будете использовать пакет SDK для службы "Речь" для создания пользовательского приложения голосового помощника, которое подключается к боту, который вы уже создали и настроили. Если необходимо создать бот, см. дополнительные сведения в исчерпывающем руководстве.

После выполнения нескольких предварительных требований подключение пользовательского интерфейса пользователя займет всего несколько шагов:

  • Создайте объект BotFrameworkConfig, содержащий ключ и регион подписки.
  • Создайте объект DialogServiceConnector, используя приведенный выше объект BotFrameworkConfig.
  • С помощью объекта DialogServiceConnector запустите процесс прослушивания для одного речевого фрагмента.
  • Проверьте возвращенный результат ActivityReceivedEventArgs.

Примечание

Пакет SDK службы "Речь" для C++, JavaScript, Objective-C, Python и Swift поддерживает пользовательские голосовые помощники, но здесь пока нет соответствующего руководства.

Вы можете просмотреть или скачать все примеры для пакета SDK службы "Речь" для C# на сайте GitHub.

Предварительные требования

Перед началом работы нужно сделать следующее:

Примечание

Ознакомьтесь со списком поддерживаемых регионов для голосовых помощников и убедитесь, что ваши ресурсы развернуты в одном из этих регионов.

Откройте проект в Visual Studio.

Сначала необходимо убедиться, что проект открыт в Visual Studio.

Добавление стандартного кода

Добавим код, который выступает в качестве основы для нашего проекта.

  1. Откройте MainPage.xaml в обозревателе решений.

  2. В представлении XAML конструктора замените все содержимое следующим фрагментом кода, который определяет элементарный пользовательский интерфейс:

    <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,0,10,0" Click="EnableMicrophone_ButtonClicked" 
                        Height="35"/>
                <Button x:Name="ListenButton" Content="Talk to your bot" 
                        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>
    

Конструктор обновляется для отображения пользовательского интерфейса приложения.

  1. В Обозревателе решений откройте исходный файл кода программной части MainPage.xaml.cs. (Он сгруппирован в MainPage.xaml.) Замените содержимое этого файла приведенным ниже, которое включает:
  • using инструкции для Speech и Speech.Dialog пространства имен

  • простая реализация доступа к микрофону с привязкой к обработчику кнопки;

  • базовые вспомогательные функции пользовательского интерфейса для представления сообщений и ошибок в приложении;

  • целевая точка для пути кода инициализации, который будет добавлен позже;

  • Вспомогатель для воспроизведения текста в речь (без поддержки потоковой передачи)

  • пустой обработчик кнопки воспроизведения, который будет заполнен позже.

    using Microsoft.CognitiveServices.Speech;
    using Microsoft.CognitiveServices.Speech.Audio;
    using Microsoft.CognitiveServices.Speech.Dialog;
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Text;
    using Windows.Foundation;
    using Windows.Storage.Streams;
    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
            }
        }
    }
    
  1. Добавьте следующий фрагмент кода в текст метода InitializeDialogServiceConnector. Этот код создает DialogServiceConnector с помощью сведений о подписке.

    // Create a BotFrameworkConfig by providing a Speech service subscription key
    // the botConfig.Language property is optional (default en-US)
    const string speechSubscriptionKey = "YourSpeechSubscriptionKey"; // Your subscription key
    const string region = "YourServiceRegion"; // Your subscription service region.
    
    var botConfig = BotFrameworkConfig.FromSubscription(speechSubscriptionKey, region);
    botConfig.Language = "en-US";
    connector = new DialogServiceConnector(botConfig);
    

    Примечание

    Ознакомьтесь со списком поддерживаемых регионов для голосовых помощников и убедитесь, что ваши ресурсы развернуты в одном из этих регионов.

    Примечание

    Для получения сведений о настройке бота см. документацию по Bot Framework для канала Direct Line Speech.

  2. Замените строки YourSpeechSubscriptionKey, и YourServiceRegion на собственные значения для вашей подписки на службу "Речь" и региона.

  3. Добавьте следующий фрагмент кода в конец текста метода InitializeDialogServiceConnector. Этот код настраивает обработчики событий, на которые полагается DialogServiceConnector для передачи информации о деятельности ботов, результатах распознавания речи и другой информации.

    // ActivityReceived is the main way your bot will communicate with the client 
    // and uses bot framework activities
    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}");
    };
    
  4. В текст метода ListenButton_ButtonClicked в классе MainPage добавьте следующее. Этот код настраивается DialogServiceConnector для прослушивания, так как вы уже установили конфигурацию и зарегистрировали обработчики событий.

    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 to your speech-enabled bot
        var listenTask = connector.ListenOnceAsync();
    
        // You can also send activities to your bot as JSON strings -- 
        // Microsoft.Bot.Schema can simplify this
        string speakActivity = 
            @"{""type"":""message"",""text"":""Greeting Message"", ""speak"":""Hello there!""}";
        await connector.SendActivityAsync(speakActivity);
    
    }
    catch (Exception ex)
    {
        NotifyUser($"Exception: {ex.ToString()}", NotifyType.ErrorMessage);
    }
    

Создание и запуск приложения

Теперь можно приступать к созданию приложения и проверке пользовательского голосового помощника, используя службу "Речь".

  1. В строке меню выберите Сборка>Построить решение, чтобы создать приложение. Теперь код должен компилироваться без ошибок.

  2. Выберите Отладка>Начать отладку(или нажмите клавишу F5), чтобы запустить приложение. Откроется окно helloworld.

    Пример приложения голосового помощника UWP на C# — краткое руководство

  3. Выберите Включить микрофон, а когда появится запрос на разрешение доступа, выберите Да.

    Запрос на разрешение доступа к микрофону

  4. Щелкните Talk to your bot (Разговор с ботом) и произнесите фразу или предложение на английском языке в микрофон устройства. Ваша речь передастся в канал "Речь Direct Line" и преобразуется в текст, который появится в том же окне.

Дальнейшие действия


Вы можете просмотреть или скачать все примеры для пакета SDK службы "Речь" для Java на сайте GitHub.

Выберите целевую среду

Предварительные требования

Перед началом работы нужно сделать следующее:

Примечание

Ознакомьтесь со списком поддерживаемых регионов для голосовых помощников и убедитесь, что ваши ресурсы развернуты в одном из этих регионов.

Создание и настройка проекта

Создайте проект Eclipse и установите пакет SDK для службы "Речь".

Кроме того, для включения ведения журнала обновите файл pom.xml, чтобы добавить следующие зависимости.

 <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-simple</artifactId>
     <version>1.7.5</version>
 </dependency>

Добавление примеров кода

  1. Выберите Файл>Создать>Класс, чтобы добавить пустой класс в проект Java.

  2. В окне New Java Class (Новый класс Java) введите speechsdk.quickstart в поле Пакет и Main в поле Имя.

    Снимок экрана окна

  3. Откройте только что созданный класс Main и замените содержимое файла Main.java следующим начальным кодом.

    package speechsdk.quickstart;
    
    import com.microsoft.cognitiveservices.speech.audio.AudioConfig;
    import com.microsoft.cognitiveservices.speech.audio.PullAudioOutputStream;
    import com.microsoft.cognitiveservices.speech.dialog.BotFrameworkConfig;
    import com.microsoft.cognitiveservices.speech.dialog.DialogServiceConnector;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.sound.sampled.AudioFormat;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.DataLine;
    import javax.sound.sampled.SourceDataLine;
    import java.io.InputStream;
    
    public class Main {
        final Logger log = LoggerFactory.getLogger(Main.class);
    
        public static void main(String[] args) {
            // New code will go here
        }
    
        private void playAudioStream(PullAudioOutputStream audio) {
            ActivityAudioStream stream = new ActivityAudioStream(audio);
            final ActivityAudioStream.ActivityAudioFormat audioFormat = stream.getActivityAudioFormat();
            final AudioFormat format = new AudioFormat(
                    AudioFormat.Encoding.PCM_SIGNED,
                    audioFormat.getSamplesPerSecond(),
                    audioFormat.getBitsPerSample(),
                    audioFormat.getChannels(),
                    audioFormat.getFrameSize(),
                    audioFormat.getSamplesPerSecond(),
                    false);
            try {
                int bufferSize = format.getFrameSize();
                final byte[] data = new byte[bufferSize];
    
                SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
                SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
                line.open(format);
    
                if (line != null) {
                    line.start();
                    int nBytesRead = 0;
                    while (nBytesRead != -1) {
                        nBytesRead = stream.read(data);
                        if (nBytesRead != -1) {
                            line.write(data, 0, nBytesRead);
                        }
                    }
                    line.drain();
                    line.stop();
                    line.close();
                }
                stream.close();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
  4. В методе main сначала настройте DialogServiceConfig и используйте его для создания экземпляра DialogServiceConnector. Этот экземпляр подключается к каналу "Речь Direct Line" для взаимодействия с ботом. Экземпляр AudioConfig также используется для указания источника звуковых входных данных. В этом примере микрофон по умолчанию используется с AudioConfig.fromDefaultMicrophoneInput().

    • Замените строку YourSubscriptionKey ключом ресурса службы "Речь", который можно получить на портале Azure.
    • Замените строку YourServiceRegion на регион, связанный с вашим ресурсом службы "Речь".

    Примечание

    Ознакомьтесь со списком поддерживаемых регионов для голосовых помощников и убедитесь, что ваши ресурсы развернуты в одном из этих регионов.

    final String subscriptionKey = "YourSubscriptionKey"; // Your subscription key
    final String region = "YourServiceRegion"; // Your speech subscription service region
    final BotFrameworkConfig botConfig = BotFrameworkConfig.fromSubscription(subscriptionKey, region);
    
    // Configure audio input from a microphone.
    final AudioConfig audioConfig = AudioConfig.fromDefaultMicrophoneInput();
    
    // Create a DialogServiceConnector instance.
    final DialogServiceConnector connector = new DialogServiceConnector(botConfig, audioConfig);
    
  5. Соединитель DialogServiceConnector использует несколько событий, чтобы сообщать о работе бота, результатах распознавания речи и других данных. Далее добавьте эти прослушиватели событий.

    // Recognizing will provide the intermediate recognized text while an audio stream is being processed.
    connector.recognizing.addEventListener((o, speechRecognitionResultEventArgs) -> {
        log.info("Recognizing speech event text: {}", speechRecognitionResultEventArgs.getResult().getText());
    });
    
    // Recognized will provide the final recognized text once audio capture is completed.
    connector.recognized.addEventListener((o, speechRecognitionResultEventArgs) -> {
        log.info("Recognized speech event reason text: {}", speechRecognitionResultEventArgs.getResult().getText());
    });
    
    // SessionStarted will notify when audio begins flowing to the service for a turn.
    connector.sessionStarted.addEventListener((o, sessionEventArgs) -> {
        log.info("Session Started event id: {} ", sessionEventArgs.getSessionId());
    });
    
    // SessionStopped will notify when a turn is complete and it's safe to begin listening again.
    connector.sessionStopped.addEventListener((o, sessionEventArgs) -> {
        log.info("Session stopped event id: {}", sessionEventArgs.getSessionId());
    });
    
    // Canceled will be signaled when a turn is aborted or experiences an error condition.
    connector.canceled.addEventListener((o, canceledEventArgs) -> {
        log.info("Canceled event details: {}", canceledEventArgs.getErrorDetails());
        connector.disconnectAsync();
    });
    
    // ActivityReceived is the main way your bot will communicate with the client and uses Bot Framework activities.
    connector.activityReceived.addEventListener((o, activityEventArgs) -> {
        final String act = activityEventArgs.getActivity().serialize();
            log.info("Received activity {} audio", activityEventArgs.hasAudio() ? "with" : "without");
            if (activityEventArgs.hasAudio()) {
                playAudioStream(activityEventArgs.getAudio());
            }
        });
    
  6. Подключите DialogServiceConnector к каналу "Речь Direct Line", вызвав метод connectAsync(). Чтобы протестировать свой бот, вы можете вызвать метод listenOnceAsync для отправки звуковых входных данных со своего микрофона. Вы можете также использовать метод sendActivityAsync для отправки пользовательского действия в виде сериализованной строки. Эти пользовательские действия могут предоставить дополнительные данные, которые ваш бот использует в разговоре.

    connector.connectAsync();
    // Start listening.
    System.out.println("Say something ...");
    connector.listenOnceAsync();
    
    // connector.sendActivityAsync(...)
    
  7. Сохраните изменения в файле Main.

  8. Чтобы поддержать воспроизведение ответа, добавьте дополнительный класс, который преобразовывает объект PullAudioOutputStream, возвращенный из API getAudio(), в InputStream для Java, чтобы упростить обработку. ActivityAudioStream — это специализированный класс, который обрабатывает аудиоотклик из канала "Речь Direct Line". Он предоставляет методы доступа для получения сведений о звуковом формате для обработки воспроизведения. Для этого выберитеFile (Файл)>New (Создать)>Class (Класс).

  9. В окне New Java Class (Новый класс Java) введите speechsdk.quickstart в поле Пакет и ActivityAudioStream — в поле Имя.

  10. Откройте только что созданный класс ActivityAudioStream и замените его содержимое следующим кодом.

    package com.speechsdk.quickstart;
    
    import com.microsoft.cognitiveservices.speech.audio.PullAudioOutputStream;
    
    import java.io.IOException;
    import java.io.InputStream;
    
     public final class ActivityAudioStream extends InputStream {
         /**
          * The number of samples played per second (16 kHz).
          */
         public static final long SAMPLE_RATE = 16000;
         /**
          * The number of bits in each sample of a sound that has this format (16 bits).
          */
         public static final int BITS_PER_SECOND = 16;
         /**
          * The number of audio channels in this format (1 for mono).
          */
         public static final int CHANNELS = 1;
         /**
          * The number of bytes in each frame of a sound that has this format (2).
          */
         public static final int FRAME_SIZE = 2;
    
         /**
          * Reads up to a specified maximum number of bytes of data from the audio
          * stream, putting them into the given byte array.
          *
          * @param b   the buffer into which the data is read
          * @param off the offset, from the beginning of array <code>b</code>, at which
          *            the data will be written
          * @param len the maximum number of bytes to read
          * @return the total number of bytes read into the buffer, or -1 if there
          * is no more data because the end of the stream has been reached
          */
         @Override
         public int read(byte[] b, int off, int len) {
             byte[] tempBuffer = new byte[len];
             int n = (int) this.pullStreamImpl.read(tempBuffer);
             for (int i = 0; i < n; i++) {
                 if (off + i > b.length) {
                     throw new ArrayIndexOutOfBoundsException(b.length);
                 }
                 b[off + i] = tempBuffer[i];
             }
             if (n == 0) {
                 return -1;
             }
             return n;
         }
    
         /**
          * Reads the next byte of data from the activity audio stream if available.
          *
          * @return the next byte of data, or -1 if the end of the stream is reached
          * @see #read(byte[], int, int)
          * @see #read(byte[])
          * @see #available
          * <p>
          */
         @Override
         public int read() {
             byte[] data = new byte[1];
             int temp = read(data);
             if (temp <= 0) {
                 // we have a weird situation if read(byte[]) returns 0!
                 return -1;
             }
             return data[0] & 0xFF;
         }
    
         /**
          * Reads up to a specified maximum number of bytes of data from the activity audio stream,
          * putting them into the given byte array.
          *
          * @param b the buffer into which the data is read
          * @return the total number of bytes read into the buffer, or -1 if there
          * is no more data because the end of the stream has been reached
          */
         @Override
         public int read(byte[] b) {
             int n = (int) pullStreamImpl.read(b);
             if (n == 0) {
                 return -1;
             }
             return n;
         }
    
         /**
          * Skips over and discards a specified number of bytes from this
          * audio input stream.
          *
          * @param n the requested number of bytes to be skipped
          * @return the actual number of bytes skipped
          * @throws IOException if an input or output error occurs
          * @see #read
          * @see #available
          */
         @Override
         public long skip(long n) {
             if (n <= 0) {
                 return 0;
             }
             if (n <= Integer.MAX_VALUE) {
                 byte[] tempBuffer = new byte[(int) n];
                 return read(tempBuffer);
             }
             long count = 0;
             for (long i = n; i > 0; i -= Integer.MAX_VALUE) {
                 int size = (int) Math.min(Integer.MAX_VALUE, i);
                 byte[] tempBuffer = new byte[size];
                 count += read(tempBuffer);
             }
             return count;
         }
    
         /**
          * Closes this audio input stream and releases any system resources associated
          * with the stream.
          */
         @Override
         public void close() {
             this.pullStreamImpl.close();
         }
    
         /**
          * Fetch the audio format for the ActivityAudioStream. The ActivityAudioFormat defines the sample rate, bits per sample, and the # channels.
          *
          * @return instance of the ActivityAudioFormat associated with the stream
          */
         public ActivityAudioStream.ActivityAudioFormat getActivityAudioFormat() {
             return activityAudioFormat;
         }
    
         /**
          * Returns the maximum number of bytes that can be read (or skipped over) from this
          * audio input stream without blocking.
          *
          * @return the number of bytes that can be read from this audio input stream without blocking.
          * As this implementation does not buffer, this will be defaulted to 0
          */
         @Override
         public int available() {
             return 0;
         }
    
         public ActivityAudioStream(final PullAudioOutputStream stream) {
             pullStreamImpl = stream;
             this.activityAudioFormat = new ActivityAudioStream.ActivityAudioFormat(SAMPLE_RATE, BITS_PER_SECOND, CHANNELS, FRAME_SIZE, AudioEncoding.PCM_SIGNED);
         }
    
         private PullAudioOutputStream pullStreamImpl;
    
         private ActivityAudioFormat activityAudioFormat;
    
         /**
          * ActivityAudioFormat is an internal format which contains metadata regarding the type of arrangement of
          * audio bits in this activity audio stream.
          */
         static class ActivityAudioFormat {
    
             private long samplesPerSecond;
             private int bitsPerSample;
             private int channels;
             private int frameSize;
             private AudioEncoding encoding;
    
             public ActivityAudioFormat(long samplesPerSecond, int bitsPerSample, int channels, int frameSize, AudioEncoding encoding) {
                 this.samplesPerSecond = samplesPerSecond;
                 this.bitsPerSample = bitsPerSample;
                 this.channels = channels;
                 this.encoding = encoding;
                 this.frameSize = frameSize;
             }
    
             /**
              * Fetch the number of samples played per second for the associated audio stream format.
              *
              * @return the number of samples played per second
              */
             public long getSamplesPerSecond() {
                 return samplesPerSecond;
             }
    
             /**
              * Fetch the number of bits in each sample of a sound that has this audio stream format.
              *
              * @return the number of bits per sample
              */
             public int getBitsPerSample() {
                 return bitsPerSample;
             }
    
             /**
              * Fetch the number of audio channels used by this audio stream format.
              *
              * @return the number of channels
              */
             public int getChannels() {
                 return channels;
             }
    
             /**
              * Fetch the default number of bytes in a frame required by this audio stream format.
              *
              * @return the number of bytes
              */
             public int getFrameSize() {
                 return frameSize;
             }
    
             /**
              * Fetch the audio encoding type associated with this audio stream format.
              *
              * @return the encoding associated
              */
             public AudioEncoding getEncoding() {
                 return encoding;
             }
         }
    
         /**
          * Enum defining the types of audio encoding supported by this stream.
          */
         public enum AudioEncoding {
             PCM_SIGNED("PCM_SIGNED");
    
             String value;
    
             AudioEncoding(String value) {
                 this.value = value;
             }
         }
     }
    
    
  11. Сохраните изменения в файле ActivityAudioStream.

Создание и запуск приложения

Нажмите клавишу F11 или выберите Запустить>Отладка. На консоли отобразится сообщение Say something (Скажите что-нибудь). В этот момент вы можете произнести на английском языке фразу или предложение, которое бот сможет распознать. Ваша речь передается боту через канал "Речь Direct Line", где она распознается и обрабатывается ботом. Ответ возвратится в качестве действия. Если ваш бот в качестве ответа возвращает речь, аудио воспроизводится с помощью класса AudioPlayer.

Снимок экрана выходных данных консоли после успешного распознавания

Дальнейшие действия

Вы можете просмотреть или скачать все примеры для пакета SDK службы "Речь" для Go на сайте GitHub.

Предварительные требования

Необходимые условия:

Примечание

Ознакомьтесь со списком поддерживаемых регионов для голосовых помощников и убедитесь, что ваши ресурсы развернуты в одном из этих регионов.

Настройка среды

Обновите файл go.mod, используя последнюю версию пакета SDK. Для этого добавьте следующую строку:

require (
    github.com/Microsoft/cognitive-services-speech-sdk-go v1.15.0
)

Добавление стандартного кода

Замените содержимое этого исходного файла (например, quickstart.go) следующим содержимым:

  • определение пакета main;
  • импорт необходимых модулей из пакета SDK службы "Речь";
  • переменные для хранения сведений о боте, которые будут заменены далее в этом кратком руководстве;
  • простая реализация с использованием микрофона для получения входных аудиоданных;
  • обработчики событий для различных событий, происходящих во время взаимодействия.
package main

import (
    "fmt"
    "time"

    "github.com/Microsoft/cognitive-services-speech-sdk-go/audio"
    "github.com/Microsoft/cognitive-services-speech-sdk-go/dialog"
    "github.com/Microsoft/cognitive-services-speech-sdk-go/speech"
)

func main() {
    subscription :=  "YOUR_SUBSCRIPTION_KEY"
    region := "YOUR_BOT_REGION"

    audioConfig, err := audio.NewAudioConfigFromDefaultMicrophoneInput()
    if err != nil {
        fmt.Println("Got an error: ", err)
        return
    }
    defer audioConfig.Close()
    config, err := dialog.NewBotFrameworkConfigFromSubscription(subscription, region)
    if err != nil {
        fmt.Println("Got an error: ", err)
        return
    }
    defer config.Close()
    connector, err := dialog.NewDialogServiceConnectorFromConfig(config, audioConfig)
    if err != nil {
        fmt.Println("Got an error: ", err)
        return
    }
    defer connector.Close()
    activityReceivedHandler := func(event dialog.ActivityReceivedEventArgs) {
        defer event.Close()
        fmt.Println("Received an activity.")
    }
    connector.ActivityReceived(activityReceivedHandler)
    recognizedHandle := func(event speech.SpeechRecognitionEventArgs) {
        defer event.Close()
        fmt.Println("Recognized ", event.Result.Text)
    }
    connector.Recognized(recognizedHandle)
    recognizingHandler := func(event speech.SpeechRecognitionEventArgs) {
        defer event.Close()
        fmt.Println("Recognizing ", event.Result.Text)
    }
    connector.Recognizing(recognizingHandler)
    connector.ListenOnceAsync()
    <-time.After(10 * time.Second)
}

Замените значения YOUR_SUBSCRIPTION_KEY и YOUR_BOT_REGION фактическими значениями из ресурса службы "Речь".

  • Перейдите на портал Azure и откройте раздел своего ресурса службы "Речь".

  • Выберите слева раздел Keys and Endpoint (Ключи и конечная точка). В нем вы увидите два ключа подписки.

    • Используйте один из них в качестве замены значения YOUR_SUBSCRIPTION_KEY.
  • Откройте слева раздел Обзор, запишите имя региона и сопоставьте его с идентификатором региона.

    • Используйте идентификатор региона для замены значения YOUR_BOT_REGION, например: "westus" для Западная часть США.

    Примечание

    Ознакомьтесь со списком поддерживаемых регионов для голосовых помощников и убедитесь, что ваши ресурсы развернуты в одном из этих регионов.

    Примечание

    Для получения сведений о настройке бота см. документацию по Bot Framework для канала Direct Line Speech.

Пояснение к коду

Для создания объекта конфигурации службы "Речь" нужно указать регион и ключ подписки службы "Речь". Объект конфигурации нужен для создания экземпляра объекта распознавателя речи.

Экземпляр распознавателя предоставляет несколько способов распознавания речи. В этом примере речь распознается непрерывно. Так служба "Речь" узнает, что для распознавания отправляется несколько фраз и что для остановки распознавания программа завершает работу. По мере получения результатов код будет записывать их в консоль.

Сборка и запуск

Теперь настройка для создания проекта и проверки пользовательского голосового помощника с помощью службы "Речь" выполнена.

  1. Выполнение сборки проекта, например go build
  2. Запустите модуль и произнесите фразу или предложение в микрофон устройства. Ваша речь передастся в канал "Речь Direct Line" и преобразуется в текст, который появится в качестве выходных данных.

Примечание

Пакет SDK для службы "Речь" по умолчанию распознает использование языкового стандарта en-us. Сведения о выборе исходного языка см. в разделе об изменении исходного языка.

Дальнейшие действия

Поддержка дополнительных языков и платформ

Если вы щелкнули эту вкладку, вы, вероятно, не увидели краткого руководства для предпочитаемого языка программирования. Не беспокойтесь. У нас есть дополнительные материалы по быстрому запуску и примеры кода, доступные на сайте GitHub. Используйте таблицу, чтобы найти правильный пример для своего сочетания языка программирования, платформы и ОС.

Язык Примеры кода
C# .NET Framework, .NET Core, UWP, Unity, Xamarin
C++ Windows, Linux, macOS
Java Android, JRE
JavaScript Браузер, Node.js
Objective-C iOS, macOS
Python Windows, Linux, macOS
Swift iOS, macOS