facebook/duckling项目的scala复刻版,本项目目前只服务于中文解析,暂时只提供中文文档。
每一种支持的解析类型,比如时间、数字等,被称为一个dimension。
想更多了解duckling是什么,与同类工具的比较可以参考Duckling/Introduction。
目前文档稀少,需要补充什么,欢迎在Issue区提。
在使用之前,适当进行繁转简、全角转半角,可以减轻匹配压力。
返回结果的结构需要提前了解定义,暂不在此中列出,目前需要自行查看代码。
目前只发布了scala_2.11/2.12/2.13的版本,3.0尚未适配,有需要可以在Issue区留言。
maven
<dependency>
<groupId>com.xiaomi.duckling</groupId>
<artifactId>duckling-core_2.1x</artifactId>
<version>x.y.z</version>
</dependency>
sbt
"com.xiaomi.duckling" % "duckling-core" %% "x.y.z"
import duckling.Api
import duckling.dimension.place.{Place, PlaceData}
val answers = Api.analyze(ns, new Context(), Options(targets = Set(Place)))
val candidates = answers.flatMap { answer =>
// answer.token.value是一个ResolvedValue,ResolvedValue是所有结果的共同trait,需要强转/匹配至实现
answer.token.value match {
case placeData: PlaceData =>
placeData.candidates.map(c => (c.getPathStr(), answer.token))
case _ => Nil
}
}
做了方便Java使用的analyzeJ方法,如果觉得使用不够顺滑可以在issue区提出难受的点。
gradle - duckling:duckling-core_2.11:VERSION
import com.google.common.collect.Sets;
import duckling.Api;
import duckling.Types.Context;
import duckling.Types.Options;
import duckling.dimension.EnumeratedDimension;
List<EnumeratedDimension> dims = Lists.newArrayList(EnumeratedDimension.Time, EnumeratedDimension.Duration);
final Types.Context context = new Types.Context(ZonedDateTime.now(), Locale.CHINA);
final Types.Options options = new Types.Options(dims, false);
Context context = new Context(LocalDateTime.now(), Locale.CHINA);
String query = ...;
List<Answer> answers = Api.analyzeJ(query, context, options);
answers.stream().map(answer -> {
answer.token().range(); // 文本区间 [x, y)
ResolvedValue value = answer.token().value();
if(value instanceof TimeValue) {
TimeValue tv = (TimeValue) value;
tv.holiday(); // 如果是从清明节识别来的,这里会标记"清明"
// 时间点
if(tv.timeValue() instanceof SimpleValue) {
InstantValue t = ((SimpleValue) tv.timeValue()).instant();
t.datetime(); // LocalDateTime 时间点
t.grain(); // 粒度
} else if(tv.timeValue() instanceof IntervalValue) {
// 左闭右开
IntervalValue interval = (IntervalValue) tv.timeValue();
interval.start().datetime();
interval.end().datetime();
}
}
// ...
});
项目从duckling.wit.ai抽取了部分样式,仿了一版可视化解析的代码(无意冒犯,侵删)。
测试
sbt
> project server
> runMain com.xiaomi.duckling.server.DucklingApplication
打包
# (可选)训练模型,如果不提供naive_bayes.json,会在启动时现场训练
sbt "project server; runMain duckling.ranking.NaiveBayesRank naive_bayes.json"
cp server/naive_bayes.json server/src/main/resources/
# 打包
sbt server/stage
cd server/target/universal/stage
bash bin/duckling-server
借助于sbt/console可以在命令行中进行尝试,例如
> sbt core/console
> com.xiaomi.duckling.task.NaiveBayesConsole.run()
# 设置解析维度,可以按tab进行自动补全(下面都可以补全)
> dimension time duration
> 三天后
# -2.76096 => {"timeValue":{...,"grain":"Second"}}...}
# 设置参数,开放了四个,有需要可以增加
> option inherit-duration-grain true
> 三天后
# -2.76096 => {"timeValue":{...,"grain":"Day"}}...}
在线体验Demo:/duckling?dim=...&query=...
URL中有dim参数,多个dim用,隔开,dim需要在URL中手工输入,了解前端的同学可以帮忙贡献一个页面交互(现在的开发对这些一窍不通)。
API调用:/api?dim=...&query=...
Intellij IDEA的设置中打开Editor -> Code Style -> Scala
,点击Scheme右侧的小按钮,Import Scheme…
,选择本项目下的intellij_formating.xml
。
参照olafurpg/sbt-ci-release,main分支上的代码会自动更新至sonatype的snapshot,推送名字为"*D"的分支则会触发github actions中的duckling的部署。
// 发布确保version.sbt中的版本与待发布版本一致:ThisBuild / version := "x.y.z"
git tag -a "vx.y.zD" -m "duckling x.y.z"
git push origin vx.y.zD
// 或者直接使用脚本
sh bin/release.sh x.y.z
duckling-fork-chinese 对每一类模式词的抽取,创建了一类Dimension,如:Numeral, Time, PhoneNumber, ...等等 需要新增一类模式词时请注意以下要求:
- 在core/src/main/scala/duckling/dimension路径下新增该如何新增一个Dimension的目录
- 在FullDimensions和EnumeratedDimension中引入新定义的Dimension
- 在新目录下给出该功能的测试Examples
- 在编写该Dimension的解析规则时尽可能复用现有的Dimension
我们在做时间解析的农历部分时,大量使用了LunarCalendar,并得到了heqiao2010的支持,在此表示非常感谢。
duckling-fork-chinese Apache 2.0
项目是在用Scala重写facebook/duckling的基础上开展的,另附上duckling的原BSD License