Skip to content

Commit

Permalink
BOT: minor enhancement
Browse files Browse the repository at this point in the history
each chat chain now has safeThen wrapper that catches exception
  • Loading branch information
sbaldin committed Apr 24, 2022
1 parent 5883965 commit 446f366
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class GreetingChainPresenter(locale: Locale) : DialogChain {
private val longHelpStoryMsg: String

init {
ResourceBundle.getBundle("bot_dialogs", locale).apply {
ResourceBundle.getBundle(getInitialChainLabel(), locale).apply {
greetingWordMsg = getStringWithEmoji("greeting_dialog_hi_message")
greetingAboutBotMsg = getStringWithEmoji("greeting_dialog_about_message")
longHelpStoryMsg = getStringWithEmoji("greeting_dialog_help_msg")
Expand All @@ -35,7 +35,7 @@ class GreetingChainPresenter(locale: Locale) : DialogChain {
}
}

private fun chainPredicate(msg: Message): Boolean {
override fun chainPredicate(msg: Message): Boolean {
return msg.isSentInLast5minutes() && msg.exactCommand("/start")
}

Expand Down Expand Up @@ -63,6 +63,7 @@ class GreetingChainPresenter(locale: Locale) : DialogChain {
}

override fun logger(): Logger = log
override fun getInitialChainLabel(): String = "bot_dialogs"

private fun createGreetingMsg(msg: Message): String {
val greetingWithName = msg.from?.let { "$greetingWordMsg, ${it.first_name}!" } ?: "$greetingWordMsg!"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class GuessBirdByChatMentionChainPresenter(
),
),
)
}.then(label = "guess_bird_photo_finish_step") { msg ->
}.safeThen(label = "guess_bird_photo_finish_step", bot = bot) { msg ->
var lastDialogMsg = ""
handleGuessingResults(
msg = msg,
Expand All @@ -75,6 +75,8 @@ class GuessBirdByChatMentionChainPresenter(

override fun logger(): Logger = log

override fun getInitialChainLabel(): String = "mention_in_chat"

companion object {
val log: Logger = LoggerFactory.getLogger(GuessBirdByChatMentionChainPresenter::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import com.github.sbaldin.tbot.domain.PhotoInteractor
import com.github.sbaldin.tbot.hasPhoto
import com.github.sbaldin.tbot.presentation.base.BaseGuessBirdChainPresenter
import com.github.sbaldin.tbot.toPercentage
import java.text.MessageFormat
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.text.MessageFormat

class GuessBirdByChatPhotoChainPresenter(
conf: BotConf,
Expand Down Expand Up @@ -47,7 +47,7 @@ class GuessBirdByChatPhotoChainPresenter(
),
),
)
}.then(label = "guess_bird_photo_finish_step") { msg ->
}.safeThen(label = "guess_bird_photo_finish_step", bot = bot) { msg ->
var lastDialogMsg = ""
handleGuessingResults(
msg = msg,
Expand All @@ -67,6 +67,8 @@ class GuessBirdByChatPhotoChainPresenter(

override fun logger(): Logger = log

override fun getInitialChainLabel(): String = "new_photo_in_chat_start"

companion object {
val log: Logger = LoggerFactory.getLogger(GuessBirdByChatMentionChainPresenter::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.github.sbaldin.tbot.presentation

import com.elbekD.bot.Bot
import com.elbekD.bot.feature.chain.ChainBuilder
import com.elbekD.bot.feature.chain.jumpToAndFire
import com.elbekD.bot.types.KeyboardButton
import com.elbekD.bot.types.Message
import com.elbekD.bot.types.ReplyKeyboardMarkup
Expand Down Expand Up @@ -37,12 +38,12 @@ class GuessBirdByCmdChainPresenter(
return super.chainPredicate(msg) && startChainPredicates.any { msg.text?.contains(it) ?: false }
}

override fun chain(bot: Bot): ChainBuilder = bot.safeChain("guess_bird_start", this::chainPredicate) { msg ->
override fun chain(bot: Bot): ChainBuilder = bot.safeChain(getInitialChainLabel(), this::chainPredicate) { msg ->
bot.sendMessage(msg.chat.id, startDialogMsg)
}.then(label = "object_detection_step") { msg ->
}.safeThen(label = "object_detection_step", bot = bot) { msg ->
if (msg.new_chat_photo == null && msg.photo == null) {
abortChain(bot, msg.chat.id, msg.from?.id, abortDialogMsg)
return@then
return@safeThen
}
bot.sendMessage(msg.chat.id, guessingInProgressMsg)
when (val objectDetectionResult = detectBirds(bot, msg)) {
Expand All @@ -67,10 +68,11 @@ class GuessBirdByCmdChainPresenter(
chatId = msg.chat.id,
text = "$noDetectedObjMsg ",
)
// jump to next step
bot.jumpToAndFire("guess_bird_photo_crop_photo_step", msg)
}
}
}.then(label = "guess_bird_photo_crop_photo_step") { msg ->
bot.sendMessage(msg.chat.id, guessingInProgressMsg)
}.safeThen(label = "guess_bird_photo_crop_photo_step", bot = bot) { msg ->
val croppedImage = cropDetectedObject(msg, bot)
val birdDistribution = getBirdClassDistribution(croppedImage)
val bestBird = birdInteractor.getBirdWithHighestRate(birdDistribution)
Expand Down Expand Up @@ -99,7 +101,7 @@ class GuessBirdByCmdChainPresenter(
),
),
)
}.then(label = "guess_bird_photo_finish_step") { msg ->
}.safeThen(label = "guess_bird_photo_finish_step", bot = bot) { msg ->
log.info("Finishing step. With message: ${msg.text}")

var lastDialogMsg = ""
Expand All @@ -121,6 +123,8 @@ class GuessBirdByCmdChainPresenter(

override fun logger(): Logger = log

override fun getInitialChainLabel(): String = "guess_bird_start"

companion object {
val log: Logger = LoggerFactory.getLogger(GuessBirdByChatMentionChainPresenter::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,22 @@ abstract class BaseBirdDetectionChainPresenter(
detectionResult.detectedObjects[selectedObj]
}
is ObjectDetectionFailedModel -> {
logger().info("Cropping step has been skipped, due to failed object detection step. Initial image will be used.")
detectionResult.initialPhoto.asDetectedObjects()
}
}

val file = imageCropInteractor.crop(msg.chat.id, msg.from?.id, detectionResult.initialPhoto, detectedObj)
logger().info("Cropping was finished.")
bot.sendPhoto(
chatId = msg.chat.id,
photo = file,
caption = "debug message",
)
/*
Here we output cropped images to be sure that detection and cropping steps were correct
Uncomment in cose you need to test cropping
bot.sendPhoto(
chatId = msg.chat.id,
photo = file,
caption = "debug message",
)
*/
return file
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.sbaldin.tbot.presentation.base

import com.elbekD.bot.Bot
import com.elbekD.bot.feature.chain.ChainBuilder
import com.elbekD.bot.feature.chain.terminateChain
import com.elbekD.bot.types.Message
import com.elbekD.bot.types.ReplyKeyboardMarkup
Expand Down Expand Up @@ -53,6 +54,8 @@ abstract class BaseGuessBirdChainPresenter(
protected val guessingSuccessKeyboard: String
protected val guessingFailKeyboard: String

protected val catchExceptionMessage: String

init {
ResourceBundle.getBundle("bot_dialogs", locale).apply {
startDialogMsg = getStringWithEmoji("find_bird_dialog_start_message")
Expand All @@ -70,13 +73,14 @@ abstract class BaseGuessBirdChainPresenter(

guessingSuccessKeyboard = getStringWithEmoji("find_bird_dialog_success_message")
guessingFailKeyboard = getStringWithEmoji("find_bird_dialog_fail_message")
catchExceptionMessage = getStringWithEmoji("find_bird_dialog_catch_exception_message")
}
}

/**
* Determines whether to run the chain or not
*/
protected open fun chainPredicate(msg: Message): Boolean = msg.isSentInLast5minutes()
override fun chainPredicate(msg: Message): Boolean = msg.isSentInLast5minutes()

protected open fun clearState(chatId: Long, userId: Int?) {
birdClassDistributionByChatId.remove(getUniqueId(chatId, userId))
Expand Down Expand Up @@ -128,6 +132,35 @@ abstract class BaseGuessBirdChainPresenter(
}
}

/**
* Adds the next step for the chain. Steps are executed in the
* order you add them.
* Fallback allow you to send the predicate were used
* to initiate chain, predicate will terminate current chain state and launched it again(currently supports by cmd like /bird)
* @param label a label of the step. If null then label is
* generated by builder. Default is `null`
* @param isTerminal if true then chain terminates on the current step.
* Default is `false`
* @param action an action for the current step
* @return [ChainBuilder]
*/
public fun ChainBuilder.safeThen(
label: String,
isTerminal: Boolean = false,
bot: Bot,
action: (Message) -> Unit,
): ChainBuilder = apply {
val fallbackWrapper = { msg: Message ->
try {
action(msg)
} catch (e: Exception) {
logger().error("Error during chain processing", e)
abortChain(bot, msg.chat.id, msg.from?.id, catchExceptionMessage)
}
}
this.then(label, isTerminal, fallbackWrapper)
}

fun abortChain(bot: Bot, chatId: Long, userId: Int?, message: String) {
bot.sendMessage(
chatId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import com.elbekD.bot.Bot
import com.elbekD.bot.feature.chain.Chain
import com.elbekD.bot.feature.chain.ChainBuilder
import com.elbekD.bot.feature.chain.chain
import com.elbekD.bot.feature.chain.terminateChain
import com.elbekD.bot.types.Message
import com.github.sbaldin.tbot.presentation.base.message.isSentInLast5minutes
import com.vdurmont.emoji.EmojiParser
import org.slf4j.Logger
import java.util.ResourceBundle
Expand All @@ -15,6 +17,16 @@ interface DialogChain {

fun logger(): Logger

/**
* Return label that was used in [DialogChain.safeChain] method as first step label
*/
fun getInitialChainLabel(): String

/**
* Determines whether to run the chain or not
*/
fun chainPredicate(msg: Message): Boolean = msg.isSentInLast5minutes()

/**
* Helper method for creating a [Chain] that is triggered by text message.
* Catches all exception in action and predicate lambdas.
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/bot_dialogs_ru.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ find_bird_dialog_fail_finish_keyboard=Упс...:speak_no_evil: Тогда дер
find_bird_dialog_obj_detection_failed_message=Похоже на фото нет птиц, пожалуйста, отправьте фото с птицами
find_bird_dialog_obj_detection_successful_message=Продолжить
find_bird_dialog_success_message=:thumbsup: Да, ты молодец!
find_bird_dialog_fail_message=:thumbsdown: Хм, ну не знаю...
find_bird_dialog_fail_message=:thumbsdown: Хм, ну не знаю...
find_bird_dialog_catch_exception_message=Упс! что-то пошло не так! Попробуй позднее...
32 changes: 32 additions & 0 deletions todo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
com.github.sbaldin.tbot.domain.GuessingStateHandler - Handle Failed Guessing. Photo from msg(-1217107103) will be added to training dataset. -- исправить лог
com.github.sbaldin.tbot.presentation.base.BaseGuessBirdChainPresenter$safeThen$$inlined$apply$lambda$1 - Error during chain processing
java.nio.file.NoSuchFileException: /Users/fesswood/.cyber_anna_bot/photos/-1217107103.jpg
at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
at java.base/sun.nio.fs.UnixCopyFile.copy(UnixCopyFile.java:546)
at java.base/sun.nio.fs.UnixFileSystemProvider.copy(UnixFileSystemProvider.java:258)
at java.base/java.nio.file.Files.copy(Files.java:1299)
at com.github.sbaldin.tbot.domain.PhotoInteractor.putPhotoToTrainingStorage(PhotoInteractor.kt:65)
at com.github.sbaldin.tbot.domain.GuessingStateHandler.onFailedGuessing(GuessingStateHandler.kt:15)
at com.github.sbaldin.tbot.presentation.base.BaseGuessBirdChainPresenter.handleGuessingResults(BaseGuessBirdChainPresenter.kt:130)
at com.github.sbaldin.tbot.presentation.GuessBirdByChatPhotoChainPresenter$chain$3.invoke(GuessBirdByChatPhotoChainPresenter.kt:52)
at com.github.sbaldin.tbot.presentation.GuessBirdByChatPhotoChainPresenter$chain$3.invoke(GuessBirdByChatPhotoChainPresenter.kt:17)
at com.github.sbaldin.tbot.presentation.base.BaseGuessBirdChainPresenter$safeThen$$inlined$apply$lambda$1.invoke(BaseGuessBirdChainPresenter.kt:155)
at com.github.sbaldin.tbot.presentation.base.BaseGuessBirdChainPresenter$safeThen$$inlined$apply$lambda$1.invoke(BaseGuessBirdChainPresenter.kt:24)
at com.elbekD.bot.feature.chain.Chain.fire$library(Chain.kt:25)
at com.elbekD.bot.feature.chain.ChainController.handle(ChainController.kt:46)
at com.elbekD.bot.UpdateHandler.handle$library(UpdateHandler.kt:87)
at com.elbekD.bot.TelegramBot.onUpdate(TelegramBot.kt:56)
at com.elbekD.bot.TelegramBot.onUpdate(TelegramBot.kt:53)
at com.elbekD.bot.LongPollingBot$start$$inlined$timer$1$lambda$1.accept(LongPollingBot.kt:35)
at com.elbekD.bot.LongPollingBot$start$$inlined$timer$1$lambda$1.accept(LongPollingBot.kt:6)
at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:714)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2137)
at com.elbekD.bot.http.CompletableFutureCoroutine.resumeWith(future.kt:23)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)

0 comments on commit 446f366

Please sign in to comment.