NL/Duration: Support composite durations (#503)

Summary:
E.g. "1 uur en drie kwartier", "1 dag 4 uur", etc.

Pull Request resolved: https://github.com/facebook/duckling/pull/503

Reviewed By: patapizza

Differential Revision: D22260615

Pulled By: chessai

fbshipit-source-id: 40689f7630b4d5bab498df730528ce6bf768fa89
This commit is contained in:
Arjan Scherpenisse 2021-01-27 11:12:21 -08:00 committed by Facebook GitHub Bot
parent a82684e723
commit d095b05060
6 changed files with 89 additions and 1 deletions

View File

@ -60,6 +60,18 @@ allExamples = concat
, examples (DurationData 90 Minute)
[ "anderhalf uur"
]
, examples (DurationData 75 Minute)
[ "een uur en een kwartier"
, "een uur en 15 minuten"
, "een uur, 15 minuten"
, "een uur 15 minuten"
]
, examples (DurationData 165 Minute)
[ "twee uur en drie kwartier"
, "twee uur, 3 kwartier"
, "twee uur, 45 minuten"
, "twee uur 45 minuten"
]
, examples (DurationData 1 Hour)
[ "een uur"
, "één uur"
@ -68,6 +80,7 @@ allExamples = concat
]
, examples (DurationData 30 Day)
[ "30 dagen"
, "4 weken en 2 dagen"
]
, examples (DurationData 7 Day)
[ "7 dagen"

View File

@ -7,6 +7,7 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
module Duckling.Duration.NL.Rules
( rules ) where
@ -18,10 +19,12 @@ import qualified Data.Text as Text
import Duckling.Dimensions.Types
import Duckling.Duration.Helpers
import Duckling.Duration.Types (DurationData(..))
import Duckling.Numeral.Helpers (parseInt, parseInteger)
import Duckling.Numeral.Types (NumeralData(..))
import Duckling.Regex.Types
import Duckling.Types
import qualified Duckling.Duration.Types as TDuration
import qualified Duckling.Numeral.Types as TNumeral
import qualified Duckling.TimeGrain.Types as TG
@ -109,6 +112,41 @@ ruleDurationOneAndHalfHour = Rule
, prod = \_ -> Just . Token Duration $ duration TG.Minute 90
}
-- | NOTE: Oxford comma is not supported.
ruleCompositeDurationCommasAnd :: Rule
ruleCompositeDurationCommasAnd = Rule
{ name = "composite <duration> (with ,/and)"
, pattern =
[ Predicate isNatural
, dimension TimeGrain
, regex ",|en|plus"
, dimension Duration
]
, prod = \case
(Token Numeral NumeralData{TNumeral.value = v}:
Token TimeGrain g:
_:
Token Duration dd@DurationData{TDuration.grain = dg}:
_) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd
_ -> Nothing
}
ruleCompositeDuration :: Rule
ruleCompositeDuration = Rule
{ name = "composite <duration>"
, pattern =
[ Predicate isNatural
, dimension TimeGrain
, dimension Duration
]
, prod = \case
(Token Numeral NumeralData{TNumeral.value = v}:
Token TimeGrain g:
Token Duration dd@DurationData{TDuration.grain = dg}:
_) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd
_ -> Nothing
}
ruleDurationPrecision :: Rule
ruleDurationPrecision = Rule
{ name = "about|exactly <duration>"
@ -125,6 +163,8 @@ rules :: [Rule]
rules =
[ ruleDurationQuarterOfAnHour
, ruleDurationKwartier
, ruleCompositeDurationCommasAnd
, ruleCompositeDuration
, ruleDurationHalfAnHour
, ruleDurationThreeQuartersOfAnHour
, ruleDurationDotNumeralHours

View File

@ -1705,6 +1705,18 @@ classifiers
koData =
ClassData{prior = -infinity, unseen = -1.3862943611198906,
likelihoods = HashMap.fromList [], n = 0}}),
("composite <duration>",
Classifier{okData =
ClassData{prior = -infinity, unseen = -1.0986122886681098,
likelihoods = HashMap.fromList [], n = 0},
koData =
ClassData{prior = 0.0, unseen = -1.9459101490553135,
likelihoods =
HashMap.fromList
[("integer (numeric)hour (grain)<integer> + '\"",
-0.6931471805599453),
("hourminute", -0.6931471805599453)],
n = 2}}),
("summer",
Classifier{okData =
ClassData{prior = 0.0, unseen = -1.0986122886681098,

View File

@ -1698,6 +1698,18 @@ classifiers
koData =
ClassData{prior = -infinity, unseen = -1.3862943611198906,
likelihoods = HashMap.fromList [], n = 0}}),
("composite <duration>",
Classifier{okData =
ClassData{prior = -infinity, unseen = -1.0986122886681098,
likelihoods = HashMap.fromList [], n = 0},
koData =
ClassData{prior = 0.0, unseen = -1.9459101490553135,
likelihoods =
HashMap.fromList
[("integer (numeric)hour (grain)<integer> + '\"",
-0.6931471805599453),
("hourminute", -0.6931471805599453)],
n = 2}}),
("summer",
Classifier{okData =
ClassData{prior = 0.0, unseen = -1.0986122886681098,

View File

@ -1705,6 +1705,18 @@ classifiers
koData =
ClassData{prior = -infinity, unseen = -1.3862943611198906,
likelihoods = HashMap.fromList [], n = 0}}),
("composite <duration>",
Classifier{okData =
ClassData{prior = -infinity, unseen = -1.0986122886681098,
likelihoods = HashMap.fromList [], n = 0},
koData =
ClassData{prior = 0.0, unseen = -1.9459101490553135,
likelihoods =
HashMap.fromList
[("integer (numeric)hour (grain)<integer> + '\"",
-0.6931471805599453),
("hourminute", -0.6931471805599453)],
n = 2}}),
("summer",
Classifier{okData =
ClassData{prior = 0.0, unseen = -1.0986122886681098,

View File

@ -10,7 +10,6 @@ module Duckling.Duration.NL.Tests
) where
import Data.String
import Prelude
import Test.Tasty
import Duckling.Dimensions.Types