This is simple framework for easy develop bots in FSM style on Scala language based on Akka. For now it's support Slack, Skype and Telegram messengers.
For the beginning you need to add dependency for your SBT project:
libraryDependencies += "com.github.kerzok" %% "scalabotapi" % "0.2.8"
Also you need to create bot on different providers:
After that you will can make your own bot.
The AbstractBot trait handle all messages from users and send it to conversations by different criteria.
First of all we need to create new file called EchoBot.scala
and inherits from AbstractBot
.
AbstractBot
apply Data
class as generic argument. As we need no any additional data we use EmptyData
class.
class EchoBot extends AbstractBot[EmptyData] {
override protected var data: EmptyData = EmptyData()
override protected def id: String = ???
override def printHelp: String = ???
override def printUnknown: String = ???
override def startConversation: PartialFunction[Intent, Conversation] = ???
}
After that we need specify id
which need for configuration and also add help and unknown text.
override protected def id: String = "EchoBot"
override def printHelp: String = "This is example echo bot"
override def printUnknown: String = "I don't understand you"
startConversation
is a function which handle all incoming messages and select suitable conversation to handle it.
In our case we need to handle all text messages.
override def startConversation: PartialFunction[Intent, Conversation] = {
case intent: TextIntent => EchoConversation()(intent)
}
EchoConversation
is the class inherited from Conversation
which contains states like FSM.
It applies Intent
and return new BotState
with optionally reply to user.
Our bot will have only one BotState
.
case class EchoConversation() extends Conversation {
override def initialState: BotState = BotState {
case intent: TextIntent => Reply(Exit).withIntent(ReplyMessageIntent(intent.sender, intent.text))
}
}
Exit
is the system BotState
which finish conversation and turn user chat to Idle
.
In configuration file we need to define API keys and tokens for messengers to connect.
EchoBot {
TelegramSource {
id = "Your Telegram API token here"
}
SlackSource {
id = "Your Slack API token here"
}
SkypeSource {
id = "Your Skype API token here"
secret = "Your Skype secret here"
}
}
Also we need to add to specify some Akka Persistence parameters needs for internal use.
akka.persistence.journal.plugin = "akka.persistence.journal.leveldb"
akka.persistence.snapshot-store.plugin = "akka.persistence.snapshot-store.local"
akka.persistence.journal.leveldb.dir = "target/example/journal"
akka.persistence.snapshot-store.local.dir = "target/example/snapshots"
As the result we can run our EchoBot.
object EchoBotMain {
BotHelper.registerBot(classOf[EchoBot])
}
More examples you can find Here.
Extensions is a special mixin for AbstractBot
which contains additional functionality.
There is several extensions available for use:
###Scheduler Extension
Scheduler extension provides job scheduler based on Quartz Job Scheduler.
Job can be set by cron like expression or duration expressions.
Scheduler extension provides special type of intent — SchedulerIntent
— which is send to the bot system as usual intent every time the scheduler triggered.
Example:
val schedulerState = BotState {
...
repeat(s"0 */2 * ? * *", SchedulerIntent("job1", "Hello")) //Will send SchedulerIntent("job1", "Hello") to the bot system every 2 minutes
repeatEvery(3 minutes, SchedulerIntent("job2", "World")) //Will send SchedulerIntent("job2", "World") to the bot system every 3 minutes
...
Reply(Exit)
}
You can catch this Intent
in startConversation
method.
override def startConversation: PartialFunction[Intent, Conversation] = {
...
case intent@SchedulerIntent(_, "Hello") => SchedulerHandlerConversation()(intent)
...
}
To cancel job use delete("jobId")
method.
delete("job1")
###Socket Extension
Socket extension provides requests to the remote servers.
To use this extension you need to call makeRequest
method with SocketIntent which contains params:
sender
— Chat which will be send the resulturl
— Url to callrequestParams
— Parameters of the request
Example:
val params = RequestParams(canCache = true).put("streamId", "feed/https://bash.org.ru/rss/")
makeRequest[BashResponse](SocketIntent(intent.sender, "http://cloud.feedly.com/v3/streams/contents", params))
The answer will be sent to the system and can be processed in BotState
handler .
val responseFromBashHandler: BotState = BotState {
case ResultIntent(sender, result: BashResponse) =>
val itemNumber = Random.nextInt(result.items.size)
val article = result.items(itemNumber)
Reply(Exit)
.withIntent(ReplyMessageIntent(sender, s"<b>${article.title.trim}</b>\n${article.summary.content.trim.replaceAll("<br>", "\n")}"))
}
###TextRazor Extension TextRazor extension is Natural Language Processing Extension (NLP Extension) for improve parsing commands based on TextRazor API. This extension build dependency tree of user command and can be matched with pattern.
To configure TextRazor you need to specify razorApiKey
value in code of your bot.
Example:
override def startConversation: PartialFunction[Intent, Conversation] = {
case intent@TextIntent(_, text) if text.nlpMatch("add|create" -> "team" -> "new") =>
CreateTeamConversation(data)(intent) // Applies expressions like "Create new team", "Please, add new team", "Can you create new team", etc.
case intent@TextIntent(_, text) if text.nlpMatch("teams" -> "manage") =>
ManageTeamsConversation(data)(intent) // Applies expressions like "Menage teams", "Can you manage teams", etc
case intent@TextIntent(_, text) if text.nlpMatch("join" -> * -> "team") =>
JoinTeamConversation(data)(intent) // Applies expressions like "Join SomeTeam team" or something like this
...
}
To write your own extension you need to inherit from Extension trait.
##Intents Intents is a part of data which is used for communicate between part of the bot system and users. There are several types of default intent, but you can create your own intent:
TextIntent
— Simple wrap of user's text sent to bot.
PositiveIntent
— User's positive answer of a question (e.g. "yes").
NegativeIntent
— User's negative answer of a question (e.g. "no").
NumberIntent
— User's number answer. Use when user need to select one of the few answers.
AskChangeStateIntent
— Request to change state of other user (Can be declined if canChange
parameter of the BotState
is true
).
RequireChangeStateIntent
— Requires to change state of other user (Can't be declined).
SystemPositiveIntent
— System positive answer of some request (e.g. ask for change state of other user).
SystemNegativeIntent
— System negative answer of some request (e.g. ask for change state of other user).
ReplyMessageIntent
— Send some text to user (usually use when bot state is changed).
ScheduleIntent
— Message sent by SchedulerExtension when scheduler triggered.
SocketIntent
— Intent for SocketExtension which specify parameters for HTTP request.
SocketReply
— Message sent by SocketExtension which contains the result of HTTP request.
You can create your own Intent by inherited Intent trait and parse it by overriding handleCustomIntent
method.