Распознавание речи с помощью служб речи Azure
Служба "Речь Azure" — это облачный API, который предлагает следующие функции:
- Преобразование аудиофайлов или потоков в текст речи в текст.
- Текст в речь преобразует входной текст в синтезированную речь человека.
- Перевод речи обеспечивает перевод речи в режиме реального времени, многоязычный перевод для преобразования речи в текст и речь.
- Голосовые помощники могут создавать человеческую беседу для приложений.
В этой статье объясняется, как речь в тексте реализована в примере Xamarin.Forms приложения с помощью службы "Речь Azure". На следующих снимках экрана показан пример приложения на iOS и Android:
Создание ресурса службы "Речь Azure"
Служба "Речь Azure" является частью Azure Cognitive Services, которая предоставляет облачные API для таких задач, как распознавание изображений, распознавание речи и перевод, а также поиск Bing. Дополнительные сведения см. в статье "Что такое Azure Cognitive Services?".
Пример проекта требует создания ресурса Azure Cognitive Services в портал Azure. Ресурс Cognitive Services можно создать для одной службы, например службы "Речь" или в качестве ресурса с несколькими службами. Ниже приведены действия по созданию ресурса службы распознавания речи.
- Войдите в портал Azure.
- Создайте ресурс с несколькими службами или одиночными службами.
- Получите сведения о ключе API и регионе для ресурса.
- Обновите пример файла Constants.cs .
Пошаговое руководство по созданию ресурса см. в разделе "Создание ресурса Cognitive Services".
Примечание.
Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начать работу. После получения учетной записи можно создать ресурс с одним обслуживанием на бесплатном уровне, чтобы попробовать службу.
Настройка приложения с помощью службы "Речь"
После создания ресурса Cognitive Services файл Constants.cs можно обновить с помощью региона и ключа API из ресурса Azure:
public static class Constants
{
public static string CognitiveServicesApiKey = "YOUR_KEY_GOES_HERE";
public static string CognitiveServicesRegion = "westus";
}
Установка пакета службы "Речь NuGet"
Пример приложения использует пакет NuGet Microsoft.CognitiveServices.Speech для подключения к службе "Речь Azure". Установите этот пакет NuGet в общем проекте и каждом проекте платформы.
Создание интерфейса IMicrophoneService
Для каждой платформы требуется разрешение на доступ к микрофону. Пример проекта предоставляет IMicrophoneService
интерфейс в общем проекте и использует Xamarin.FormsDependencyService
для получения реализаций платформы интерфейса.
public interface IMicrophoneService
{
Task<bool> GetPermissionAsync();
void OnRequestPermissionResult(bool isGranted);
}
Создание макета страницы
Пример проекта определяет базовый макет страницы в файле MainPage.xaml . Элементы макета ключей — это Button
процесс транскрибирования, Label
содержащий транскрибируемый текст, а ActivityIndicator
также отображаемое при выполнении транскрибирования:
<ContentPage ...>
<StackLayout>
<Frame ...>
<ScrollView x:Name="scroll"
...>
<Label x:Name="transcribedText"
... />
</ScrollView>
</Frame>
<ActivityIndicator x:Name="transcribingIndicator"
IsRunning="False" />
<Button x:Name="transcribeButton"
...
Clicked="TranscribeClicked"/>
</StackLayout>
</ContentPage>
Реализация службы "Речь"
Файл кода MainPage.xaml.cs содержит всю логику для отправки звука и получения транскрибированного текста из службы распознавания речи Azure.
Конструктор MainPage
получает экземпляр IMicrophoneService
интерфейса из DependencyService
:
public partial class MainPage : ContentPage
{
SpeechRecognizer recognizer;
IMicrophoneService micService;
bool isTranscribing = false;
public MainPage()
{
InitializeComponent();
micService = DependencyService.Resolve<IMicrophoneService>();
}
// ...
}
Метод TranscribeClicked
вызывается при нажатии экземпляра transcribeButton
:
async void TranscribeClicked(object sender, EventArgs e)
{
bool isMicEnabled = await micService.GetPermissionAsync();
// EARLY OUT: make sure mic is accessible
if (!isMicEnabled)
{
UpdateTranscription("Please grant access to the microphone!");
return;
}
// initialize speech recognizer
if (recognizer == null)
{
var config = SpeechConfig.FromSubscription(Constants.CognitiveServicesApiKey, Constants.CognitiveServicesRegion);
recognizer = new SpeechRecognizer(config);
recognizer.Recognized += (obj, args) =>
{
UpdateTranscription(args.Result.Text);
};
}
// if already transcribing, stop speech recognizer
if (isTranscribing)
{
try
{
await recognizer.StopContinuousRecognitionAsync();
}
catch(Exception ex)
{
UpdateTranscription(ex.Message);
}
isTranscribing = false;
}
// if not transcribing, start speech recognizer
else
{
Device.BeginInvokeOnMainThread(() =>
{
InsertDateTimeRecord();
});
try
{
await recognizer.StartContinuousRecognitionAsync();
}
catch(Exception ex)
{
UpdateTranscription(ex.Message);
}
isTranscribing = true;
}
UpdateDisplayState();
}
Метод TranscribeClicked
выполняет следующие действия:
- Проверяет, имеет ли приложение доступ к микрофону и завершает работу рано, если это не так.
- Создает экземпляр класса,
SpeechRecognizer
если он еще не существует. - Останавливает непрерывное транскрибирование, если оно выполняется.
- Вставляет метку времени и запускает непрерывную транскрибирование, если она не выполняется.
- Уведомляет приложение об обновлении внешнего вида на основе нового состояния приложения.
Остальные MainPage
методы класса являются вспомогательными средствами для отображения состояния приложения:
void UpdateTranscription(string newText)
{
Device.BeginInvokeOnMainThread(() =>
{
if (!string.IsNullOrWhiteSpace(newText))
{
transcribedText.Text += $"{newText}\n";
}
});
}
void InsertDateTimeRecord()
{
var msg = $"=================\n{DateTime.Now.ToString()}\n=================";
UpdateTranscription(msg);
}
void UpdateDisplayState()
{
Device.BeginInvokeOnMainThread(() =>
{
if (isTranscribing)
{
transcribeButton.Text = "Stop";
transcribeButton.BackgroundColor = Color.Red;
transcribingIndicator.IsRunning = true;
}
else
{
transcribeButton.Text = "Transcribe";
transcribeButton.BackgroundColor = Color.Green;
transcribingIndicator.IsRunning = false;
}
});
}
Метод UpdateTranscription
записывает предоставленный Label
newText
string
элемент с именем.transcribedText
Это заставляет это обновление выполняться в потоке пользовательского интерфейса, чтобы его можно было вызывать из любого контекста, не вызывая исключений. Записывает InsertDateTimeRecord
текущую дату и время transcribedText
в экземпляр, чтобы пометить начало нового транскрибирования. Наконец, UpdateDisplayState
метод обновляет Button
и ActivityIndicator
элементы, чтобы отразить, выполняется ли транскрибирование.
Создание служб микрофона платформы
Приложение должно иметь доступ к микрофону для сбора речевых данных. Интерфейс IMicrophoneService
должен быть реализован и зарегистрирован на каждой DependencyService
платформе для работы приложения.
Android
Пример проекта определяет реализацию IMicrophoneService
для Android с именем AndroidMicrophoneService
:
[assembly: Dependency(typeof(AndroidMicrophoneService))]
namespace CognitiveSpeechService.Droid.Services
{
public class AndroidMicrophoneService : IMicrophoneService
{
public const int RecordAudioPermissionCode = 1;
private TaskCompletionSource<bool> tcsPermissions;
string[] permissions = new string[] { Manifest.Permission.RecordAudio };
public Task<bool> GetPermissionAsync()
{
tcsPermissions = new TaskCompletionSource<bool>();
if ((int)Build.VERSION.SdkInt < 23)
{
tcsPermissions.TrySetResult(true);
}
else
{
var currentActivity = MainActivity.Instance;
if (ActivityCompat.CheckSelfPermission(currentActivity, Manifest.Permission.RecordAudio) != (int)Permission.Granted)
{
RequestMicPermissions();
}
else
{
tcsPermissions.TrySetResult(true);
}
}
return tcsPermissions.Task;
}
public void OnRequestPermissionResult(bool isGranted)
{
tcsPermissions.TrySetResult(isGranted);
}
void RequestMicPermissions()
{
if (ActivityCompat.ShouldShowRequestPermissionRationale(MainActivity.Instance, Manifest.Permission.RecordAudio))
{
Snackbar.Make(MainActivity.Instance.FindViewById(Android.Resource.Id.Content),
"Microphone permissions are required for speech transcription!",
Snackbar.LengthIndefinite)
.SetAction("Ok", v =>
{
((Activity)MainActivity.Instance).RequestPermissions(permissions, RecordAudioPermissionCode);
})
.Show();
}
else
{
ActivityCompat.RequestPermissions((Activity)MainActivity.Instance, permissions, RecordAudioPermissionCode);
}
}
}
}
У AndroidMicrophoneService
него есть следующие функции:
- Атрибут
Dependency
регистрирует класс сDependencyService
помощью . - Метод
GetPermissionAsync
проверяет, требуются ли разрешения на основе версии пакета SDK для Android, и вызываетсяRequestMicPermissions
, если разрешение еще не было предоставлено. - Метод
RequestMicPermissions
используетSnackbar
класс для запроса разрешений от пользователя, если требуется обоснование, в противном случае он напрямую запрашивает разрешения записи звука. - Метод
OnRequestPermissionResult
вызывается с результатомbool
после того, как пользователь ответил на запрос разрешений.
Класс MainActivity
настраивается для обновления экземпляра AndroidMicrophoneService
при завершении запросов разрешений:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
IMicrophoneService micService;
internal static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
Instance = this;
// ...
micService = DependencyService.Resolve<IMicrophoneService>();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
// ...
switch(requestCode)
{
case AndroidMicrophoneService.RecordAudioPermissionCode:
if (grantResults[0] == Permission.Granted)
{
micService.OnRequestPermissionResult(true);
}
else
{
micService.OnRequestPermissionResult(false);
}
break;
}
}
}
Класс MainActivity
определяет статическую ссылку Instance
, которая требуется AndroidMicrophoneService
объектом при запросе разрешений. Он переопределяет OnRequestPermissionsResult
метод для обновления AndroidMicrophoneService
объекта, когда запрос разрешений утвержден или отклонен пользователем.
Наконец, приложение Android должно включать разрешение на запись звука в файл AndroidManifest.xml :
<manifest ...>
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>
iOS
Пример проекта определяет реализацию IMicrophoneService
для iOS с именем iOSMicrophoneService
:
[assembly: Dependency(typeof(iOSMicrophoneService))]
namespace CognitiveSpeechService.iOS.Services
{
public class iOSMicrophoneService : IMicrophoneService
{
TaskCompletionSource<bool> tcsPermissions;
public Task<bool> GetPermissionAsync()
{
tcsPermissions = new TaskCompletionSource<bool>();
RequestMicPermission();
return tcsPermissions.Task;
}
public void OnRequestPermissionResult(bool isGranted)
{
tcsPermissions.TrySetResult(isGranted);
}
void RequestMicPermission()
{
var session = AVAudioSession.SharedInstance();
session.RequestRecordPermission((granted) =>
{
tcsPermissions.TrySetResult(granted);
});
}
}
}
У iOSMicrophoneService
него есть следующие функции:
- Атрибут
Dependency
регистрирует класс сDependencyService
помощью . - Метод
GetPermissionAsync
вызываетRequestMicPermissions
запрос разрешений от пользователя устройства. - Метод
RequestMicPermissions
использует общийAVAudioSession
экземпляр для запроса разрешений записи. - Метод
OnRequestPermissionResult
обновляетTaskCompletionSource
экземпляр указанным значениемbool
.
Наконец, приложение iOS Info.plist должно содержать сообщение, которое сообщает пользователю, почему приложение запрашивает доступ к микрофону. Измените файл Info.plist, чтобы включить в элемент следующие теги <dict>
:
<plist>
<dict>
...
<key>NSMicrophoneUsageDescription</key>
<string>Voice transcription requires microphone access</string>
</dict>
</plist>
UWP
Пример проекта определяет реализацию IMicrophoneService
для UWP с именем UWPMicrophoneService
:
[assembly: Dependency(typeof(UWPMicrophoneService))]
namespace CognitiveSpeechService.UWP.Services
{
public class UWPMicrophoneService : IMicrophoneService
{
public async Task<bool> GetPermissionAsync()
{
bool isMicAvailable = true;
try
{
var mediaCapture = new MediaCapture();
var settings = new MediaCaptureInitializationSettings();
settings.StreamingCaptureMode = StreamingCaptureMode.Audio;
await mediaCapture.InitializeAsync(settings);
}
catch(Exception ex)
{
isMicAvailable = false;
}
if(!isMicAvailable)
{
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-microphone"));
}
return isMicAvailable;
}
public void OnRequestPermissionResult(bool isGranted)
{
// intentionally does nothing
}
}
}
У UWPMicrophoneService
него есть следующие функции:
- Атрибут
Dependency
регистрирует класс сDependencyService
помощью . - Метод
GetPermissionAsync
пытается инициализироватьMediaCapture
экземпляр. Если это не удается, он запускает запрос пользователя для включения микрофона. - Метод
OnRequestPermissionResult
существует для удовлетворения интерфейса, но не требуется для реализации UWP.
Наконец, пакет UWP Package.appxmanifest должен указать, что приложение использует микрофон. Дважды щелкните файл Package.appxmanifest и выберите параметр микрофона на вкладке "Возможности " в Visual Studio 2019:
Тестирование приложения
Запустите приложение и нажмите кнопку Transcribe . Приложение должно запросить доступ к микрофону и начать процесс транскрибирования. Будет ActivityIndicator
анимация, показывающая, что транскрибирование активно. Когда вы говорите, приложение будет передавать звуковые данные в ресурс Служб распознавания речи Azure, который будет отвечать на транскрибированные тексты. Транскрибированные текст будут отображаться в элементе Label
по мере получения.
Примечание.
Эмуляторы Android не загружают и инициализируют библиотеки службы "Речь". Тестирование на физическом устройстве рекомендуется для платформы Android.