3 Commits

Author SHA1 Message Date
65ddca2ea4 fix: optimize import 2024-07-07 18:03:19 +08:00
a6f570e4f0 fix: remove debug 2024-07-07 18:02:41 +08:00
29dfc1590b feat: ocr 2024-07-07 17:51:51 +08:00
10 changed files with 276 additions and 1 deletions

View File

@ -0,0 +1,15 @@
package com.tencent.mobileqq.l0.b;
public class a {
public void b () {
}
public void c (c cVar) {
}
public void onUpdate(int progress, boolean z, Object obj) {
}
}

View File

@ -0,0 +1,23 @@
package com.tencent.mobileqq.l0.b;
import android.graphics.Point;
import java.util.ArrayList;
public class b {
// text
public String a;
// confidence
public int b;
// coordinates
public ArrayList<Point> c;
/* renamed from: d */
public int d;
/* renamed from: e */
public boolean e;
}

View File

@ -0,0 +1,39 @@
package com.tencent.mobileqq.l0.b;
import java.util.ArrayList;
import java.util.HashMap;
public class c {
// image
public String a;
// width
public int b;
// height
public int c;
// lang
public String d;
// url
public String e;
// results
public ArrayList<b> f;
public ArrayList<String> g;
public HashMap<String, String> h;
public int i;
public int j;
public int k;
public String l;
public int m;
}

View File

@ -0,0 +1,38 @@
package com.tencent.mobileqq.ocr.a;
public class a {
public String a;
// 1
public int b;
// file location
public String c;
// null
public String d;
// 0
public long e;
// md5
public String f;
// null
public String g;
// false
public boolean h;
// 0
public int i;
// 0
public int j;
// 0
public long k;
// null
public String l;
}

View File

@ -0,0 +1,10 @@
package com.tencent.mobileqq.ocr.api;
import mqq.app.api.IRuntimeService;
public interface IPicOcrService extends IRuntimeService {
void putOcrResult(String str, com.tencent.mobileqq.l0.b.c cVar);
void requestOcr(com.tencent.mobileqq.ocr.a.a aVar, com.tencent.mobileqq.l0.b.a callback);
}

View File

@ -0,0 +1,4 @@
package com.tencent.mobileqq.ocr.api.impl;
public class OcrServiceImpl {
}

View File

@ -0,0 +1,4 @@
package com.tencent.mobileqq.ocr.api.impl;
public class PicOcrServiceImpl {
}

View File

@ -0,0 +1,134 @@
package moe.fuqiuluo.shamrock.remote.action.handlers
import com.tencent.mobileqq.l0.b.c
import com.tencent.mobileqq.ocr.a.a
import com.tencent.mobileqq.ocr.api.IPicOcrService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
import moe.fuqiuluo.shamrock.utils.FileUtils
import moe.fuqiuluo.shamrock.utils.MD5
import moe.fuqiuluo.symbols.OneBotHandler
import java.io.File
import kotlin.coroutines.resume
@OneBotHandler("ocr_image")
internal object OcrImage: IActionHandler() {
override suspend fun internalHandle(session: ActionSession): String {
val image = session.getString("image")
return invoke(image, session.echo)
}
suspend operator fun invoke(image: String, echo: JsonElement = EmptyJsonString): String {
val file = FileUtils.getFile(image).let {
if (!it.exists()) {
return@let FileUtils.parseAndSave(image)
}
it
}
LogCenter.log("${file.absoluteFile.absolutePath}进行OCR", Level.DEBUG)
val retryCount = 10
val delayMillis = 1000L
repeat(retryCount) {
val result = getOcrResult(file)
if (result.isSuccess) {
return ok(result.getOrNull(), echo)
} else if (result.isFailure && result.exceptionOrNull()?.message == "no cache") {
withContext(Dispatchers.IO) {
Thread.sleep(delayMillis)
}
} else {
return error(result.exceptionOrNull()?.message ?: "", echo)
}
}
return error("ocr failed", echo)
}
private suspend fun getOcrResult(file: File): Result<OcrResult> {
val ocrService = BaseSvc.app.getRuntimeService(IPicOcrService::class.java, "all")
?: return Result.failure(Error("获取OCR服务失败"))
return withTimeoutOrNull(5000) {
suspendCancellableCoroutine { continuation ->
ocrService.requestOcr(
a().apply {
this.b = 1
this.c = file.absolutePath
this.f = MD5.genFileMd5Hex(file.absolutePath)
}, object : com.tencent.mobileqq.l0.b.a() {
override fun b() {
// call uploadOcrPic and then call b
continuation.resume(Result.failure(Error("no cache")))
}
override fun c(result: c?) {
continuation.resume(Result.success(OcrResult(
texts = result?.f?.map {
TextDetection(
text = it.a,
confidence = it.b,
coordinates = it.c.map {
ArrayList<Int>().apply {
add(it.x)
add(it.y)
}
}
)
}!!,
language = result.h[result.d] ?: result.d,
url = result.e
)))
}
override fun onUpdate(i2: Int, z: Boolean, obj: Any?) {
LogCenter.log("$i2, $z, ${obj.toString()}")
if (i2 == 100) {
val result = obj as c
continuation.resume(Result.success(OcrResult(
texts = result.f.map {
TextDetection(
text = it.a,
confidence = it.b,
coordinates = it.c.map {
ArrayList<Int>().apply {
add(it.x)
add(it.y)
}
}
)
},
language = result.h[result.d] ?: result.d,
url = result.e
)))
}
}
})
}
} ?: Result.failure(Exception("OCR timed out"))
}
override val requiredParams: Array<String> = arrayOf("group_id", "user_id")
@Serializable
data class OcrResult (
val texts: List<TextDetection>,
val language: String,
val url: String
)
@Serializable
data class TextDetection (
val text: String,
val confidence: Int,
val coordinates: List<List<Int>>
)
}

View File

@ -12,6 +12,7 @@ import io.ktor.server.routing.post
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.JsonObject
import moe.fuqiuluo.shamrock.remote.action.handlers.CleanCache
import moe.fuqiuluo.shamrock.remote.action.handlers.DownloadFile
@ -19,8 +20,8 @@ import moe.fuqiuluo.shamrock.remote.action.handlers.GetDeviceBattery
import moe.fuqiuluo.shamrock.remote.action.handlers.GetVersionInfo
import moe.fuqiuluo.shamrock.remote.action.handlers.RestartMe
import moe.fuqiuluo.shamrock.remote.action.handlers.UploadFileToShamrock
import moe.fuqiuluo.shamrock.remote.structures.Status
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.remote.structures.Status
import moe.fuqiuluo.shamrock.tools.asString
import moe.fuqiuluo.shamrock.tools.fetchOrNull
import moe.fuqiuluo.shamrock.tools.fetchOrThrow
@ -34,6 +35,7 @@ import moe.fuqiuluo.shamrock.utils.FileUtils
import moe.fuqiuluo.shamrock.utils.MD5
import java.io.File
@OptIn(ExperimentalSerializationApi::class)
fun Routing.otherAction() {
if (ShamrockConfig.allowShell()) {
@ -144,4 +146,5 @@ fun Routing.otherAction() {
ShamrockConfig[key] = value
respond(true, Status.Ok, "success")
}
}

View File

@ -37,6 +37,11 @@ fun Routing.fetchRes() {
call.respondText(GetImage(file), ContentType.Application.Json)
}
getOrPost("/ocr_image") {
val file = fetchOrThrow("image")
call.respondText(OcrImage(file), ContentType.Application.Json)
}
getOrPost("/upload_group_file") {
val groupId = fetchOrThrow("group_id").toLong()
val file = fetchOrThrow("file")