Udostępnij za pośrednictwem


Rozpoznawanie mowy przy użyciu usługi Azure Speech Service

Azure Speech Service to oparty na chmurze interfejs API, który oferuje następujące funkcje:

  • Zamiana mowy na tekst transkrypuje pliki audio lub strumienie do tekstu.
  • Zamiana tekstu na mowę konwertuje tekst wejściowy na syntetyzowany mowę przypominającą człowieka.
  • Tłumaczenie mowy umożliwia tłumaczenie w czasie rzeczywistym w wielu językach zarówno dla zamiany mowy na tekst, jak i zamiany mowy na mowę.
  • Asystentzy głosowi mogą tworzyć interfejsy konwersacji przypominające człowieka dla aplikacji.

W tym artykule wyjaśniono, jak zaimplementowano mowę do tekstu w przykładowej Xamarin.Forms aplikacji przy użyciu usługi Azure Speech Service. Na poniższych zrzutach ekranu przedstawiono przykładową aplikację w systemach iOS i Android:

Zrzuty ekranu przykładowej aplikacji w systemach iOS i Android

Tworzenie zasobu usługi Azure Speech Service

Usługa Azure Speech Service jest częścią usług Azure Cognitive Services, która udostępnia oparte na chmurze interfejsy API dla zadań takich jak rozpoznawanie obrazów, rozpoznawanie mowy i tłumaczenie oraz wyszukiwanie Bing. Aby uzyskać więcej informacji, zobacz Co to są usługi Azure Cognitive Services?.

Przykładowy projekt wymaga utworzenia zasobu usług Azure Cognitive Services w witrynie Azure Portal. Zasób usług Cognitive Services można utworzyć dla jednej usługi, takiej jak usługa Mowa, lub jako zasób z wieloma usługami. Kroki tworzenia zasobu usługi Mowa są następujące:

  1. Zaloguj się do witryny Azure Portal.
  2. Utwórz zasób z wieloma usługami lub pojedynczą usługą.
  3. Uzyskaj informacje o kluczu interfejsu API i regionie zasobu.
  4. Zaktualizuj przykładowy plik Constants.cs .

Aby zapoznać się z przewodnikiem krok po kroku dotyczącym tworzenia zasobu, zobacz Tworzenie zasobu usług Cognitive Services.

Uwaga

Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto. Po utworzeniu konta można utworzyć zasób z jedną usługą w warstwie Bezpłatna, aby wypróbować usługę.

Konfigurowanie aplikacji za pomocą usługi Mowa

Po utworzeniu zasobu usług Cognitive Services plik Constants.cs można zaktualizować przy użyciu regionu i klucza interfejsu API z zasobu platformy Azure:

public static class Constants
{
    public static string CognitiveServicesApiKey = "YOUR_KEY_GOES_HERE";
    public static string CognitiveServicesRegion = "westus";
}

Instalowanie pakietu usługi Rozpoznawanie mowy NuGet

Przykładowa aplikacja używa pakietu NuGet Microsoft.CognitiveServices.Speech w celu nawiązania połączenia z usługą Azure Speech Service. Zainstaluj ten pakiet NuGet w udostępnionym projekcie i każdym projekcie platformy.

Tworzenie interfejsu IMicrophoneService

Każda platforma wymaga uprawnień dostępu do mikrofonu. Przykładowy projekt udostępnia IMicrophoneService interfejs w udostępnionym projekcie i używa go Xamarin.FormsDependencyService do uzyskiwania implementacji platformy interfejsu.

public interface IMicrophoneService
{
    Task<bool> GetPermissionAsync();
    void OnRequestPermissionResult(bool isGranted);
}

Tworzenie układu strony

Przykładowy projekt definiuje podstawowy układ strony w pliku MainPage.xaml . Kluczowe elementy układu to element Button , który rozpoczyna proces transkrypcji, element do Label zawierania transkrypcji tekstu i do ActivityIndicator pokazania, gdy transkrypcja jest w toku:

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

Implementowanie usługi Mowa

Plik MainPage.xaml.cs zawierający całą logikę wysyłania dźwięku i odbierania transkrypcji tekstu z usługi Azure Speech Service.

Konstruktor MainPage pobiera wystąpienie interfejsu IMicrophoneService z elementu DependencyService:

public partial class MainPage : ContentPage
{
    SpeechRecognizer recognizer;
    IMicrophoneService micService;
    bool isTranscribing = false;

    public MainPage()
    {
        InitializeComponent();

        micService = DependencyService.Resolve<IMicrophoneService>();
    }

    // ...
}

Metoda jest wywoływana TranscribeClicked po naciśnięciu transcribeButton wystąpienia:

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();
}

Metoda TranscribeClicked wykonuje następujące czynności:

  1. Sprawdza, czy aplikacja ma dostęp do mikrofonu i kończy się wcześnie, jeśli nie.
  2. Tworzy wystąpienie SpeechRecognizer klasy, jeśli jeszcze nie istnieje.
  3. Zatrzymuje ciągłą transkrypcję, jeśli jest w toku.
  4. Wstawia znacznik czasu i uruchamia ciągłą transkrypcję, jeśli nie jest w toku.
  5. Powiadamia aplikację o zaktualizowaniu wyglądu na podstawie stanu nowej aplikacji.

Pozostała część MainPage metod klasy to pomocnicy wyświetlania stanu aplikacji:

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

Metoda UpdateTranscription zapisuje podany newTextstring element w elemecie Label o nazwie transcribedText. Wymusza to, aby ta aktualizacja miała miejsce w wątku interfejsu użytkownika, dzięki czemu może być wywoływana z dowolnego kontekstu bez powodowania wyjątków. Zapisuje InsertDateTimeRecord bieżącą datę i godzinę transcribedText wystąpienia, aby oznaczyć początek nowej transkrypcji. Na koniec metoda aktualizuje Button elementy i ActivityIndicator w celu odzwierciedlenia, UpdateDisplayState czy transkrypcja jest w toku.

Tworzenie usług mikrofonu platformy

Aplikacja musi mieć dostęp do mikrofonu w celu zbierania danych mowy. Interfejs IMicrophoneService należy zaimplementować i zarejestrować DependencyService na każdej platformie, aby aplikacja działała.

Android

Przykładowy projekt definiuje implementację IMicrophoneService dla systemu Android o nazwie 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);
            }
        }
    }
}

Ma AndroidMicrophoneService następujące funkcje:

  1. Atrybut Dependency rejestruje klasę za pomocą klasy DependencyService.
  2. Metoda GetPermissionAsync sprawdza, czy uprawnienia są wymagane w oparciu o wersję zestawu Android SDK, i wywołuje RequestMicPermissions metodę , jeśli nie udzielono jeszcze uprawnień.
  3. Metoda RequestMicPermissions używa Snackbar klasy do żądania uprawnień od użytkownika, jeśli wymagane jest uzasadnienie, w przeciwnym razie bezpośrednio żąda uprawnień do nagrywania dźwięku.
  4. Metoda jest wywoływana OnRequestPermissionResult z bool wynikiem, gdy użytkownik odpowiedział na żądanie uprawnień.

Klasa MainActivity jest dostosowywana do aktualizowania wystąpienia po zakończeniu AndroidMicrophoneService żądań uprawnień:

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

Klasa MainActivity definiuje statyczne odwołanie o nazwie Instance, które jest wymagane przez AndroidMicrophoneService obiekt podczas żądania uprawnień. Zastępuje metodę OnRequestPermissionsResult w celu zaktualizowania AndroidMicrophoneService obiektu, gdy żądanie uprawnień zostanie zatwierdzone lub odrzucone przez użytkownika.

Na koniec aplikacja systemu Android musi zawierać uprawnienia do rejestrowania dźwięku w pliku AndroidManifest.xml :

<manifest ...>
    ...
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>

iOS

Przykładowy projekt definiuje implementację IMicrophoneService dla systemu iOS o nazwie 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);
            });
        }
    }
}

Ma iOSMicrophoneService następujące funkcje:

  1. Atrybut Dependency rejestruje klasę za pomocą klasy DependencyService.
  2. Metoda GetPermissionAsync wywołuje RequestMicPermissions żądanie uprawnień od użytkownika urządzenia.
  3. Metoda RequestMicPermissions używa udostępnionego AVAudioSession wystąpienia do żądania uprawnień rejestrowania.
  4. Metoda OnRequestPermissionResult aktualizuje TaskCompletionSource wystąpienie przy użyciu podanej bool wartości.

Na koniec aplikacja systemu iOS Info.plist musi zawierać komunikat informujący użytkownika, dlaczego aplikacja żąda dostępu do mikrofonu. Edytuj plik Info.plist, aby uwzględnić następujące tagi w elemecie <dict> :

<plist>
    <dict>
        ...
        <key>NSMicrophoneUsageDescription</key>
        <string>Voice transcription requires microphone access</string>
    </dict>
</plist>

Platforma UWP

Przykładowy projekt definiuje implementację IMicrophoneService platformy UWP o nazwie 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
        }
    }
}

Ma UWPMicrophoneService następujące funkcje:

  1. Atrybut Dependency rejestruje klasę za pomocą klasy DependencyService.
  2. Metoda GetPermissionAsync próbuje zainicjować MediaCapture wystąpienie. Jeśli to się nie powiedzie, uruchomi żądanie użytkownika, aby włączyć mikrofon.
  3. Metoda OnRequestPermissionResult istnieje, aby spełnić wymagania interfejsu, ale nie jest wymagana do implementacji platformy UWP.

Na koniec pakiet.appxmanifest platformy UWP musi określić, że aplikacja używa mikrofonu. Kliknij dwukrotnie plik Package.appxmanifest i wybierz opcję Mikrofon na karcie Możliwości w programie Visual Studio 2019:

Zrzut ekranu przedstawiający manifest w programie Visual Studio 2019

Testowanie aplikacji

Uruchom aplikację i kliknij przycisk Transkrypcja . Aplikacja powinna zażądać dostępu do mikrofonu i rozpocząć proces transkrypcji. Animuje ActivityIndicator , pokazując, że transkrypcja jest aktywna. Jak mówisz, aplikacja będzie przesyłać strumieniowo dane audio do zasobu usług Azure Speech Services, który odpowie za pomocą transkrypcji tekstu. Transkrypowany tekst pojawi się w elemecie w miarę Label odbierania.

Uwaga

Nie można załadować emulatorów systemu Android i zainicjować bibliotek usługi Mowa. Testowanie na urządzeniu fizycznym jest zalecane dla platformy Android.