add caching model

This commit is contained in:
mphstar 2025-03-12 00:04:45 +07:00
parent 957a63ca7c
commit c7f37f589e
7 changed files with 150 additions and 50 deletions

View File

@ -2,12 +2,14 @@ import LayoutPage from "@/components/templates/LayoutPage";
import { useEffect, useRef, useState } from "react";
import { FaCircleCheck } from "react-icons/fa6";
import * as tf from "@tensorflow/tfjs";
import { FilesetResolver, HandLandmarker } from "@mediapipe/tasks-vision";
import { HandLandmarker } from "@mediapipe/tasks-vision";
import calcLandmarkList from "@/utils/CalculateLandmark";
import preProcessLandmark from "@/utils/PreProcessLandmark";
import ConvertResult from "@/utils/ConvertResult";
import useNavbarStore from "@/stores/NavbarStore";
import { AnimatePresence, motion } from "framer-motion";
import { loadTensorFlowModel } from "@/utils/tensorflowModelLoader";
import { loadHandLandmarker } from "@/utils/handLandmarkerLoader";
type PredictResult = {
abjad: String;
@ -50,12 +52,13 @@ const Home = () => {
const loadModel = async () => {
setLoadCamera(false);
try {
const lm = await tf.loadLayersModel("/model/model.json");
const lm = await loadTensorFlowModel();
model = lm;
const emptyInput = tf.tensor2d([[0, 0]]);
// const emptyInput = tf.tensor2d([[0, 0]]);
model.predict(emptyInput) as tf.Tensor;
// model.predict(emptyInput) as tf.Tensor;
setLoadCamera(true);
} catch (error) {
@ -65,17 +68,8 @@ const Home = () => {
const initializeHandDetection = async () => {
try {
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"
);
handLandmarker = await HandLandmarker.createFromOptions(vision, {
baseOptions: {
modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
},
numHands: 2,
runningMode: "VIDEO",
});
handLandmarker = await loadHandLandmarker();
detectHands();
} catch (error) {
console.error("Error initializing hand detection:", error);
@ -117,11 +111,13 @@ const Home = () => {
performance.now()
);
setHandPresence(detections.handedness.length > 0);
// Assuming detections.landmarks is an array of landmark objects
if (detections.landmarks) {
if (detections.handednesses.length > 0) {
console.log(detections);
// console.log(detections);
if (detections.handednesses[0][0].displayName === "Right") {
const landm = detections.landmarks[0].map((landmark) => landmark);
@ -184,10 +180,7 @@ const Home = () => {
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<p className="ml-2">
Gunakan tangan kanan dan pastikan gambar pada kamera terlihat
jelas
</p>
<p className="ml-2">Gunakan tangan kanan. Pencahayaan ideal 300 Lux, jarak maksimal 2 meter dari kamera.</p>
</div>
<button
onClick={() => setInfo(false)}

View File

@ -80,6 +80,12 @@ const Kamus = () => {
<div className="flex flex-col md:flex-row gap-6 overflow-y-auto flex-1">
<div className="flex flex-col order-2 md:order-1">
<p>{selectedKamus?.keterangan}</p>
<a href="/">
<button className="btn mt-8 bg-slate-900 text-white hover:bg-slate-950 w-fit">
Coba Sekarang
</button>
</a>
{/* <div className="flex flex-wrap gap-2 mt-3">
{selectedKamus?.badge.map((item, index) => (
<span

View File

@ -1,7 +1,7 @@
import LayoutPage from "@/components/templates/LayoutPage";
import { useEffect, useRef, useState } from "react";
import * as tf from "@tensorflow/tfjs";
import { FilesetResolver, HandLandmarker } from "@mediapipe/tasks-vision";
import { HandLandmarker } from "@mediapipe/tasks-vision";
import calcLandmarkList from "@/utils/CalculateLandmark";
import preProcessLandmark from "@/utils/PreProcessLandmark";
import { abjads } from "@/utils/ConvertResult";
@ -10,6 +10,8 @@ import { MdOutlineQuiz } from "react-icons/md";
import useMenyusunHurufStore from "@/stores/MenyusunHurufStore";
import { useNavigate } from "react-router-dom";
import Swal from "sweetalert2";
import { loadTensorFlowModel } from "@/utils/tensorflowModelLoader";
import { loadHandLandmarker } from "@/utils/handLandmarkerLoader";
// type PredictResult = {
// abjad: String;
@ -61,7 +63,7 @@ const Quiz = () => {
const loadModel = async () => {
setLoadCamera(false);
try {
const lm = await tf.loadLayersModel("/model/model.json");
const lm = await loadTensorFlowModel();
model = lm;
const emptyInput = tf.tensor2d([[0, 0]]);
@ -76,16 +78,7 @@ const Quiz = () => {
const initializeHandDetection = async () => {
try {
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"
);
handLandmarker = await HandLandmarker.createFromOptions(vision, {
baseOptions: {
modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
},
numHands: 2,
runningMode: "VIDEO",
});
handLandmarker = await loadHandLandmarker();
detectHands();
} catch (error) {

View File

@ -1,7 +1,7 @@
import LayoutPage from "@/components/templates/LayoutPage";
import { useEffect, useRef, useState } from "react";
import * as tf from "@tensorflow/tfjs";
import { FilesetResolver, HandLandmarker } from "@mediapipe/tasks-vision";
import { HandLandmarker } from "@mediapipe/tasks-vision";
import calcLandmarkList from "@/utils/CalculateLandmark";
import preProcessLandmark from "@/utils/PreProcessLandmark";
import ConvertResult, { abjads } from "@/utils/ConvertResult";
@ -11,6 +11,8 @@ import { MdOutlineQuiz } from "react-icons/md";
import useTebakHurufStore from "@/stores/TebakHurufStore";
import { useNavigate } from "react-router-dom";
import Swal from "sweetalert2";
import { loadTensorFlowModel } from "@/utils/tensorflowModelLoader";
import { loadHandLandmarker } from "@/utils/handLandmarkerLoader";
// type PredictResult = {
// abjad: String;
@ -63,7 +65,7 @@ const Quiz = () => {
const loadModel = async () => {
setLoadCamera(false);
try {
const lm = await tf.loadLayersModel("/model/model.json");
const lm = await loadTensorFlowModel();
model = lm;
const emptyInput = tf.tensor2d([[0, 0]]);
@ -78,16 +80,7 @@ const Quiz = () => {
const initializeHandDetection = async () => {
try {
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"
);
handLandmarker = await HandLandmarker.createFromOptions(vision, {
baseOptions: {
modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
},
numHands: 2,
runningMode: "VIDEO",
});
handLandmarker = await loadHandLandmarker();
detectHands();
} catch (error) {
@ -161,11 +154,13 @@ const Quiz = () => {
setTimeout(() => {
setShowAnswer(false);
isLoading = false;
setProgress(0);
noSoal++;
previousResult = [];
quizStore.setSoalIndex(noSoal);
setTimeout(() => {
isLoading = false;
setProgress(0);
noSoal++;
previousResult = [];
quizStore.setSoalIndex(noSoal);
}, 500);
if (noSoal === quizStore.listSoal.length) {
quizStore.setSession(false);
@ -231,7 +226,7 @@ const Quiz = () => {
const store = useNavbarStore();
const quizStore = useTebakHurufStore();
console.log(quizStore.jawaban);
// console.log(quizStore.jawaban);
useEffect(() => {
if (!quizStore.session) {

View File

@ -0,0 +1,34 @@
import { FilesetResolver, HandLandmarker } from "@mediapipe/tasks-vision";
import { getHandLandmarkerModel, saveHandLandmarkerModel } from "./indexedDBHelper";
let handLandmarker: HandLandmarker | null = null;
export async function loadHandLandmarker(): Promise<HandLandmarker> {
if (handLandmarker) return handLandmarker; // Jika model sudah ada, langsung kembalikan
let modelBlob = await getHandLandmarkerModel();
if (!modelBlob) {
console.log("🔄 Model Hand Landmarker tidak ditemukan di cache, mengunduh...");
const response = await fetch(
"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task"
);
modelBlob = await response.blob();
await saveHandLandmarkerModel(modelBlob);
} else {
console.log("✅ Model Hand Landmarker ditemukan di cache, menggunakan model lokal.");
}
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"
);
const modelURL = URL.createObjectURL(modelBlob);
handLandmarker = await HandLandmarker.createFromOptions(vision, {
baseOptions: { modelAssetPath: modelURL },
numHands: 2,
runningMode: "VIDEO",
});
return handLandmarker;
}

View File

@ -0,0 +1,59 @@
import * as tf from "@tensorflow/tfjs";
const DB_NAME = "ModelCacheDB";
const STORE_NAME = "models";
const TENSORFLOW_MODEL_KEY = "tensorflow_model";
const HAND_LANDMARKER_MODEL_KEY = "hand_landmarker_model";
// Membuka IndexedDB
export function openDB(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, 1);
request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME);
}
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 🟢 **Simpan Model TensorFlow.js ke IndexedDB**
export async function saveTensorFlowModel(model: tf.LayersModel): Promise<void> {
await model.save(`indexeddb://${TENSORFLOW_MODEL_KEY}`);
}
// 🟢 **Ambil Model TensorFlow.js dari IndexedDB**
export async function getTensorFlowModel(): Promise<tf.LayersModel | null> {
try {
return await tf.loadLayersModel(`indexeddb://${TENSORFLOW_MODEL_KEY}`);
} catch (error) {
console.warn("⚠️ Model TensorFlow tidak ditemukan di cache:", error);
return null;
}
}
// 🟢 **Simpan Model Hand Landmarker ke IndexedDB**
export async function saveHandLandmarkerModel(blob: Blob): Promise<void> {
const db = await openDB();
const transaction = db.transaction(STORE_NAME, "readwrite");
const store = transaction.objectStore(STORE_NAME);
store.put(blob, HAND_LANDMARKER_MODEL_KEY);
}
// 🟢 **Ambil Model Hand Landmarker dari IndexedDB**
export async function getHandLandmarkerModel(): Promise<Blob | null> {
const db = await openDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(STORE_NAME, "readonly");
const store = transaction.objectStore(STORE_NAME);
const request = store.get(HAND_LANDMARKER_MODEL_KEY);
request.onsuccess = () => resolve(request.result as Blob | null);
request.onerror = () => reject(request.error);
});
}

View File

@ -0,0 +1,20 @@
import * as tf from "@tensorflow/tfjs";
import { getTensorFlowModel, saveTensorFlowModel } from "./indexedDBHelper";
let model: tf.LayersModel | null = null;
export async function loadTensorFlowModel(): Promise<tf.LayersModel> {
if (model) return model; // Jika model sudah dimuat, langsung kembalikan
model = await getTensorFlowModel();
if (!model) {
console.log("🔄 Model TensorFlow tidak ditemukan di cache, mengunduh...");
model = await tf.loadLayersModel("/model/model.json");
await saveTensorFlowModel(model);
} else {
console.log("✅ Model TensorFlow ditemukan di cache, menggunakan model lokal.");
}
return model;
}