Skip to content

Commit 690c33b

Browse files
feat: Improved recurrence support, testing for position and recurrence, weekday support, update README (#5)
1 parent a2ac7a6 commit 690c33b

File tree

17 files changed

+567
-190
lines changed

17 files changed

+567
-190
lines changed

Duckling/Dimensions.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ dependents (Seal Ordinal) = HashSet.singleton (Seal Numeral)
9292
dependents (Seal PhoneNumber) = HashSet.empty
9393
dependents (Seal Position) = HashSet.fromList [Seal Numeral, Seal Ordinal]
9494
dependents (Seal Quantity) = HashSet.singleton (Seal Numeral)
95-
dependents (Seal Recurrence) = HashSet.fromList [Seal Numeral, Seal TimeGrain]
95+
dependents (Seal Recurrence) =
96+
HashSet.fromList [Seal Numeral, Seal Duration, Seal Ordinal, Seal TimeGrain, Seal Time]
9697
dependents (Seal RegexMatch) = HashSet.empty
9798
dependents (Seal Temperature) = HashSet.singleton (Seal Numeral)
9899
dependents (Seal Time) =

Duckling/Position/EN/Corpus.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,20 @@ negativeCorpus = (testContext, testOptions, examples)
3434

3535
allExamples :: [Example]
3636
allExamples = concat
37-
[ examples (PositionData 0 1 TPosition.Start)
38-
[ "first one from the left side"
37+
[ examples (PositionData 1 0 TPosition.Start)
38+
[ "first one from the left"
3939
, "one from the top"
4040
, "first from the top"
41-
, "the first relative to the start"
41+
, "first relative to the start"
4242
]
43-
, examples (PositionData (- 1) 1 TPosition.End)
43+
, examples (PositionData 1 (- 1) TPosition.End)
4444
[ "last"
4545
, "bottom one"
46-
, "the one on the right"
46+
, "one on the right"
4747
]
4848
, examples (PositionData 1 1 TPosition.Start)
49-
[ "the second one"
50-
, "the second from the top"
49+
[ "second one"
50+
, "second from the top"
5151
, "second relative to the left"
5252
]
5353
]

Duckling/Ranking/Classifiers/IT_XX.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,10 @@ classifiers
327327
unseen = -4.31748811353631,
328328
likelihoods =
329329
HashMap.fromList
330-
[("<integer> (latent time-of-day)", -0.9718605830289657),
330+
[("<integer> (latent time-of-day)", -0.9718605830289658),
331331
("intersect by \"di\", \"della\", \"del\"", -3.20545280453606),
332332
("day", -2.3581549441488563), ("Lunedi", -3.6109179126442243),
333-
("hour", -0.9718605830289657),
333+
("hour", -0.9718605830289658),
334334
("two time tokens separated by `di`", -3.20545280453606),
335335
("Domenica", -3.6109179126442243)],
336336
n = 33}}),

Duckling/Ranking/Classifiers/TE_XX.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ import qualified Data.HashMap.Strict as HashMap
1919
import Duckling.Ranking.Types
2020

2121
classifiers :: Classifiers
22-
classifiers = HashMap.fromList []
22+
classifiers = HashMap.fromList []

Duckling/Recurrence/EN/Corpus.hs

Lines changed: 142 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,61 @@ module Duckling.Recurrence.EN.Corpus
1212
, negativeCorpus
1313
) where
1414

15-
import Prelude
16-
import Data.String
15+
import Data.Aeson ( ToJSON(toJSON), Object, Value(Object) )
16+
import qualified Data.HashMap.Strict as HashMap
17+
import Data.Text (Text)
1718

18-
import Duckling.Recurrence.Types
19+
import Duckling.Recurrence.Types (RecurrenceValue(..))
20+
import Duckling.Resolve (Context)
1921
import Duckling.Testing.Types
22+
( examplesCustom,
23+
testContext,
24+
testOptions,
25+
Corpus,
26+
Datetime,
27+
Example,
28+
NegativeCorpus,
29+
TestPredicate )
30+
import Duckling.Time.Corpus (datetime, datetimeHoliday)
31+
import Duckling.Time.Types (TimeValue(..))
2032
import Duckling.TimeGrain.Types (Grain(..))
33+
import Duckling.Types (ResolvedToken(Resolved, rval), ResolvedVal(RVal))
34+
import qualified Duckling.Recurrence.Types as TRecurrence
35+
36+
check :: ToJSON a => (Context -> a) -> TestPredicate
37+
check f context Resolved{rval = RVal _ v} = case toJSON v of
38+
Object o -> deleteValues (toJSON (f context)) == deleteValues (Object o)
39+
_ -> False
40+
where
41+
-- need to access and delete values if anchor is set
42+
deleteValues :: Value -> Value
43+
deleteValues (Object o) = do
44+
case unwrapAnchor $ o HashMap.! "anchor" of
45+
Nothing -> Object o
46+
Just a -> do
47+
let anch = Object $ HashMap.delete "values" a
48+
Object $ HashMap.insert "anchor" anch o
49+
deleteValues _ = Object HashMap.empty
50+
51+
unwrapAnchor :: Value -> Maybe Object
52+
unwrapAnchor (Object x) = Just x
53+
unwrapAnchor _ = Nothing
54+
55+
examples :: ToJSON a => (Context -> a) -> [Text] -> [Example]
56+
examples f = examplesCustom (check f)
57+
58+
recurrence :: Int -> Int -> Grain -> Context -> RecurrenceValue
59+
recurrence v t g ctx = RecurrenceValue{TRecurrence.rValue = v, TRecurrence.rTimes = t, TRecurrence.rGrain = g, TRecurrence.rAnchor = Nothing}
60+
61+
anchoredRecurrence :: Int -> Int -> Grain -> Datetime -> Grain -> Context -> RecurrenceValue
62+
anchoredRecurrence v t g dt dtg ctx = RecurrenceValue{TRecurrence.rValue = v, TRecurrence.rTimes = t, TRecurrence.rGrain = g, TRecurrence.rAnchor = a}
63+
where
64+
a = Just $ datetime dt dtg ctx
65+
66+
anchoredRecurrenceHoliday :: Int -> Int -> Grain -> Datetime -> Grain -> Text -> Context -> RecurrenceValue
67+
anchoredRecurrenceHoliday v t g dt dtg h ctx = RecurrenceValue{TRecurrence.rValue = v, TRecurrence.rTimes = t, TRecurrence.rGrain = g, TRecurrence.rAnchor = a}
68+
where
69+
a = Just $ datetimeHoliday dt dtg h ctx
2170

2271
corpus :: Corpus
2372
corpus = (testContext, testOptions, allExamples)
@@ -35,53 +84,94 @@ negativeCorpus = (testContext, testOptions, examples)
3584

3685
allExamples :: [Example]
3786
allExamples = concat
38-
[ examples (RecurrenceData 1 Second Nothing)
39-
[ "every second"
40-
, "per second"
41-
, "each second"
42-
]
43-
, examples (RecurrenceData 1 Minute Nothing)
44-
[ "every minute"
45-
, "per minute"
46-
, "every minute"
47-
]
48-
, examples (RecurrenceData 1 Hour Nothing)
49-
[ "every hour"
50-
, "per hour"
51-
, "every hour"
52-
]
53-
, examples (RecurrenceData 1 Day Nothing)
54-
[ "every day"
55-
, "per day"
56-
, "daily"
57-
]
58-
, examples (RecurrenceData 2 Day Nothing)
59-
[ "every 2 days"
60-
, "per 2 days"
61-
]
62-
, examples (RecurrenceData 1 Week Nothing)
63-
[ "every week"
64-
, "per week"
65-
, "weekly"
66-
]
67-
, examples (RecurrenceData 2 Week Nothing)
68-
[ "every 2 weeks"
69-
, "per 2 week"
70-
, "biweekly"
71-
]
72-
, examples (RecurrenceData 1 Month Nothing)
73-
[ "every month"
74-
, "per month"
75-
, "monthly"
76-
]
77-
, examples (RecurrenceData 1 Year Nothing)
78-
[ "every year"
79-
, "per year"
80-
, "yearly"
81-
]
82-
, examples (RecurrenceData 1 Decade Nothing)
83-
[ "every decade"
84-
, "per decade"
85-
, "each decade"
86-
]
87+
[ examples (recurrence 1 1 Second)
88+
[ "every second"
89+
, "per second"
90+
, "each second"
91+
]
92+
, examples (recurrence 1 1 Minute)
93+
[ "every minute"
94+
, "per minute"
95+
, "every minute"
96+
]
97+
, examples (recurrence 1 1 Hour)
98+
[ "every hour"
99+
, "per hour"
100+
, "every hour"
101+
, "hourly"
102+
]
103+
, examples (recurrence 1 1 Day)
104+
[ "every day"
105+
, "per day"
106+
, "daily"
107+
, "once every day"
108+
]
109+
, examples (recurrence 2 1 Day)
110+
[ "every 2 days"
111+
, "per 2 days"
112+
, "bidaily"
113+
]
114+
, examples (recurrence 1 1 Week)
115+
[ "every week"
116+
, "per week"
117+
, "weekly"
118+
]
119+
, examples (recurrence 2 1 Week)
120+
[ "every 2 weeks"
121+
, "per 2 week"
122+
, "biweekly"
123+
]
124+
, examples (recurrence 1 1 Month)
125+
[ "every month"
126+
, "per month"
127+
, "monthly"
128+
]
129+
, examples (recurrence 1 1 Year)
130+
[ "every year"
131+
, "per year"
132+
, "yearly"
133+
, "annually"
134+
, "annual"
135+
]
136+
, examples (recurrence 1 1 Decade)
137+
[ "every decade"
138+
, "per decade"
139+
, "each decade"
140+
]
141+
, examples (anchoredRecurrence 1 1 Week (2013, 2, 17, 0, 0, 0) Day)
142+
[ "every sunday"
143+
, "per sunday"
144+
, "each sunday"
145+
]
146+
, examples (anchoredRecurrence 1 1 Year (2013, 6, 2, 0, 0, 0) Day)
147+
[ "every June 2nd"
148+
, "per 2nd of June"
149+
, "each Jun 2"
150+
]
151+
, examples (recurrence 1 3 Day)
152+
[ "thrice daily"
153+
, "three times every day"
154+
, "3 times a day"
155+
]
156+
, examples (recurrence 1 2 Week)
157+
[ "twice weekly"
158+
, "two times every week"
159+
, "2 times a week"
160+
]
161+
, examples (recurrence 1 5 Year)
162+
[ "five times each year"
163+
, "five times yearly"
164+
, "5 times annually"
165+
]
166+
, examples (anchoredRecurrenceHoliday 2 3 Year (2013, 12, 25, 0, 0, 0) Day "Christmas")
167+
[ "three times every other christmas"
168+
, "thrice each two xmas"
169+
, "3 times per alternating christmas day"
170+
]
171+
, examples (recurrence 2 1 Quarter)
172+
[ "every 2 quarters"
173+
, "per 2 quarters"
174+
, "biquarterly"
175+
, "every two quarters"
176+
]
87177
]

0 commit comments

Comments
 (0)