Skip to content

Commit 4a628be

Browse files
committed
Add /msgall command; bump to 0.1.0
1 parent bcda374 commit 4a628be

File tree

3 files changed

+95
-14
lines changed

3 files changed

+95
-14
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ who don't have a username. Either way, just type the `@` character and select a
2222
You can also include an optional "seed" word following the user mention to tell the bot which word to start with when it generates
2323
the message: `/msg @some_user blah`
2424

25+
### /msgall
26+
To generate a message based on the messages from all users, use the `/msgall` command. Just like with `/msg`, you can
27+
include an optional "seed" word following the command.
28+
2529
### /deletemydata
2630
The `/deletemydata` command allows you to delete your own Markov chain data for the current group. Simply send the command and
2731
confirm your choice when the bot asks.
@@ -42,6 +46,7 @@ Create a Telegram bot via @BotFather. Take down your bot's access token, and set
4246
read all messages in its groups. If privacy mode is enabled, the bot won't be able to build Markov chains. Then, using @BotFather's /setcommands command, copy and paste the following text as your input to set your bot's command list.
4347

4448
msg - Generate message from a user
49+
msgall - Generate message based on all users in this group
4550
deletemydata - Delete your Markov chain data in this group
4651
deletemessagedata - Delete a message from your Markov chain data in this group
4752
deleteuserdata - (Admin only) Delete a user's Markov chain data in this group

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
<groupId>clockvapor.telegram.markov-telegram-bot</groupId>
99
<artifactId>markov-telegram-bot</artifactId>
10-
<version>0.0.0</version>
10+
<version>0.1.0</version>
1111

1212
<properties>
1313
<kotlin.version>1.3.21</kotlin.version>
@@ -27,7 +27,7 @@
2727
<dependency>
2828
<groupId>com.github.clockvapor</groupId>
2929
<artifactId>markov</artifactId>
30-
<version>0.0.0</version>
30+
<version>0.2.0</version>
3131
</dependency>
3232
<dependency>
3333
<groupId>com.github.clockvapor</groupId>

src/main/kotlin/clockvapor/telegram/markov/MarkovTelegramBot.kt

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ class MarkovTelegramBot(private val token: String, private val dataPath: String)
110110
matchesCommand(e0Text, "msg") ->
111111
doMessageCommand(bot, message, chatId, text, entities)
112112

113+
matchesCommand(e0Text, "msgall") ->
114+
doMessageTotalCommand(bot, message, chatId, text, entities)
115+
113116
matchesCommand(e0Text, "deletemydata") ->
114117
doDeleteMyDataCommand(bot, message, chatId, senderId)
115118

@@ -231,6 +234,29 @@ class MarkovTelegramBot(private val token: String, private val dataPath: String)
231234
reply(bot, message, replyText, parseMode)
232235
}
233236

237+
private fun doMessageTotalCommand(bot: Bot, message: Message, chatId: String, text: String,
238+
entities: List<MessageEntity>) {
239+
240+
val e0 = entities[0]
241+
val remainingTexts = text.substring(e0.offset + e0.length).trim().takeIf { it.isNotBlank() }
242+
?.split(whitespaceRegex).orEmpty()
243+
val replyText = when (remainingTexts.size) {
244+
0 -> generateMessageTotal(chatId)
245+
246+
1 -> generateMessageTotal(chatId, remainingTexts.first())?.let { result ->
247+
when (result) {
248+
is MarkovChain.GenerateWithSeedResult.NoSuchSeed ->
249+
"<no such seed exists>"
250+
is MarkovChain.GenerateWithSeedResult.Success ->
251+
result.message.takeIf { it.isNotEmpty() }?.joinToString(" ")
252+
}
253+
}
254+
255+
else -> "<expected only one seed word>"
256+
} ?: "<no data available>"
257+
reply(bot, message, replyText)
258+
}
259+
234260
private fun doDeleteMyDataCommand(bot: Bot, message: Message, chatId: String, senderId: String) {
235261
wantToDeleteOwnData.getOrPut(chatId) { mutableSetOf() } += senderId
236262
val replyText = "Are you sure you want to delete your Markov chain data in this group? " +
@@ -285,18 +311,44 @@ class MarkovTelegramBot(private val token: String, private val dataPath: String)
285311

286312
private fun analyzeMessage(chatId: String, userId: String, text: String) {
287313
val path = getMarkovPath(chatId, userId)
288-
val markovChain = tryOrNull { MarkovChain.read(path) } ?: MarkovChain()
289-
markovChain.add(text.split(whitespaceRegex))
314+
val markovChain = tryOrNull(reportException = false) { MarkovChain.read(path) } ?: MarkovChain()
315+
val totalMarkovChain = getOrCreateTotalMarkovChain(chatId)
316+
val words = text.split(whitespaceRegex)
317+
markovChain.add(words)
290318
markovChain.write(path)
319+
totalMarkovChain.add(words)
320+
totalMarkovChain.write(getTotalMarkovPath(chatId))
321+
}
322+
323+
private fun getOrCreateTotalMarkovChain(chatId: String): MarkovChain {
324+
val path = getTotalMarkovPath(chatId)
325+
var markovChain = tryOrNull(reportException = false) { MarkovChain.read(path) }
326+
if (markovChain == null) {
327+
markovChain = MarkovChain()
328+
for (personalMarkovChain in readAllPersonalMarkov(chatId)) {
329+
markovChain.add(personalMarkovChain)
330+
}
331+
markovChain.write(path)
332+
}
333+
return markovChain
291334
}
292335

293336
private fun generateMessage(chatId: String, userId: String): String? =
294-
tryOrNull { MarkovChain.read(getMarkovPath(chatId, userId)) }?.generate()
337+
tryOrNull(reportException = false) { MarkovChain.read(getMarkovPath(chatId, userId)) }?.generate()
295338
?.takeIf { it.isNotEmpty() }?.joinToString(" ")
296339

297340
private fun generateMessage(chatId: String, userId: String,
298341
seed: String): MarkovChain.GenerateWithSeedResult? =
299-
tryOrNull { MarkovChain.read(getMarkovPath(chatId, userId)) }?.generateWithCaseInsensitiveSeed(seed)
342+
tryOrNull(reportException = false) { MarkovChain.read(getMarkovPath(chatId, userId)) }
343+
?.generateWithCaseInsensitiveSeed(seed)
344+
345+
private fun generateMessageTotal(chatId: String): String? =
346+
tryOrNull(reportException = false) { MarkovChain.read(getTotalMarkovPath(chatId)) }?.generate()
347+
?.takeIf { it.isNotEmpty() }?.joinToString(" ")
348+
349+
private fun generateMessageTotal(chatId: String, seed: String): MarkovChain.GenerateWithSeedResult? =
350+
tryOrNull(reportException = false) { MarkovChain.read(getTotalMarkovPath(chatId)) }
351+
?.generateWithCaseInsensitiveSeed(seed)
300352

301353
private fun reply(bot: Bot, message: Message, text: String, parseMode: ParseMode? = null) {
302354
bot.sendMessage(message.chat.id, text, replyToMessageId = message.messageId, parseMode = parseMode)
@@ -313,10 +365,10 @@ class MarkovTelegramBot(private val token: String, private val dataPath: String)
313365
}
314366

315367
private fun getUserIdForUsername(username: String): String? =
316-
tryOrNull { readUsernames() }?.get(username.toLowerCase(Locale.ENGLISH))
368+
tryOrNull(reportException = false) { readUsernames() }?.get(username.toLowerCase(Locale.ENGLISH))
317369

318370
private fun storeUsername(username: String, userId: String) {
319-
val usernames = tryOrNull { readUsernames() } ?: mutableMapOf()
371+
val usernames = tryOrNull(reportException = false) { readUsernames() } ?: mutableMapOf()
320372
usernames[username.toLowerCase(Locale.ENGLISH)] = userId
321373
writeUsernames(usernames)
322374
}
@@ -333,20 +385,44 @@ class MarkovTelegramBot(private val token: String, private val dataPath: String)
333385
private fun deleteChat(chatId: String): Boolean =
334386
File(getChatPath(chatId)).deleteRecursively()
335387

336-
private fun deleteMarkov(chatId: String, userId: String): Boolean =
337-
File(getMarkovPath(chatId, userId)).delete()
388+
private fun deleteMarkov(chatId: String, userId: String): Boolean {
389+
// remove personal markov chain from total markov chain
390+
val path = getMarkovPath(chatId, userId)
391+
val markovChain = tryOrNull(reportException = false) { MarkovChain.read(path) } ?: MarkovChain()
392+
val totalMarkovChain = getOrCreateTotalMarkovChain(chatId)
393+
totalMarkovChain.remove(markovChain)
394+
totalMarkovChain.write(getTotalMarkovPath(chatId))
395+
396+
// delete personal markov chain
397+
return File(path).delete()
398+
}
338399

339400
private fun deleteMessage(chatId: String, userId: String, text: String) {
401+
val words = text.split(whitespaceRegex)
402+
403+
// remove from personal markov chain
340404
val path = getMarkovPath(chatId, userId)
341-
MarkovChain.read(path).let { markovChain ->
342-
markovChain.remove(text.split(whitespaceRegex))
343-
markovChain.write(path)
344-
}
405+
val markovChain = tryOrNull(reportException = false) { MarkovChain.read(path) } ?: MarkovChain()
406+
markovChain.remove(words)
407+
markovChain.write(path)
408+
409+
// remove from total markov chain
410+
val totalMarkovChain = getOrCreateTotalMarkovChain(chatId)
411+
totalMarkovChain.remove(words)
412+
totalMarkovChain.write(getTotalMarkovPath(chatId))
345413
}
346414

415+
private fun readAllPersonalMarkov(chatId: String): List<MarkovChain> =
416+
File(getChatPath(chatId)).listFiles()
417+
.filter { !it.name.endsWith("total.json") }
418+
.map { MarkovChain.read(it.path) }
419+
347420
private fun getMarkovPath(chatId: String, userId: String): String =
348421
Paths.get(getChatPath(chatId), "$userId.json").toString()
349422

423+
private fun getTotalMarkovPath(chatId: String): String =
424+
Paths.get(getChatPath(chatId), "total.json").toString()
425+
350426
private fun getChatPath(chatId: String): String =
351427
Paths.get(dataPath, chatId).toString().also { File(it).mkdirs() }
352428

0 commit comments

Comments
 (0)