Skip to content
This repository has been archived by the owner on Aug 12, 2024. It is now read-only.

Commit

Permalink
feat: ocr
Browse files Browse the repository at this point in the history
  • Loading branch information
ikechan8370 committed Jul 7, 2024
1 parent ffeda0a commit 29dfc15
Show file tree
Hide file tree
Showing 10 changed files with 306 additions and 0 deletions.
15 changes: 15 additions & 0 deletions qqinterface/src/main/java/com/tencent/mobileqq/l0/b/a.java
Original file line number Diff line number Diff line change
@@ -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 changes: 23 additions & 0 deletions qqinterface/src/main/java/com/tencent/mobileqq/l0/b/b.java
Original file line number Diff line number Diff line change
@@ -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 changes: 39 additions & 0 deletions qqinterface/src/main/java/com/tencent/mobileqq/l0/b/c.java
Original file line number Diff line number Diff line change
@@ -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 changes: 38 additions & 0 deletions qqinterface/src/main/java/com/tencent/mobileqq/ocr/a/a.java
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tencent.mobileqq.ocr.api.impl;

public class OcrServiceImpl {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tencent.mobileqq.ocr.api.impl;

public class PicOcrServiceImpl {
}
Original file line number Diff line number Diff line change
@@ -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>>
)
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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()) {
Expand Down Expand Up @@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down

0 comments on commit 29dfc15

Please sign in to comment.