Skip to content

Instantly share code, notes, and snippets.

Created December 23, 2014 10:43
Show Gist options
  • Save thinkbeforecoding/37ae152c6fe24a649d86 to your computer and use it in GitHub Desktop.
Save thinkbeforecoding/37ae152c6fe24a649d86 to your computer and use it in GitHub Desktop.
Speaking computers for more fun !
(**# Speaking computers for more fun !
*I didn't try it on mono, but it should also work with some tweaking, see details [here](*
Xmas is a good time to surprise kids, and what's more fun than a talking computer ?!
## Hello world !
Nothing's easier, and this kind of Hello World will appeal them to programming in a flash :
#r "System.Speech"
open System.Speech.Synthesis
let synt = new SpeechSynthesizer()
let say s = synt.Speak(s: string)
say "Hello world !"
(** Of course, if you're french like me, it'll say this with an awful french accent - something
like **hélo ouorld** !
But you can select a different voice if available by providing hints:
open System.Globalization
let english = CultureInfo.GetCultureInfo("en-US")
synt.SelectVoiceByHints(VoiceGender.NotSet, VoiceAge.NotSet, 1, english)
say "Hello world !"
(** Far better !
## Can you beat it ?
Now, a talking fizz buzz, up to 100 ! Can you beat it ?
[1 .. 100]
|> (fun n ->
match n%3, n%5 with
| 0, 0 -> "FizzBuzz"
| 0, _ -> "Fizz"
| _, 0 -> "Buzz"
| _ -> string n )
|> List.iter say
## Even harder !
Now with a recognizer, we can wait for voice user input.
The problem with the Grammar API is that it's totally mutable and not really DSL oriented.
Let's correct that :
open System.Speech.Recognition
type Grammar =
| Phrase of text:string * result: string
| Lst of Grammar list
| Alt of Grammar list
| Repeat of min: int * max: int * Grammar
let rec build = function
| Phrase (text, result) ->
// Just build the a single phrase
| Lst grammars ->
// Append parts of grammars one after the other
let builder = GrammarBuilder()
|> build
|> List.iter builder.Append
| Alt alternatives ->
// Create alternatives
let choices =
|> build
|> List.toArray
| Repeat(min, max, grammar) ->
// Repeat a part of the grammar
GrammarBuilder(build grammar, min, max)
This is not a full DSL for speach recognition, you can look at all the GrammarBuilder methods
to add more possibilities.. Even here, I'll use only Phrase and Alt.
Now, we need a recognizer and wire the grammar with functions that will be called when a part of
the grammar is recognized or rejected.
It is mandatory to set grammar's culture to the recognizer's culture.
There's usually a single recognizer installed by default on your system and it uses installed system's
culture. In my case, it'll be french.
let recog = new SpeechRecognizer()
let recognize grammar recognized rejected =
let builder = build grammar
builder.Culture <- recog.RecognizerInfo.Culture
printfn "%A" recog.RecognizerInfo.Culture
recog.LoadGrammar(Grammar builder)
recog.SpeechRecognized |> Event.add (fun e -> recognized e.Result.Text (string e.Result.Semantics.Value))
recog.SpeechRecognitionRejected |> Event.add (fun e -> rejected ())
We can then use this to create a little Christmass quizz thanks to the FSharp.Data FreeBase Type Provider !
We'll use free base to find a list of Actors who plaid Santa in movies.
For this, install the FSharp.Data NuGet:
nuget install FSharp.Data -o packages -x
The dll should be in .\packages\FSharp.Data\lib\net40\FSharp.Data.dll
#r @"packages\FSharp.Data\lib\net40\FSharp.Data.dll"
open FSharp.Data
let fb =FreebaseData.GetDataContext()
Let's build the grammar
let santaActorsFilms =
fb.``Arts and Entertainment``
.``Film characters``
.``Santa Claus``
.``Portrayed in films``
|> (fun c -> c.Actor.Name, c.Film.Name)
|> Seq.toList
let santaActorsGrammar =
|> (fun (actor,film) -> Phrase(actor, film))
|> Alt
Here is the function to call when an actor is recognized.
I tried to pass a discriminated union as a value, but even if the API uses an object, the documentation
states that it has to be a bool, an int or a string. I used only strings here.
let recognized text value =
say (sprintf "True ! %s was Santa in %s" text value)
Here is the function when the speech could not be matched with the grammar.
It is also possible to get the audio of the text in this case. I decided to ignore it due to time constraints.
let rejected () = say "No, Not a Santa !"
(** Now, let's run it !! *)
recognize santaActorsGrammar recognized rejected
At this point the speech recognition configuration should appear if it's the
first time you use it.
Once done you should be able to try the quizz !
If your OS culture is not english, don't hesitate to use a local accent for
actor's name !
## Conlusion
I hope you had fun with this API, and that you'll want to tweak it for your own demo !
**Happy Christmass !**
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment