Android 语音识别将数据传回 Xamarin Forms

Posted

技术标签:

【中文标题】Android 语音识别将数据传回 Xamarin Forms【英文标题】:Android speech recognition pass data back to Xamarin Forms 【发布时间】:2017-03-29 14:07:56 【问题描述】:

我现在真的卡住了,我对 Xamarin 很陌生。 我使用 Xamarin Forms 开发具有语音识别功能的应用程序。

我只创建了一个带有按钮和输入框的简单 UI。

工作:

按下按钮并显示带有语音识别的弹出窗口 将口语读入 var

不工作:

将数据传回 Xamarin Forms UI(条目)

StartPage.xaml.cs:

    private void BtnRecord_OnClicked(object sender, EventArgs e)
    
        WaitForSpeechToText();
     

    private async void WaitForSpeechToText()
    
        EntrySpeech.Text = await DependencyService.Get<Listener.ISpeechToText>().SpeechToTextAsync();
    

ISpeechToText.cs:

public interface ISpeechToText

    Task<string> SpeechToTextAsync();

调用本机代码。

SpeechToText_android.cs:

    public class SpeechToText_Android : ISpeechToText
    
    private const int VOICE = 10;

    public SpeechToText_Android()  

    public Task<string> SpeechToTextAsync()
    
        var tcs = new TaskCompletionSource<string>();

        try
        
            var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
            voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
            voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, "Sprechen Sie jetzt");
            voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1500);
            voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1500);
            voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 15000);
            voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
            voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);

            try
            
                ((Activity)Forms.Context).StartActivityForResult(voiceIntent, VOICE);

            
            catch (ActivityNotFoundException a)
            
                tcs.SetResult("Device doesn't support speech to text");
            
        
        catch (Exception ex)
        

            tcs.SetException(ex);
        

        return tcs.Task;
    

MainActivity.cs:

    protected override void OnActivityResult(int requestCode, Result resultVal, Intent data)
      
        if (requestCode == VOICE)
        
            if (resultVal == Result.Ok)
            
                var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
                if (matches.Count != 0)
                
                    string textInput = matches[0].ToString();
                    if (textInput.Length > 500)
                        textInput = textInput.Substring(0, 500);
                
                // RETURN 
            
        
        base.OnActivityResult(requestCode, resultVal, data);
    

首先我认为我可以通过

return tcs.Task;

回到 ui,但后来我注意到这个返回发生在 语音识别的弹出窗口已完成渲染。这一刻,一句话也没说。

口语在 OnActivityResult 函数中的字符串“textInput”中, 但是我怎样才能将此字符串传递回 Xamarin.Forms UI?

谢谢大家!

【问题讨论】:

SpeechToTextAsync 需要用 async 关键字标记。 【参考方案1】:

我会使用 AutoResetEvent 暂停返回,直到调用 OnActivityResult,直到用户记录某些内容、取消或您在 AutoResetEvent 中超时他们的操作。

从您的 SpeechToTextAsync 方法返回一个 Task&lt;string&gt;

public interface ISpeechToText

    Task<string> SpeechToTextAsync();

AutoResetEvent 添加到暂停执行:

注意:包裹AutoResetEvent.WaitOne以防止挂起应用程序循环

public class SpeechToText_Android : Listener.ISpeechToText

    public static AutoResetEvent autoEvent = new AutoResetEvent(false);
    public static string SpeechText;
    const int VOICE = 10;

    public async Task<string> SpeechToTextAsync()
    
        var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
        voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
        voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, "Sprechen Sie jetzt");
        voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1500);
        voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1500);
        voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 15000);
        voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
        voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);

        SpeechText = "";
        autoEvent.Reset();
        ((Activity)Forms.Context).StartActivityForResult(voiceIntent, VOICE);
        await Task.Run(() =>  autoEvent.WaitOne(new TimeSpan(0, 2, 0)); );
        return SpeechText;
    

MainActivity OnActivityResult:

    const int VOICE = 10;
    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    
        base.OnActivityResult(requestCode, resultCode, data);
        if (requestCode == VOICE)
        
            if (resultCode == Result.Ok)
            
                var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
                if (matches.Count != 0)
                
                    var textInput = matches[0];
                    if (textInput.Length > 500)
                        textInput = textInput.Substring(0, 500);
                    SpeechToText_Android.SpeechText = textInput;
                
            
            SpeechToText_Android.autoEvent.Set();
        
    

注意:这是使用几个静态变量来简化此示例的实现...有些开发人员会说这是代码异味,我半同意,但您不能拥有多个 Google语音识别器一次运行....

Hello World 示例:

public class App : Application

    public App()
    
        var speechTextLabel = new Label
        
            HorizontalTextAlignment = TextAlignment.Center,
            Text = "Waiting for text"
        ;

        var speechButton = new Button();
        speechButton.Text = "Fetch Speech To Text Results";
        speechButton.Clicked += async (object sender, EventArgs e) =>
        
            var speechText = await WaitForSpeechToText();
            speechTextLabel.Text = string.IsNullOrEmpty(speechText) ? "Nothing Recorded" : speechText;
        ;

        var content = new ContentPage
        
            Title = "Speech",
            Content = new StackLayout
            
                VerticalOptions = LayoutOptions.Center,
                Children = 
                    new Label 
                        HorizontalTextAlignment = TextAlignment.Center,
                        Text = "Welcome to Xamarin Forms!"
                    ,
                    speechButton,
                    speechTextLabel
                
            
        ;
        MainPage = new NavigationPage(content);
    

    async Task<string> WaitForSpeechToText()
    
        return await DependencyService.Get<Listener.ISpeechToText>().SpeechToTextAsync();
    

【讨论】:

非常感谢@SushiHangover!它就像一个魅力。如果我做对了,那么您创建了一个最多等待 2 分钟的线程(autoEvent)。它阻止函数的返回。然后你通过“autoEvent.Set()”发信号通知线程在你得到语音输入后继续,我做对了吗? @user3769192 完全正确,此方法有效,但并不完美....您可能会超时,而当您超时时,您将无法取消 Google 识别器。 “正确”方法是创建一个SpeechRecognizer(通过SpeechRecognizer.CreateSpeechRecognizer),构建您自己的用户界面,设置一个RecognitionListener作为您的回调,从而处理发送到的任何单词您的侦听器在另一个线程中可以取消/停止识别器,在超时或用户取消后,然后拆除您的自定义 UI .... 我尝试了使用 SpeechRecognizer 创建自己的界面的方式,但我认为我失败了。所以我决定回到标准实现。感谢您的解释和您的帮助! @SushiHangover 我可以与您联系以获取有关此主题的后续问题吗?

以上是关于Android 语音识别将数据传回 Xamarin Forms的主要内容,如果未能解决你的问题,请参考以下文章

图像识别将图像转换为android中的文本

语音识别不适用于 Android 5.1.1 Xamarin

关于语音识别的 Android 附加功能不起作用

语音识别以登录 Web 应用程序

深度学习角度 | 图像识别将何去何从?

通过 Xamarin 在 UWP 上使用文本转语音