Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
LaoLittle committed May 28, 2022
1 parent 0af6e0e commit 9f8ec5f
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 110 deletions.
5 changes: 1 addition & 4 deletions src/main/kotlin/CodecExtension.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package org.laolittle.plugin.draw

import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.Codec
import org.jetbrains.skia.Image

operator fun Codec.get(frame: Int) {
val bitmap = Bitmap()
bitmap.allocPixels(imageInfo)
readPixels(bitmap, frame)
}

fun Bitmap.asImage() = Image.makeFromBitmap(this)
}
7 changes: 7 additions & 0 deletions src/main/kotlin/DrawMeme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ object DrawMeme : KotlinPlugin(

// 零溢事件
finding(zeroReg) { r ->
if (message.firstIsInstance<PlainText>()
.content
.trim()
.replace("#", "")
.contains(Regex("""\D"""))
) return@finding // avoid #\dxxx

val real = r.groupValues[1].toInt()

if (real > 100) return@finding
Expand Down
108 changes: 2 additions & 106 deletions src/main/kotlin/General.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ package org.laolittle.plugin.draw
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import kotlinx.coroutines.TimeoutCancellationException
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageSource.Key.quote
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.firstIsInstanceOrNull
import net.mamoe.mirai.message.nextMessage
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.Rect
import java.nio.file.Path
import kotlin.io.path.readBytes
import kotlin.math.max
import kotlin.math.min
import org.jetbrains.skia.Image as SkImage

internal val httpClient = HttpClient(OkHttp)
Expand Down Expand Up @@ -68,106 +66,4 @@ internal suspend fun MessageEvent.getOrWaitImage(): Image? {
}).firstIsInstanceOrNull<Image>()
}

internal fun String.fuzzyMatchWith(target: String): Double {
if (this == target) {
return 1.0
}
var match = 0
for (i in 0..(max(this.lastIndex, target.lastIndex))) {
val t = target.getOrNull(match) ?: break
if (t == this.getOrNull(i)) {
match++
}
}

val longerLength = max(this.length, target.length)
val shorterLength = min(this.length, target.length)

return match.toDouble() / (longerLength + (shorterLength - match))
}

/**
* @return candidates
*/
internal fun Group.fuzzySearchMember(
nameCardTarget: String,
minRate: Double = 0.2, // 参与判断, 用于提示可能的解
matchRate: Double = 0.6,// 最终选择的最少需要的匹配率, 减少歧义
/**
* 如果有多个值超过 [matchRate], 并相互差距小于等于 [disambiguationRate], 则认为有较大歧义风险, 返回可能的解的列表.
*/
disambiguationRate: Double = 0.1,
): List<Pair<Member, Double>> {
val candidates = (this.members + botAsMember)
.asSequence()
.associateWith { it.nameCardOrNick.fuzzyMatchWith(nameCardTarget) }
.filter { it.value >= minRate }
.toList()
.sortedByDescending { it.second }

val bestMatches = candidates.filter { it.second >= matchRate }

return when {
bestMatches.isEmpty() -> candidates
bestMatches.size == 1 -> listOf(bestMatches.single().first to 1.0)
else -> {
if (bestMatches.first().second - bestMatches.last().second <= disambiguationRate) {
// resolution ambiguity
candidates
} else {
listOf(bestMatches.first().first to 1.0)
}
}
}
}

/**
* 通过消息获取联系人
* 若[Contact]为[Group],则可通过群员昵称获取联系人
* 否则通过QQ号查找,查找失败返回``null``
* @param msg 传入的消息[String]
* @return User if only one is found null otherwise
* */
fun Contact.findUserOrNull(msg: String): User? {
val noneAt = msg.replace("@", "").replace(" ", "")
if (noneAt.isBlank()) {
return null
}
return if (noneAt.contains(Regex("""\D"""))) {
when (this) {
is Group -> this.findMemberOrNull(noneAt)
else -> null
}
} else {
val number = noneAt.toLong()
when (this) {
is Group -> this[number]
else -> bot.getFriend(number) ?: bot.getStranger(number)
}
}
}

/**
* 从一个群中模糊搜索昵称是[nameCard]的群员
* @param nameCard 群员昵称
* @return Member if only one exist or null otherwise
* @author mamoe
* */
private fun Group.findMemberOrNull(nameCard: String): Member? {
this.members.singleOrNull { it.nameCardOrNick.contains(nameCard) }?.let { return it }
this.members.singleOrNull { it.nameCardOrNick.contains(nameCard, ignoreCase = true) }?.let { return it }

val candidates = this.fuzzySearchMember(nameCard)
candidates.singleOrNull()?.let {
if (it.second == 1.0) return it.first // single match
}
var maxPerMember: Member? = null
if (candidates.isNotEmpty()) {
var maxPer = 0.0
candidates.forEach {
if (it.second > maxPer) maxPerMember = it.first
maxPer = it.second
}
}
return maxPerMember
}
fun Bitmap.asImage() = org.jetbrains.skia.Image.makeFromBitmap(this)
110 changes: 110 additions & 0 deletions src/main/kotlin/Match.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.laolittle.plugin.draw

import net.mamoe.mirai.contact.*
import kotlin.math.max
import kotlin.math.min


internal fun String.fuzzyMatchWith(target: String): Double {
if (this == target) {
return 1.0
}
var match = 0
for (i in 0..(max(this.lastIndex, target.lastIndex))) {
val t = target.getOrNull(match) ?: break
if (t == this.getOrNull(i)) {
match++
}
}

val longerLength = max(this.length, target.length)
val shorterLength = min(this.length, target.length)

return match.toDouble() / (longerLength + (shorterLength - match))
}

/**
* @return candidates
*/
internal fun Group.fuzzySearchMember(
nameCardTarget: String,
minRate: Double = 0.2, // 参与判断, 用于提示可能的解
matchRate: Double = 0.6,// 最终选择的最少需要的匹配率, 减少歧义
/**
* 如果有多个值超过 [matchRate], 并相互差距小于等于 [disambiguationRate], 则认为有较大歧义风险, 返回可能的解的列表.
*/
disambiguationRate: Double = 0.1,
): List<Pair<Member, Double>> {
val candidates = (this.members + botAsMember)
.asSequence()
.associateWith { it.nameCardOrNick.fuzzyMatchWith(nameCardTarget) }
.filter { it.value >= minRate }
.toList()
.sortedByDescending { it.second }

val bestMatches = candidates.filter { it.second >= matchRate }

return when {
bestMatches.isEmpty() -> candidates
bestMatches.size == 1 -> listOf(bestMatches.single().first to 1.0)
else -> {
if (bestMatches.first().second - bestMatches.last().second <= disambiguationRate) {
// resolution ambiguity
candidates
} else {
listOf(bestMatches.first().first to 1.0)
}
}
}
}

/**
* 通过消息获取联系人
* 若[Contact]为[Group],则可通过群员昵称获取联系人
* 否则通过QQ号查找,查找失败返回``null``
* @param msg 传入的消息[String]
* @return User if only one is found null otherwise
* */
fun Contact.findUserOrNull(msg: String): User? {
val noneAt = msg.replace("@", "").replace(" ", "")
if (noneAt.isBlank()) {
return null
}
return if (noneAt.contains(Regex("""\D"""))) {
when (this) {
is Group -> this.findMemberOrNull(noneAt)
else -> null
}
} else {
val number = noneAt.toLong()
when (this) {
is Group -> this[number]
else -> bot.getFriend(number) ?: bot.getStranger(number)
}
}
}

/**
* 从一个群中模糊搜索昵称是[nameCard]的群员
* @param nameCard 群员昵称
* @return Member if only one exist or null otherwise
* @author mamoe
* */
private fun Group.findMemberOrNull(nameCard: String): Member? {
this.members.singleOrNull { it.nameCardOrNick.contains(nameCard) }?.let { return it }
this.members.singleOrNull { it.nameCardOrNick.contains(nameCard, ignoreCase = true) }?.let { return it }

val candidates = this.fuzzySearchMember(nameCard)
candidates.singleOrNull()?.let {
if (it.second == 1.0) return it.first // single match
}
var maxPerMember: Member? = null
if (candidates.isNotEmpty()) {
var maxPer = 0.0
candidates.forEach {
if (it.second > maxPer) maxPerMember = it.first
maxPer = it.second
}
}
return maxPerMember
}

0 comments on commit 9f8ec5f

Please sign in to comment.