Skip to content

Commit

Permalink
feat: image to image
Browse files Browse the repository at this point in the history
  • Loading branch information
Nekoer committed Oct 10, 2022
1 parent dbd6696 commit 324b019
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 9 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
}

group = "com.hcyacg"
version = "0.1.0"
version = "0.2.0"

repositories {
maven("https://maven.aliyun.com/repository/public")
Expand Down
159 changes: 156 additions & 3 deletions src/main/kotlin/Generate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import net.mamoe.mirai.event.events.GroupMessageEvent
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.Image.Key.queryUrl
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.lang.Character.UnicodeBlock
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern

object Generate {
var json = Json {
Expand All @@ -31,7 +35,7 @@ object Generate {
}
private val client = OkHttpClient.Builder().connectTimeout(10, TimeUnit.MINUTES).readTimeout(10, TimeUnit.MINUTES).build()
private val charPool : List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
suspend fun register(tags: String, translated: Boolean = false,event : GroupMessageEvent):Image {
suspend fun textRegister(tags: String, translated: Boolean = false,event : GroupMessageEvent):Image {
var seed = "";
if (Config.seed == -1){
for (i in 0 until 10){
Expand All @@ -47,7 +51,7 @@ object Generate {
.map(charPool::get)
.joinToString("");

val data = PostData(data = arrayOf(tags,
val data = PostData(data = arrayOf(if(!translated && !isChinese(tags)) tags else tags.split(",").joinToString(",") { translate(it) },
Config.negativePrompt,
Config.promptStyle,
Config.promptStyle2,
Expand Down Expand Up @@ -82,6 +86,7 @@ object Generate {
Config.keepRandomSeeds,
null,
"",""),fn_index=11,session_hash = randomString)

val request = Request.Builder().apply {
url("http://127.0.0.1:7860/api/predict/")
post(json.encodeToString(PostData.serializer(),data).toRequestBody())
Expand Down Expand Up @@ -110,7 +115,116 @@ object Generate {
return image
}

fun translate(text: String): String {
suspend fun imageRegister(translated: Boolean = false, event : GroupMessageEvent):Image{
val text = event.message.find { it is PlainText } as PlainText
val tags = text.contentToString().replace("/ai image ","")
val tmpImage = event.message.find { it is Image } as Image
val url = tmpImage.queryUrl()
val urlRequest = Request.Builder().apply {
url(url)
get()
addHeader("content-type","application/json")
}.build()
val resp = client.newCall(urlRequest).execute()
val byteArray = resp.body?.bytes()
val base64Image = "data:image/png;base64,"+Base64.getEncoder().encodeToString(byteArray)


var seed = "";
if (Config.seed == -1){
for (i in 0 until 10){
seed = seed.plus((0..9).random())
}
}else{
seed = Config.seed.toString()
}


val randomString = (1..11)
.map { i -> kotlin.random.Random.nextInt(0, charPool.size) }
.map(charPool::get)
.joinToString("");

val data = PostData(data = arrayOf(
Config.mode,
if(!translated && !isChinese(tags)) tags else tags.split(",").joinToString(",") { translate(it) },
Config.negativePrompt,
Config.promptStyle,
Config.promptStyle2,
base64Image,//原始图片
if(Config.initImgWithMask == -1) null else Config.initImgWithMask,
if(Config.initImgInPaint == -1) null else Config.initImgWithMask,
if(Config.initMaskInPaint == -1) null else Config.initImgWithMask,
Config.maskMode,
Config.steps,
Config.samplerIndex,
Config.maskBlur,
Config.inPaintingFill,
Config.restoreFaces,
Config.tiling,
Config.nIter,
Config.batchSize,
Config.cfgScale,
Config.denoisingStrength,
seed.toBigInteger(),
Config.subSeed,
Config.subSeedStrength,
Config.seedResizeFromH,
Config.seedResizeFromW,
Config.seedEnableExtras,
Config.height,
Config.width,
Config.resizeMode,
Config.inPaintFullRes,
Config.inPaintFullResPadding,
Config.inPaintingMaskInvert,
"",
"",
"None",
"",
"",
1,50,0,false,4,1,"",128,8,
arrayOf("left","right","up", "down"),
1,0.05,128,4,"fill",
arrayOf("left","right","up", "down"),
false,false,null,"","",64,
"None",
"Seed",
Config.xvalues,
"Steps",
Config.yvalues,
Config.drawLegend,
Config.keepRandomSeeds,
null,
"",""),fn_index=29,session_hash = randomString)

val request = Request.Builder().apply {
url("http://127.0.0.1:7860/api/predict/")
post(json.encodeToString(PostData.serializer(),data).toRequestBody())
addHeader("content-type","application/json")
}.build()
event.subject.sendMessage("请稍后,预计需要1分钟")
val response = client.newCall(request).execute()
val element = json.parseToJsonElement(response.body!!.string())
var base64 = element.jsonObject["data"]?.jsonArray?.get(0)?.jsonArray?.get(0)?.jsonPrimitive?.content

if (base64?.contains("data:") == true) {
val start: Int = base64.indexOf(",")
base64 = base64.substring(start + 1)
}
var file = base64?.replace("\r|\n", "");
file = file?.trim();

val toExternalResource = Base64.getDecoder().decode(file).toExternalResource()
val image = toExternalResource.uploadAsImage(event.group)
withContext(Dispatchers.IO) {
toExternalResource.close()
}

return image
}

private fun translate(text: String): String {
val request = Request.Builder().apply {
url("https://fanyi.youdao.com/translate?&doctype=json&type=AUTO&i=${text}")
get()
Expand All @@ -119,4 +233,43 @@ object Generate {
val result = json.decodeFromString<TranslateResult>(client.newCall(request).execute().body!!.string())
return result.translateResult[0][0].tgt
}

// 根据Unicode编码完美的判断中文汉字和符号
private fun isChinese(c: Char): Boolean {
val ub = UnicodeBlock.of(c)
return ub == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B || ub == UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS || ub == UnicodeBlock.GENERAL_PUNCTUATION
}

// 完整的判断中文汉字和符号
fun isChinese(strName: String): Boolean {
val ch = strName.toCharArray()
for (i in ch.indices) {
val c = ch[i]
if (isChinese(c)) {
return true
}
}
return false
}

// 只能判断部分CJK字符(CJK统一汉字)
fun isChineseByREG(str: String?): Boolean {
if (str == null) {
return false
}
val pattern: Pattern = Pattern.compile("[\\u4E00-\\u9FBF]+")
return pattern.matcher(str.trim { it <= ' ' }).find()
}

// 只能判断部分CJK字符(CJK统一汉字)
fun isChineseByName(str: String?): Boolean {
if (str == null) {
return false
}
// 大小写不同:\\p 表示包含,\\P 表示不包含
// \\p{Cn} 的意思为 Unicode 中未被定义字符的编码,\\P{Cn} 就表示 Unicode中已经被定义字符的编码
val reg = "\\p{InCJK Unified Ideographs}&&\\P{Cn}"
val pattern: Pattern = Pattern.compile(reg)
return pattern.matcher(str.trim { it <= ' ' }).find()
}
}
6 changes: 5 additions & 1 deletion src/main/kotlin/Novelai.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ object Novelai : KotlinPlugin(

globalEventChannel().subscribeGroupMessages {
content { message.contentToString().contains("/ai text ") } quoteReply {
Generate.register(message.contentToString().replace("/ai text ",""),event = this)
Generate.textRegister(message.contentToString().replace("/ai text ",""),event = this, translated = Config.translated)
}
content { message.contentToString().contains("/ai image ") } quoteReply {
Generate.imageRegister(event = this, translated = Config.translated)
}

}
}
}
52 changes: 48 additions & 4 deletions src/main/kotlin/config/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,53 @@ import net.mamoe.mirai.console.data.ValueName
import net.mamoe.mirai.console.data.value

object Config : AutoSavePluginConfig("config") {
@ValueName("prompt")
@ValueDescription("词条")
var prompt: String by value()
@ValueName("mode")
@ValueDescription("模式,仅限image2image")
var mode:Int by value(0)

@ValueName("initImgWithMask")
@ValueDescription("[暂时不清楚该填什么]原始图蒙版模式,仅限image2image")
var initImgWithMask:Int by value(-1)

@ValueName("initImgInPaint")
@ValueDescription("[暂时不清楚该填什么]原始图图层,仅限image2image")
var initImgInPaint:Int by value(-1)

@ValueName("initMaskInPaint")
@ValueDescription("[暂时不清楚该填什么]原始蒙版图层,仅限image2image")
var initMaskInPaint:Int by value(-1)

@ValueName("maskMode")
@ValueDescription("蒙版模式,仅限image2image,[Upload mask|Draw mask]")
var maskMode:String by value("Draw mask")

@ValueName("maskBlur")
@ValueDescription("模糊遮罩滤镜,仅限image2image")
var maskBlur:Int by value(4)

@ValueName("inPaintingFill")
@ValueDescription("修复填充,仅限image2image,[fill|original|latent noise|latent nothing]")
var inPaintingFill:String by value("original")

@ValueName("resizeMode")
@ValueDescription("尺寸调整模式,仅限image2image [Crop and resize|Just resize|Resize and fill]")
var resizeMode:String by value("Just resize")

@ValueName("inPaintFullRes")
@ValueDescription("尺寸调整模式,仅限image2image")
var inPaintFullRes:Boolean by value(false)

@ValueName("inPaintFullResPadding")
@ValueDescription("图层全分辨率填充,仅限image2image")
var inPaintFullResPadding:Int by value(32)

@ValueName("inPaintingMaskInvert")
@ValueDescription("图层模板倒置,仅限image2image,[Inpaint not masked|Inpaint masked]")
var inPaintingMaskInvert:String by value("Inpaint masked")

@ValueName("translated")
@ValueDescription("翻译词条")
var translated: Boolean by value(true)

@ValueName("negativePrompt")
@ValueDescription("过滤词条")
Expand All @@ -27,7 +71,7 @@ object Config : AutoSavePluginConfig("config") {
var steps: Int by value(40)

@ValueName("samplerIndex")
@ValueDescription("采样器索引,Euler a|Euler|LMS|Heun|DPM2|DPM2 a|DPM fast|DPM adaptive|LMS Karras|DPM2 Karras|DPM2 a Karras|DDIM|PLMS")
@ValueDescription("采样器索引,Euler a|Euler|LMS|Heun|DPM2|DPM2 a|DPM fast|DPM adaptive|LMS Karras|DPM2 Karras|DPM2 a Karras|DDIM|PLMS, 图片转图片[Euler a|Euler|LMS|Heun|DPM2|DPM2 a|LMS Karras|DPM2 Karras|DPM2 a Karras|DDIM]")
var samplerIndex: String by value("Euler a")

@ValueName("restoreFaces")
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/data/PostData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ private fun Any?.toJsonElement(): JsonElement{
// !!! key simply converted to string
is Map<*, *> -> JsonObject(this.map { it.key.toString() to it.value.toJsonElement() }.toMap())
// add custom convert
is Array<*> -> JsonArray(this.map { it.toJsonElement() })
else -> throw Exception("不支持类型 ${this::class}=${this}}")
}
}
Expand Down

0 comments on commit 324b019

Please sign in to comment.