Repository: XiaoMi/MiNLP (language: python)

Issue:
[DUCK] 23号上午8点 form 错误
12H = true，应该是false


Discussion / hints:

Fix patch:
diff --git a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/time/Rules.scala b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/time/Rules.scala
index 64727f4..85b8f51 100644
--- a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/time/Rules.scala
+++ b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/time/Rules.scala
@@ -34,7 +34,7 @@ import com.xiaomi.duckling.dimension.time.enums.{Grain, Hint, IntervalDirection}
 import com.xiaomi.duckling.dimension.time.enums.Grain._
 import com.xiaomi.duckling.dimension.time.enums.Hint._
 import com.xiaomi.duckling.dimension.time.enums.IntervalType.{Closed, Open}
-import com.xiaomi.duckling.dimension.time.form.{PartOfDay, TimeOfDay, Weekend}
+import com.xiaomi.duckling.dimension.time.form.{DayOfWeek, PartOfDay, TimeOfDay, Weekend}
 import com.xiaomi.duckling.dimension.time.grain.{GrainData, TimeGrain}
 import com.xiaomi.duckling.dimension.time.helper.TimeDataHelpers._
 import com.xiaomi.duckling.dimension.time.predicates._
@@ -183,13 +183,19 @@ trait Rules extends DimRules {
         else if (td1.timeGrain == Year && td2.hint == MonthOnly) YearMonth
         else if (td2.hint == Hint.PartOfDay || td2.form.nonEmpty) Hint.PartOfDay
         else Intersect
+      val form = (td1.form, td2.form) match {
+        case (Some(PartOfDay(_)), Some(tod: TimeOfDay)) => Some(tod.copy(is12H = false))
+        case (Some(DayOfWeek), Some(_: TimeOfDay)) => td2.form
+        case (None, _) => td2.form
+        case _ => None
+      }
       // 10号八点，需要去掉AMPM (今天是10号9点时，不应再出20点)
       // 今天8点，需要根据当前时间是出8/20点
       val _td2 = if (td1.hint == Hint.RecentNominal) td2 else removeAMPM(td2)
       val _td1 = FuzzyDayIntervals.enlarge(td1, options.timeOptions.beforeEndOfInterval)
       hint match {
         case Sequence => sequenceProd(_td1, _td2)
-        case _ => tt(intersect(_td1, _td2).map(_.copy(hint = hint, form = td2.form)))
+        case _ => tt(intersect(_td1, _td2).map(_.copy(hint = hint, form = form)))
       }
     }
   }


Test patch:
diff --git a/duckling-fork-chinese/core/src/test/scala/com/xiaomi/duckling/dimension/time/FormTest.scala b/duckling-fork-chinese/core/src/test/scala/com/xiaomi/duckling/dimension/time/FormTest.scala
new file mode 100644
index 0000000..0b909d8
--- /dev/null
+++ b/duckling-fork-chinese/core/src/test/scala/com/xiaomi/duckling/dimension/time/FormTest.scala
@@ -0,0 +1,33 @@
+package com.xiaomi.duckling.dimension.time
+
+import com.xiaomi.duckling.{Api, UnitSpec}
+import com.xiaomi.duckling.dimension.implicits._
+import com.xiaomi.duckling.dimension.time.form.{Form, PartOfDay, TimeOfDay}
+import com.xiaomi.duckling.dimension.time.repeat.{Repeat, RepeatData}
+import com.xiaomi.duckling.ranking.Testing
+
+class FormTest extends UnitSpec {
+  describe("Form") {
+
+    val cases = Table[String, Option[Form]](("query", "form")
+      , ("每个月五号的早上", PartOfDay("早上"))
+      , ("23号8点", TimeOfDay(8, true))
+      , ("23号上午8点", TimeOfDay(8, false))
+      , ("8点", TimeOfDay(8, true))
+      , ("上午8点", TimeOfDay(8, false))
+      , ("23号上午", PartOfDay("上午"))
+      , ("明天上午", PartOfDay("上午"))
+    )
+
+    it("form test") {
+      forEvery(cases) { (query, form) =>
+        val answers = Api.analyze(query, Testing.testContext, Testing.testOptions.copy(targets = Set(Time, Repeat)))
+        answers should not be empty
+        answers.head.token.node.token.data match {
+          case td: TimeData => td.form shouldBe form
+          case repeat: RepeatData => repeat.start.get.form shouldBe form
+        }
+      }
+    }
+  }
+}