
story.SearchHandler.kt Maven / Gradle / Ivy
/*
* This file is part of the tock-bot-open-data distribution.
* (https://github.com/theopenconversationkit/tock-bot-open-data)
* Copyright (c) 2017 VSCT.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package ai.tock.bot.open.data.story
import ai.tock.bot.connector.ConnectorMessage
import ai.tock.bot.connector.ga.GAHandler
import ai.tock.bot.connector.ga.carouselItem
import ai.tock.bot.connector.ga.gaFlexibleMessageForCarousel
import ai.tock.bot.connector.ga.gaImage
import ai.tock.bot.connector.messenger.MessengerHandler
import ai.tock.bot.connector.messenger.genericElement
import ai.tock.bot.connector.messenger.genericTemplate
import ai.tock.bot.definition.ConnectorDef
import ai.tock.bot.definition.HandlerDef
import ai.tock.bot.definition.ParameterKey
import ai.tock.bot.definition.storyDef
import ai.tock.bot.engine.BotBus
import ai.tock.bot.open.data.OpenDataConfiguration.trainImage
import ai.tock.bot.open.data.SecondaryIntent.indicate_location
import ai.tock.bot.open.data.SecondaryIntent.indicate_origin
import ai.tock.bot.open.data.client.sncf.SncfOpenDataClient
import ai.tock.bot.open.data.client.sncf.model.Journey
import ai.tock.bot.open.data.client.sncf.model.Place
import ai.tock.bot.open.data.client.sncf.model.Section
import ai.tock.bot.open.data.story.MessageFormat.datetimeFormat
import ai.tock.bot.open.data.story.MessageFormat.timeFormat
import ai.tock.bot.open.data.story.SearchDef.SearchParameter.proposal
import ai.tock.translator.by
import java.time.LocalDateTime
/**
* The search intent handler.
*/
val search = storyDef(
"search",
setOf(indicate_origin),
setOf(indicate_location)
) {
//handle generic location intent
if (isIntent(indicate_location) && location != null) {
if (destination == null || origin != null) {
destination = returnsAndRemoveLocation()
} else {
origin = returnsAndRemoveLocation()
}
}
//check mandatory entities
when {
destination == null -> end("For which destination?")
origin == null -> end("For which origin?")
departureDate == null -> end("When?")
}
}
/**
* The search handler definition.
*/
@GAHandler(GASearchConnector::class)
@MessengerHandler(MessengerSearchConnector::class)
class SearchDef(bus: BotBus) : HandlerDef(bus) {
enum class SearchParameter : ParameterKey {
proposal
}
private val d: Place = bus.destination!!
private val o: Place = bus.origin!!
private val date: LocalDateTime = bus.departureDate!!
override fun answer() {
send("From {0} to {1}", o, d)
send("Departure on {0}", date by datetimeFormat)
val journeys = SncfOpenDataClient.journey(o, d, date)
if (journeys.isEmpty()) {
end("Sorry, no routes found :(")
} else {
send("Here is the first proposal:")
connector?.sendFirstJourney(journeys.first())
end()
}
}
}
/**
* Connector specific behaviour.
*/
sealed class SearchConnector(context: SearchDef) : ConnectorDef(context) {
fun Section.title(): CharSequence = i18n("{0} - {1}", from, to)
fun Section.content(): CharSequence =
i18n(
"Departure at {0}, arrival at {1}",
stopDateTimes.first().departureDateTime by timeFormat,
stopDateTimes.last().arrivalDateTime by timeFormat
)
fun sendFirstJourney(journey: Journey) = withMessage(sendFirstJourney(journey.publicTransportSections()))
abstract fun sendFirstJourney(sections: List): ConnectorMessage
}
/**
* Messenger specific behaviour.
*/
class MessengerSearchConnector(context: SearchDef) : SearchConnector(context) {
override fun sendFirstJourney(sections: List): ConnectorMessage =
genericTemplate(
sections.map { section ->
with(section) {
genericElement(
title(),
content(),
trainImage
)
}
}
)
}
/**
* Google Assistant specific behaviour.
*/
class GASearchConnector(context: SearchDef) : SearchConnector(context) {
override fun sendFirstJourney(sections: List): ConnectorMessage =
gaFlexibleMessageForCarousel(
sections.mapIndexed { i, section ->
with(section) {
carouselItem(
search,
title(),
content(),
gaImage(trainImage, "train"),
proposal[i]
)
}
}
)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy