mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
feat: ocr
This commit is contained in:
parent
ffeda0a472
commit
29dfc1590b
15
qqinterface/src/main/java/com/tencent/mobileqq/l0/b/a.java
Normal file
15
qqinterface/src/main/java/com/tencent/mobileqq/l0/b/a.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
23
qqinterface/src/main/java/com/tencent/mobileqq/l0/b/b.java
Normal file
23
qqinterface/src/main/java/com/tencent/mobileqq/l0/b/b.java
Normal 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;
|
||||
|
||||
}
|
39
qqinterface/src/main/java/com/tencent/mobileqq/l0/b/c.java
Normal file
39
qqinterface/src/main/java/com/tencent/mobileqq/l0/b/c.java
Normal 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;
|
||||
|
||||
}
|
38
qqinterface/src/main/java/com/tencent/mobileqq/ocr/a/a.java
Normal file
38
qqinterface/src/main/java/com/tencent/mobileqq/ocr/a/a.java
Normal 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;
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.tencent.mobileqq.ocr.api.impl;
|
||||
|
||||
public class OcrServiceImpl {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.tencent.mobileqq.ocr.api.impl;
|
||||
|
||||
public class PicOcrServiceImpl {
|
||||
}
|
@ -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>>
|
||||
)
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package moe.fuqiuluo.shamrock.remote.api
|
||||
|
||||
import com.tencent.mobileqq.dt.app.Dtc
|
||||
import com.tencent.mobileqq.dt.model.FEBound
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.content.PartData
|
||||
import io.ktor.http.content.forEachPart
|
||||
@ -12,7 +14,14 @@ 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.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.CleanCache
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.DownloadFile
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetDeviceBattery
|
||||
@ -21,6 +30,8 @@ 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.CommonResult
|
||||
import moe.fuqiuluo.shamrock.tools.GlobalJson5
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.tools.fetchOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.fetchOrThrow
|
||||
@ -32,8 +43,11 @@ import moe.fuqiuluo.shamrock.tools.json
|
||||
import moe.fuqiuluo.shamrock.tools.respond
|
||||
import moe.fuqiuluo.shamrock.utils.FileUtils
|
||||
import moe.fuqiuluo.shamrock.utils.MD5
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import mqq.app.MobileQQ
|
||||
import java.io.File
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun Routing.otherAction() {
|
||||
|
||||
if (ShamrockConfig.allowShell()) {
|
||||
@ -144,4 +158,24 @@ fun Routing.otherAction() {
|
||||
ShamrockConfig[key] = value
|
||||
respond(true, Status.Ok, "success")
|
||||
}
|
||||
|
||||
getOrPost("/dt") {
|
||||
val version = PlatformUtils.getQQVersionCode()
|
||||
val qua = PlatformUtils.getQUA()
|
||||
call.respondText(Json.encodeToString(
|
||||
buildJsonObject {
|
||||
put("qua", JsonPrimitive(qua))
|
||||
put("version", JsonPrimitive(version))
|
||||
}
|
||||
), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/mmkv") {
|
||||
val key = fetchOrThrow("key")
|
||||
call.respondText(Json.encodeToString(
|
||||
buildJsonObject {
|
||||
put("value", JsonPrimitive(Dtc.mmKVValue(key)))
|
||||
}
|
||||
), ContentType.Application.Json)
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user