-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Florian Hanke
committed
Mar 31, 2008
1 parent
7d1b9a6
commit 00ab79d
Showing
62 changed files
with
49,565 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This folder contains configuration files for james itself. | ||
|
||
The files are in YAML format (http://de.wikipedia.org/wiki/YAML). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# names for the two voices | ||
female: jamie | ||
male: james |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# with this file it is possible to configure your james's core | ||
# commands are denoted with an exclamation mark | ||
# it is not possible to use multiple command words | ||
sleep!: sleep | ||
return from dialogue!: thank you | ||
# when james ... he says one of ... | ||
wakes up: | ||
- yes? | ||
- sir? | ||
- ready! | ||
- ok! | ||
- tell me! | ||
- yes, sir? | ||
- your wish is my command. | ||
- at your service. | ||
goes to sleep: | ||
- good night! | ||
- good bye! | ||
- hasta la vista, baby! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Commented voices are Apple built-in voices. Can be changed by replacing the last part e.g.'Vicki' with e.g.'Laura' | ||
# much better female voice from iVox: | ||
# female: com.acapela.iVox.voice.iVoxHeather22k | ||
# much better male voice from iVox: | ||
# male: com.acapela.iVox.voice.iVoxRyan22k | ||
female: com.apple.speech.synthesis.voice.Vicki | ||
# male: com.apple.speech.synthesis.voice.Bruce | ||
male: com.apple.speech.synthesis.voice.Alex |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# TODO all | ||
|
||
# configures | ||
class Configurator | ||
def self.configure | ||
|
||
end | ||
end | ||
|
||
require 'osx/cocoa' | ||
|
||
... | ||
|
||
def initialize | ||
# get and configure a recognizer interface | ||
@recognizer = OSX::NSSpeechRecognizer.alloc.init | ||
@recognizer.setDelegate(self) | ||
@recognizer.startListening | ||
# get a synthesizer interface | ||
@synthesizer = OSX::NSSpeechSynthesizer.alloc.init | ||
end | ||
|
||
# callback method from the speech interface | ||
def speechRecognizer_didRecognizeCommand( sender, command ) | ||
# do something with the command | ||
# command needs to be converted to a proper ruby string: command.to_s | ||
end | ||
|
||
def speak(text) | ||
# say something using the speech synthesizer | ||
@synthesizer.startSpeakingString(text) | ||
end | ||
|
||
state :to, { | ||
'back' => :from, | ||
'next train' => :result, | ||
'nowhere' => :result | ||
}.merge(CITIES) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
class Dialogue | ||
|
||
# choose one reply randomly from the given replies | ||
def random_reply(replies) | ||
replies[rand(replies.size)] | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# require 'cocoa' | ||
|
||
# TODO make ['HB','berne','geneva'] => :from possible using the splat operator | ||
# add ability to chain dialogues a la chain_dialogue :state, <dialogue_name> | ||
|
||
# superclass for dialogue modules | ||
# dialogues move along the moves | ||
# if a state is entered, enter_#{state_name} is called | ||
# if a state is exited, exit_#{state_name} is called | ||
class DialogueExtension < Dialogue | ||
|
||
attr_reader :state | ||
|
||
alias :old_initialize :initialize | ||
|
||
# every subclass of this class automatically has its state set to :entry on creation | ||
# def initialize(*args) | ||
# puts "Resetting ", self.name, "\n" | ||
# reset | ||
# old_initialize(*args) | ||
# end | ||
|
||
# # automatically adds a hook phrase | ||
# # meaning: adds a move from :awake to this hook word | ||
# # and also a method | ||
def initialize | ||
# reset | ||
end | ||
# | ||
# # TODO improve this such that reset doesn't need to be called in each initializer! | ||
def reset | ||
@state = :entry | ||
end | ||
|
||
# TODO think about saying something after each method call though like this it is kept simple which is good | ||
def hear(phrase) | ||
# if next state | ||
return nil unless next_state(phrase) | ||
# call exit method | ||
send("exit_#{@state}".intern, phrase) if respond_to?("exit_#{@state}") | ||
# TODO say(response) | ||
# set actual state | ||
@state = self.next_state(phrase) | ||
# call entry method | ||
send("enter_#{@state}".intern) if respond_to?("enter_#{@state}") | ||
end | ||
|
||
# next possible phrases | ||
# TODO splat | ||
def expects | ||
self.class.moves[@state].keys | ||
end | ||
|
||
def next_state(phrase) | ||
self.class.moves[@state][phrase] if self.class.moves[@state] | ||
end | ||
|
||
# returns the possible states of this dialogue | ||
def self.possible_states | ||
self.moves.keys | ||
end | ||
|
||
# metaprog | ||
|
||
# hook words - these define when this dialogue is entered | ||
# adds a hooks method | ||
# TODO get hooks from yaml file | ||
def self.hook_words(*hooks) | ||
self.class_eval do | ||
# set entry state correctly | ||
entry = {} | ||
hooks.each do |hook| | ||
entry[hook] = self.initial | ||
end | ||
# add moves class variable | ||
class <<self | ||
attr_accessor :moves | ||
end | ||
self.moves ||= {} | ||
self.moves[:entry] = entry | ||
# define an instance method | ||
define_method(:hooks) do | ||
hooks | ||
end | ||
end | ||
end | ||
|
||
# initial state | ||
def self.initial_state(initial) | ||
self.class_eval do | ||
# add accessor for | ||
class <<self | ||
attr_accessor :initial | ||
end | ||
self.initial = initial | ||
end | ||
end | ||
|
||
# state definitions like | ||
# state :name, { moves } | ||
def self.state(name, moves) | ||
self.class_eval do | ||
self.moves ||= {} | ||
self.moves[name] ||= {} | ||
# split arrays here instead of handling later specifically | ||
# can change the implementation later if needed | ||
moves.each do |words,state| | ||
words.each do |word| | ||
self.moves[name][word] = state | ||
end | ||
end | ||
# | ||
# self.moves[name] = moves | ||
# puts "moves for #{self.name} are #{self.moves.inspect}" | ||
end | ||
# puts "#{self.name} === #{self.moves.inspect}" | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
require 'osx/cocoa' | ||
require 'main_dialogue' | ||
|
||
# TODO move some stuff in the dialogue | ||
# TODO extract cocoa connection | ||
# TODO implement callback | ||
|
||
# debug | ||
USE_TEXTUAL_INTERFACE = false | ||
|
||
class DialogueFrontend | ||
|
||
attr_reader :dialogue | ||
|
||
def initialize | ||
# load voices | ||
load_voices | ||
|
||
# get a dialogue | ||
@dialogue = MainDialogue.new(self) | ||
|
||
# get and configure a recognizer interface | ||
start_recognizer | ||
|
||
# get a synthesizer interface | ||
start_synthesizer | ||
|
||
# default voice | ||
male | ||
end | ||
|
||
# callback method from the speech interface | ||
def speechRecognizer_didRecognizeCommand( sender, command ) | ||
command = command.to_s | ||
# call the dialogue system | ||
@dialogue.hear(command) | ||
# set actual commands | ||
self.commands = @dialogue.expects | ||
end | ||
|
||
# callback method from dialogue | ||
def say(text) | ||
@synthesizer.startSpeakingString(text) | ||
end | ||
|
||
# callback from dialogue | ||
def male | ||
self.voice = @male_voice | ||
end | ||
|
||
# callback from dialogue | ||
def female | ||
self.voice = @female_voice | ||
end | ||
|
||
# wrapper for the cocoa setCommands | ||
def commands=(commands) | ||
@recognizer.setCommands(commands) | ||
puts "expects: #{commands.join(', ')}" | ||
end | ||
|
||
private | ||
|
||
# specialized setter for voice | ||
def voice=(voice) | ||
@synthesizer.setVoice(voice) | ||
end | ||
|
||
# start recognizing words | ||
def start_recognizer | ||
@recognizer = OSX::NSSpeechRecognizer.alloc.init | ||
@recognizer.setBlocksOtherRecognizers(true) | ||
@recognizer.setListensInForegroundOnly(false) | ||
@recognizer.setDelegate(self) | ||
self.commands = @dialogue.expects | ||
@recognizer.startListening | ||
end | ||
|
||
# start speaking | ||
def start_synthesizer | ||
@synthesizer = OSX::NSSpeechSynthesizer.alloc.init | ||
end | ||
|
||
# load voices from yaml | ||
def load_voices | ||
yaml_voices = '' | ||
File.open('config/voices.yml') do |f| yaml_voices << f.read end | ||
voices = YAML.load(yaml_voices) | ||
@male_voice = voices['male'] | ||
@female_voice = voices['female'] | ||
end | ||
|
||
end | ||
|
||
controller = DialogueFrontend.new | ||
|
||
# code to use a textual interface | ||
while USE_TEXTUAL_INTERFACE | ||
exit_words = ['quit','exit'] | ||
puts "'#{exit_words.join("' or '")}' to quit. Expects: #{controller.dialogue.expects.join(', ')}" | ||
input = gets.chomp | ||
if exit_words.include?(input) | ||
break | ||
end | ||
controller.dialogue.hear(input) | ||
end | ||
|
||
OSX::NSApplication.sharedApplication.run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
require 'rubycocoa' | ||
|
||
# superclass for dialogue modules | ||
# dialogues move along the moves | ||
# if a state is entered, enter_#{state_name} is called | ||
# if a state is exited, exit_#{state_name} is called | ||
class DialoguePlugin | ||
|
||
# automatically adds a hook phrase | ||
# meaning: adds a move from :awake to this hook word | ||
# and also a method | ||
def initialize | ||
# actual state in this module | ||
@state = nil | ||
# defines possible moves from one state to another | ||
@moves = { | ||
|
||
} | ||
end | ||
|
||
# returns the possible states of this dialogue | ||
def possible_states | ||
@moves.keys | ||
end | ||
|
||
# next possible phrases | ||
def expects_phrases | ||
@moves[@state].keys | ||
end | ||
|
||
def next_state(phrase) | ||
@moves[@state][phrase] | ||
end | ||
|
||
def hear(phrase) | ||
# if next state | ||
return unless next_state(phrase) | ||
# call exit method | ||
response = send("exit_#{@state}".intern, phrase) | ||
say response | ||
# set actual state | ||
@state = next_state(phrase) | ||
# call entry method | ||
response = send("enter_#{@state}") | ||
say response | ||
end | ||
|
||
def say(text) | ||
# TODO blah | ||
end | ||
|
||
# hook words - these define when this dialogue is entered | ||
def hook_words(names = nil) | ||
names.each do |name| | ||
# TODO | ||
end | ||
end | ||
|
||
def initial_state(initial) | ||
define_method(:reset) do | ||
@state = initial | ||
end | ||
end | ||
|
||
end |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
TODO: load the jokes from somewhere | ||
With this dialogue part, james can tell jokes! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
require 'joke_dialogue' |
Oops, something went wrong.