Skip to content
Snippets Groups Projects
Commit 4898b8a9 authored by Benoit Favre's avatar Benoit Favre
Browse files

refactor actions; push words through osc

parent 6d59f30b
No related branches found
No related tags found
No related merge requests found
......@@ -12,33 +12,41 @@ copy libgstkaldionline2.so to ./asr/ or change GST_PLUGIN_PATH in main.py to poi
Run:
python2 main.py
- The main program:
./start.sh
Doc:
- The osc server:
python2 osc.py
Doc:
developing with pygtk3: http://lazka.github.io/pgi-docs/, https://python-gtk-3-tutorial.readthedocs.org/en/latest/
Todo:
DONE configuration for osc
DONE non intrusive animated scrolling
DONE make configuration box options persistant
DONE push words through osc
DONE global action send which deals with
DONE - show a warning (optional)
DONE - send action through osc
DONE - show an action performed message (message log with timing?)
events = click action or words to resynchronize ?
click line = synchronize to that line
click section = select that section
click action = perform action and synchronize to the next line
non intrusive animated scrolling
global action send which deals with
- show a warning (optional)
- sned action through osc
- show an action performed message (message log with timing?)
add global timer which shows elapsed time
change xml view to reflect already performed actions, already recognized text
configuration for osc
move slu to asr
make selector a proper window
make configuration box options persistant
add thread for slu
allow sequence advance in slu, add UI for that
remove section changer UI
add global keybindings (1-9 for sections, y/n)...
from gi.repository import Gtk
class ActionView(Gtk.HBox):
def __init__(self):
super(ActionView, self).__init__()
self.actions = set(['next', 'previous', 'light-on', 'light-off'])
self.pack_start(Gtk.Label('Actions:'), False, False, 5)
for action in self.actions:
button = Gtk.Button(action)
button.connect('clicked', self._perform)
self.pack_start(button, False, False, 5)
self.confiermer = None
def _perform(self, button):
action = button.get_label()
if self.confirmer:
self.confirmer.confirm('Perform action "%s"?' % action, 4, lambda: self.perform(action))
else:
self.perform(action)
def perform(self, action):
if action in self.actions:
print 'PERFORM', action
return True
return False
def actions(self):
return self.actions
def set_confirmer(self, confirmer):
self.confirmer = confirmer
import osc, log
class Action:
def __init__(self, text, **kwargs):
self.text = text
for key, value in kwargs:
setattr(self, key, value)
class ActionManager:
def __init__(self, host, port, confirmer, highlighter, logger=log.ConsoleLogger()):
#self.client = osc.Client(host, port)
self.confirmer = confirmer
self.highlighter = highlighter
self.logger = logger
def confirmed_perform(self, action):
osc.client.send_action(action)
self.highlighter.highlight(action)
self.logger.log(action)
def perform(self, action, confirm=True, timeout=3):
if confirm:
self.confirmer.confirm('Perform action "%s"?' % action.text, time, lambda: self.confirmed_perform(action))
else:
self.confirmed_perform(action)
manager = None
def setup(confirmer, highlighter, logger):
global manager
manager = ActionManager(confirmer, highlighter, logger)
def perform_action(action, confirm=True, timeout=3):
global manager
manager.perform(action, confirm, timeout)
......@@ -9,13 +9,13 @@ def cancel():
LINEAR=1
DECELERATE=2
def animate_value(callback, current, target, policy=DECELERATE):
def animate_value(callback, current, target, policy=DECELERATE, speed=32):
global timer
if current != target:
if policy == DECELERATE:
delta = abs(target - current) / 2
else:
delta = 32
delta = speed
if current > target:
current -= delta
else:
......
......@@ -8,6 +8,8 @@ GObject.threads_init()
Gdk.threads_init()
Gst.init(None)
import osc
class ASR(Gtk.HBox):
def __init__(self, asr_config, hyp_callback = None, partial_hyp_callback = None):
super(ASR, self).__init__()
......@@ -110,6 +112,10 @@ class ASR(Gtk.HBox):
Gdk.threads_enter()
if len(self.hyp) == 0:
self.hyp = ['']
if hyp != self.hyp[-1]:
osc.client.send_words(len(self.hyp), hyp)
self.hyp[-1] = hyp
if self.partial_hyp_callback:
self.partial_hyp_callback(self.hyp)
......
......@@ -31,6 +31,7 @@ class ConfirmationBox(Gtk.HBox):
self.yes_button.get_child().set_text("YES (%d)" % self.counter)
self.timer = GObject.timeout_add_seconds(1, self.countdown)
self.yes_button.grab_focus()
self.show()
def click_yes(self, button = None):
......
log.py 0 → 100644
from gi.repository import Gtk
import actions
class ConsoleLogger:
def __init__(self):
pass
def log(self, action):
print 'Performed:', action.text
class GtkLogger(Gtk.HBox):
def __init__(self):
super(Log, self).__init__()
self.text = Gtk.TextView()
self.text.set_editable(False)
self.text.set_cursor_visible(False)
self.buffer = self.text.get_buffer()
self.scrolled = Gtk.ScrolledWindow()
self.scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
self.scrolled.add_with_viewport(self.text)
#self.scrolled.set_size_request(-1, 100)
self.pack_start(self.scrolled, True, True, 5)
def log(self, action):
self.buffer.insert_at_cursor('Performed: %s\n' % action.text)
adj = self.scrolled.get_vadjustment()
adj.set_value(adj.get_upper() - adj.get_page_size())
if __name__ == '__main__':
window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
logger = GtkLogger()
window.add(logger)
window.show_all()
logger.log(actions.Action('coucou'))
Gtk.main()
......@@ -5,8 +5,10 @@ import os
import glob, re
# set to location of libgstkaldionline2.so
os.environ['GST_PLUGIN_PATH'] = './asr/'
directory = os.path.dirname(__file__) or '.'
os.environ['GST_PLUGIN_PATH'] = directory + '/asr/'
os.environ['GTK_THEME'] = 'light'
print 'gst plugin path =', os.environ['GST_PLUGIN_PATH']
# import gtk stuff
from threading import Thread
......@@ -22,21 +24,23 @@ import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
# import local stuff
import confirm, asr, action, xmlview_widgets
import levenstein, SLU
import confirm, asr, actions, xmlview_widgets
import sections
import levenstein, SLU, osc
class ScriptedASR(Gtk.Window):
def __init__(self, xml_filename, asr_config_file):
def __init__(self, xml_filename, asr_config_file, osc_host, osc_port):
super(ScriptedASR, self).__init__()
osc.setup(osc_host, osc_port)
self.connect("destroy", self.quit)
self.set_default_size(800,600)
self.set_default_size(1024, 768)
self.set_border_width(10)
self.set_title('ScriptedASR [%s]' % xml_filename)
self.set_title('ASR Transcript [xml=%s asr=%s osc=%s:%s]' % (xml_filename, asr_config_file, osc_host, osc_port))
vbox = Gtk.VBox()
import section
self.sections = section.SectionManager()
self.sections = sections.SectionManager()
vbox.pack_start(self.sections, False, True, 5)
self.xmlview = xmlview_widgets.XmlView(xml_filename)
......@@ -140,8 +144,8 @@ if __name__ == '__main__':
xml_filename = sys.argv[1]
if len(sys.argv) > 2:
asr_config_file = sys.argv[2]
xml_filename, asr_config_file = selector.ModelSelector(xml_filename, asr_config_file).run()
if xml_filename == None or asr_config_file == None:
xml_filename, asr_config_file, osc_host, osc_port = selector.ModelSelector(xml_filename, asr_config_file).run()
if xml_filename == None or asr_config_file == None or osc_host == None or osc_port == None:
sys.exit(0)
app = ScriptedASR(xml_filename, asr_config_file)
app = ScriptedASR(xml_filename, asr_config_file, osc_host, osc_port)
Gtk.main()
import liblo, sys
class ActionSender:
class Client:
def __init__(self, host = '127.0.0.1', port = 1234):
try:
self.target = liblo.Address(host, port)
......@@ -13,24 +13,35 @@ class ActionSender:
except:
print >>sys.stderr, 'OSC: failed to send message [%s]' % str(message)
class ActionReceiver:
def send_action(self, action):
self.send('ACTION: %s' % action.text)
def send_words(self, start, words):
self.send('WORDS(%d): %s' % (start, words))
class Server:
def __init__(self, host = '127.0.0.1', port = 1234):
print 'OSC: Creating server at %s:%d' % (host, port)
self.server = liblo.Server(port)
self.server.add_method(None, None, self.callback)
def callback(self, message):
print 'OSC: Recieved [%s]' % message
print 'OSC: Received [%s]' % message
def run(self):
print 'OSC: Waiting for messages'
while True:
self.server.recv(100)
client = None
def setup(host, port):
global client
client = Client(host, port)
if __name__ == '__main__':
if len(sys.argv) > 1:
client = ActionSender()
client = Client()
client.send(' '.join(sys.argv[1:]))
else:
server = ActionReceiver()
server = Server()
server.run()
File moved
from gi.repository import GObject, Gtk, Gdk
import os, sys, glob
import os, sys, glob, re
import config
class ModelSelector(Gtk.Dialog):
def __init__(self, xml_filename = '', asr_model = ''):
super(ModelSelector, self).__init__()
self.options = {'xml_filename': xml_filename, 'asr_model': asr_model, 'osc_host': '127.0.0.1', 'osc_port': '1234'}
self.load_options()
self.set_title('Configuration')
self.set_border_width(10)
self.add_button("Cancel", Gtk.ResponseType.CANCEL)
self.add_button("OK", Gtk.ResponseType.OK)
box = self.get_content_area()
xml_box = Gtk.HBox()
xml_box.pack_start(Gtk.Label('XML file:'), False, False, 10)
xml_box.pack_start(Gtk.Label('XML file:'), False, False, 5)
xml_entry = Gtk.Entry()
xml_entry.set_text(xml_filename)
xml_entry.set_width_chars(len(xml_filename))
xml_entry.set_text(self.options['xml_filename'])
xml_entry.set_width_chars(len(self.options['xml_filename']))
self.xml_entry = xml_entry
xml_box.pack_start(xml_entry, True, True, 10)
xml_box.pack_start(xml_entry, True, True, 5)
xml_button = Gtk.Button("Choose...")
xml_button.connect('clicked', self.show_filechooser)
xml_box.pack_start(xml_button, False, False, 10)
xml_box.pack_start(xml_button, False, False, 5)
box.pack_start(xml_box, False, False, 5)
model_box = Gtk.HBox()
model_box.pack_start(Gtk.Label('ASR model:'), False, False, 10)
model_box.pack_start(Gtk.Label('ASR model:'), False, False, 5)
model_chooser = Gtk.ComboBoxText()
model_chooser.set_entry_text_column(0)
target_index = 0
for i, model in enumerate(self.list_models()):
model_chooser.append_text(model)
if asr_model == self.models[i]:
if self.options['asr_model'] == self.models[i]:
target_index = i
model_chooser.set_active(target_index)
self.model_chooser = model_chooser
model_box.pack_start(model_chooser, True, True, 10)
model_box.pack_start(model_chooser, True, True, 5)
box.pack_start(model_box, False, False, 5)
osc_box = Gtk.HBox()
osc_box.pack_start(Gtk.Label('OSC host:'), False, False, 10)
osc_box.pack_start(Gtk.Label('OSC host:'), False, False, 5)
osc_host = Gtk.Entry()
osc_host.set_text('127.0.0.1')
osc_host.set_text(self.options['osc_host'])
osc_host.set_width_chars(len(osc_host.get_text()))
osc_box.pack_start(osc_host, True, True, 10)
osc_box.pack_start(Gtk.Label('Port:'), False, False, 10)
self.osc_host = osc_host
osc_box.pack_start(osc_host, True, True, 5)
osc_box.pack_start(Gtk.Label('Port:'), False, False, 5)
osc_port = Gtk.Entry()
osc_port.set_text('1234')
osc_port.set_text(self.options['osc_port'])
osc_port.set_width_chars(len(osc_port.get_text()))
osc_box.pack_start(osc_port, True, True, 10)
self.osc_port = osc_port
osc_box.pack_start(osc_port, True, True, 5)
box.pack_start(osc_box, False, False, 5)
......@@ -56,16 +62,38 @@ class ModelSelector(Gtk.Dialog):
okButton = self.get_widget_for_response(response_id=Gtk.ResponseType.OK)
okButton.set_can_default(True)
okButton.grab_default()
okButton.grab_focus()
self.show_all()
def save_options(self):
try:
with open('.options.txt', 'w') as fp:
for key, value in self.options.items():
print >>fp, '%s: %s' % (key, str(value))
except:
print 'Warning: could not save options'
def load_options(self):
try:
with open('.options.txt') as fp:
for line in fp:
line = line.strip()
found = re.search('^([^:]*):(.*)', line)
if found:
key = found.group(1).strip()
value = found.group(2).strip()
self.options[key] = value
except:
print 'Warning: could not load options'
def show_filechooser(self, button):
dialog = Gtk.FileChooserDialog("Please choose a file", self, Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
filter_text = Gtk.FileFilter()
filter_text.set_name("XML files")
filter_text.add_mime_type("text/xml")
dialog.add_filter(filter_text)
dialog.set_current_folder('%s/data' % os.path.dirname(__file__))
dialog.set_current_folder('%s/data' % (os.path.dirname(__file__) or '.'))
response = dialog.run()
if response == Gtk.ResponseType.OK:
......@@ -90,9 +118,12 @@ class ModelSelector(Gtk.Dialog):
def run(self):
response = super(ModelSelector, self).run()
if response != Gtk.ResponseType.OK:
return None, None
asr_model = self.models[self.model_chooser.get_active()]
xml_filename = self.xml_entry.get_text()
return None, None, None, None
self.options['asr_model'] = self.models[self.model_chooser.get_active()]
self.options['xml_filename'] = self.xml_entry.get_text()
self.options['osc_host'] = self.osc_host.get_text()
self.options['osc_port'] = self.osc_port.get_text()
self.save_options()
self.destroy()
return xml_filename, asr_model
return self.options['xml_filename'], self.options['asr_model'], self.options['osc_host'], self.options['osc_port']
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment