6月,Yandex在语音技能开发人员中组织了一次在线黑客马拉松。Just AI上的我们只是在Kotlin上更新了我们的开源框架,以支持新的酷炫Alice功能。并且有必要为自述文件提供一些简单的示例...
关于Kotlin上的几百行代码如何变成Yandex.Station
爱丽丝+科特林= JAICF
Just AI具有用于开发语音应用程序和文本聊天机器人JAICF的开源和完全免费的框架。它是用Kotlin编写的,这是JetBrains的一种编程语言,所有编写血腥企业(或者从Java重写企业)的android和服务器都众所周知。该框架旨在促进为各种语音,文本甚至电话助手创建精确的对话应用程序。
Yandex拥有Alice,它是语音助手,具有令人愉悦的语音和面向第三方开发人员的开放API。也就是说,任何开发人员都可以为数百万用户扩展Alice的功能,甚至可以从Yandex那里获得收益。
我们当然与Alice成为JAICF的正式朋友,因此,您现在可以在Kotlin中编写技能。这就是它的样子。
脚本-> Webhook->对话
Alicia的任何技能都是用户与数字助理之间的语音对话。该对话在JAICF中以脚本的形式描述,然后在webhook服务器上运行,该服务器已在Yandex.Dialogues中注册。
情境
让我们来学习一下黑客马拉松的技巧。在商店购物时,这有助于节省金钱。首先,看看它是如何工作的。
在这里,您可以看到用户如何问爱丽丝- “告诉我什么更有利可图-这么多,这么多或那么多的卢布?”
爱丽丝立即启动我们的技能(因为它被称为“什么是更有利可图的”),并将所有必要的信息传递给它-用户的意图和请求中的数据。
该技能反过来对意图做出反应,处理数据并返回有用的响应。爱丽丝说出答案并关闭,因为该技能结束了会议(他们称此为“一次通过技能”)。
这是一个简单的场景,但是,您可以通过它快速计算出一种产品比另一种产品更有利可图。同时赢得Yandex的演讲专栏。
Kotlin看起来像什么?
object MainScenario: Scenario() {
init {
state("profit") {
activators {
intent("CALCULATE.PROFIT")
}
action {
activator.alice?.run {
val a1 = slots["first_amount"]
val a2 = slots["second_amount"]
val p1 = slots["first_price"]
val p2 = slots["second_price"]
val u1 = slots["first_unit"]
val u2 = slots["second_unit"] ?: firstUnit
context.session["first"] = Product(a1?.value?.double ?: 1.0, p1!!.value.int, u1!!.value.content)
context.session["second"] = p2?.let {
Product(a2?.value?.double ?: 1.0, p2.value.int, u2!!.value.content)
}
reactions.go("calculate")
}
}
state("calculate") {
action {
val first = context.session["first"] as? Product
val second = context.session["second"] as? Product
if (second == null) {
reactions.say(" ?")
} else {
val profit = try {
ProfitCalculator.calculateProfit(first!!, second)
} catch (e: Exception) {
reactions.say(" , . .")
return@action
}
if (profit == null || profit.percent == 0) {
reactions.say(" .")
} else {
val variant = when {
profit.product === first -> ""
else -> ""
}
var reply = "$variant "
reply += when {
profit.percent < 10 -> " ${profit.percent}%."
profit.percent < 100 -> " ${profit.percent}%."
else -> " ${profit.percent}%."
}
context.client["last_reply"] = reply
reactions.say(reply)
reactions.alice?.endSession()
}
}
}
}
state("second") {
activators {
intent("SECOND.PRODUCT")
}
action {
activator.alice?.run {
val a2 = slots["second_amount"]
val p2 = slots["second_price"]
val u2 = slots["second_unit"]
val first = context.session["first"] as Product
context.session["second"] = Product(
a2?.value?.double ?: 1.0,
p2!!.value.int,
u2?.value?.content ?: first.unit
)
reactions.go("../calculate")
}
}
}
}
fallback {
reactions.say(", . " +
" : , 2 230 3 400.")
}
}
}
完整脚本可在Github上获得。
如您所见,这是一个常规对象,它扩展了JAICF库中的Scenario类。基本上,脚本是状态机,其中每个节点都是会话的可能状态。因为对话的上下文是任何语音应用程序中非常重要的组成部分,所以这就是我们在上下文中实现工作的方式。
假设根据对话的上下文,同一短语的解释可能有所不同。顺便说一下,这就是我们选择Kotlin作为我们的框架的原因之一-它允许您创建简单的DSL,在其中可以方便地管理此类嵌套上下文和它们之间的过渡。
状态被激活激活器(例如,一个intent)并执行嵌套的代码块-action。在操作内部,您可以做任何想做的事情,但是最主要的是向用户返回一些有用的答案或询问某些事情。这是通过反应来完成的。单击链接以找到每个实体的详细描述。
意向和广告位
目的是用户请求的语言无关表示。实际上,这是用户希望从您的会话应用程序中获取的内容的标识符。如果您先描述一种特殊的语法,那么
爱丽丝最近学会了如何自动定义技能的意图。此外,她知道如何从形式短语提取必要的数据插槽-例如,价格和货物的体积,在我们的例子。
要使其全部工作,您需要描述此语法和slot。这是我们技能的语法,这些是空位我们在其中使用它。这使我们的技能不仅可以在入口处接收俄语的用户请求行,而且还可以接收已经独立于语言的标识符和转换后的广告位(每种产品的价格及其数量)。
JAICF当然支持任何其他NLU引擎(例如Caila或Dialogflow),但是在我们的示例中,我们希望使用此特定的Alice功能来展示其工作原理。
Webhook
好的,我们有脚本。我们如何检查它是否有效?
当然,测试驱动开发方法的拥护者会喜欢JAICF中针对交互式脚本的内置自动测试机制的存在,由于我们从事大型项目,因此我们个人经常使用该机制,因为我们很难手动检查所有更改。但是我们的示例很小,因此我们最好立即启动服务器,并尝试与Alice交谈。
要运行脚本,您需要一个Webhook-一个服务器,当用户开始与您的技能交谈时,该服务器接受Yandex的传入请求。服务器一点也不难启动-您只需要配置bot并在其上挂一些端点即可。
val skill = BotEngine(
model = MainScenario.model,
activators = arrayOf(
AliceIntentActivator,
BaseEventActivator,
CatchAllActivator
)
)
这是机器人的配置方式-我们在这里描述其中使用了哪些脚本,在何处存储用户数据以及该脚本起作用所需的激活器(可能有多个)。
fun main() {
embeddedServer(Netty, System.getenv("PORT")?.toInt() ?: 8080) {
routing {
httpBotRouting("/" to AliceChannel(skill, useDataStorage = true))
}
}.start(wait = true)
}
但这就是带有Webhook的服务器如何启动的方式-您只需要指定端点应在哪个通道上工作即可。我们在这里运行JetBrains Ktor服务器,但是您可以在JAICF中使用任何其他服务器。
在这里,我们使用了Alice的另一个功能-将用户数据存储在她的内部数据库中(useDataStorage选项)。JAICF将自动从那里保存和恢复上下文,以及脚本编写的所有内容。序列化是透明的。
对话
终于我们可以测试全部了!该服务器在本地运行,因此我们需要一个临时的公共URL,以便来自Alice的请求可以从Internet到达我们的Webhook。为此,使用免费的ngrok工具非常方便,只需在终端中运行命令即可,例如“
ngrok http 8080
所有请求”将实时到达您的PC上-因此您可以调试和编辑代码。
现在,您可以使用接收到的https URL并在Yandex上创建新的Aliego对话框时指定它。对话。在这里,您还可以测试带有文本的对话框。但是,如果您想用声音与某个技能对话,那么爱丽丝现在可以迅速发布私人技能,在开发时仅向您提供。因此,无需经过Yandex的长时间审核,您就可以直接从Alice的应用程序或智能扬声器开始与您的技能进行交谈。
出版物
我们已经测试了所有内容,并准备向所有Alice用户发布该技能!为此,我们的webhook必须托管在具有恒定URL的公共服务器上的某个位置。原则上,JAICF上的应用程序可以在支持Java的任何地方运行(甚至在Android智能手机上)。
我们在Heroku上运行了示例。我们刚刚创建了一个新应用程序,并注册了存储技能代码的Github存储库的地址。Heroku从源代码本身构建并运行一切。我们只需要在Yandex中注册生成的公共URL。对话,然后将其发送给所有人。
总
本小教程紧随Yandex黑客马拉松的脚步,上面的场景“哪个更有利可图”赢得了三个Yandex.Stations之一!顺便说一下,在这里,您会看到它的样子。
Kotlin上的JAICF框架帮助我快速实现和调试对话框脚本,而不必费心使用Alice的API,上下文和数据库,同时又不限制可能性(与相似的库通常如此)。
有用的链接
JAICF的完整文档在这里。
说明爱丽丝创建它的技能是在这里。
该技术本身的来源可以发现那里。
如果你喜欢
就像Yandex的同事们所做的一样, 随时为JAICF做出贡献,或在Github上留下一个星号。 如果您有任何问题,我们都会在舒适的Slack中立即回答。