Compile SRGS Grammars
Compiling your XML grammar to a binary grammar file with the .cfg extension can reduce the time consumed by searches for a match, especially in grammars that require recognition of a large number of words and phrases.
The SrgsGrammarCompiler class contains three overloaded Compile() methods that compile a grammar to a binary grammar file with the .cfg extension. These methods can be used to:
Compile a dynamically-created grammar contained in an SrgsDocument instance , using Compile(SrgsDocument, Stream).
The first parameter represents the grammar to compile, and the second is a FileStream object that represents the location to which the compiled grammar will be written.
Compile an existing XML grammar, using Compile(String, Stream).
The first parameter represents the existing XML grammar to compile, and the second is a FileStream object that represents the location to which the compiled grammar will be written.
Compile an XmlReader grammar that can reside in memory or in physical file, using Compile(XmlReader, Stream).
The first parameter represents the XmlReader instance to compile, and the second is a FileStream object that represents the location to which the compiled grammar will be written.
Compile an SrgsDocument
The first example in the following group of four examples uses the Compile(SrgsDocument, Stream) method to compile an SrgsDocument instance. The other examples include an event handler for the SpeechRecognized event and helper methods that the first example calls to perform three tasks:
Create an SrgsDocument instance
Create a grammar
Compile the grammar
The grammar that is created in the CreateGrammar method recognizes phrases such as "I want to fly from Miami to Chicago." The two semantic values in the grammar are the departure city and the destination city. The semantic keys for these semantic values are "LeavingFrom" and "GoingTo."
Note
The SpeechRecognizer instance, sr, is declared outside this method.
private void Form1_Load(object sender, EventArgs e)
{
// Create an SrgsDocument instance and compile it.
SrgsDocument srgsDoc = new SrgsDocument();
srgsDoc = CreateGrammar();
CompileGrammar(srgsDoc, @"C:\test\AirportCodes.cfg");
Grammar g = new Grammar(@"C:\test\AirportCodes.cfg", "flightBooker");
// Load the grammar to the SpeechRecognitionEngine.
sr.LoadGrammar(g);
// Attach a handler for the SpeechRecognized event.
sr.SpeechRecognized +=
new EventHandler<SpeechRecognizedEventArgs>(sr_SpeechRecognized);
// Keep the console window open.
Console.ReadLine();
}
The following example is the handler for the SpeechRecognized event. This handler uses the semantic keys "LeavingFrom" and "GoingTo" as indexes into the e.Result.Semantics collection.
void sr_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
string recoString = e.Result.Text;
string departCity = e.Result.Semantics["LeavingFrom"].Value.ToString();
string arriveCity = e.Result.Semantics["GoingTo"].Value.ToString();
MessageBox.Show(String.Format("Recognized phrase: {0}\nDeparting from: {1}\nArriving at: {2}", recoString, departCity, arriveCity));
}
The following method is a helper whose job is to create the SrgsDocument instance, which makes up the bulk of the grammar used in this example. The SrgsDocument instance contains two rules whose identifiers are "flightBooker" and "cities". The rule named "cities" recognizes city names and returns the three-letter airport code for a recognized city. The "flightBooker" rule recognizes phrases of the form "I want to fly from <rule reference> to <rule reference>," where each rule reference points to the rule named "cities". The example uses SrgsSemanticInterpretationTag objects after the SrgsRuleRef objects in the "flightBooker" rule to assign semantic keys to the recognition result from the "cities" rule. The keys identify each city as the departure city or as the arrival city.
private SrgsDocument CreateGrammar()
{
SrgsDocument srgsDoc = new SrgsDocument();
// Create a rule for cities, assign a semantic value to each city.
SrgsRule cities = new SrgsRule("flightCities");
SrgsItem chi = new SrgsItem("Chicago");
chi.Add(new SrgsSemanticInterpretationTag("out = \"ORD\";"));
SrgsItem bos = new SrgsItem("Boston");
bos.Add(new SrgsSemanticInterpretationTag("out = \"BOS\";"));
SrgsItem mia = new SrgsItem("Miami");
mia.Add(new SrgsSemanticInterpretationTag("out = \"MIA\";"));
SrgsItem dal = new SrgsItem("Dallas");
dal.Add(new SrgsSemanticInterpretationTag("out = \"DFW\";"));
SrgsOneOf airports = new SrgsOneOf(chi, bos, mia, dal);
cities.Add(airports);
cities.Scope = SrgsRuleScope.Private;
// Create a rule reference to the rule for cities.
SrgsRuleRef cityRef = new SrgsRuleRef(cities);
// Create the root rule for the grammar.
SrgsRule bookFlight = new SrgsRule("flightBooker");
bookFlight.Add(new SrgsItem("I want to fly from"));
bookFlight.Add(cityRef);
bookFlight.Add(new SrgsSemanticInterpretationTag("out.LeavingFrom=rules.latest();"));
bookFlight.Add(new SrgsItem("to"));
bookFlight.Add(cityRef);
bookFlight.Add(new SrgsSemanticInterpretationTag("out.GoingTo=rules.latest();"));
bookFlight.Scope = SrgsRuleScope.Public;
// Add the rules to the SrgsDocument object and set the root rule.
srgsDoc.Rules.Add(cities);
srgsDoc.Rules.Add(bookFlight);
srgsDoc.Root = bookFlight;
// Write the completed grammar to an XML-format SRGS grammar file.
System.Xml.XmlWriter writer =
System.Xml.XmlWriter.Create("c:\\test\\AirportCodes.grxml");
srgsDoc.WriteSrgs(writer);
writer.Close();
return srgsDoc;
}
Note
See SrgsSemanticInterpretationTag for more information about specifying semantics for grammars authored programmatically using members of the System.Speech.Recognition.SrgsGrammar namespace.
The final example in this section is a helper method. It creates a new FileStream object, and then calls the static method Compile(SrgsDocument, Stream) to compile the grammar created in the call to the previous example, CreateGrammar.
private void CompileGrammar(SrgsDocument srgsDoc, string cfgPath)
{
FileStream fs = new FileStream(cfgPath, FileMode.Create);
SrgsGrammarCompiler.Compile(srgsDoc, (Stream)fs);
fs.Close();
}
Compile an XML Grammar in an External File
The Compile(String, Stream) method can be used to compile an existing grammar file that conforms to the Speech Recognition Grammar Specification (SRGS) Version 1.0.
The next example shows the SRGS grammar that is used as input in the C# example that follows it. The grammar recognizes sentences of the form "I want to fly from <starting city> to <destination city>." The semantic values returned by this grammar are the three-letter airport codes.
<?xml version="1.0" encoding="utf-8"?>
<grammar xml:lang="en-US" root="flightBooker"
tag-format="semantics/1.0" version="1.0"
xmlns="http://www.w3.org/2001/06/grammar">
<rule id="flightBooker" scope="public">
<item> I want to fly from </item>
<ruleref uri="#flightCities" />
<tag> out.LeavingFrom=rules.latest(); </tag>
<item> to </item>
<ruleref uri="#flightCities" />
<tag> out.GoingTo=rules.latest(); </tag>
</rule>
<rule id="flightCities" scope="private">
<one-of>
<item> Chicago <tag> out="ORD"; </tag></item>
<item> Boston <tag> out="BOS"; </tag></item>
<item> Miami <tag> out="MIA"; </tag></item>
<item> Dallas <tag> out="DFW"; </tag></item>
</one-of>
</rule>
</grammar>
Note
The example above uses tag elements to add semantic information to the grammar. For more information about using tag elements, see tag Element and Using the tag Element.
The following example compiles the XML grammar shown in the preceding example to a binary grammar file with the .cfg extension, sending the compiled version to the location specified by the fs parameter in the call to the Compile(String, Stream) method. After the binary grammar file is created, it is used to create and initialize the Grammar instance named gr. The binary grammar file is then loaded into the speech recognizer by a call to the LoadGrammar(Grammar) method.
Note
The SpeechRecognizer instance, sr, is declared outside this method.
private void Form1_Load(object sender, EventArgs e)
{
sr = new SpeechRecognizer();
string grammarPath = @"C:\test\";
FileStream fs = new FileStream(grammarPath + "AirportCodes.cfg", FileMode.Create);
SrgsGrammarCompiler.Compile(grammarPath + "AirportCodes.grxml", (Stream)fs);
fs.Close();
Grammar gr = new Grammar(grammarPath + "AirportCodes.cfg", "flightBooker");
sr.LoadGrammar(gr);
sr.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(sr_SpeechRecognized);
}
Compile an XmlReader Grammar
The third Compile(XmlReader, Stream) overloaded method takes an XmlReader object as its input and it is similar to the Compile(XmlReader, Stream) overloaded method that takes an XML file as input. The difference between these two overloaded methods is that the XmlReader can exist in memory or as an external file.
The following example shows the steps involved in using this Compile(XmlReader, Stream) overloaded method. The first step is to create a FileStream instance that identifies where the compiled binary grammar file will be written. Next, a XmlReader instance is created, using the static Create method on the XmlReader class. In this example, the XmlReader instance that is created comes from an XML grammar file named "AirportCodes.grxml." At this point, the contents of the XmlReader instance are compiled and sent to the location designated by the outputStream parameter, after which the FileStream instance is closed. Finally, a Grammar instance is created from the binary grammar file with the .cfg extension, and the grammar is loaded into the speech recognizer.
Note
The SpeechRecognizer instance, sr, is declared outside this method.
string grammarPath = @"C:\test\";
string xmlGrammar = grammarPath + "AirportCodes.grxml";
string cfgGrammar = grammarPath + "AirportCodes.cfg";
FileStream fs = new FileStream(cfgGrammar, FileMode.Create);
XmlReader reader = XmlReader.Create(xmlGrammar);
SrgsGrammarCompiler.Compile(reader, (Stream)fs);
fs.Close();
Grammar g = new Grammar(cfgGrammar, "flightBooker");
sr.LoadGrammar(g);