替换菜品识别模型,暂时取消相似的判断,查询全部数据测试新模型效果,暂时取消查询前后数据量不一致的判断避免查不出数据

This commit is contained in:
mazengfei
2026-02-11 18:05:40 +08:00
parent 655e9cd56e
commit f562abc12f
9 changed files with 274 additions and 125 deletions
Binary file not shown.
+199 -76
View File
@@ -1,113 +1,236 @@
{ {
"class_names": [ "class_names": [
"三黄鸡",
"上海青WP2026020200041",
"冰草WP2026020900054",
"刀豆",
"北豆腐WP2025111900007", "北豆腐WP2025111900007",
"味精WP2026013000034",
"圆生菜WP2026020900053",
"圆白菜[卷心菜,包菜]WP2025111000063", "圆白菜[卷心菜,包菜]WP2025111000063",
"基围虾WP2025110700019", "基围虾WP2025110700019",
"多宝鱼WP2025112600011", "多宝鱼WP2025112600011",
"大白菜WP2025111000064", "大白菜WP2025111000064",
"大葱WP2025111000060", "大葱WP2026013000025",
"姜[黄姜]WP2025112000071", "姜[黄姜]WP2025112000071",
"娃娃菜WP2025120300018", "娃娃菜WP2026020200005",
"小米辣椒WP2026013000027",
"小葱WP2026013000029",
"山药(带皮)WP2026020200008",
"巨人笋",
"广东菜心WP2025120100014", "广东菜心WP2025120100014",
"松花蛋",
"松茸菌WP2025120100016", "松茸菌WP2025120100016",
"沙葱",
"洋葱(鲜)[葱头]WP2025111000061", "洋葱(鲜)[葱头]WP2025111000061",
"牛腩WP2025110700043", "牛腩WP2025110700043",
"猪五花肉WP2026020300048",
"猪腿肉WP2025110700040", "猪腿肉WP2025110700040",
"玉米WP2025120100017", "玉米WP2025120100017",
"番茄WP2025110700016", "番茄WP2025110700016",
"白吉饼WP2026013000024",
"笋",
"粉丝",
"紫甘蓝",
"红提子WP2025111900006", "红提子WP2025111900006",
"红椒",
"红美人椒WP2026020300049",
"红薯",
"红薯粉条(袋)",
"羊排WP2025120300021", "羊排WP2025120300021",
"羊血WP2026013000038",
"胡萝卜WP2025110600008", "胡萝卜WP2025110600008",
"芋头",
"花卷",
"芹菜WP2025111000065", "芹菜WP2025111000065",
"苦菊",
"茄子(紫皮,长)WP2025110700024", "茄子(紫皮,长)WP2025110700024",
"茼蒿WP2025111900005", "茼蒿WP2026020200045",
"莴笋(鲜)[莴苣]WP2025111000056", "莲藕(带皮)",
"莴笋(鲜)[莴苣]WP2026020200009",
"菜花(白色)[花椰菜]",
"蒜WP2025111400003", "蒜WP2025111400003",
"蒜苗WP2026013000028",
"蒸鱼豉油WP2026013000032",
"西兰花[绿菜花]WP2025110700029", "西兰花[绿菜花]WP2025110700029",
"西葫芦",
"豆腐皮WP2025111000059", "豆腐皮WP2025111000059",
"豆角",
"辣椒(红,小)WP2025111000066", "辣椒(红,小)WP2025111000066",
"辣椒(青辣椒,螺丝椒)WP2025110700017", "辣椒(青辣椒,螺丝椒)WP2025110700017",
"醪糟",
"金针菇WP2025111900010", "金针菇WP2025111900010",
"马铃薯[土豆、洋芋]WP2025110600006", "青线椒WP2026013000031",
"韭黄",
"香菇",
"香菜WP2026013000030",
"马铃薯[土豆、洋芋]WP2026012900001",
"鸡全腿(带骨)",
"鸡翅(带骨)",
"鸡腿肉WP2025110700048", "鸡腿肉WP2025110700048",
"鸡蛋(代表值)WP2025112000070", "鸡腿(带骨)",
"鸡蛋(代表值)WP2026013000039",
"麦芹",
"黄瓜(鲜)[胡瓜]WP2025110700031", "黄瓜(鲜)[胡瓜]WP2025110700031",
"黄豆芽WP2026020200042",
"黑袋子", "黑袋子",
"黑鱼(整条鱼)WP2025110600012" "黑鱼(整条鱼)WP2025110600012"
], ],
"class_to_idx": { "class_to_idx": {
"北豆腐WP2025111900007": 0, "三黄鸡": 0,
"圆白菜[卷心菜,包菜]WP2025111000063": 1, "上海青WP2026020200041": 1,
"基围虾WP2025110700019": 2, "冰草WP2026020900054": 2,
"多宝鱼WP2025112600011": 3, "刀豆": 3,
"大白菜WP2025111000064": 4, "北豆腐WP2025111900007": 4,
"大葱WP2025111000060": 5, "味精WP2026013000034": 5,
"姜[黄姜]WP2025112000071": 6, "圆生菜WP2026020900053": 6,
"娃娃菜WP2025120300018": 7, "圆白菜[卷心菜,包菜]WP2025111000063": 7,
"广东菜心WP2025120100014": 8, "基围虾WP2025110700019": 8,
"松茸菌WP2025120100016": 9, "多宝鱼WP2025112600011": 9,
"洋葱(鲜)[葱头]WP2025111000061": 10, "大白菜WP2025111000064": 10,
"牛腩WP2025110700043": 11, "大葱WP2026013000025": 11,
"猪腿肉WP2025110700040": 12, "姜[黄姜]WP2025112000071": 12,
"玉米WP2025120100017": 13, "娃娃菜WP2026020200005": 13,
"番茄WP2025110700016": 14, "小米辣椒WP2026013000027": 14,
"红提子WP2025111900006": 15, "小葱WP2026013000029": 15,
"羊排WP2025120300021": 16, "山药(带皮)WP2026020200008": 16,
"胡萝卜WP2025110600008": 17, "巨人笋": 17,
"芹菜WP2025111000065": 18, "广东菜心WP2025120100014": 18,
"茄子(紫皮,长)WP2025110700024": 19, "松花蛋": 19,
"茼蒿WP2025111900005": 20, "松茸菌WP2025120100016": 20,
"莴笋(鲜)[莴苣]WP2025111000056": 21, "沙葱": 21,
"WP2025111400003": 22, "洋葱(鲜)[葱头]WP2025111000061": 22,
"西兰花[绿菜花]WP2025110700029": 23, "牛腩WP2025110700043": 23,
"豆腐皮WP2025111000059": 24, "猪五花肉WP2026020300048": 24,
"辣椒(红,小)WP2025111000066": 25, "猪腿肉WP2025110700040": 25,
"辣椒(青辣椒,螺丝椒)WP2025110700017": 26, "玉米WP2025120100017": 26,
"金针菇WP2025111900010": 27, "番茄WP2025110700016": 27,
"马铃薯[土豆、洋芋]WP2025110600006": 28, "白吉饼WP2026013000024": 28,
"鸡腿肉WP2025110700048": 29, "": 29,
"鸡蛋(代表值)WP2025112000070": 30, "粉丝": 30,
"黄瓜(鲜)[胡瓜]WP2025110700031": 31, "紫甘蓝": 31,
"黑袋子": 32, "红提子WP2025111900006": 32,
"黑鱼(整条鱼)WP2025110600012": 33 "红椒": 33,
"红美人椒WP2026020300049": 34,
"红薯": 35,
"红薯粉条(袋)": 36,
"羊排WP2025120300021": 37,
"羊血WP2026013000038": 38,
"胡萝卜WP2025110600008": 39,
"芋头": 40,
"花卷": 41,
"芹菜WP2025111000065": 42,
"苦菊": 43,
"茄子(紫皮,长)WP2025110700024": 44,
"茼蒿WP2026020200045": 45,
"莲藕(带皮)": 46,
"莴笋(鲜)[莴苣]WP2026020200009": 47,
"菜花(白色)[花椰菜]": 48,
"蒜WP2025111400003": 49,
"蒜苗WP2026013000028": 50,
"蒸鱼豉油WP2026013000032": 51,
"西兰花[绿菜花]WP2025110700029": 52,
"西葫芦": 53,
"豆腐皮WP2025111000059": 54,
"豆角": 55,
"辣椒(红,小)WP2025111000066": 56,
"辣椒(青辣椒,螺丝椒)WP2025110700017": 57,
"醪糟": 58,
"金针菇WP2025111900010": 59,
"青线椒WP2026013000031": 60,
"韭黄": 61,
"香菇": 62,
"香菜WP2026013000030": 63,
"马铃薯[土豆、洋芋]WP2026012900001": 64,
"鸡全腿(带骨)": 65,
"鸡翅(带骨)": 66,
"鸡腿肉WP2025110700048": 67,
"鸡腿(带骨)": 68,
"鸡蛋(代表值)WP2026013000039": 69,
"麦芹": 70,
"黄瓜(鲜)[胡瓜]WP2025110700031": 71,
"黄豆芽WP2026020200042": 72,
"黑袋子": 73,
"黑鱼(整条鱼)WP2025110600012": 74
}, },
"idx_to_class": { "idx_to_class": {
"0": "北豆腐WP2025111900007", "0": "三黄鸡",
"1": "圆白菜[卷心菜,包菜]WP2025111000063", "1": "上海青WP2026020200041",
"2": "基围虾WP2025110700019", "2": "冰草WP2026020900054",
"3": "多宝鱼WP2025112600011", "3": "刀豆",
"4": "大白菜WP2025111000064", "4": "北豆腐WP2025111900007",
"5": "大葱WP2025111000060", "5": "味精WP2026013000034",
"6": "姜[黄姜]WP2025112000071", "6": "圆生菜WP2026020900053",
"7": "娃娃菜WP2025120300018", "7": "圆白菜[卷心菜,包菜]WP2025111000063",
"8": "广东菜心WP2025120100014", "8": "基围虾WP2025110700019",
"9": "松茸菌WP2025120100016", "9": "多宝鱼WP2025112600011",
"10": "洋葱(鲜)[葱头]WP2025111000061", "10": "大白菜WP2025111000064",
"11": "牛腩WP2025110700043", "11": "大葱WP2026013000025",
"12": "猪腿肉WP2025110700040", "12": "姜[黄姜]WP2025112000071",
"13": "玉米WP2025120100017", "13": "娃娃菜WP2026020200005",
"14": "番茄WP2025110700016", "14": "小米辣椒WP2026013000027",
"15": "红提子WP2025111900006", "15": "小葱WP2026013000029",
"16": "羊排WP2025120300021", "16": "山药(带皮)WP2026020200008",
"17": "胡萝卜WP2025110600008", "17": "巨人笋",
"18": "芹菜WP2025111000065", "18": "广东菜心WP2025120100014",
"19": "茄子(紫皮,长)WP2025110700024", "19": "松花蛋",
"20": "茼蒿WP2025111900005", "20": "松茸菌WP2025120100016",
"21": "莴笋(鲜)[莴苣]WP2025111000056", "21": "沙葱",
"22": "WP2025111400003", "22": "洋葱(鲜)[葱头]WP2025111000061",
"23": "西兰花[绿菜花]WP2025110700029", "23": "牛腩WP2025110700043",
"24": "豆腐皮WP2025111000059", "24": "猪五花肉WP2026020300048",
"25": "辣椒(红,小)WP2025111000066", "25": "猪腿肉WP2025110700040",
"26": "辣椒(青辣椒,螺丝椒)WP2025110700017", "26": "玉米WP2025120100017",
"27": "金针菇WP2025111900010", "27": "番茄WP2025110700016",
"28": "马铃薯[土豆、洋芋]WP2025110600006", "28": "白吉饼WP2026013000024",
"29": "鸡腿肉WP2025110700048", "29": "",
"30": "鸡蛋(代表值)WP2025112000070", "30": "粉丝",
"31": "黄瓜(鲜)[胡瓜]WP2025110700031", "31": "紫甘蓝",
"32": "黑袋子", "32": "红提子WP2025111900006",
"33": "黑鱼(整条鱼)WP2025110600012" "33": "红椒",
"34": "红美人椒WP2026020300049",
"35": "红薯",
"36": "红薯粉条(袋)",
"37": "羊排WP2025120300021",
"38": "羊血WP2026013000038",
"39": "胡萝卜WP2025110600008",
"40": "芋头",
"41": "花卷",
"42": "芹菜WP2025111000065",
"43": "苦菊",
"44": "茄子(紫皮,长)WP2025110700024",
"45": "茼蒿WP2026020200045",
"46": "莲藕(带皮)",
"47": "莴笋(鲜)[莴苣]WP2026020200009",
"48": "菜花(白色)[花椰菜]",
"49": "蒜WP2025111400003",
"50": "蒜苗WP2026013000028",
"51": "蒸鱼豉油WP2026013000032",
"52": "西兰花[绿菜花]WP2025110700029",
"53": "西葫芦",
"54": "豆腐皮WP2025111000059",
"55": "豆角",
"56": "辣椒(红,小)WP2025111000066",
"57": "辣椒(青辣椒,螺丝椒)WP2025110700017",
"58": "醪糟",
"59": "金针菇WP2025111900010",
"60": "青线椒WP2026013000031",
"61": "韭黄",
"62": "香菇",
"63": "香菜WP2026013000030",
"64": "马铃薯[土豆、洋芋]WP2026012900001",
"65": "鸡全腿(带骨)",
"66": "鸡翅(带骨)",
"67": "鸡腿肉WP2025110700048",
"68": "鸡腿(带骨)",
"69": "鸡蛋(代表值)WP2026013000039",
"70": "麦芹",
"71": "黄瓜(鲜)[胡瓜]WP2025110700031",
"72": "黄豆芽WP2026020200042",
"73": "黑袋子",
"74": "黑鱼(整条鱼)WP2025110600012"
}, },
"embedding_dim": 512, "embedding_dim": 512,
"total_images": 2065, "total_images": 4254,
"build_time": "2025-12-05T10:16:42.915631" "build_time": "2026-02-10T08:08:53.308245"
} }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -607,6 +607,7 @@ class FoodCollectionActivity : ComponentActivity() {
tip tip
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog) mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show() mDialogWaiting!!.show()
mDialogWaiting!!.setCanceledOnTouchOutside(true)
mDialogWaiting!!.setCancelable(true) mDialogWaiting!!.setCancelable(true)
} }
} }
@@ -628,6 +629,7 @@ class FoodCollectionActivity : ComponentActivity() {
val view = View.inflate(this, R.layout.dialog_waiting, null) val view = View.inflate(this, R.layout.dialog_waiting, null)
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog) mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show() mDialogWaiting!!.show()
mDialogWaiting!!.setCanceledOnTouchOutside(true)
mDialogWaiting!!.setCancelable(true) mDialogWaiting!!.setCancelable(true)
} }
val contentView = mDialogWaiting?.findViewById<ViewGroup>(android.R.id.content) val contentView = mDialogWaiting?.findViewById<ViewGroup>(android.R.id.content)
@@ -377,7 +377,8 @@ abstract class GoodsListActivity : ComponentActivity() {
if (newBmp.isRecycled.not()) { if (newBmp.isRecycled.not()) {
newBmp.recycle() newBmp.recycle()
} }
val count = foodList.count { it.score < 0.15 } // val count = foodList.count { it.score < 0.15 }
val count = foodList.size
if (count == 0) { if (count == 0) {
//未识别到满足相似度>=0.85的,显示识别率最高的 //未识别到满足相似度>=0.85的,显示识别率最高的
var tempList = foodList.filter { it.name.contains("黑袋子").not() } var tempList = foodList.filter { it.name.contains("黑袋子").not() }
@@ -429,7 +430,9 @@ abstract class GoodsListActivity : ComponentActivity() {
return@runOnUiThread return@runOnUiThread
} }
handleGoodsResult( handleGoodsResult(
goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(), // TODO: 暂时取消不一致判断,显示查询到的菜品
// goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(),
goodsList = goodsList,
// file = null, // file = null,
// name = foodList.joinToString(",") // name = foodList.joinToString(",")
) )
@@ -16,9 +16,9 @@ class RequestInterceptor : Interceptor {
val requestBuilder = originalRequest.newBuilder() val requestBuilder = originalRequest.newBuilder()
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Accept", "application/json") .header("Accept", "application/json")
.header("deviceId", GlobalData.deviceId) .header("deviceId", if (GlobalData.deviceId == "5a41a2cf-3cee-3731-911d-a28b10164f7a") "bcf396ed-78f6-3864-9837-7c37c5b2ec41" else GlobalData.deviceId)
.header("X-DEVICE-CODE", GlobalData.deviceId) // .header("X-DEVICE-CODE", GlobalData.deviceId)
// .header("X-DEVICE-CODE", "bcf396ed-78f6-3864-9837-7c37c5b2ec41") .header("X-DEVICE-CODE", if (GlobalData.deviceId == "5a41a2cf-3cee-3731-911d-a28b10164f7a") "bcf396ed-78f6-3864-9837-7c37c5b2ec41" else GlobalData.deviceId)
.header("x-access-token", GlobalData.appToken) .header("x-access-token", GlobalData.appToken)
.header("authorization", "57ee87183f2a4fa59683ec9ef41c8f5d") .header("authorization", "57ee87183f2a4fa59683ec9ef41c8f5d")
// .header("Authorization", "Bearer ${getToken()}") // .header("Authorization", "Bearer ${getToken()}")
@@ -4,10 +4,12 @@ import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.renderscript.Element.DataType import android.renderscript.Element.DataType
import android.util.Log
import androidx.core.graphics.scale import androidx.core.graphics.scale
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.sw.inbound.MyApp import com.sw.inbound.MyApp
import com.sw.inbound.objbox.ObjectBox.boxStore
import com.sw.inbound.utils.AssetsTool import com.sw.inbound.utils.AssetsTool
import com.sw.inbound.utils.ImageUtil import com.sw.inbound.utils.ImageUtil
import com.sw.inbound.utils.ext.toJsonString import com.sw.inbound.utils.ext.toJsonString
@@ -16,6 +18,7 @@ import io.objectbox.kotlin.boxFor
import io.objectbox.query.IdWithScore import io.objectbox.query.IdWithScore
import io.objectbox.query.Query import io.objectbox.query.Query
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
import org.pytorch.IValue import org.pytorch.IValue
@@ -31,12 +34,14 @@ import java.io.InputStream
object FoodModule { object FoodModule {
private lateinit var module_mobile: Module private lateinit var module_mobile: Module
// private lateinit var box: Box<Food>
// private lateinit var box: Box<Food>
private lateinit var embeddingsList: List<List<Float>> private lateinit var embeddingsList: List<List<Float>>
private lateinit var labelsList: IntArray private lateinit var labelsList: IntArray
private lateinit var classInfo: FoodClassInfo private lateinit var classInfo: FoodClassInfo
private val NO_MEAN_RGB = floatArrayOf(0.0f, 0.0f, 0.0f) private val NO_MEAN_RGB = floatArrayOf(0.0f, 0.0f, 0.0f)
private val NO_STD_RGB = floatArrayOf(1.0f, 1.0f, 1.0f) private val NO_STD_RGB = floatArrayOf(1.0f, 1.0f, 1.0f)
// 1. 定义你的模型固定输入尺寸 (根据你的tflite模型修改,比如224x224) // 1. 定义你的模型固定输入尺寸 (根据你的tflite模型修改,比如224x224)
private const val MODEL_INPUT_WIDTH = 300 private const val MODEL_INPUT_WIDTH = 300
private const val MODEL_INPUT_HEIGHT = 300 private const val MODEL_INPUT_HEIGHT = 300
@@ -47,12 +52,7 @@ object FoodModule {
suspend fun init(context: Context) { suspend fun init(context: Context) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
module_mobile = Module.load(copyAssetToCache(context, "best_embedding_model_mobile.pt")) module_mobile = Module.load(copyAssetToCache(context, "best_embedding_model_mobile.pt"))
ObjectBox.safeDbOp { initDefFoodData(context)
val box = ObjectBox.getBox<Food>()
if (box?.all?.isEmpty() == true) {
initDefFoodData(context)
}
}
} }
} }
@@ -65,13 +65,13 @@ object FoodModule {
// } // }
fun bitmap2FloatArray(originBitmap: Bitmap, isRecycle: Boolean): FloatArray? { fun bitmap2FloatArray(originBitmap: Bitmap, isRecycle: Boolean): FloatArray? {
var rgb565Bitmap: Bitmap?=null var rgb565Bitmap: Bitmap? = null
try { try {
val scaledBitmap = originBitmap.scale(MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT) val scaledBitmap = originBitmap.scale(MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT)
if (isRecycle) { if (isRecycle) {
originBitmap.recycle() originBitmap.recycle()
} }
rgb565Bitmap = scaledBitmap.copy(Bitmap.Config.RGB_565, false) rgb565Bitmap = scaledBitmap.copy(Bitmap.Config.RGB_565, false)
scaledBitmap.recycle() scaledBitmap.recycle()
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor( val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
rgb565Bitmap, rgb565Bitmap,
@@ -114,7 +114,10 @@ object FoodModule {
// return queryFoodNameScore(floatArray, queryCount) // return queryFoodNameScore(floatArray, queryCount)
// } // }
suspend fun queryFoodNameScore(floatArray: FloatArray?, queryCount: Int = 15): List<IdNameScore> { suspend fun queryFoodNameScore(
floatArray: FloatArray?,
queryCount: Int = 15
): List<IdNameScore> {
if (floatArray == null) return emptyList() if (floatArray == null) return emptyList()
// val query: Query<Food> = box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build() // val query: Query<Food> = box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build()
// //查询比较分数 // //查询比较分数
@@ -126,15 +129,18 @@ object FoodModule {
// // 先关闭Query,释放Cursor // // 先关闭Query,释放Cursor
// query.close() // query.close()
// } // }
Timber.tag("FoodModule").d("queryFood向量:${floatArray.slice(0 until 50).toJsonString()}")
val idScoreList = ObjectBox.query(floatArray, queryCount) val idScoreList = ObjectBox.query(floatArray, queryCount)
val nameScoreList = mutableListOf<IdNameScore>() val nameScoreList = mutableListOf<IdNameScore>()
idScoreList.forEach { idScoreList.forEach {
val name = ObjectBox.get(it.id)?.name?:"" val name = ObjectBox.get(it.id)?.name ?: ""
nameScoreList.add(IdNameScore(id = it.id, name = name, score = it.score)) nameScoreList.add(IdNameScore(id = it.id, name = name, score = it.score))
} }
Timber.tag("FoodModule").d("queryFood数据:${nameScoreList.toJsonString()}") Timber.tag("FoodModule").d("queryFood数据:${nameScoreList.toJsonString()}")
return nameScoreList return nameScoreList
} }
suspend fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> { suspend fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
val floatArray = bitmap2FloatArray(bitmap, false) ?: return emptyList() val floatArray = bitmap2FloatArray(bitmap, false) ?: return emptyList()
Timber.tag("FoodModule").d("向量:${floatArray.toJsonString()}") Timber.tag("FoodModule").d("向量:${floatArray.toJsonString()}")
@@ -165,6 +171,7 @@ object FoodModule {
Timber.tag("FoodModule").d("getFoodScoreList数据:${sortedScoreList.toJsonString()}") Timber.tag("FoodModule").d("getFoodScoreList数据:${sortedScoreList.toJsonString()}")
return sortedScoreList return sortedScoreList
} }
suspend fun queryFood(floatArray: FloatArray, queryCount: Int = 15): List<String> { suspend fun queryFood(floatArray: FloatArray, queryCount: Int = 15): List<String> {
val map = mutableMapOf<String, Int>() val map = mutableMapOf<String, Int>()
val nameScoreList = queryFoodNameScore(floatArray, queryCount) val nameScoreList = queryFoodNameScore(floatArray, queryCount)
@@ -177,39 +184,51 @@ object FoodModule {
} }
data class IdNameScore( data class IdNameScore(
val id:Long, val id: Long,
var name:String, var name: String,
val score: Double val score: Double
) )
suspend fun initDefFoodData(context: Context, action:()-> Unit={}) { suspend fun initDefFoodData(context: Context, action: () -> Unit = {}) {
val count = ObjectBox.getBox<Food>()?.all?.count { it.foodIdx == DEFAULT_FOOD_INDEX }?:0 try {
if (count > 0) { val count =
return ObjectBox.getBox<Food>()?.all?.count { it.foodIdx == DEFAULT_FOOD_INDEX } ?: 0
} if (count > 0) {
val embeddingsJson = AssetsTool.readAssetsFile(context, "data/embeddings.json") return
val labelsJson = AssetsTool.readAssetsFile(context, "data/labels.json") }
val classInfoJson = AssetsTool.readAssetsFile(context, "data/class_info.json") val embeddingsJson = AssetsTool.readAssetsFile(context, "data/embeddings.json")
val labelsJson = AssetsTool.readAssetsFile(context, "data/labels.json")
val classInfoJson = AssetsTool.readAssetsFile(context, "data/class_info.json")
embeddingsList = embeddingsList =
Gson().fromJson(embeddingsJson, object : TypeToken<List<List<Float>>>() {}.type) Gson().fromJson(embeddingsJson, object : TypeToken<List<List<Float>>>() {}.type)
labelsList = Gson().fromJson(labelsJson, IntArray::class.java) labelsList = Gson().fromJson(labelsJson, IntArray::class.java)
classInfo = classInfo =
Gson().fromJson(classInfoJson, FoodClassInfo::class.java) Gson().fromJson(classInfoJson, FoodClassInfo::class.java)
val foodMap = classInfo.idx_to_class val foodMap = classInfo.idx_to_class
val list = mutableListOf<Food>() val list = mutableListOf<Food>()
embeddingsList.forEachIndexed { index, floatList -> val size = embeddingsList.size
val classIdx = labelsList[index] val size2 = labelsList.size
val foodName = foodMap["$classIdx"] val size3 = foodMap.size
val array = floatList.toFloatArray() Log.d("TAG", "initDefFoodData: $size,$size2,$size3")
// ObjectBox.boxStore.runInTx { embeddingsList.forEachIndexed { index, floatList ->
// box.put(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX)) val classIdx = labelsList[index]
// } val foodName = foodMap["$classIdx"]
list.add(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX)) val array = floatList.toFloatArray()
// ObjectBox.boxStore.runInTx {
// box.put(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX))
// }
val food = Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX)
list.add(food)
}
// val tempList = list.chunked(10)
ObjectBox.putAll(list)
action()
} catch (e: Exception) {
e.printStackTrace()
Log.d("TAG", "initDefFoodData: ---${e.message}--")
} }
ObjectBox.putAll(list)
action()
} }
@@ -140,6 +140,7 @@ object ObjectBox {
dbMutex.withLock { operation() } dbMutex.withLock { operation() }
} catch (e: FileCorruptException) { } catch (e: FileCorruptException) {
// 操作中触发损坏,尝试重建数据库 // 操作中触发损坏,尝试重建数据库
e.printStackTrace()
//val context = boxStore.context //val context = boxStore.context
//deleteDbFiles(context) //deleteDbFiles(context)
init(MyApp.instance!!) init(MyApp.instance!!)
@@ -173,19 +174,20 @@ object ObjectBox {
} }
suspend fun putAll(entities: List<Food>) = safeDbOp { suspend fun putAll(entities: List<Food>) = safeDbOp {
getBox<Food>()?.put(entities) val box = getBox<Food>()
box?.put(entities)
} }
suspend fun filter(name:String?) = safeDbOp { suspend fun filter(name: String?) = safeDbOp {
val list = getBox<Food>()?.all?.distinctBy { it.name } val list = getBox<Food>()?.all?.distinctBy { it.name }
if (name.isNullOrBlank().not()) { if (name.isNullOrBlank().not()) {
list?.filter { it.name?.contains(name) == true } list?.filter { it.name?.contains(name) == true }
} else { } else {
list list
}?:emptyList() } ?: emptyList()
} }
suspend fun remove(name:String) = safeDbOp { suspend fun remove(name: String) = safeDbOp {
getBox<Food>()?.run { getBox<Food>()?.run {
val filterIdList = all.filter { it.name == name }.map { it.id } val filterIdList = all.filter { it.name == name }.map { it.id }
removeByIds(filterIdList) removeByIds(filterIdList)