Hi,
I’m trying to replace the SpeechRecognitionServer.app with a library module using NSSpeechRecognizer. Has anyone done this before and do you think that there is a possibility that it could be better?
Thanks,
kel
Hi,
I’m trying to replace the SpeechRecognitionServer.app with a library module using NSSpeechRecognizer. Has anyone done this before and do you think that there is a possibility that it could be better?
Thanks,
kel
Come to think of it, if nobody has tried it, then we will never know. It doesn’t look too complicated.
Edited: btw, here’s how I’m starting off. Here’s the calling script which I can run from the script editor:
use theScript : script "SpeechLib"
theScript's listenFor:{"hello", "say something", "bye"}
Here’s the library script:
use framework "AppKit"
property userInput : missing value
on listenFor:userInput
set theSpeechSynth to current application's NSSpeechRecognizer's alloc's init()
theSpeechSynth's setCommands:{userInput}
return (theSpeechSynth's commands) as list
end listenFor:
Note that you save the library script to “Script Library”, in the user’s home folder, as “SpeechLib”" and as type script bundle. After you save the library item, in the script editor, click on the bundle identifier button in the Script Editor window. Check to see if the “AppleScript/ObjC” option is checked.
Just the beginnings.
Edited: made a mistake on in the library script:
use framework "AppKit"
property userInput : missing value
on listenFor:userInput
set theSpeechSynth to current application's NSSpeechRecognizer's alloc's init()
theSpeechSynth's setCommands:userInput
return (theSpeechSynth's commands) as list
end listenFor:
Edited: cleaned up the library script (base):
use framework "AppKit"
property userInput : missing value
on listenFor:userInput
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(userInput)
return (theSpeechRecognizer's commands) as list
end listenFor:
Now can start.
Good luck and thanks anyway,
kel
This is a hard one. You know why? When you wait it adds more delays.
You’d have to set your script as the delegate of the recognizer:
theSpeechRecognizer's setDelegate:me
And then implement the delegate method -speechRecognizer:didRecognizeCommand:
on speechRecognizer:theRecognizer didRecognizeCommand:aCommand
-- see what aCommand is, and act accordingly
end speechRecognizer:didRecognizeCommand:
Hi Shane,
That’s what I was missing. It has been a while.
Thanks a lot,
kel
Finally got the library script working with the window. Need to add more stuff, but if anyone is interested:
use framework "AppKit"
use scripting additions
property theCommands : missing value
property theSpeechRecognizer : missing value
property isDone : false
on listenFor:theCommands
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(theCommands)
theSpeechRecognizer's setDelegate:(me)
theSpeechRecognizer's setDisplayedCommandsTitle:("Testing")
theSpeechRecognizer's startListening()
repeat until isDone
delay 2
end repeat
return
end listenFor:
on speechRecognizer:theSpeechRecognizer didRecognizeCommand:aCommand
theSpeechRecognizer's stopListening()
set isDone to true
beep 2
return (aCommand as text)
end speechRecognizer:didRecognizeCommand:
It has to be run as an application. If you call this script from Script Editor, then the windows won’t close. I still need to return the command to the calling application.
gl,
kel
Alright, got it working well so far. Here’s the library script:
use framework "AppKit"
use scripting additions
property theCommands : missing value
property theSpeechRecognizer : missing value
property isDone : false
property userCommand : missing value
on listenFor:theCommands
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(theCommands)
theSpeechRecognizer's setDelegate:(me)
theSpeechRecognizer's setDisplayedCommandsTitle:("Testing")
theSpeechRecognizer's startListening()
repeat until isDone
delay 2
end repeat
return userCommand
end listenFor:
on speechRecognizer:theSpeechRecognizer didRecognizeCommand:aCommand
theSpeechRecognizer's stopListening()
set isDone to true
set userCommand to (aCommand as text)
beep 2
return true
end speechRecognizer:didRecognizeCommand:
And here’s the calling application script:
use theScript : script "SpeechLib"
use scripting additions
theScript's listenFor:{"hello", "say something", "bye"}
set r to result
display dialog r
Now I can change it to different forms.
Thanks a lot Shane. I was writing the receiving handler wrongly.
Edited: note that if you accidentally run it from Script Editor, then go to quit the process Speech Recognition Server to get rid of the Feedback Window.
gl,
kel
Oops, eliminated some bad properties:
use framework "AppKit"
use scripting additions
property isDone : false
property userCommand : missing value
on listenFor:theCommands
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(theCommands)
theSpeechRecognizer's setDelegate:(me)
theSpeechRecognizer's setDisplayedCommandsTitle:("Testing")
theSpeechRecognizer's startListening()
repeat until isDone
delay 2
end repeat
return userCommand
end listenFor:
on speechRecognizer:theSpeechRecognizer didRecognizeCommand:aCommand
theSpeechRecognizer's stopListening()
set isDone to true
set userCommand to (aCommand as text)
return true
end speechRecognizer:didRecognizeCommand:
gl,
kel
Instead of that delay in the library script, I was thinking that this could be a stay open application. Then, you send the command to open hanker in the main app. Then, I can get rid of the repeat loop.
FYI, that’s because it has to be run on the main thread, and ASE runs scripts on a background thread. Of course, you can also run it in ASObjC Explorer, via the Use main switch.
Much better.
Fixed the problem when running repeatedly. If SpeechRecognitionServer or SpeechFeedbackServer is still running from a previous call it is buggy. Used the blocks other recognizers thing:
use framework "AppKit"
use scripting additions
property isDone : false
property userCommand : missing value
on listenFor:theCommands
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(theCommands)
theSpeechRecognizer's setDelegate:(me)
theSpeechRecognizer's setDisplayedCommandsTitle:("Testing")
-- to run repeatedly while the old SpeechFeedbackServer
-- or SpeechRecognitionServer is still running
theSpeechRecognizer's setBlocksOtherRecognizers:(true)
theSpeechRecognizer's startListening()
repeat until isDone
delay 2
end repeat
return userCommand
end listenFor:
on speechRecognizer:theSpeechRecognizer didRecognizeCommand:aCommand
theSpeechRecognizer's stopListening()
set isDone to true
set userCommand to (aCommand as text)
return true
end speechRecognizer:didRecognizeCommand:
SpeechRecognitionServer.app has the same problem, but here we can fix it! Alright!
Still thinking about the stay open application. Maybe use a reopen handler. Can’t remember right now if you can pass back parameters to the reopen.
Edited: alright, I can pass the command back to any subroutine in the stay open.
gl,
kel
Hi,
Finally got it working right. Here’s the calling stay open application:
use theScript : script "SpeechLib3"
use scripting additions
on run
set commandScript to "/Users/kelhome/Desktop/Script1.scpt"
theScript's listenFor:{"hello", "say something", "bye"} aScript:commandScript sender:current application
end run
on reopen
quit
end reopen
on idle
return 2
end idle
Here’s the Script Libraries script:
use framework "AppKit"
use scripting additions
property userCommand : missing value
property theSender : missing value
property commandScript : missing value
on listenFor:theCommands aScript:aScript sender:sender
set theSender to sender
set commandScript to aScript
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(theCommands)
theSpeechRecognizer's setDelegate:(me)
theSpeechRecognizer's setDisplayedCommandsTitle:("Testing")
-- to run repeatedly while the old SpeechFeedbackServer
-- or SpeechRecognitionServer is still running
theSpeechRecognizer's setBlocksOtherRecognizers:(true)
theSpeechRecognizer's startListening()
return true
end listenFor:aScript:sender:
on speechRecognizer:theSpeechRecognizer didRecognizeCommand:aCommand
theSpeechRecognizer's stopListening()
set userCommand to (aCommand as text)
run script commandScript with parameters userCommand
tell theSender to quit
return true
end speechRecognizer:didRecognizeCommand:
Here’s the command script on the desktop:
on run p
set p to p as string
if p is "hello" then
display dialog p
else if p is "say something" then
say "something"
else
say "goodbye"
end if
end run
I think that instead of running the external command script, you can pass a script or handler to the library script. Still working on that, but this should get whoever is interested started.
Edited: the library script. Removed the is done variable.
gl,
kel
Hi,
Got it working great with sending a handler. Here’s the calling stay open application:
use theScript : script "SpeechLib4"
use scripting additions
on run
--set commandScript to "/Users/kelhome/Desktop/Script1.scpt"
theScript's listenFor:{"hello", "say something", "bye"} aHandler:processCommand sender:current application
end run
on reopen
quit
end reopen
on idle
return 2
end idle
on processCommand(p)
if p is "hello" then
display dialog p
else if p is "say something" then
say "something"
else
say "goodbye"
end if
end processCommand
Here’s the library script:
use framework "AppKit"
use scripting additions
property userCommand : missing value
property theSender : missing value
property commandHandler : missing value
on listenFor:theCommands aHandler:aHandler sender:sender
set theSender to sender
set commandHandler to aHandler
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(theCommands)
theSpeechRecognizer's setDelegate:(me)
theSpeechRecognizer's setDisplayedCommandsTitle:("Testing")
-- to run repeatedly while the old SpeechFeedbackServer
-- or SpeechRecognitionServer is still running
theSpeechRecognizer's setBlocksOtherRecognizers:(true)
theSpeechRecognizer's startListening()
return true
end listenFor:aHandler:sender:
on speechRecognizer:theSpeechRecognizer didRecognizeCommand:aCommand
theSpeechRecognizer's stopListening()
set userCommand to (aCommand as text)
commandHandler(userCommand)
tell theSender to quit
return true
end speechRecognizer:didRecognizeCommand:
Now I can rest.
Thanks for everything and good luck,
kel
Hi,
Here’s the final scripts that you can modify. You might want to change some things to manage memory better.
Here’s the calling script that is saved as a stay open application:
use theScript : script "SpeechLib4"
use scripting additions
on run
theScript's listenFor:{"hello", "say something", "bye"} aHandler:processCommand sender:current application
end run
-- double click icon to quit
on reopen
quit
end reopen
on idle
return 2
end idle
on quit
try
display dialog "Quit?"
continue quit
on error
run (current application)
end try
end quit
on processCommand(p)
if p is "hello" then
say "hi"
else if p is "say something" then
say "something"
else
say "goodbye"
end if
end processCommand
Still need to test the effect of the idle times.
Here’s the Script Libraries script which you save as a script bundle.
use framework "AppKit"
use scripting additions
property userCommand : missing value
property theSender : missing value
property processCommand : missing value
on listenFor:theCommands aHandler:aHandler sender:sender
set theSender to sender
set processCommand to aHandler
set theSpeechRecognizer to current application's NSSpeechRecognizer's alloc's init()
theSpeechRecognizer's setCommands:(theCommands)
theSpeechRecognizer's setDelegate:(me)
theSpeechRecognizer's setDisplayedCommandsTitle:("Testing")
-- to run repeatedly while the old SpeechFeedbackServer
-- or SpeechRecognitionServer is still running
theSpeechRecognizer's setBlocksOtherRecognizers:(true)
theSpeechRecognizer's startListening()
return true
end listenFor:aHandler:sender:
on speechRecognizer:theSpeechRecognizer didRecognizeCommand:aCommand
theSpeechRecognizer's stopListening()
theSpeechRecognizer's setBlocksOtherRecognizers:(false)
set userCommand to (aCommand as text)
processCommand(userCommand)
tell theSender to quit
return true
end speechRecognizer:didRecognizeCommand:
After saving to Script Libraries in the Library folder, click on Bundle Contents and check AppleScript/Objective-C Library in the drawer.
I wouldn’t pass a big handler to the library script.
Edited: just thought of a use for the idle handler besides keeping the app running. You could use it for setting an idle time for quitting. i.e. if the user doesn’t respond within 5 minutes, then quit.
gl,
kel