Sprachgesteuerter Kalender: Umsetzung

Juni 6, 2023Einblick

Aufgabenstellung

Im Rahmen eines Forschungsprojekts soll eine Erweiterung (auch Skill genannt) für den Sprachassistenten Mycroft programmiert werden. Dieser Skill soll es ermöglichen, über Sprachkommandos mit dem NextCloud Kalender zu interagieren. Der genaue Funktionsumfang wurde in einem Pflichtenheft festgehalten.

Den Artikel bezüglich der Vorbereitung finden Sie hier.

Abfrage des nächsten Termins

Punkt 1 des Pflichtenhefts war die Umsetzung einer Funktion, dass die nächsten Termine über ein Sprachkommando abgefragt werden sollen. Ein Beispielablauf wäre:

User: What's my next appointment?
Mycroft: Your next appointment is on January 11, 2023 and is entitled Team Meeting

Für eine natürliche Eingabe wurden hier mehrere Varianten berücksichtigt:

(What's my | What is my | What are my | ) next {event}?

Der Handler für diesen Intent ist die handle_next_event_intent(self, message) Funktion. Dort wird mithilfe der getNextAppointments() Methode des connectors eine Liste der nächsten Termine abgerufen. Die gefundenen Events werden von Mycroft über die Sprachausgabe verständlich mitgeteilt. Dafür wird ein zuvor definierte Dialog genutzt.

self.speak_dialog('calendar.next.event', {
    'date': helpers.speakDate(event),
    'title': event.getTitle(),
    'event': event_type
})

Abfrage Termine an einem bestimmten Datum

Punkt 2 des Pflichtenhefts war die Umsetzung, Termine an einem bestimmten Datum abzufragen. Auch hier wurden mehrere Varianten für das Sprachkommando definiert:

(What are my|What's my|What is my|) {event} (on|) {date}

Im handle_events_at_day_intent(self, message) Handler wird zunächst das Datum mithilfe der helpers.getDateFromMessage(message) Funktion aus der Spracheingabe gefiltert. Hierbei werden ebenfalls Befehle wie ‚today‘ oder ‚tomorrow‘ berücksichtigt. Dies steigert die natürliche Kommunikation mit Mycroft.

Im Folgenden wird zur Übersicht ausgegeben, wie viele Events an diesem Tag gefunden wurden und anschließend um welche Termine es sich genau handelt:

self.speak(f"{helpers.speakDate_date(target_date)},
you have {len(events)} event{'s:'[:len(events) ^ 1]}")

Neuen Termin anlegen

Punkt 3 des Pflichtenhefts beinhaltet die Umsetzung, neue Termine zum Kalender über ein Sprachkommando hinzuzufügen. Um die Eingabe zu erleichtern, wurde der Befehl aufgeteilt.

Um den Erstellungsprozess zu starten, gibt es einen Befehl mit mehreren Sprachvariationen:

(Create (a new |) | New) {event}

Damit wird der handle_new_event_intent(self,message) Handler aufgerufen. Dieser fragt zunächst nach dem Startpunkt des Termins (self.askForDate(‚Name a start time:‘)). Dabei ist die Eingabe eines Datums oder die Eingabe eines Datums mit Uhrzeit möglich. Neben den gewöhnlichen Befehlen werden hier zudem Eingaben wie z.B. ’next sunday‘ berücksichtigt. Falls Mycroft das Datum nicht versteht, oder die Eingabe fehlerhaft ist, wird noch einmal nach dem Startdatum gefragt.

Nachdem dieses eingegeben wurde, wird auf gleicherweise nach dem Enddatum des Termins gefragt (self.askForDate(‚Name an end time:‘)). Hier wird ebenfalls erneut nachgefragt, falls die Eingabe fehlerhaft, oder nicht verstanden wurde.

Anschließend wird über die self.get_response(‚Name a title:‘) Funktion die Angabe des Termintitels entgegengenommen. Anschließend wird der Termin im connector über die addEvent(title_response, start_time, end_time) Methode angelegt. Nach erfolgreicher Durchführung wird der neue Termin über die Sprachausgabe bestätigt.

Bestimmten Termin löschen

Punkt 4 des Pflichtenhefts beschreibt die Funktionalität, über Sprachkommando einen Termin löschen zu können. Dabei soll es möglich sein, mit der Kombination von Name und Datum diesen Termin zu bestimmen. Gestartet werden kann der Prozess mit diesen Kommandovarianten:

Delete (a| an |) {event}
Remove {event}

Ähnlich wie bei den zuvor beschriebenen Abläufen wird anschließend nach dem Datum des zu löschenden Termins gefragt. Nach erfolgreicher Angabe wird die Angabe des Namen des Termins gefragt. Falls die beiden Angaben mehrere Treffer zur Folge haben, also mindestens zwei Termine am selben Tag, den gleichen Namen besitzen, erfolgt eine zusätzliche Abfrage. Bsp.:

Mycorft: "Found 2 events with the same title"
Mycroft: "Coffee Break on June 10 at 10 AM"
Mycroft: "Coffee Break on June 10 at 3 PM"
Mycroft: "Please select one"

Nun kann über die Spracheingabe einer dieser Termine genannt werden. Nachdem der genaue Termin definiert wurde, der gelöscht werden soll, wird von Mycroft noch eine Sicherheitsabfrage durchgeführt. Dies geschieht über:

response = self.ask_yesno('calendar.delete.event.security.query', {
            'date': date,
            'title': title,
            'event': event_type
        })
return response == 'yes'

Nach dem Aufruf der connector.deleteEventWithNameAndDate(start_time, title, True, beforeDelete, afterDelete, handleMultipleMatches) Methode und der erfolgreichen Löschung wird der Vorgang durch Mycroft bestätigt. Wenn während des Vorgangs kein Termin mit dem angegebenen Namen und dem Datum gefunden wurde, wird der Vorgang an dieser Stelle abgebrochen und mit self.speak_dialog(f“Sorry, cound not found an appointment {helpers.speakDate_date(start_time.date())} with the title {title}“) begründet.

Bestimmten Termin umbenennen

Punkt 5 des Pflichtenhefts, ist die Funktion zum Umbenennen eines Termins. Dabei sollte es möglich sein, die Auswahl des Termins nur mit dem Namen, oder mit Namen und Datum vorzunehmen. Dafür wurden zwei Varianten des Intents ausgearbeitet:

(Change|Rename) (all|the|) (event|appointment) {title} to {new_title}
(Change|Rename) (the|) (event|appointment) {title} on {date} at {event_time} to {new_title}

Dabei werden, wie folgt, alle benötigten Informationen aus der Spracheingabe gefiltert:

eventTitle = helpers.getTitleVar(message)
newEventTitle = helpers.getNewTitleVar(message)
eventDate = helpers.getDateFromMessage(message)
eventTime = helpers.getTimeVar(message)

Wenn nun für das Datum eine Angabe getätigt wurde, wird mithilfe der connector.renameEventWithNameAndDate(eventTitle,newEventTitle,date,False) Methode der Termin umbenannt. Falls kein Datum angegeben wurde, wird die connector.renameEventWithName(eventTitle,newEventTitle) Methode genutzt. Anschließend wird die Änderung über die Sprachausgabe bestätigt.

Let’s talk business

Kontaktieren Sie uns und lassen Sie sich bei einem kostenlosen Erstgespräch von uns beraten. Wir freuen uns darauf, Sie kennenzulernen.

“Gemeinsam gestalten wir ihre digitale Identität”

Philipp Zimmermann

Philipp Zimmermann

Ihr Ansprechpartner

13 + 4 =