Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 127 additions & 8 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import calendar
import datetime
import os
import re
Expand All @@ -28,6 +29,7 @@
from ovos_utils.time import now_local, get_next_leap_year
from ovos_utterance_normalizer import UtteranceNormalizerPlugin
from ovos_workshop.decorators import intent_handler
from ovos_workshop.resource_files import ResourceFile
from ovos_workshop.skills import OVOSSkill
from timezonefinder import TimezoneFinder

Expand Down Expand Up @@ -216,6 +218,48 @@ def _mentions_current_weekend(self, utterance: str) -> bool:
normalized_utterance = utterance.casefold()
return any(phrase in normalized_utterance for phrase in current_weekend_phrases)

def _load_cached_entity(self, name: str):
"""Load and cache a locale entity resource."""
cache_key = f"{self.lang}:{name}.entity"
if cache_key not in self.resources.static:
entity_resource = ResourceFile(self.resources.types.entity, name)
values = []
if entity_resource.file_path:
with open(entity_resource.file_path, encoding="utf-8") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#"):
values.append(line)
self.resources.static[cache_key] = values
return self.resources.static[cache_key]

def _get_requested_weekday(self, message):
"""Extract the requested weekday from intent-matched entities."""
weekday_name = (message.data.get("weekday") or "").strip().lower()
if not weekday_name:
return None

weekdays = [day.lower() for day in self._load_cached_entity("weekday")]
try:
weekday_index = weekdays.index(weekday_name)
except ValueError:
return None
return weekday_index, self._render_weekday(weekday_index)

def _render_weekday(self, weekday_index: int) -> str:
"""Render a localized weekday from a weekday index."""
reference_monday = datetime.datetime(2024, 1, 1)
return nice_weekday(reference_monday + datetime.timedelta(days=weekday_index),
lang=self.lang)

def _get_leap_year_query_scope(self, utterance: str) -> str:
"""Return whether the user asked about the current, next, or either year."""
if self.voc_match(utterance, "leap.year.scope.either", lang=self.lang):
return "either"
if self.voc_match(utterance, "leap.year.scope.next", lang=self.lang):
return "next"
return "current"

@staticmethod
def _get_timezone_from_builtins(location_string: str) -> Optional[datetime.tzinfo]:
"""Attempt to resolve a timezone from a location name using geocoding.
Expand Down Expand Up @@ -474,7 +518,7 @@ def handle_query_date(self, message, response_type="simple"):
now = self.get_datetime() # session aware
try:
dt, utt = extract_datetime(utt, anchorDate=now, lang=self.lang) or (now, utt)
except Exception as e:
except Exception:
self.log.exception(f"failed to extract date from '{utt}'")
dt = now

Expand Down Expand Up @@ -565,17 +609,56 @@ def handle_weekday(self, message):
anchorDate=now, lang=self.lang) or (None, None)
if not dt:
self.speak_dialog("extract.date.error")
return

if dt >= now:
dialog = "weekday.at.date.future"
else:
if dt >= now:
dialog = "weekday.at.date.future"
else:
dialog = "weekday.at.date.past"
# TODO - "today" should never trigger this intent, but if it does,
# should we handle it better? nice_date will return "today" in that case
self.speak_dialog(dialog, {
dialog = "weekday.at.date.past"
# TODO - "today" should never trigger this intent, but if it does,
# should we handle it better? nice_date will return "today" in that case
self.speak_dialog(dialog, {
"date": nice_date(dt, lang=self.lang, now=now),
"weekday": nice_weekday(dt, lang=self.lang)})

@intent_handler("weekday.matches.date.intent")
def handle_weekday_match(self, message):
"""Handle yes/no questions about whether a date matches a weekday."""
now = self.get_datetime() # session aware
utterance = message.data.get("utterance", "")
weekday = self._get_requested_weekday(message)
dt, _ = extract_datetime(message.data.get("date") or utterance,
anchorDate=now, lang=self.lang) or (None, None)
if not dt or weekday is None:
self.speak_dialog("extract.date.error")
return

expected_weekday, expected_name = weekday
data = {
"date": nice_date(dt, lang=self.lang, now=now),
"weekday": expected_name,
"actual_weekday": nice_weekday(dt, lang=self.lang)
}
if dt.date() > now.date():
dialog = (
"weekday.matches.date.future.yes"
if dt.weekday() == expected_weekday
else "weekday.matches.date.future.no"
)
elif dt.date() == now.date():
dialog = (
"weekday.matches.date.today.yes"
if dt.weekday() == expected_weekday
else "weekday.matches.date.today.no"
)
else:
dialog = (
"weekday.matches.date.past.yes"
if dt.weekday() == expected_weekday
else "weekday.matches.date.past.no"
)
self.speak_dialog(dialog, data)

@intent_handler("what.month.is.it.intent")
def handle_current_month(self, message):
"""
Expand Down Expand Up @@ -660,6 +743,42 @@ def handle_query_next_leap_year(self, message):
next_leap_year = get_next_leap_year(year)
self.speak_dialog('next.leap.year', {'year': next_leap_year})

@intent_handler("is.leap.year.intent")
def handle_is_leap_year(self, message):
"""Handle yes/no questions about leap years."""
utterance = message.data.get("utterance", "")
now = self.get_datetime()
current_year = now.year
next_year = current_year + 1
scope = self._get_leap_year_query_scope(utterance)

if scope == "either":
if calendar.isleap(current_year):
self.speak_dialog("leap.year.either.yes",
{"year": current_year})
elif calendar.isleap(next_year):
self.speak_dialog("leap.year.either.yes",
{"year": next_year})
else:
self.speak_dialog("leap.year.either.no",
{"year": get_next_leap_year(next_year + 1)})
return

if scope == "next":
if calendar.isleap(next_year):
self.speak_dialog("leap.year.next.yes", {"year": next_year})
else:
self.speak_dialog("leap.year.next.no",
{"year": get_next_leap_year(next_year)})
return

if calendar.isleap(current_year):
self.speak_dialog("leap.year.current.yes",
{"year": current_year})
else:
self.speak_dialog("leap.year.current.no",
{"year": get_next_leap_year(current_year)})

######################################################################
# GUI / Faceplate
def show_date(self, dt: datetime.datetime, location: str):
Expand Down
1 change: 1 addition & 0 deletions locale/en-US/dialog/leap.year.current.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No, {year} is not a leap year.
1 change: 1 addition & 0 deletions locale/en-US/dialog/leap.year.current.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Yes, {year} is a leap year.
1 change: 1 addition & 0 deletions locale/en-US/dialog/leap.year.either.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No. The next leap year after that will be {year}.
1 change: 1 addition & 0 deletions locale/en-US/dialog/leap.year.either.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Yes, {year} is a leap year.
1 change: 1 addition & 0 deletions locale/en-US/dialog/leap.year.next.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No, {year} will not be a leap year.
1 change: 1 addition & 0 deletions locale/en-US/dialog/leap.year.next.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Yes, {year} will be a leap year.
1 change: 1 addition & 0 deletions locale/en-US/dialog/weekday.matches.date.future.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No, {date} will be {actual_weekday}, not {weekday}.
1 change: 1 addition & 0 deletions locale/en-US/dialog/weekday.matches.date.future.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Yes, {date} will be {weekday}.
1 change: 1 addition & 0 deletions locale/en-US/dialog/weekday.matches.date.past.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No, {date} was {actual_weekday}, not {weekday}.
1 change: 1 addition & 0 deletions locale/en-US/dialog/weekday.matches.date.past.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Yes, {date} was {weekday}.
1 change: 1 addition & 0 deletions locale/en-US/dialog/weekday.matches.date.today.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No, {date} is {actual_weekday}, not {weekday}.
1 change: 1 addition & 0 deletions locale/en-US/dialog/weekday.matches.date.today.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Yes, {date} is {weekday}.
4 changes: 4 additions & 0 deletions locale/en-US/intents/is.leap.year.intent
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
is next year a leap year
is this year a leap year
is this year a leap year or next
is this year a leap year or the next one
6 changes: 1 addition & 5 deletions locale/en-US/intents/next.leap.year.intent
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
can you tell me when next leap year is
can you tell me when the next leap year is
is next year a leap year
is this year a leap year
is this year a leap year or next
is this year a leap year or the next one
tell me when next leap year is
tell me when the next leap year is
what date is the next leap year
Expand Down Expand Up @@ -41,4 +37,4 @@ when will we have leap year again
when will we have a leap year again
when will we see leap year again
when will we see a leap year again
which year is the next leap year
which year is the next leap year
30 changes: 1 addition & 29 deletions locale/en-US/intents/weekday.for.date.intent
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,6 @@ do you know which day {date} is
do you know which day {date} was
do you know which weekday {date} is
do you know which weekday {date} was
is {date} a Friday
is {date} a Monday
is {date} a Saturday
is {date} a Sunday
is {date} a Thursday
is {date} a Tuesday
is {date} a Wednesday
is {date} on a Friday
is {date} on a Monday
is {date} on a Saturday
is {date} on a Sunday
is {date} on a Thursday
is {date} on a Tuesday
is {date} on a Wednesday
on what day does {date} fall on
on what day is {date}
on what day of the week does {date} fall on
Expand Down Expand Up @@ -78,20 +64,6 @@ tell me what day {date} is
tell me what day {date} was
tell me what weekday {date} is
tell me what weekday {date} was
was {date} a Friday
was {date} a Monday
was {date} a Saturday
was {date} a Sunday
was {date} a Thursday
was {date} a Tuesday
was {date} a Wednesday
was {date} on a Friday
was {date} on a Monday
was {date} on a Saturday
was {date} on a Sunday
was {date} on a Thursday
was {date} on a Tuesday
was {date} on a Wednesday
what day does {date} fall on
what day is {date}
what day of the week does {date} fall on
Expand Down Expand Up @@ -129,4 +101,4 @@ which weekday is {date}
which weekday was {date}
which weekday will it be on {date}
which weekday {date} is
which weekday {date} was
which weekday {date} was
6 changes: 6 additions & 0 deletions locale/en-US/intents/weekday.matches.date.intent
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
does {date} fall on a {weekday}
is {date} a {weekday}
is {date} on a {weekday}
was {date} a {weekday}
was {date} on a {weekday}
will {date} be on a {weekday}
2 changes: 2 additions & 0 deletions locale/en-US/vocab/leap.year.scope.either.voc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
or next
or the next one
1 change: 1 addition & 0 deletions locale/en-US/vocab/leap.year.scope.next.voc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
next year
Comment thread
JarbasAl marked this conversation as resolved.
7 changes: 7 additions & 0 deletions locale/en-US/weekday.entity
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
monday
tuesday
wednesday
thursday
friday
saturday
sunday
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/leap.year.current.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Non, {year} n'est pas une année bissextile.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/leap.year.current.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Oui, {year} est une année bissextile.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/leap.year.either.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Non. La prochaine année bissextile après cela sera {year}.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/leap.year.either.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Oui, {year} est une année bissextile.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/leap.year.next.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Non, {year} ne sera pas une année bissextile.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/leap.year.next.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Oui, {year} sera une année bissextile.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/weekday.matches.date.future.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Non, {date}, ce sera {actual_weekday}, pas {weekday}.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/weekday.matches.date.future.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Oui, {date}, ce sera {weekday}.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/weekday.matches.date.past.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Non, {date}, c'était {actual_weekday}, pas {weekday}.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/weekday.matches.date.past.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Oui, {date}, c'était bien {weekday}.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/weekday.matches.date.today.no.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Non, {date}, c'est {actual_weekday}, pas {weekday}.
1 change: 1 addition & 0 deletions locale/fr-FR/dialog/weekday.matches.date.today.yes.dialog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Oui, {date}, c'est {weekday}.
12 changes: 12 additions & 0 deletions locale/fr-FR/intents/is.leap.year.intent
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cette année est-elle bissextile
cette année est-elle bissextile ou l'an prochain
cette année est-elle bissextile ou l'année prochaine
cette année est-elle bissextile ou la prochaine
est-ce que cette année est bissextile
est-ce que cette année est bissextile ou l'an prochain
est-ce que cette année est bissextile ou l'année prochaine
est-ce que cette année est bissextile ou la prochaine
est-ce que l'an prochain est bissextile
est-ce que l'année prochaine est bissextile
l'an prochain est-il bissextile
l'année prochaine est-elle bissextile
4 changes: 4 additions & 0 deletions locale/fr-FR/intents/weekday.matches.date.intent
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
est-ce que {date} tombe un {weekday}
le {date} tombe-t-il un {weekday}
le {date} tombait-il un {weekday}
le {date} tombera-t-il un {weekday}
4 changes: 4 additions & 0 deletions locale/fr-FR/vocab/leap.year.scope.either.voc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ou la prochaine
ou l'année prochaine
ou l'an prochain
ou la suivante
2 changes: 2 additions & 0 deletions locale/fr-FR/vocab/leap.year.scope.next.voc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
année prochaine
an prochain
7 changes: 7 additions & 0 deletions locale/fr-FR/weekday.entity
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
lundi
mardi
mercredi
jeudi
vendredi
samedi
dimanche
38 changes: 37 additions & 1 deletion translations/en-us/dialogs.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,42 @@
"This year is {year}",
"The current year is {year}",
"We're in {year} right now"
],
"/dialog/leap.year.current.no.dialog": [
"No, {year} is not a leap year."
],
"/dialog/leap.year.current.yes.dialog": [
"Yes, {year} is a leap year."
],
"/dialog/leap.year.either.no.dialog": [
"No. The next leap year after that will be {year}."
],
"/dialog/leap.year.either.yes.dialog": [
"Yes, {year} is a leap year."
],
"/dialog/leap.year.next.no.dialog": [
"No, {year} will not be a leap year."
],
"/dialog/leap.year.next.yes.dialog": [
"Yes, {year} will be a leap year."
],
"/dialog/weekday.matches.date.future.no.dialog": [
"No, {date} will be {actual_weekday}, not {weekday}."
],
"/dialog/weekday.matches.date.future.yes.dialog": [
"Yes, {date} will be {weekday}."
],
"/dialog/weekday.matches.date.past.no.dialog": [
"No, {date} was {actual_weekday}, not {weekday}."
],
"/dialog/weekday.matches.date.past.yes.dialog": [
"Yes, {date} was {weekday}."
],
"/dialog/weekday.matches.date.today.no.dialog": [
"No, {date} is {actual_weekday}, not {weekday}."
],
"/dialog/weekday.matches.date.today.yes.dialog": [
"Yes, {date} is {weekday}."
]

}
}
Loading
Loading