Dodawanie do kalendarza - Voice Assistant

To będzie mój drugi temat z prób z Voice Assistant. Wcześniej był o zmianie programów w TV. Jest tutaj.
Podaje link, bo tam jest kilka zdań jak mam skonfigurowany VA. Generalnie szukam na VA bardziej przydatnych funkcji, jednak cały czas w oparciu na lokalnym asystencie, bez AI. Przyszła pora na wpis do kalendarza. To w/g mnie przydatna funkcja, aby na szybko coś zapisać aby nie zapomnieć.
Po kolei - sentencja (w custom_sentences/pl)

   AddCalendarEvent:
     data:
       - sentences:
          - "dodaj do kalendarza {event} <date> [(o|na) [godzin(ę|ie)] <time>]"
          - "dodaj {event} do kalendarza <date> [(o|na) [godzin(ę|ie)] <time>]"
          - "zapisz w kalendarzu {event} <date> [(o|na) [godzin(ę|ie)] <time>]"
          - "dodaj do kalendarza <date> {event} [(o|na)  [godzin(ę|ie)] <time>]"
          - "zapisz w kalendarzu <date> {event} [(o|na)  [godzin(ę|ie)] <time>]"

         expansion_rules:
           date: "{day}{month_num}"
           # H, H:MM, H.MM, H MM
           time: "{hour}[:{minute}]|{hour}[.{minute}]|{hour}[ {minute}]|{hour}"

         lists:
            # <<< dowolny tekst 
            event:
              wildcard: true

  month_num:
    values:
      - in: "stycznia"
        out: "01"
      - in: "lutego"
        out: "02"
      - in: "marca"
        out: "03"
      - in: "kwietnia"
        out: "04"
      - in: "maja"
        out: "05"
      - in: "czerwca"
        out: "06"
      - in: "lipca"
        out: "07"
      - in: "sierpnia"
        out: "08"
      - in: "września"
        out: "09"
      - in: "października"
        out: "10"
      - in: "listopada"
        out: "11"
      - in: "grudnia"
        out: "12"


Tutaj można się wykazać całą masą innych pomysłów. Zamiana miesiąca na numer w tym miejscu jest prostsza niż robienie tego w skrypcie. Może również przydać się w innych komendach, których jeszcze nie wymyśliłem.
Kolej na intens_script:

AddCalendarEvent:
    speech:
      text: "OK"
    action:
      - variables:
          calendar_entity: "calendar.kalendarz"   # <-- PODMIEŃ NA SWÓJ
          year: "{{ now().year }}"
          # czas istnieje już wtedy, gdy jest jakakolwiek godzina (minuty opcjonalne)
          has_time: "{{ (hour|string|trim) != '' }}"
          day_i: "{{ day|int(0) }}"
          day_ok: "{{ 1 <= day_i <= 31 }}"
          # rzutowania
          hour_i: >-
            {% if has_time %}
              {{ (hour|string|trim|replace(',', '.')|float|int) }}
            {% else %} 0 {% endif %}
          minute_i: >-
            {% if has_time and (minute|string|trim) != '' %}
              {{ (minute|string|trim|replace(',', '.')|float|int) }}
            {% else %} 0 {% endif %}
          date_str: "{{ '%04d-%s-%s' % (year, month_num, day) }}"
          start_dt_str: >-
            {% if has_time %}{{ date_str ~ ' ' ~ '%02d:%02d:00'|format(hour_i, minute_i) }}{% else %}{{ '' }}{% endif %}
          end_dt_str: >-
            {% if has_time %}
              {{ (as_datetime(date_str ~ ' ' ~ '%02d:%02d:00'|format(hour_i, minute_i)) + timedelta(minutes=60)).strftime('%Y-%m-%d %H:%M:%S') }}
            {% else %}{{ '' }}{% endif %}
          # all-day: end = start + 1 dzień (string!)
          end_date_all_day_str: "{{ (as_datetime(date_str) + timedelta(days=1)).strftime('%Y-%m-%d') }}"

      - choose:
          # Wariant Z GODZINĄ
          - conditions:
              - condition: template
                value_template: "{{ has_time and day_ok }}"
            sequence:
              - service: calendar.create_event
                target:
                  entity_id: "{{ calendar_entity }}"
                data:
                  summary: "{{ event | trim }}"
                  start_date_time: "{{ start_dt_str }}"   # "YYYY-MM-DD HH:MM:SS"
                  end_date_time: "{{ end_dt_str }}"
        default:
          # Wariant CAŁODNIOWY
          - condition: template
            value_template: "{{ day_ok }}"
          - service: calendar.create_event
            target:
              entity_id: "{{ calendar_entity }}"
            data:
              summary: "{{ event | trim }}"
              start_date: "{{ date_str }}"              # "YYYY-MM-DD"
              end_date: "{{ end_date_all_day_str }}"    # "YYYY-MM-DD" (start+1)

Proszę o wybaczenie wszystkich programistów, ja tego skryptu nie pisałem, to wynik nierównej walki z AI. Udało się chyba po godzinie.

Dodatkowe wyjaśnienia. Od razu przyjąłem pewne uproszczenia. Jak nie podamy godziny, to tworzy się wydarzenia całodzienne. Nie ma możliwości (oczywiście tylko u mnie) zrobić jakiegoś powtórzenie (np. co rok) . Jak podamy godzinę, to z góry zakładamy, że wydarzenia trwa 60 minut. Generalnie działa.
To wszystko ma na celu stworzenie przydatnego asystenta. Kolejne pomysły już są w głowie…

1 polubienie

Problemy

Zauważyłem tutaj 3 problemy a mianowicie:

  • Problem końca roku: Obecnie skrypt zawsze przyjmuje now().year. Jeśli 30 grudnia powiesz “dodaj wydarzenie na 5 stycznia”, asystent spróbuje dodać je do roku, który właśnie mija (czyli w przeszłości).

  • Walidacja daty: Masz prosty warunek 1 <= day_i <= 31. Jeśli ktoś powie “31 lutego”, skrypt się wyłoży przy próbie konwersji na datę.

  • Relatywne określenia: W asystencie głosowym najczęściej używamy słów “dzisiaj”, “jutro”, “pojutrze”. W Twoim obecnym systemie musisz zawsze podać konkretną datę i miesiąc.

Co bym dodał:

Potwierdzenie głosowe (TTS)

Zamiast “OK”, asystent mógłby powtórzyć co zrozumiał. To daje pewność, że wildcard {event} wyłapał właściwe słowa.

  • Przykład: text: "Dodałem do kalendarza: {{ event }} na dzień {{ day }} {{ month_name }}."

Powiadomienia o konfliktach

Zanim asystent doda wydarzenie, mógłby sprawdzić, czy już coś masz w tym czasie.

  • Jak to zrobić?
    Użyć usługi calendar.get_events przed dodaniem i jeśli lista nie jest pusta, odpowiedzieć: “Uwaga, masz już plany na tę godzinę. Czy na pewno dodać?”

Moja ocena.

Jak narazie oceniam kod na mocne 7/10.
Jak dodasz to te poprawki według mnie ocena poprawi się na 9.5/10.

4 polubienia

Tak, wiem o tych problemach, pewnie się kiedyś nimi zajmę, ale nie teraz. Na razie sprawdzam możliwości asystenta. Co do odpowiedzi TTS - to jest przemyślane. Nie lubię jak do mnie “gada” , chyba już bym wolał powiadomienie na telefon, aby sprawdzić poprawność. Na razie tak zostaje. Może ktoś lepszy poprawi te braki. Ja już pracuje nad kolejnym pomysłem. Generalnie dzięki, bo dla mnie ta ocena jest super.

1 polubienie