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. A skill author uses a small Python toolkit to push data to the screen and ask for a page to be displayed. It is a developer topic. For the GUI rework, 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 for the full picture
The skill GUI API is legacy. OVOS has no generally usable GUI, and the replacement is not released. Voice is 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 manual 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. In 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.
Alpha channel only
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 (in the
released code, 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), because skills under the GUI rework do not ship QML. No published ovos-workshop carries this change. In every published release, self.gui is
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, 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, as described above.
The OVOS-GUI-1 spec box above says image keys carry only
an http(s) URL or data: URI, never a local path. That is the contract
for interchangeable render backends. The code does not enforce it. Use a URL or
data: URI in a skill to stay compatible with the spec.
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, ...).
Pending change: a wider template surface in the standalone package
The templates above are what ovos_bus_client.apis.gui.GUIInterface ships. The
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.
They are the template set for skills after the rebind merges.
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 · GUI Service (ovos-gui) · GUI Adapter Plugins