def get_websocket(host, port, route='/', ssl=False): """ Returns a connection to a websocket """ client = MessageBusClient(host, port, route, ssl) client.run_in_thread() return client
def handle_radio_talanthus(self, message): print('Setting up client to connect to a local mycroft instance') client = MessageBusClient() client.run_in_thread() print('Sending speak message...') client.emit(Message('speak', data={'utterance': 'Currently at the top of the bounty board is the calamo five at ten million credits a head'}))
def main(): global client print('Setting up client to connect to a local mycroft instance') client = MessageBusClient() client.run_in_thread() client.emit(Message('speak', data={'utterance': 'Ping'})) print('looking for microbit') ser_micro = find_comport(PID_MICROBIT, VID_MICROBIT, 115200) if not ser_micro: print('microbit not found') return print('opening and monitoring microbit port') ser_micro.open() while True: line = ser_micro.readline() if line: # If it isn't a blank line line = line.strip().decode('UTF-8') parse_message(line) ser_micro.close()
from mycroft.skills.core import MycroftSkill, intent_handler, intent_file_handler from mycroft_bus_client import MessageBusClient, Message from adapt.intent import IntentBuilder from google_calendar import getEventData from OpenWeather_api_client import weatherClient client = MessageBusClient() client.run_in_thread() eventDataDict = getEventData() class GoogleCalendarReaderSkill(MycroftSkill): def __init__(self): MycroftSkill.__init__(self) # super(GoogleCalendarReaderSkill, self).__init__( # name='GoogleCalendarReaderSkill') @intent_file_handler("hello.intent") def handle_reader_calendar_google(self, message): self.speak_dialog("hello", data=eventDataDict) # client.emit( # Message('speak', data=eventDataDict)) # def stop(self): # pass def create_skill(): return GoogleCalendarReaderSkill()
class Enclosure: def __init__(self): # Load full config config = get_mycroft_compatible_config() self.lang = config['lang'] self.config = config.get("enclosure") LOG.info(config) config["gui_websocket"] = config.get("gui_websocket", { "host": "0.0.0.0", "base_port": 18181, "route": "/gui", "ssl": False }) config['gui_websocket']["base_port"] = config["gui_websocket"].get( "base_port", config["gui_websocket"].get("port", 18181)) self.global_config = config # Create Message Bus Client self.bus = MessageBusClient() self.gui = create_gui_service(self, config['gui_websocket']) # This datastore holds the data associated with the GUI provider. Data # is stored in Namespaces, so you can have: # self.datastore["namespace"]["name"] = value # Typically the namespace is a meaningless identifier, but there is a # special "SYSTEM" namespace. self.datastore = {} # self.loaded is a list, each element consists of a namespace named # tuple. # The namespace namedtuple has the properties "name" and "pages" # The name contains the namespace name as a string and pages is a # mutable list of loaded pages. # # [Namespace name, [List of loaded qml pages]] # [ # ["SKILL_NAME", ["page1.qml, "page2.qml", ... , "pageN.qml"] # [...] # ] self.loaded = [] # list of lists in order. self.explicit_move = True # Set to true to send reorder commands # Listen for new GUI clients to announce themselves on the main bus self.active_namespaces = [] self.bus.on("mycroft.gui.connected", self.on_gui_client_connected) self.register_gui_handlers() # First send any data: self.bus.on("gui.value.set", self.on_gui_set_value) self.bus.on("gui.page.show", self.on_gui_show_page) self.bus.on("gui.page.delete", self.on_gui_delete_page) self.bus.on("gui.clear.namespace", self.on_gui_delete_namespace) self.bus.on("gui.event.send", self.on_gui_send_event) self.bus.on("gui.status.request", self.handle_gui_status_request) def run(self): """Start the Enclosure after it has been constructed.""" # Allow exceptions to be raised to the Enclosure Service # if they may cause the Service to fail. self.bus.run_in_thread() def stop(self): """Perform any enclosure shutdown processes.""" pass ###################################################################### # GUI client API @property def gui_connected(self): """Returns True if at least 1 gui is connected, else False""" return len(GUIWebsocketHandler.clients) > 0 def handle_gui_status_request(self, message): """Reply to gui status request, allows querying if a gui is connected using the message bus""" self.bus.emit( message.reply("gui.status.request.response", {"connected": self.gui_connected})) def send(self, msg_dict): """ Send to all registered GUIs. """ for connection in GUIWebsocketHandler.clients: try: connection.send(msg_dict) except Exception as e: LOG.exception(repr(e)) def on_gui_send_event(self, message): """ Send an event to the GUIs. """ try: data = { 'type': 'mycroft.events.triggered', 'namespace': message.data.get('__from'), 'event_name': message.data.get('event_name'), 'params': message.data.get('params') } self.send(data) except Exception as e: LOG.error('Could not send event ({})'.format(repr(e))) def on_gui_set_value(self, message): data = message.data namespace = data.get("__from", "") # Pass these values on to the GUI renderers for key in data: if key not in RESERVED_KEYS: try: self.set(namespace, key, data[key]) except Exception as e: LOG.exception(repr(e)) def set(self, namespace, name, value): """ Perform the send of the values to the connected GUIs. """ if namespace not in self.datastore: self.datastore[namespace] = {} if self.datastore[namespace].get(name) != value: self.datastore[namespace][name] = value # If the namespace is loaded send data to GUI if namespace in [l.name for l in self.loaded]: msg = { "type": "mycroft.session.set", "namespace": namespace, "data": { name: value } } self.send(msg) def on_gui_delete_page(self, message): """ Bus handler for removing pages. """ page, namespace, _ = _get_page_data(message) try: with namespace_lock: self.remove_pages(namespace, page) except Exception as e: LOG.exception(repr(e)) def on_gui_delete_namespace(self, message): """ Bus handler for removing namespace. """ try: namespace = message.data['__from'] with namespace_lock: self.remove_namespace(namespace) except Exception as e: LOG.exception(repr(e)) def on_gui_show_page(self, message): try: page, namespace, index = _get_page_data(message) # Pass the request to the GUI(s) to pull up a page template with namespace_lock: self.show(namespace, page, index) except Exception as e: LOG.exception(repr(e)) def __find_namespace(self, namespace): for i, skill in enumerate(self.loaded): if skill[0] == namespace: return i return None def __insert_pages(self, namespace, pages): """ Insert pages into the namespace Args: namespace (str): Namespace to add to pages (list): Pages (str) to insert """ LOG.debug("Inserting new pages") if not isinstance(pages, list): raise ValueError('Argument must be list of pages') self.send({ "type": "mycroft.gui.list.insert", "namespace": namespace, "position": len(self.loaded[0].pages), "data": [{ "url": p } for p in pages] }) # Insert the pages into local reprensentation as well. updated = Namespace(self.loaded[0].name, self.loaded[0].pages + pages) self.loaded[0] = updated def __remove_page(self, namespace, pos): """ Delete page. Args: namespace (str): Namespace to remove from pos (int): Page position to remove """ LOG.debug("Deleting {} from {}".format(pos, namespace)) self.send({ "type": "mycroft.gui.list.remove", "namespace": namespace, "position": pos, "items_number": 1 }) # Remove the page from the local reprensentation as well. self.loaded[0].pages.pop(pos) # Add a check to return any display to idle from position 0 if (pos == 0 and len(self.loaded[0].pages) == 0): self.bus.emit(Message("mycroft.device.show.idle")) def __insert_new_namespace(self, namespace, pages): """ Insert new namespace and pages. This first sends a message adding a new namespace at the highest priority (position 0 in the namespace stack) Args: namespace (str): The skill namespace to create pages (str): Pages to insert (name matches QML) """ LOG.debug("Inserting new namespace") self.send({ "type": "mycroft.session.list.insert", "namespace": "mycroft.system.active_skills", "position": 0, "data": [{ "skill_id": namespace }] }) # Load any already stored Data data = self.datastore.get(namespace, {}) for key in data: msg = { "type": "mycroft.session.set", "namespace": namespace, "data": { key: data[key] } } self.send(msg) LOG.debug("Inserting new page") self.send({ "type": "mycroft.gui.list.insert", "namespace": namespace, "position": 0, "data": [{ "url": p } for p in pages] }) # Make sure the local copy is updated self.loaded.insert(0, Namespace(namespace, pages)) def __move_namespace(self, from_pos, to_pos): """ Move an existing namespace to a new position in the stack. Args: from_pos (int): Position in the stack to move from to_pos (int): Position to move to """ LOG.debug("Activating existing namespace") # Seems like the namespace is moved to the top automatically when # a page change is done. Deactivating this for now. if self.explicit_move: LOG.debug("move {} to {}".format(from_pos, to_pos)) self.send({ "type": "mycroft.session.list.move", "namespace": "mycroft.system.active_skills", "from": from_pos, "to": to_pos, "items_number": 1 }) # Move the local representation of the skill from current # position to position 0. self.loaded.insert(to_pos, self.loaded.pop(from_pos)) def __switch_page(self, namespace, pages): """ Switch page to an already loaded page. Args: pages (list): pages (str) to switch to namespace (str): skill namespace """ try: num = self.loaded[0].pages.index(pages[0]) except Exception as e: LOG.exception(repr(e)) num = 0 LOG.debug('Switching to already loaded page at ' 'index {} in namespace {}'.format(num, namespace)) self.send({ "type": "mycroft.events.triggered", "namespace": namespace, "event_name": "page_gained_focus", "data": { "number": num } }) def show(self, namespace, page, index): """ Show a page and load it as needed. Args: page (str or list): page(s) to show namespace (str): skill namespace index (int): ??? TODO: Unused in code ??? TODO: - Update sync to match. - Separate into multiple functions/methods """ LOG.debug("GUIConnection activating: " + namespace) pages = page if isinstance(page, list) else [page] # find namespace among loaded namespaces try: index = self.__find_namespace(namespace) if index is None: # This namespace doesn't exist, insert them first so they're # shown. self.__insert_new_namespace(namespace, pages) return else: # Namespace exists if index > 0: # Namespace is inactive, activate it by moving it to # position 0 self.__move_namespace(index, 0) # Find if any new pages needs to be inserted new_pages = [p for p in pages if p not in self.loaded[0].pages] if new_pages: self.__insert_pages(namespace, new_pages) else: # No new pages, just switch self.__switch_page(namespace, pages) except Exception as e: LOG.exception(repr(e)) def remove_namespace(self, namespace): """ Remove namespace. Args: namespace (str): namespace to remove """ index = self.__find_namespace(namespace) if index is None: return else: LOG.debug("Removing namespace {} at {}".format(namespace, index)) self.send({ "type": "mycroft.session.list.remove", "namespace": "mycroft.system.active_skills", "position": index, "items_number": 1 }) # Remove namespace from loaded namespaces self.loaded.pop(index) def remove_pages(self, namespace, pages): """ Remove the listed pages from the provided namespace. Args: namespace (str): The namespace to modify pages (list): List of page names (str) to delete """ try: index = self.__find_namespace(namespace) if index is None: return else: # Remove any pages that doesn't exist in the namespace pages = [p for p in pages if p in self.loaded[index].pages] # Make sure to remove pages from the back indexes = [self.loaded[index].pages.index(p) for p in pages] indexes = sorted(indexes) indexes.reverse() for page_index in indexes: self.__remove_page(namespace, page_index) except Exception as e: LOG.exception(repr(e)) ###################################################################### # GUI client socket # # The basic mechanism is: # 1) GUI client announces itself on the main messagebus # 2) Mycroft prepares a port for a socket connection to this GUI # 3) The port is announced over the messagebus # 4) The GUI connects on the socket # 5) Connection persists for graphical interaction indefinitely # # If the connection is lost, it must be renegotiated and restarted. def on_gui_client_connected(self, message): # GUI has announced presence LOG.info('GUI HAS ANNOUNCED!') port = self.global_config["gui_websocket"]["base_port"] LOG.debug("on_gui_client_connected") gui_id = message.data.get("gui_id") LOG.debug("Heard announcement from gui_id: {}".format(gui_id)) # Announce connection, the GUI should connect on it soon self.bus.emit( Message("mycroft.gui.port", { "port": port, "gui_id": gui_id })) def register_gui_handlers(self): # TODO: Register handlers for standard (Mark 1) events # self.bus.on('enclosure.eyes.on', self.on) # self.bus.on('enclosure.eyes.off', self.off) # self.bus.on('enclosure.eyes.blink', self.blink) # self.bus.on('enclosure.eyes.narrow', self.narrow) # self.bus.on('enclosure.eyes.look', self.look) # self.bus.on('enclosure.eyes.color', self.color) # self.bus.on('enclosure.eyes.level', self.brightness) # self.bus.on('enclosure.eyes.volume', self.volume) # self.bus.on('enclosure.eyes.spin', self.spin) # self.bus.on('enclosure.eyes.timedspin', self.timed_spin) # self.bus.on('enclosure.eyes.reset', self.reset) # self.bus.on('enclosure.eyes.setpixel', self.set_pixel) # self.bus.on('enclosure.eyes.fill', self.fill) # self.bus.on('enclosure.mouth.reset', self.reset) # self.bus.on('enclosure.mouth.talk', self.talk) # self.bus.on('enclosure.mouth.think', self.think) # self.bus.on('enclosure.mouth.listen', self.listen) # self.bus.on('enclosure.mouth.smile', self.smile) # self.bus.on('enclosure.mouth.viseme', self.viseme) # self.bus.on('enclosure.mouth.text', self.text) # self.bus.on('enclosure.mouth.display', self.display) # self.bus.on('enclosure.mouth.display_image', self.display_image) # self.bus.on('enclosure.weather.display', self.display_weather) # self.bus.on('recognizer_loop:record_begin', self.mouth.listen) # self.bus.on('recognizer_loop:record_end', self.mouth.reset) # self.bus.on('recognizer_loop:audio_output_start', self.mouth.talk) # self.bus.on('recognizer_loop:audio_output_end', self.mouth.reset) pass
class AppMainWindow(QtWidgets.QMainWindow): def __init__(self, ws): super().__init__() self.ws = ws self.user_utterance = '' self.mycroft_response = '' self.mic_muted = False self.active_skills = [] self.unactive_skills = [] self.title = 'UBUVoiceAssistant 1.2' self.top = 0 self.left = 0 self.width = 500 self.height = 600 self.next_message = 0 self.intent_labels = [] self.setup_ui() def setup_ui(self): self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) self.center_on_screen() self.centralwidget = QtWidgets.QWidget(self) self.setCentralWidget(self.centralwidget) self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) spacer_item = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacer_item, 1, 2, 1, 3) self.verticalLayout_intents = QtWidgets.QVBoxLayout() self.gridLayout.addLayout(self.verticalLayout_intents, 2, 1, 1, 1) self.label_intent1 = self.create_intent_label() self.label_intent2 = self.create_intent_label() self.label_intent3 = self.create_intent_label() self.label_intent4 = self.create_intent_label() self.label_intent5 = self.create_intent_label() self.label_intent6 = self.create_intent_label() self.label_intent7 = self.create_intent_label() self.line = QtWidgets.QFrame(self.centralwidget) size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.line.sizePolicy().hasHeightForWidth()) self.line.setSizePolicy(size_policy) self.line.setLineWidth(1) self.line.setMidLineWidth(0) self.line.setFrameShape(QtWidgets.QFrame.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.gridLayout.addWidget(self.line, 3, 1, 1, 5) self.lineEdit_chat_message = QtWidgets.QLineEdit(self.centralwidget) size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.lineEdit_chat_message.sizePolicy().hasHeightForWidth()) self.lineEdit_chat_message.setSizePolicy(size_policy) self.gridLayout.addWidget(self.lineEdit_chat_message, 8, 1, 1, 4) self.label_intents_title = QtWidgets.QLabel(self.centralwidget) size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.label_intents_title.sizePolicy().hasHeightForWidth()) self.label_intents_title.setSizePolicy(size_policy) font_questions_title = QtGui.QFont() font_questions_title.setPointSize(16) self.label_intents_title.setFont(font_questions_title) self.gridLayout.addWidget(self.label_intents_title, 1, 1, 1, 1) self.scrollArea = QtWidgets.QScrollArea(self.centralwidget) size_policy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.scrollArea.sizePolicy().hasHeightForWidth()) self.scrollArea.setSizePolicy(size_policy) self.scrollArea.setWidgetResizable(True) self.scrollAreaWidgetContents = QtWidgets.QWidget() self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 768, 410)) self.verticalLayout = QtWidgets.QVBoxLayout( self.scrollAreaWidgetContents) self.gridLayout_conversation = QtWidgets.QGridLayout() self.verticalLayout.addLayout(self.gridLayout_conversation) self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.gridLayout.addWidget(self.scrollArea, 7, 1, 1, 5) self.label_chat_title = QtWidgets.QLabel(self.centralwidget) size_policy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.label_chat_title.sizePolicy().hasHeightForWidth()) font_chat_title = QtGui.QFont() font_chat_title.setPointSize(14) self.label_chat_title.setSizePolicy(size_policy) self.label_chat_title.setFont(font_chat_title) self.gridLayout.addWidget(self.label_chat_title, 5, 1) self.pushButton_mic = QtWidgets.QPushButton(self.centralwidget) size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.pushButton_mic.sizePolicy().hasHeightForWidth()) self.pushButton_mic.setSizePolicy(size_policy) self.mic_icon = QtGui.QIcon() self.mic_icon.addPixmap(QtGui.QPixmap("imgs/mic.svg")) self.mic_muted_icon = QtGui.QIcon() self.mic_muted_icon.addPixmap(QtGui.QPixmap("imgs/mic_muted.svg")) self.pushButton_mic.setIcon(self.mic_icon) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(115, 210, 22)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush) self.pushButton_mic.setPalette(palette) self.pushButton_mic.clicked.connect(self.on_mic_pressed) self.gridLayout.addWidget(self.pushButton_mic, 5, 5) self.pushButton_send = QtWidgets.QPushButton(self.centralwidget) self.pushButton_send.setGeometry(QtCore.QRect(399, 550, 50, 30)) self.pushButton_send.setPalette(palette) self.pushButton_send.clicked.connect(self.on_send_pressed) self.gridLayout.addWidget(self.pushButton_send, 8, 5, 1, 1) self.pushButton_logs = QtWidgets.QPushButton(self.centralwidget) self.pushButton_logs.setGeometry(QtCore.QRect(370, 10, 120, 40)) self.logs_file_icon = QtGui.QIcon() self.logs_file_icon.addPixmap(QtGui.QPixmap("imgs/file.svg")) self.pushButton_logs.setIcon(self.logs_file_icon) self.pushButton_logs.clicked.connect(self.on_logs_pressed) self.gridLayout.addWidget(self.pushButton_logs, 1, 5, 1, 1) self.skills_dialog = QtWidgets.QDialog(self) self.skills_dialog.setWindowTitle('Mycroft Skills') self.skills_dialog.resize(600, 600) self.pushButton_skills = QtWidgets.QPushButton(self.centralwidget) self.pushButton_skills.setGeometry(QtCore.QRect(370, 60, 120, 40)) self.skills_list_icon = QtGui.QIcon() self.skills_list_icon.addPixmap(QtGui.QPixmap("imgs/list.svg")) self.pushButton_skills.setIcon(self.skills_list_icon) self.pushButton_skills.clicked.connect(self.on_skills_pressed) self.gridLayout.addWidget(self.pushButton_skills, 2, 5, 1, 1) self.pushButton_manage_skills = QtWidgets.QPushButton( self.skills_dialog) self.pushButton_manage_skills.setGeometry( QtCore.QRect(470, 10, 120, 40)) self.pushButton_manage_skills.clicked.connect( self.on_manage_skills_pressed) # List of the skills that the user should not interact with dangerous_skills = [ 'mycroft-volume.mycroftai', 'mycroft-stop.mycroftai', 'fallback-unknown.mycroftai', 'fallback-query.mycroftai', 'mycroft-configuration.mycroftai' ] # List of the skills in the /opt/mycroft/skills folder [self.active_skills.append(name) for name in listdir('/opt/mycroft/skills/') \ if path.isdir('/opt/mycroft/skills/' + name) and name not in dangerous_skills] # Check if the chat needs to be updated every second self.timer = QtCore.QTimer(self) self.timer.setInterval(1000) self.timer.timeout.connect(self.check_for_chat_update) self.timer.start() self.retranslate_ui() # Send the webservice class to Mycroft server_socket = Thread(target=util.create_server_socket, args=[self.ws]) server_socket.setDaemon(True) server_socket.start() # Start Mycroft services subprocess.run([ 'bash', path.expanduser('~') + '/mycroft-core/start-mycroft.sh', 'all', 'restart' ]) # Wait until Mycroft services are started, there might be a better solution time.sleep(15) # Thread connected to Mycroft MessageBusClient self.bus = MessageBusClient() self.bus.run_in_thread() self.bus.on('speak', self.handle_speak) self.bus.on('recognizer_loop:utterance', self.handle_utterance) # Deactivate mycroft-volume.mycroftai skill, mic works weird when it's active self.bus.emit( Message('skillmanager.deactivate', {'skill': 'mycroft-volume.mycroftai'})) def retranslate_ui(self): if environ['lang'] == 'es-es': self.lineEdit_chat_message.setPlaceholderText( "O puedes escribir tu pregunta") self.label_chat_title.setText("Conversacion") self.pushButton_send.setText("Enviar") self.pushButton_logs.setText("Abrir Logs") self.pushButton_skills.setText("Administrar Skills") self.pushButton_mic.setText('Mute') self.label_intents_title.setText( 'Puedes preguntar: "Hey Mycroft...') self.label_intent1.setText('...abre el calendario"') self.label_intent2.setText('...dime los eventos de (asignatura)"') self.label_intent5.setText('...dime los foros de (asignatura)"') self.label_intent6.setText('...dime mis notas"') self.label_intent3.setText( '...dime los eventos del (dia) de (mes) de (año)"') self.label_intent4.setText('...dime los cambios en (asignatura)"') self.label_intent7.setText('...dime las notas de (asignatura)"') self.pushButton_manage_skills.setText("Guardar") elif environ['lang'] == 'en-us': self.lineEdit_chat_message.setPlaceholderText( "Or you can ask via text") self.label_chat_title.setText("Conversation") self.pushButton_send.setText("Send") self.pushButton_logs.setText("Open Logs") self.pushButton_skills.setText("Manage Skills") self.pushButton_mic.setText('Mute') self.label_intents_title.setText('You can ask: "Hey Mycroft...') self.label_intent1.setText('...open the calendar"') self.label_intent5.setText( '...tell me about the forums of (course)"') self.label_intent6.setText('...tell me my grades"') self.label_intent2.setText( '...tell me about the events of (course)"') self.label_intent3.setText( '...tell me about the events on (month) (day) (year)"') self.label_intent4.setText( '...tell me about the changes of (course)"') self.label_intent7.setText('...tell me the grades of (course)') self.pushButton_manage_skills.setText("Save") def create_intent_label(self): intent_label = QtWidgets.QLabel(self.centralwidget) size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( intent_label.sizePolicy().hasHeightForWidth()) intent_label.setSizePolicy(size_policy) self.verticalLayout_intents.addWidget(intent_label) return intent_label def update_chat(self, source): """ Adds a new label to the chat's gridLayout to the corresponding side --- Parameters: - Char source: 'r' to add to the right side (the response) 'u' to add to the left side (the user) """ tmp_label = QtWidgets.QLabel(self.scrollAreaWidgetContents) tmp_label.setWordWrap(True) if source == 'r': self.gridLayout.addWidget(tmp_label, self.next_message, 1) self.gridLayout_conversation.addWidget(tmp_label, self.next_message, 1) tmp_label.setText(self.mycroft_response) self.mycroft_response = '' elif source == 'u': self.gridLayout_conversation.addWidget(tmp_label, self.next_message, 0) tmp_label.setText(self.user_utterance) self.user_utterance = '' self.next_message += 1 def handle_speak(self, message): self.mycroft_response = message.data.get('utterance') def handle_utterance(self, message): self.user_utterance = message.data['utterances'][0] def check_for_chat_update(self): """ Checks if there's a new message either in self.user_utterance or self.mycroft_response and updates the chat if so """ if self.user_utterance: self.update_chat('u') if self.mycroft_response: self.update_chat('r') def on_send_pressed(self): self.user_utterance = self.lineEdit_chat_message.text() self.bus.emit( Message('recognizer_loop:utterance', {'utterances': [self.user_utterance]})) self.lineEdit_chat_message.setText('') def on_mic_pressed(self): # Switch between muted and unmuted when the mic is pressed if self.mic_muted: self.mic_muted = False self.pushButton_mic.setIcon(self.mic_icon) self.pushButton_mic.setText('Mute') palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(115, 210, 22)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush) self.pushButton_mic.setPalette(palette) self.bus.emit(Message('mycroft.mic.unmute')) else: self.mic_muted = True self.pushButton_mic.setIcon(self.mic_muted_icon) self.pushButton_mic.setText('Unmute') palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 35, 35)) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush) self.pushButton_mic.setPalette(palette) self.bus.emit(Message('mycroft.mic.mute')) def on_logs_pressed(self): self.log_dialog = LogDialog() self.log_dialog.show() def on_skills_pressed(self): scroll_area_skills = QtWidgets.QScrollArea(self.skills_dialog) scroll_area_skills.setGeometry(QtCore.QRect(10, 10, 450, 580)) scroll_area_skills.setWidgetResizable(True) scroll_area_widget_skills = QtWidgets.QWidget() scroll_area_skills.setWidget(scroll_area_widget_skills) skills_grid_layout = QtWidgets.QGridLayout(scroll_area_widget_skills) skills_grid_layout.setGeometry(QtCore.QRect(10, 10, 450, 580)) self.active_skills_checkBoxes = [] self.unactive_skills_checkBoxes = [] # Create checkboxes for every skill in self.active_skills for count, name in enumerate(self.active_skills): check_box = QtWidgets.QCheckBox(scroll_area_widget_skills) spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) check_box.setText(name) check_box.setChecked(True) logo = QtWidgets.QLabel(scroll_area_widget_skills) if 'ubu' in name: logo.setPixmap( QtGui.QPixmap('imgs/ubu_logo.jpg').scaled(20, 20)) else: logo.setPixmap( QtGui.QPixmap('imgs/Mycroft_logo.png').scaled(20, 20)) self.active_skills_checkBoxes.append(check_box) skills_grid_layout.addWidget(logo, count, 0) skills_grid_layout.addWidget(check_box, count, 1) skills_grid_layout.addItem(spacer, count, 2, QtCore.Qt.AlignLeft) # Create checkboxes for every skill in self.unactive_skills for count, name in enumerate(self.unactive_skills, len(self.active_skills)): check_box = QtWidgets.QCheckBox(scroll_area_widget_skills) check_box.setText(name) logo = QtWidgets.QLabel(scroll_area_widget_skills) if 'ubu' in name: logo.setPixmap( QtGui.QPixmap('imgs/ubu_logo.jpg').scaled(20, 20)) else: logo.setPixmap( QtGui.QPixmap('imgs/Mycroft_logo.png').scaled(20, 20)) self.unactive_skills_checkBoxes.append(check_box) skills_grid_layout.addWidget(logo, count, 0) skills_grid_layout.addWidget(check_box, count, 1) skills_grid_layout.addItem(spacer, count, 2, QtCore.Qt.AlignLeft) self.skills_dialog.show() def on_manage_skills_pressed(self): """ Adds the checked skills to self.active_skills and the unchecked to self.unactive_skills and activates or deactivates those skills. """ deactivated = [] activated = [] for cb in self.active_skills_checkBoxes: if not cb.isChecked(): self.bus.emit( Message('skillmanager.deactivate', {'skill': cb.text()})) deactivated.append(cb.text()) for cb in self.unactive_skills_checkBoxes: if cb.isChecked(): self.bus.emit( Message('skillmanager.activate', {'skill': cb.text()})) activated.append(cb.text()) self.active_skills = [ skill for skill in self.active_skills if skill not in deactivated ] self.active_skills.extend(activated) self.unactive_skills = [ skill for skill in self.unactive_skills if skill not in activated ] self.unactive_skills.extend(deactivated) self.skills_dialog.hide() self.on_skills_pressed() def keyPressEvent(self, event): if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): self.on_send_pressed() def center_on_screen(self): resolution = QtWidgets.QDesktopWidget().screenGeometry() self.move((resolution.width() / 2) - (self.frameSize().width() / 2), (resolution.height() / 2) - (self.frameSize().height() / 2)) def closeEvent(self, event): self.close = QtWidgets.QMessageBox() self.close.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel) self.close.setWindowTitle(self.title) if environ['lang'] == 'es-es': self.close.setText("¿Estas seguro?") elif environ['lang'] == 'en-us': self.close.setText("Are you sure?") self.close = self.close.exec() if self.close == QtWidgets.QMessageBox.Yes: self.timer.stop() subprocess.run([ 'bash', path.expanduser('~') + '/mycroft-core/stop-mycroft.sh' ]) event.accept() else: event.ignore()