TOC

This article has been localized into Vietnamese by the community.

Audio & Video:

Nhận dạng giọng nói (làm cho WPF lắng nghe)

Trong bài viết trước, chúng tôi đã thảo luận về cách chúng tôi có thể chuyển đổi văn bản thành các từ được nói, bằng cách sử dụng lớp SpeechSynthesizer. Trong bài viết này, chúng ta sẽ đi theo một cách khác, bằng cách biến những từ được nói thành văn bản. Để làm điều đó, chúng tôi sẽ sử dụng lớp SpeechRecognition, nằm trong System.Speech. Thuộc tính này không phải là một thuộc tính của bạn theo mặc định, nhưng ta có thể dễ dàng thêm nó. Tùy thuộc vào phiên bản Visual Studio bạn sử dụng, quy trình này trông giống như thế này:

Bây giờ, hãy bắt đầu với một ví dụ nhận dạng giọng nói cực kỳ đơn giản:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionTextSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SpeechRecognitionTextSample" Height="200" Width="300">
    <DockPanel Margin="10">
        <TextBox Margin="0,10" Name="txtSpeech" AcceptsReturn="True" />
    </DockPanel>
</Window>
using System;
using System.Speech.Recognition;
using System.Windows;

namespace WpfTutorialSamples.Audio_and_Video
{
	public partial class SpeechRecognitionTextSample : Window
	{
		public SpeechRecognitionTextSample()
		{
			InitializeComponent();
			SpeechRecognizer speechRecognizer = new SpeechRecognizer();
		}
	}
}

Đây thực sự là tất cả những gì bạn cần - văn bản trong ảnh chụp màn hình ở trên được đọc qua tai nghe của tôi và sau đó được chèn vào điều khiển TextBox dưới dạng văn bản, thông qua việc sử dụng nhận dạng giọng nói.

Ngay khi bạn khởi tạo một đối tượng SpeechRecognizer, Windows sẽ khởi động ứng dụng nhận dạng giọng nói của nó, nó sẽ làm tất cả công việc khó khăn và sau đó gửi kết quả đến ứng dụng đang hoạt động, trong trường hợp này là của chúng tôi. Nó trông như thế này:

Nếu trước đây bạn chưa sử dụng nhận dạng giọng nói trên máy tính thì Windows sẽ đưa bạn qua một hướng dẫn sẽ giúp bạn bắt đầu và thực hiện một số điều chỉnh cần thiết.

Ví dụ đầu tiên này sẽ cho phép bạn đọc chính tả văn bản cho ứng dụng của bạn, điều này thật tuyệt, nhưng còn các lệnh thì sao? Windows và WPF sẽ thực sự hoạt động cùng nhau tại đây và biến các nút của bạn thành các lệnh, có thể truy cập thông qua lời nói mà không cần thêm bất kỳ công việc nào. Đây là một ví dụ:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionTextCommandsSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SpeechRecognitionTextCommandsSample" Height="200" Width="300">
    <DockPanel Margin="10">
        <WrapPanel DockPanel.Dock="Top">
            <Button Name="btnNew" Click="btnNew_Click">New</Button>
            <Button Name="btnOpen" Click="btnOpen_Click">Open</Button>
            <Button Name="btnSave" Click="btnSave_Click">Save</Button>
        </WrapPanel>
        <TextBox Margin="0,10" Name="txtSpeech" AcceptsReturn="True" TextWrapping="Wrap" />
    </DockPanel>
</Window>
using System;
using System.Speech.Recognition;
using System.Windows;

namespace WpfTutorialSamples.Audio_and_Video
{
	public partial class SpeechRecognitionTextCommandsSample : Window
	{
		public SpeechRecognitionTextCommandsSample()
		{
			InitializeComponent();
			SpeechRecognizer recognizer = new SpeechRecognizer();
		}

		private void btnNew_Click(object sender, RoutedEventArgs e)
		{
			txtSpeech.Text = "";
		}

		private void btnOpen_Click(object sender, RoutedEventArgs e)
		{
			MessageBox.Show("Command invoked: Open");
		}

		private void btnSave_Click(object sender, RoutedEventArgs e)
		{
			MessageBox.Show("Command invoked: Save");
		}
	}
}

Bạn có thể thử chạy ví dụ và sau đó nói ra một trong các lệnh, ví dụ: "New" hoặc "Open". Điều này thực sự cho phép bạn đưa văn bản vào TextBox, đồng thời gọi các lệnh từ giao diện người dùng - thực sự khá tuyệt!

Các lệnh cụ thể

Trong ví dụ trên, Windows sẽ tự động chuyển sang chế độ đọc chính tả ngay khi focus cho text box. Windows sau đó sẽ cố gắng phân biệt giữa chính tả và lệnh, nhưng điều này tất nhiên có thể khó khăn trong một số tình huống.

Vì vậy, trong khi các ví dụ trên đã tập trung vào chính tả và tương tác với các thành phần UI, ví dụ tiếp theo này sẽ chỉ tập trung vào khả năng lắng nghe và giải thích các lệnh cụ thể. Điều này cũng có nghĩa là việc đọc chính tả sẽ bị bỏ qua hoàn toàn, mặc dù các trường nhập văn bản có focus.

Với mục đích này, chúng tôi sẽ sử dụng lớp SpeechRecognitionEngine thay vì lớp SpeechRecognizer. Một sự khác biệt lớn giữa hai loại này là lớp SpeechRecognitionEngine không yêu cầu nhận dạng giọng nói Windows để chạy và sẽ không đưa bạn qua hướng dẫn nhận dạng giọng nói. Thay vào đó, nó sẽ sử dụng nhận dạng giọng nói cơ bản và chỉ nghe cho ngữ pháp mà bạn đưa vào.

Trong ví dụ tiếp theo, chúng ta sẽ đưa một nhóm lệnh vào công cụ nhận dạng. Ý tưởng là nó nên nghe hai từ: command/property và value, trong trường hợp này sẽ được sử dụng để thay đổi màu sắc, kích thước và trọng lượng của văn bản trong điều khiển Label, chỉ dựa trên lệnh thoại của bạn. Trước khi tôi chỉ cho bạn toàn bộ mẫu mã, tôi muốn tập trung vào cách chúng ta thêm các lệnh vào công cụ. Đây là code:

GrammarBuilder grammarBuilder = new GrammarBuilder();
Choices commandChoices = new Choices("weight", "color", "size");
grammarBuilder.Append(commandChoices);

Choices valueChoices = new Choices();
valueChoices.Add("normal", "bold");
valueChoices.Add("red", "green", "blue");
valueChoices.Add("small", "medium", "large");
grammarBuilder.Append(valueChoices);

speechRecognizer.LoadGrammar(new Grammar(grammarBuilder));

Chúng tôi sử dụng GrammarBuilder để xây dựng một bộ quy tắc ngữ pháp mà chúng tôi có thể tải vào SpeechRecognitionEngine. Nó có một số phương thức chắp thêm, với phương thức đơn giản nhất là Append(). Phương pháp này có một danh sách các lựa chọn. Chúng tôi tạo một cá thể Choices, với phần đầu tiên của hướng dẫn - command/property mà chúng tôi muốn truy cập. Các lựa chọn này được thêm vào trình xây dựng với phương thức Append().

Bây giờ, mỗi khi bạn gọi một phương thức thêm trên GrammarBuilder, bạn sẽ hướng dẫn nó nghe một từ. Trong trường hợp của chúng tôi, chúng tôi muốn nó nghe hai từ, vì vậy chúng tôi tạo ra một tập hợp các lựa chọn thứ cấp, sẽ giữ giá trị cho command/property được chỉ định. Chúng tôi thêm một phạm vi giá trị cho mỗi lệnh có thể - một bộ giá trị cho lệnh weight, một bộ giá trị cho lệnh color và một bộ giá trị cho lệnh size. Tất cả đều được thêm vào cùng một Choices và sau đó được thêm vào trình tạo.

Cuối cùng, chúng tôi tải nó vào đối tượng SpeechRecognitionEngine bằng cách gọi phương thức LoadGrammer(), lấy một thể hiện Grammar làm tham số - trong trường hợp này dựa trên thể hiện GrammarBuilder của chúng tôi.

Vì vậy, với lời giải thích đó, chúng ta hãy xem toàn bộ ví dụ:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionCommandsSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SpeechRecognitionCommandsSample" Height="200" Width="325"
        Closing="Window_Closing">
    <DockPanel>
        <WrapPanel DockPanel.Dock="Bottom" HorizontalAlignment="Center" Margin="0,10">
            <ToggleButton Name="btnToggleListening" Click="btnToggleListening_Click">Listen</ToggleButton>
        </WrapPanel>
        <Label Name="lblDemo" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48">Hello, world!</Label>
    </DockPanel>
</Window>
using System;
using System.Globalization;
using System.Speech.Recognition;
using System.Windows;
using System.Windows.Media;

namespace WpfTutorialSamples.Audio_and_Video
{
	public partial class SpeechRecognitionCommandsSample : Window
	{
		private SpeechRecognitionEngine speechRecognizer = new SpeechRecognitionEngine();

		public SpeechRecognitionCommandsSample()
		{
			InitializeComponent();
			speechRecognizer.SpeechRecognized += speechRecognizer_SpeechRecognized;

			GrammarBuilder grammarBuilder = new GrammarBuilder();
			Choices commandChoices = new Choices("weight", "color", "size");
			grammarBuilder.Append(commandChoices);

			Choices valueChoices = new Choices();
			valueChoices.Add("normal", "bold");
			valueChoices.Add("red", "green", "blue");
			valueChoices.Add("small", "medium", "large");
			grammarBuilder.Append(valueChoices);

			speechRecognizer.LoadGrammar(new Grammar(grammarBuilder));
			speechRecognizer.SetInputToDefaultAudioDevice();
		}

		private void btnToggleListening_Click(object sender, RoutedEventArgs e)
		{
			if(btnToggleListening.IsChecked == true)
				speechRecognizer.RecognizeAsync(RecognizeMode.Multiple);
			else
				speechRecognizer.RecognizeAsyncStop();
		}

		private void speechRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
		{
			lblDemo.Content = e.Result.Text;
			if(e.Result.Words.Count == 2)
			{
				string command = e.Result.Words[0].Text.ToLower();
				string value = e.Result.Words[1].Text.ToLower();
				switch(command)
				{
					case "weight":
						FontWeightConverter weightConverter = new FontWeightConverter();
						lblDemo.FontWeight = (FontWeight)weightConverter.ConvertFromString(value);
						break;
					case "color":
						lblDemo.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value));
						break;
					case "size":
						switch(value)
						{
							case "small":
								lblDemo.FontSize = 12;
								break;
							case "medium":
								lblDemo.FontSize = 24;
								break;
							case "large":
								lblDemo.FontSize = 48;
								break;
						}
						break;
				}
			}
		}

		private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			speechRecognizer.Dispose();
		}
	}
}

Trên ảnh chụp màn hình, bạn thấy ứng dụng kết quả, sau khi tôi đã sử dụng lệnh thoại "weight bold" và "color blue" - khá tuyệt phải không?

Các khía cạnh ngữ pháp của ví dụ đã được giải thích và giao diện rất đơn giản, vì vậy hãy tập trung vào phần còn lại của Code-behind.

Chúng tôi sử dụng ToggleButton để bật hoặc tắt nghe, sử dụng các phương thức RecognizeAsync() và RecognizeAsyncStop(). RecognizeAsync() nhận một tham số thông báo cho công cụ nhận biết nếu nó cần thực hiện một nhận dạng đơn hoặc nhiều nhận dạng. Ví dụ của chúng tôi, chúng tôi muốn đưa ra một số lệnh, vì vậy nhiều được sử dụng. Vì vậy, để cho phép nghe, chỉ cần nhấp vào nút và để tắt nó, chỉ cần nhấp lại vào nút đó. Trạng thái được thể hiện trực quan bằng nút, nút này sẽ "down" khi được bật và bình thường khi bị tắt.

Bây giờ, bên cạnh việc xây dựng Ngữ pháp, phần thú vị nhất là nơi chúng tôi diễn giải lệnh. Điều này được thực hiện trong sự kiện SpeechRecognized, mà chúng ta nối vào trong hàm tạo. Chúng tôi sử dụng văn bản được nhận dạng đầy đủ để cập nhật nhãn demo, để hiển thị lệnh mới nhất và sau đó chúng tôi sử dụng thuộc tính Words để đào sâu hơn vào lệnh thực tế.

Trước hết, chúng tôi kiểm tra xem nó có chính xác hai từ - command/property và value. Nếu đó là trường hợp, chúng tôi kiểm tra phần lệnh trước, và đối với mỗi lệnh có thể, chúng tôi xử lý giá trị tương ứng.

Đối với các lệnh trọng lượng và màu sắc, chúng ta có thể chuyển đổi giá trị thành thứ mà nhãn có thể hiểu tự động, bằng cách sử dụng trình chuyển đổi, nhưng đối với kích thước, chúng ta diễn giải các giá trị đã cho theo cách thủ công, vì các giá trị tôi đã chọn cho ví dụ này không thể là chuyển đổi tự động. Xin lưu ý rằng bạn nên xử lý các trường hợp ngoại lệ trong mọi trường hợp, vì một lệnh như "weight blue" sẽ cố gắng gán giá trị màu xanh cho Fontweight, điều này sẽ tự nhiên dẫn đến một ngoại lệ.

Tổng kết

Như bạn có thể hy vọng, nhận dạng giọng nói với WPF vừa dễ dàng vừa rất mạnh mẽ - đặc biệt là ví dụ cuối cùng sẽ cho bạn một ý tưởng hay, mạnh mẽ như thế nào! Với khả năng sử dụng chính tả(dictation) và/hoặc các lệnh thoại cụ thể, bạn thực sự có thể cung cấp các phương tiện tuyệt vời cho đầu vào thay thế trong các ứng dụng của mình.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!