Skip to content

Commit

Permalink
Merge pull request #121 from ajinkyapandetekdi/all-2.0-offline
Browse files Browse the repository at this point in the history
  • Loading branch information
gouravmore authored Jul 23, 2024
2 parents 3c35a51 + c1859e7 commit 90ebc97
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 40 deletions.
Binary file added src/assets/images/boy-running.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
213 changes: 201 additions & 12 deletions src/components/Assesment/Assesment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ import config from "../../utils/urlConstants.json";
import panda from "../../assets/images/panda.svg";
import cryPanda from "../../assets/images/cryPanda.svg";
import { uniqueId } from "../../services/utilService";
import CircularProgressOverlay from "../CommonComponent/CircularProgressOverlay";
import ProgressOverlay from "../CommonComponent/ProgressOverlay";
import { end } from "../../services/telementryService";

export const LanguageModal = ({
lang,
setLang,
setOpenLangModal,
setLoading,
setDownloadProgress
}) => {
const [selectedLang, setSelectedLang] = useState(lang);
const [isOfflineModel, setIsOfflineModel] = useState(
Expand All @@ -66,7 +67,6 @@ export const LanguageModal = ({
let db;

// Open IndexedDB

const openDB = () => {
return new Promise((resolve, reject) => {
const request = window.indexedDB.open(dbName, dbVersion);
Expand Down Expand Up @@ -96,13 +96,34 @@ export const LanguageModal = ({
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const modelData = await response.arrayBuffer();
const uint8Array = new Uint8Array(modelData);

const transaction = await db.transaction(["models"], "readwrite");

const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0;
const chunks = [];

while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;

// Update progress
const percentage = ((receivedLength / contentLength) * 100);
setDownloadProgress(percentage.toFixed());
}

const modelData = new Uint8Array(receivedLength);
let position = 0;
for (let chunk of chunks) {
modelData.set(chunk, position);
position += chunk.length;
}

const transaction = db.transaction(["models"], "readwrite");
const store = transaction.objectStore("models");

store.put(uint8Array, modelName);
store.put(modelData, modelName);
console.log(`Stored model ${modelName} in IndexedDB`);
} catch (error) {
console.error("Error storing model in IndexedDB:", error);
Expand Down Expand Up @@ -135,7 +156,7 @@ export const LanguageModal = ({
try {
window.whisperModule.FS_unlink("whisper.bin");
} catch (e) {
// ignore
console.log(e)
}
try {
let transaction;
Expand Down Expand Up @@ -185,6 +206,7 @@ export const LanguageModal = ({
await storeModel(modelName, modelURL);
} else {
console.log(`Model ${modelName} is already stored in IndexedDB`);
return;
}
await loadModelWhisper(modelName);
} catch (error) {
Expand Down Expand Up @@ -719,6 +741,7 @@ const Assesment = ({ discoverStart }) => {
const [openLangModal, setOpenLangModal] = useState(false);
const [lang, setLang] = useState(getLocalData("lang") || "en");
const [points, setPoints] = useState(0);
const [downloadProgress, setDownloadProgress] = useState(0);

useEffect(() => {
// const level = getLocalData('userLevel');
Expand Down Expand Up @@ -799,7 +822,173 @@ const Assesment = ({ discoverStart }) => {
const { virtualId } = useSelector((state) => state.user);

const navigate = useNavigate();
const handleRedirect = () => {

const dbName = "language-ai-models";
const dbVersion = 1;
let db;

// Function to check if the model is already stored in IndexedDB
const isModelStored = async (modelName) => {
return new Promise((resolve, reject) => {
const transaction = db.transaction(["models"], "readonly");
const store = transaction.objectStore("models");
const request = store.get(modelName);

request.onerror = function (event) {
console.error(
"Error checking model in IndexedDB:",
event.target.errorCode
);
reject(event.target.error);
};

request.onsuccess = function (event) {
resolve(!!event.target.result);
};
});
};

// Function to load model in whisper cpp module
const loadModelWhisper = async (modelName) => {
try {
window.whisperModule.FS_unlink("whisper.bin");
} catch (e) {
console.log(e)
}
try {
let transaction;
let store;
let request;
try {
transaction = await db.transaction(["models"], "readonly");
store = transaction.objectStore("models");
request = await store.get(modelName);
} catch (error) {
console.error("Error accessing IndexedDB:", error);
return;
}

request.onsuccess = async () => {
const modelData = request.result;
let storeResponse = await window.whisperModule.FS_createDataFile(
"/",
"whisper.bin",
modelData,
true,
true
);
setTimeout(console.log(window.whisperModule.init("whisper.bin")), 5000);
};

request.onerror = (err) => {
console.error(`Error to get model data: ${err}`);
};

console.log(`Stored model in whisper cpp memory`);
} catch (error) {
console.error("Error storing model in IndexedDB:", error);
}
};

// Function to store model in IndexedDB
const storeModel = async (modelName, modelURL) => {
try {
const response = await fetch(modelURL);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0;
const chunks = [];

while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;

// Update progress
const percentage = ((receivedLength / contentLength) * 100);
setDownloadProgress(percentage.toFixed());
}

const modelData = new Uint8Array(receivedLength);
let position = 0;
for (let chunk of chunks) {
modelData.set(chunk, position);
position += chunk.length;
}

const transaction = db.transaction(["models"], "readwrite");
const store = transaction.objectStore("models");

store.put(modelData, modelName);
console.log(`Stored model ${modelName} in IndexedDB`);
} catch (error) {
console.error("Error storing model in IndexedDB:", error);
}
};

// Function to load model
const loadModel = async () => {
setLoading(true);
try {
await openDB();
const modelName = "en-model";
const modelURL = "./models/ggml-model-whisper-base.en-q5_1.bin";

const stored = await isModelStored(modelName);
if (!stored) {
await storeModel(modelName, modelURL);
} else {
console.log(`Model ${modelName} is already stored in IndexedDB`);
}
await loadModelWhisper(modelName);
} catch (error) {
console.log(error.message);
} finally {
setLoading(false);
}
};

// Open IndexedDB

const openDB = () => {
return new Promise((resolve, reject) => {
const request = window.indexedDB.open(dbName, dbVersion);
request.onerror = (event) => {
console.error("IndexedDB error:", event.target.errorCode);
reject(event.target.error);
};
request.onsuccess = (event) => {
db = event.target.result;
console.log("IndexedDB opened successfully");
resolve();
};
request.onupgradeneeded = (event) => {
db = event.target.result;
console.log("Creating object store for models");
if (!db.objectStoreNames.contains("models")) {
db.createObjectStore("models");
}
};
});
};

const handleRedirect = async () => {
const modelName = "en-model";
await openDB();
const stored = await isModelStored(modelName);
if (stored) {
console.log(`Model ${modelName} is already stored in IndexedDB`);
}
else{
alert(`you have to download en-offline model`)
loadModel();
return;
}
const profileName = getLocalData("profileName");
if (!username && !profileName && !virtualId && level === 0) {
// alert("please add username in query param");
Expand Down Expand Up @@ -839,7 +1028,7 @@ const Assesment = ({ discoverStart }) => {

return (
<>
{loading && <CircularProgressOverlay size="4rem" color={"#ffffff"} />}
{loading && <ProgressOverlay size="4rem" color={"#ffffff"} showLinearProgress={true} downloadProgress={downloadProgress} />}
{!!openMessageDialog && (
<MessageDialog
message={openMessageDialog.message}
Expand All @@ -851,7 +1040,7 @@ const Assesment = ({ discoverStart }) => {
/>
)}
{openLangModal && (
<LanguageModal {...{ lang, setLang, setOpenLangModal, setLoading }} />
<LanguageModal {...{ lang, setLang, setOpenLangModal, setLoading, setDownloadProgress }} />
)}
{level > 0 ? (
<Box style={sectionStyle}>
Expand Down
80 changes: 80 additions & 0 deletions src/components/CommonComponent/ProgressOverlay.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from "react";
import { Box, CircularProgress, LinearProgress, Typography } from "@mui/material";
import RunnungBoy from '../../assets/images/boy-running.gif'

const ProgressOverlay = ({
size,
color = "#ffffff",
showLinearProgress = false,
downloadProgress = 0,
}) => (
<Box
sx={{
display: "flex",
position: "absolute",
zIndex: 999,
justifyContent: "center",
width: "100%",
alignItems: "center",
height: "100vh",
backgroundColor: "rgb(0 0 0 /36%)",
}}
>
{showLinearProgress ? (
<Box sx={{ position: "relative", width: '40%' }}>
<LinearProgress
variant="determinate"
value={downloadProgress}
sx={{
borderRadius: 5,
height: 20,
'& .MuiLinearProgress-bar': {
backgroundColor: "#000000",
},
}}
/>
<Box
sx={{
position: "absolute",
top: -55, // Adjust the vertical position of the emoji
left: `${downloadProgress}%`,
transform: 'translateX(-50%)',
transition: 'left 0.2s linear', // Smooth transition for emoji movement
fontSize: 24, // Adjust the size of the emoji
}}
>
<img style={{height:'57px', paddingBottom:'10px'}} src={RunnungBoy}/>
</Box>
<Box
sx={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
pointerEvents: "none", // Prevents interaction with the overlay
textAlign: "center", // Center the text horizontally
}}
>
<Typography
variant="body2"
fontWeight="bold"
sx={{
color: "common.white",
mixBlendMode: 'difference',
}}
>
LOADING… {`${Math.round(Number(downloadProgress))}%`}
</Typography>
</Box>
</Box>
) : (
<CircularProgress size={size} sx={{ color: color }} />
)}
</Box>
);

export default ProgressOverlay;
16 changes: 8 additions & 8 deletions src/config/awsS3.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// import { S3Client } from '@aws-sdk/client-s3';
import { S3Client } from '@aws-sdk/client-s3';

// export default new S3Client({
// region: process.env.REACT_APP_AWS_S3_REGION,
// credentials: {
// accessKeyId: process.env.REACT_APP_AWS_ACCESS_KEY_ID,
// secretAccessKey: process.env.REACT_APP_AWS_SECRET_ACCESS_KEY,
// },
// });
export default new S3Client({
region: process.env.REACT_APP_AWS_S3_REGION,
credentials: {
accessKeyId: process.env.REACT_APP_AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.REACT_APP_AWS_SECRET_ACCESS_KEY,
},
});
Loading

0 comments on commit 90ebc97

Please sign in to comment.