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

update ui

parent 4898b8a9
Branches
No related tags found
No related merge requests found
......@@ -31,11 +31,12 @@ 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?)
DONE click section = select that section
DONE click action = perform action
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
click action = synchronize to the next line
add global timer which shows elapsed time
change xml view to reflect already performed actions, already recognized text
......
......@@ -3,11 +3,11 @@ import osc, log
class Action:
def __init__(self, text, **kwargs):
self.text = text
for key, value in kwargs:
for key, value in kwargs.items():
setattr(self, key, value)
class ActionManager:
def __init__(self, host, port, confirmer, highlighter, logger=log.ConsoleLogger()):
def __init__(self, confirmer, highlighter, logger=log.ConsoleLogger()):
#self.client = osc.Client(host, port)
self.confirmer = confirmer
self.highlighter = highlighter
......@@ -20,13 +20,13 @@ class ActionManager:
def perform(self, action, confirm=True, timeout=3):
if confirm:
self.confirmer.confirm('Perform action "%s"?' % action.text, time, lambda: self.confirmed_perform(action))
self.confirmer.confirm('Perform action "%s"?' % action.text, timeout, lambda: self.confirmed_perform(action))
else:
self.confirmed_perform(action)
manager = None
def setup(confirmer, highlighter, logger):
def setup(confirmer, highlighter, logger=log.ConsoleLogger()):
global manager
manager = ActionManager(confirmer, highlighter, logger)
......
......@@ -5,12 +5,14 @@ def cancel():
global timer
if timer:
GObject.source_remove(timer)
timer = None
LINEAR=1
DECELERATE=2
def animate_value(callback, current, target, policy=DECELERATE, speed=32):
global timer
timer = None
if current != target:
if policy == DECELERATE:
delta = abs(target - current) / 2
......
......@@ -26,9 +26,20 @@ class ASR(Gtk.HBox):
self.scrolled.set_size_request(-1, 100)
self.pack_start(self.scrolled, True, True, 5)
self.button = Gtk.Button("Speak")
vbox = Gtk.VBox()
self.pack_start(vbox, False, False, 5)
self.button = Gtk.Button("Record")
self.button.set_size_request(100, -1)
self.button.set_sensitive(False)
self.pack_start(self.button, False, False, 5)
vbox.pack_start(self.button, True, True, 5)
#save_state = Gtk.Button("Save state")
#save_state.connect('clicked', self.save_state)
#vbox.pack_start(save_state, False, False, 5)
#load_state = Gtk.Button("Load state")
#load_state.connect('clicked', self.load_state)
#vbox.pack_start(load_state, False, False, 5)
self.button.connect('clicked', self.button_clicked)
self.text.connect("size-allocate", self.autoscroll)
......@@ -82,28 +93,30 @@ class ASR(Gtk.HBox):
GObject.idle_add(self._finished_loading_asr)
def load_state(self):
def load_state(self, *args):
try:
with open('state.txt') as fp:
self.asr.set_property('adaptation-state', fp.read())
print "ASR: State loaded"
except:
print >> sys.stderr, 'failed to load asr state'
def save_state(self):
def save_state(self, *args):
if hasattr(self, 'asr'):
state = self.asr.get_property('adaptation-state')
try:
with open('state.txt', 'w') as fp:
fp.write(state)
print "ASR: State saved"
except:
print >> sys.stderr, 'failed to save asr state'
def _started_loading_asr(self):
self.button.set_sensitive(False)
self.button.set_label("Loading...")
self.button.set_label("Loading")
def _finished_loading_asr(self):
self.button.set_label("Speak")
self.button.set_label("Record")
self.button.set_sensitive(True)
def _on_partial_result(self, asr, hyp):
......@@ -149,12 +162,12 @@ class ASR(Gtk.HBox):
def button_clicked(self, button):
"""Handle button presses."""
if button.get_label() == "Speak":
if button.get_label() == "Record":
button.set_label("Stop")
self.asr.set_property("silent", False)
self.hyp = []
self.buffer.set_text('...')
else:
button.set_label("Speak")
button.set_label("Record")
self.asr.set_property("silent", True)
......@@ -56,6 +56,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)
else:
self.timer = None
self.click_yes()
def cancel_timer(self):
......
......@@ -15,7 +15,7 @@
font: bold;
}
.selected-section-title {
.selected-section > .section-title {
font: bold 18;
color: white;
background: #009900;
......@@ -31,7 +31,7 @@
margin: 20px;
}
.selected-section-body {
.selected-section {
background: #eeffee;
margin: 20px;
}
......
......@@ -24,43 +24,27 @@ import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
# import local stuff
import confirm, asr, actions, xmlview_widgets
import sections
import confirm, asr, actions, xmlview
import levenstein, SLU, osc
class ScriptedASR(Gtk.Window):
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(1024, 768)
self.set_border_width(10)
self.set_title('ASR Transcript [xml=%s asr=%s osc=%s:%s]' % (xml_filename, asr_config_file, osc_host, osc_port))
vbox = Gtk.VBox()
self.sections = sections.SectionManager()
vbox.pack_start(self.sections, False, True, 5)
self.xmlview = xmlview_widgets.XmlView(xml_filename)
self.xmlview = xmlview.XmlView(xml_filename)
vbox.pack_start(self.xmlview, True, True, 5)
self.lines = [x for x in self.xmlview.get_line_iterator()]
self.current_line = -1
self.xmlview.set_action_clicked_handler(self.keyword_clicked)
self.confirmer = confirm.ConfirmationBox()
vbox.pack_start(self.confirmer, False, True, 5)
#self.actions = action.ActionView()
#vbox.pack_start(self.actions, False, True, 5)
self.sections.set_confirmer(self.confirmer)
#self.actions.set_confirmer(self.confirmer)
self.sections.set_highlight(self.xmlview)
self.sections.set_section(1)
# transcript view
self.asr = asr.ASR(asr_config_file, self.hyp_changed, self.hyp_changed)
vbox.pack_start(self.asr, False, True, 5)
......@@ -71,7 +55,6 @@ class ScriptedASR(Gtk.Window):
for section_fst in glob.glob(prefix % 'section*.fst'):
found = re.search('section(\d+)\.fst$', section_fst)
if found:
print section_fst
section_id = int(found.group(1))
self.slu[section_id] = SLU.SLU(prefix % 'dico_word.txt', prefix % 'dico_action.txt', section_fst, prefix % 'clean_tail.fst')
......@@ -85,6 +68,10 @@ class ScriptedASR(Gtk.Window):
style_provider.load_from_data(open('data/style.css', 'rb').read())
Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
# setup singletons
osc.setup(osc_host, osc_port)
actions.setup(self.confirmer, self.xmlview)
def line_clicked(self, widget, event):
if self.current_line >= 0:
self.lines[self.current_line].highlight(False)
......@@ -93,22 +80,17 @@ class ScriptedASR(Gtk.Window):
self.current_line = i
self.lines[self.current_line].highlight(True)
def keyword_clicked(self, action):
self.confirmer.confirm('Force action \"%s\"?' % action, 3, None)
def hyp_changed(self, hyp):
#hyp = ' '.join(hyp).replace('[noise]', ' ').split()
words = hyp[-1].strip().replace('_', ' ').split()
section_id = self.sections.get_section()
print section_id, self.slu.keys()
section_id = int(self.xmlview.current_section.name) - 1
if section_id in self.slu:
print 'SLU: ', section_id
slu = self.slu[section_id]
previous_actions = slu.num_actions()
slu.process(words)
for action_id in range(previous_actions, slu.num_actions()):
action = slu.get_action(action_id)
self.confirmer.confirm('Perform action \"%s\"?' % action, 3, None)
actions.perform_action(actions.Action(action))
#if self.current_line >= len(self.lines) - 1:
# print "FINISHED"
......
timer.py 0 → 100644
from gi.repository import Gtk, GObject
import datetime
class Timer(Gtk.Label):
def __init__(self):
super(Timer, self).__init__()
self.start_time = datetime.datetime.now()
self.timer = GObject.timeout_add(100, self.update)
self.get_style_context().add_class('timer')
def update(self):
self.current_time = datetime.datetime.now() - self.start_time
self.set_text(self.to_string())
self.timer = GObject.timeout_add(100, self.update)
def to_string(self):
time = self.current_time
return '%02d:%02d:%02d.%01d' % (time.seconds / 3600, (time.seconds / 60) % 60, time.seconds % 60, time.microseconds / 100000)
from gi.repository import GObject, Gtk, Pango
import animate, actions
from gi.repository import GObject, Gtk, Pango, Gdk
from xml.etree import ElementTree as ET
class Section:
def __init__(self, name, start, end):
self.name = name
self.start = start
self.end = end
class Section(Gtk.VBox):
def __init__(self, section):
super(Section, self).__init__()
self.name = section.get('id')
self.get_style_context().add_class('section-body')
self.title = Gtk.Label()
self.title.set_markup('Section [<a href="%s">%s</a>]' % (self.name, self.name))
self.title.get_style_context().add_class('section-title')
self.listeners = []
self.title.connect('activate-link', self.link_clicked)
self.pack_start(self.title, True, True, 5)
self.sequences = []
num = 1
for sequence in section.findall('./sequence'):
self.sequences.append(Sequence(sequence, section.get('id') + '.' + str(num)))
self.pack_start(self.sequences[-1], True, True, 5)
num += 1
def highlight(self, active=True):
if active:
self.get_style_context().add_class('selected-section')
self.get_style_context().remove_class('section-body')
else:
self.get_style_context().remove_class('selected-section')
self.get_style_context().add_class('section-body')
class Word:
def __init__(self, text, start, end):
self.text = text
self.start = start
self.end = end
def link_clicked(self, widget, uri):
for listener in self.listeners:
listener(self)
return True
def add_listener(self, listener):
self.listeners.append(listener)
class Sequence(Gtk.VBox):
def __init__(self, sequence, name):
super(Sequence, self).__init__()
self.name = name
self.get_style_context().add_class('sequence-body')
self.label = Gtk.Label('Sequence %s' % name)
self.label.get_style_context().add_class('sequence-title')
self.pack_start(self.label, True, True, 5)
self.lines = []
elements = []
for line in sequence.text.split('\n'):
line = line.strip()
if line != '':
elements.append(Text(line))
if len(elements) > 0:
self.lines.append(Line(elements))
self.pack_start(self.lines[-1], True, True, 5)
elements = []
for node in sequence:
if node.tag == 'keyword':
text = str(node.text).strip()
if node.get('action').strip() != '':
elements.append(Keyword(text, node.get('action'), node.get('lang')))
else:
elements.append(Text(text))
for line in node.tail.split('\n'):
line = line.strip()
if line != '':
elements.append(Text(line))
if len(elements) > 0:
self.lines.append(Line(elements))
self.pack_start(self.lines[-1], True, True, 5)
elements = []
if len(elements) > 0:
self.lines.append(Line(elements))
self.pack_start(self.lines[-1], True, True, 5)
class Line(Gtk.HBox):
def __init__(self, elements):
super(Line, self).__init__()
self.pack_start(Gtk.Label(' '), False, False, 0)
for element in elements:
self.pack_start(element, False, False, 0)
self.elements = elements
self.get_style_context().add_class('text-line')
def highlight(self, active=True):
if active:
self.label.get_style_context().add_class('highlighted')
else:
self.label.get_style_context().remove_class('highlighted')
class Keyword(Gtk.Label):
def __init__(self, text, action, lang):
super(Keyword, self).__init__()
self.action = action
self.lang = lang
text = '\n'.join([x.strip() for x in text.split('\n')])
self.set_markup(text + ' [<a href="%s">%s</a>] ' % (action, action))
self.get_style_context().add_class('keyword')
self.connect('activate-link', self.link_clicked)
def link_clicked(self, widget, uri):
actions.perform_action(actions.Action(uri, keyword=widget))
return True
class Text(Gtk.Label):
def __init__(self, text):
super(Text, self).__init__()
text = '\n'.join([x.strip() for x in text.split('\n')])
self.set_text(text + ' ')
self.get_style_context().add_class('text')
class XmlView(Gtk.ScrolledWindow):
def __init__(self, filename):
......@@ -19,64 +119,49 @@ class XmlView(Gtk.ScrolledWindow):
self.sections = []
self.words = []
self.view = Gtk.TextView()
self.view.set_editable(False)
self.view.set_cursor_visible(False)
self.buffer = self.view.get_buffer()
self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
self.add_with_viewport(self.view)
#self.inactive_section = self.buffer.create_tag("inactive_section", background="#ffffff")
self.active_section = self.buffer.create_tag("active_section", background="red")
self.section_title = self.buffer.create_tag("section_title", scale=2, weight=Pango.Weight.BOLD, justification=Gtk.Justification.CENTER)
self.subsection_title = self.buffer.create_tag("subsection_title", scale=1.5, weight=Pango.Weight.BOLD, justification=Gtk.Justification.CENTER)
self.vbox = self.parse_xml(filename)
self.add_with_viewport(self.vbox)
self.parse_xml(filename)
self.connect('scroll-event', lambda widget, event: animate.cancel())
self.last_section = None
self.show_section(0)
for section in self.sections:
section.add_listener(self.section_clicked)
self.set_section(0)
def get_view(self):
return self
def parse_sequence(self, sequence, name):
self.buffer.insert_with_tags(self.buffer.get_end_iter(), 'Sequence %s\n' % name, self.subsection_title)
text = str(sequence.text)
for node in sequence:
text += node.text
text += node.tail
for line in text.split('\n'):
line = line.strip()
if line != '':
self.buffer.insert_with_tags(self.buffer.get_end_iter(), ' %s\n' % line)
def parse_section(self, section):
name = section.get('id')
section_start = self.buffer.create_mark('section-start %s' % name, self.buffer.get_end_iter(), True)
self.buffer.insert_with_tags(self.buffer.get_end_iter(), 'Section %s\n' % section.get('id'), self.section_title)
num = 1
for sequence in section.findall('./sequence'):
self.parse_sequence(sequence, section.get('id') + '.' + str(num))
num += 1
self.sections.append(Section(name, section_start, self.buffer.create_mark('section-end %s' % name, self.buffer.get_end_iter(), True)))
def parse_xml(self, filename):
self.sections = []
root = ET.parse(filename)
treestore = Gtk.TreeStore(str)
vbox = Gtk.VBox()
vbox.get_style_context().add_class('xmlview')
for section in root.findall(".//section"):
self.parse_section(section)
return treestore
def show_section(self, section):
if self.last_section != None:
self.buffer.remove_tag(self.active_section,
self.buffer.get_iter_at_mark(self.sections[self.last_section].start),
self.buffer.get_iter_at_mark(self.sections[self.last_section].end))
self.last_section = section
self.buffer.apply_tag(self.active_section,
self.buffer.get_iter_at_mark(self.sections[section].start),
self.buffer.get_iter_at_mark(self.sections[section].end))
self.sections.append(Section(section))
vbox.pack_start(self.sections[-1], True, True, 5)
return vbox
def get_line_iterator(self):
for section in self.sections:
for sequence in section.sequences:
for line in sequence.lines:
yield line
def get_section(self):
return int(self.current_section.name) - 1
def set_section(self, section_id, scroll=True):
self.current_section = self.sections[section_id]
for section in self.sections:
section.highlight(self.current_section is section)
if scroll:
animate.scroll_to(self, self.current_section)
def section_clicked(self, current):
self.set_section(int(current.name) - 1)
def highlight(self, action):
pass
import animate
from gi.repository import GObject, Gtk, Pango, Gdk
from xml.etree import ElementTree as ET
class Section(Gtk.VBox):
def __init__(self, section):
super(Section, self).__init__()
self.name = section.get('id')
self.get_style_context().add_class('section-body')
self.title = Gtk.EventBox()
self.label = Gtk.Label('Section %s' % self.name)
self.label.get_style_context().add_class('section-title')
self.title.add(self.label)
self.title.connect('button-press-event', self.clicked)
self.handler = None
#cursor = Gdk.Cursor(Gdk.CursorType.HAND1)
#self.label.get_window().set_cursor(cursor)
self.pack_start(self.title, True, True, 5)
self.sequences = []
num = 1
for sequence in section.findall('./sequence'):
self.sequences.append(Sequence(sequence, section.get('id') + '.' + str(num)))
self.pack_start(self.sequences[-1], True, True, 5)
num += 1
def highlight(self, active=True):
if active:
self.label.get_style_context().remove_class('section-title')
self.label.get_style_context().add_class('selected-section-title')
self.get_style_context().add_class('selected-section-body')
self.get_style_context().remove_class('section-body')
else:
self.label.get_style_context().remove_class('selected-section-title')
self.label.get_style_context().add_class('section-title')
self.get_style_context().remove_class('selected-section-body')
self.get_style_context().add_class('section-body')
def clicked(self, widget, event):
if self.handler:
self.handler(int(self.name) - 1)
def set_handler(self, handler):
self.handler = handler
class Sequence(Gtk.VBox):
def __init__(self, sequence, name):
super(Sequence, self).__init__()
self.name = name
self.get_style_context().add_class('sequence-body')
self.label = Gtk.Label('Sequence %s' % name)
self.label.get_style_context().add_class('sequence-title')
self.pack_start(self.label, True, True, 5)
self.lines = []
elements = []
for line in sequence.text.split('\n'):
line = line.strip()
if line != '':
elements.append(Text(line))
if len(elements) > 0:
self.lines.append(Line(elements))
self.pack_start(self.lines[-1], True, True, 5)
elements = []
for node in sequence:
if node.tag == 'keyword':
text = str(node.text).strip()
if node.get('action').strip() != '':
elements.append(Keyword(text, node.get('action'), node.get('lang')))
else:
elements.append(Text(text))
for line in node.tail.split('\n'):
line = line.strip()
if line != '':
elements.append(Text(line))
if len(elements) > 0:
self.lines.append(Line(elements))
self.pack_start(self.lines[-1], True, True, 5)
elements = []
if len(elements) > 0:
self.lines.append(Line(elements))
self.pack_start(self.lines[-1], True, True, 5)
class Line(Gtk.HBox):
def __init__(self, elements):
super(Line, self).__init__()
self.pack_start(Gtk.Label(' '), False, False, 0)
for element in elements:
self.pack_start(element, False, False, 0)
self.elements = elements
self.get_style_context().add_class('text-line')
def set_handler(self, handler):
for element in self.elements:
if hasattr(element, 'set_handler'):
element.set_handler(handler)
def highlight(self, active=True):
if active:
self.label.get_style_context().add_class('highlighted')
else:
self.label.get_style_context().remove_class('highlighted')
class Keyword(Gtk.Label):
def __init__(self, text, action, lang):
super(Keyword, self).__init__()
self.action = action
self.lang = lang
text = '\n'.join([x.strip() for x in text.split('\n')])
self.set_markup(text + ' [<a href="%s">%s</a>] ' % (action, action))
self.get_style_context().add_class('keyword')
self.connect('activate-link', self.link_clicked)
self.handler = None
def set_handler(self, handler):
self.handler = handler
def link_clicked(self, widget, uri):
if self.handler:
self.handler(uri)
return True
class Text(Gtk.Label):
def __init__(self, text):
super(Text, self).__init__()
text = '\n'.join([x.strip() for x in text.split('\n')])
self.set_text(text + ' ')
self.get_style_context().add_class('text')
class XmlView(Gtk.ScrolledWindow):
def __init__(self, filename):
super(XmlView, self).__init__()
self.sections = []
self.words = []
self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
self.vbox = self.parse_xml(filename)
self.add_with_viewport(self.vbox)
self.last_section = None
self.connect('scroll-event', lambda widget, event: animate.cancel())
def get_view(self):
return self
def parse_xml(self, filename):
self.sections = []
root = ET.parse(filename)
vbox = Gtk.VBox()
vbox.get_style_context().add_class('xmlview')
for section in root.findall(".//section"):
self.sections.append(Section(section))
vbox.pack_start(self.sections[-1], True, True, 5)
return vbox
def set_action_clicked_handler(self, handler):
for line in self.get_line_iterator():
line.set_handler(handler)
def get_line_iterator(self):
for section in self.sections:
for sequence in section.sequences:
for line in sequence.lines:
yield line
def highlight_section(self, section):
if section < 1 or section > len(self.sections):
print "invalid section", section
else:
for current in range(len(self.sections)):
self.sections[current].highlight(current == section - 1)
animate.scroll_to(self, self.sections[section - 1])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment