GUI Skills (GUIInterface)¶
In a nutshell
When an OVOS device has a screen, a skill can show things on it: text, images, a page of results. This page describes the small Python toolkit a skill author uses to push data to the screen and ask for a page to be displayed. It is a developer topic, and the screen system is being rebuilt (see GUI Adapters). Voice should stay the main way you interact, while the screen is a bonus. See the Glossary for terms.
The OVOS GUI is deprecated — see Screens on OVOS Today for the full picture
This page documents the legacy skill GUI API. There is no generally usable OVOS GUI right now, and a replacement is Upcoming. Voice should remain the primary interface.
📐 Formal specification
The forward model a skill targets is OVOS-GUI-1 — GUI Display Subsystem (a formal architecture spec). Under it, self.gui declares display intent by naming a template from the closed SYSTEM_* vocabulary (SYSTEM_text, SYSTEM_image, SYSTEM_list, SYSTEM_weather, SYSTEM_confirm, …) and pushing flat session-data. Interchangeable render backends draw it, routed by session_id. Two rules matter for skill authors. A skill MUST NOT invent template names or ship its own home/resting screen (the resting display is owned entirely by the backend, §6.9). Image keys carry an http(s) URL or data: URI, never a local filesystem path. The show_* helpers below map onto these templates. The custom-.qml path is legacy and unsupported under OVOS-GUI-1. Where this page and the spec differ, the spec is the canonical target.
Many OVOS devices have a screen. A skill can drive that screen the same way it speaks: through a small Python API. You set some values, ask for a page to be shown, and any connected GUI client (Qt shell, web, terminal, ...) renders it.
In plain terms: self.gui is a dict-like object. You put data in it
(self.gui["name"] = "OVOS"), then call a show_* method to display a page.
Under the hood, self.gui is a SkillGUI instance (a subclass of GUIInterface)
created automatically for every OVOSSkill. On current ovos-workshop the base class
lives in ovos_bus_client.apis.gui.GUIInterface. The skill wrapper is
ovos_workshop.skills.ovos.SkillGUI, namespaced to your skill_id.
Upcoming — unreleased
A planned breaking change rebinds self.gui to a
GUIInterface from the standalone ovos-gui-api-client package (instead of
ovos_bus_client.apis.gui) and drops the ui_directories constructor argument (today,
ui_directories is a dict mapping a framework name, e.g. "qt5", to its local resource
directory, which GUIInterface searches when resolving a relative image/page name to a
file on disk), since skills under the GUI rework no longer ship QML. This is not on a released ovos-workshop. On stable installs self.gui is
still the ovos_bus_client.apis.gui.GUIInterface-based SkillGUI described above. Tracked in
ovos-workshop#420.
Quick start¶
def handle_hello(self, message):
self.gui["name"] = "OpenVoiceOS"
self.gui.show_text("Hello from OVOS!")
self.gui behaves like a dictionary. Values you set are synced to the active
page whenever it (re)renders. The keys you set are visible to the page under the
skill's namespace.
You should see
On a device or emulator with a GUI client connected, triggering handle_hello should pop
up a text page reading "Hello from OVOS!". If nothing appears, confirm a GUI client (e.g.
ovos-gui or the browser-based
ovos-gui-plugin-shell-companion
— warning: archived, deprecated; superseded by
pyhtmx-gui-client)
is connected to the same messagebus as the skill.
Standard page templates¶
To get a unified look and feel without writing any UI code, GUIInterface
provides ready-made SYSTEM_* page templates. You call a helper, it sets the
needed values and shows the matching template. These render on every GUI client
according to its local capabilities.
Text¶
Display simple strings of text (auto-paginated).
Static Image¶
Display a static image such as a jpeg or png.
gui.show_image(url, caption=None, title=None, fill=None,
background_color=None, override_idle=None,
override_animations=False)
fill accepts "PreserveAspectFit", "PreserveAspectCrop", or "Stretch".
url may be a local file path or an http(s) URL. Missing local files are
logged and the call returns without showing anything.
Local paths work today, but the spec says not to rely on them
The installed show_image() (ovos_bus_client.apis.gui.GUIInterface) does accept and
resolve a local filesystem path. That is the current, working behavior described above.
The OVOS-GUI-1 spec box further up this page nonetheless says image keys should carry only
an http(s) URL or data: URI, never a local path. That is the forward-looking contract
for interchangeable render backends, not a rule the current code enforces. Prefer a URL or
data: URI in new skills if you want to stay forward-compatible.
Animated Image¶
Display an animated image such as a gif (same arguments as show_image).
gui.show_animated_image(url, caption=None, title=None, fill=None,
background_color=None, override_idle=None,
override_animations=False)
HTML Snippet¶
Display a local HTML snippet. Complex JavaScript may not be supported by all clients.
Remote URL¶
Display a webpage. Only supported by clients with a full browser engine.
Input Box¶
Show a fullscreen text-entry UI with confirm/cancel buttons.
gui.show_input_box(title=None, placeholder=None, confirm_text=None,
exit_text=None, override_idle=None,
override_animations=False)
Notifications¶
gui.show_notification(content, duration=10, action=None,
noticetype="transient", style="info", callback_data=None)
gui.show_controlled_notification(content, style="info")
gui.remove_controlled_notification()
style is one of info, warning, success, error. noticetype is
transient (auto-timeout) or sticky.
override_idle
override_idle=True keeps your page up indefinitely. An int delays the
return to the idle/home screen for that many seconds. override_animations=True
disables platform transition animations for the page.
The shipped GUIInterface also carries three animation helpers beyond the templates above:
show_face(awake=True, ...) (the classic assistant face), show_loading_animation(text, ...),
and show_status_animation(text, success, ...).
Upcoming — a wider template surface in the standalone package
The templates above are what today's ovos_bus_client.apis.gui.GUIInterface ships. The
forward-looking standalone ovos-gui-api-client GUIInterface (the package
ovos-workshop#420 rebinds
self.gui to) adds more SYSTEM_* helpers: show_list, show_grid, show_table,
show_weather, show_clock, show_timer, show_map, show_media_player,
and the two voice-first dialogue helpers show_confirm(question, ...) and
show_select(items, prompt=None, ...). These are not on a released ovos-workshop.
Treat them as the template set new skills will target once the rebind lands.
Two behavioural notes for that package:
fillvocabulary changes. The standaloneFillModeenum uses"fit"/"crop"/"stretch", not the"PreserveAspectFit"/"PreserveAspectCrop"/"Stretch"values the installedovos_bus_clientshow_image()expects. The value set flips whenself.guirebinds.- Dialogue helpers round-trip. These are visual accompaniments to a spoken question. The
skill must still ask and handle the voice response, and must not block on a GUI
event. Where the display layer supports a touch shortcut,
show_confirmfires<skill_id>.confirm.responsewith{"confirmed": bool}andshow_selectfires<skill_id>.select.responsewith{"value": ...}. The interface also auto-registers an inbound<skill_id>.sethandler so the display layer can push value changes back into the skill's session data.
Custom pages¶
Templates cover common cases, but you can also ship your own pages. Place a
gui/ folder in your skill with your UI files and request them by name:
def handle_food_places(self, message):
self.gui["foodPlaces"] = results
self.gui.show_page("foodplaces") # resolves your gui/ resource
For the Qt/QML client, custom pages are .qml files. See
Mycroft-GUI QT5 for the QML component reference, theming, event
handling, and resting faces. Other clients resolve the same logical page name to
their own format.
Useful page-control methods:
gui.show_pages(page_names, index=0, override_idle=None,
override_animations=False, remove_others=False)
gui.remove_page(page)
gui.remove_pages(page_names)
gui.clear() # reset values + pages (does NOT close the screen)
gui.release() # tell the platform the skill is done with the screen
Usage in Skills¶
self.gui provides a GUIInterface under the self.skill_id namespace, so two
skills setting self.gui["name"] never collide.
def handle_hello(self, message):
self.gui["name"] = "OpenVoiceOS"
self.gui.show_text("Hello from OVOS!")
To react to clicks/events coming back from the page, register a bus handler:
def initialize(self):
self.gui.register_handler("skill.foo.event", self.handle_foo_event)
def handle_foo_event(self, message):
self.speak(message.data["string"])
For OCP media players and idle/home screens see the GUI Service Reference.
Read next: Runtime Requirements in OVOS Related: Resource Files · Screens on OVOS Today · GUI Service (ovos-gui) · GUI Adapter Plugins