This commit is contained in:
Manav Rathi
2024-05-30 13:16:15 +05:30
parent 6e6c88826e
commit 23c73a83eb
3 changed files with 44 additions and 48 deletions

View File

@@ -1,7 +1,9 @@
import { FILE_TYPE } from "@/media/file-type";
import { decodeLivePhoto } from "@/media/live-photo";
import log from "@/next/log";
import { workerBridge } from "@/next/worker/worker-bridge";
import { Matrix } from "ml-matrix";
import DownloadManager from "services/download";
import { defaultMLVersion } from "services/machineLearning/machineLearningService";
import { getSimilarityTransformation } from "similarity-transformation";
import {
@@ -12,9 +14,8 @@ import {
translate,
} from "transformation-matrix";
import type { EnteFile } from "types/file";
import { logIdentifier } from "utils/file";
import { getRenderableImage, logIdentifier } from "utils/file";
import { saveFaceCrop } from "./crop";
import { fetchImageBitmap, getLocalFileImageBitmap } from "./file";
import {
clamp,
grayscaleIntMatrixFromNormalized2List,
@@ -39,11 +40,20 @@ import type { Face, FaceDetection, MlFileData } from "./types-old";
* they can be saved locally for offline use, and encrypts and uploads them to
* the user's remote storage so that their other devices can download them
* instead of needing to reindex.
*
* @param enteFile The {@link EnteFile} to index.
*
* @param file The contents of {@link enteFile} as a web {@link File}, if
* available. These are used when they are provided, otherwise the file is
* downloaded and decrypted from remote.
*/
export const indexFaces = async (enteFile: EnteFile, localFile?: File) => {
export const indexFaces = async (
enteFile: EnteFile,
file: File | undefined,
) => {
const startTime = Date.now();
const imageBitmap = await fetchOrCreateImageBitmap(enteFile, localFile);
const imageBitmap = await fetchOrCreateImageBitmap(enteFile, file);
let mlFile: MlFileData;
try {
mlFile = await indexFaces_(enteFile, imageBitmap);
@@ -60,20 +70,17 @@ export const indexFaces = async (enteFile: EnteFile, localFile?: File) => {
};
/**
* Return a {@link ImageBitmap}, using {@link localFile} if present otherwise
* Return a {@link ImageBitmap}, using {@link file} if present otherwise
* downloading the source image corresponding to {@link enteFile} from remote.
*/
const fetchOrCreateImageBitmap = async (
enteFile: EnteFile,
localFile: File,
) => {
const fetchOrCreateImageBitmap = async (enteFile: EnteFile, file: File) => {
const fileType = enteFile.metadata.fileType;
if (localFile) {
if (file) {
// TODO-ML(MR): Could also be image part of live photo?
if (fileType !== FILE_TYPE.IMAGE)
throw new Error("Local file of only image type is supported");
return await getLocalFileImageBitmap(enteFile, localFile);
return await getLocalFileImageBitmap(enteFile, file);
} else if ([FILE_TYPE.IMAGE, FILE_TYPE.LIVE_PHOTO].includes(fileType)) {
return await fetchImageBitmap(enteFile);
} else {
@@ -81,6 +88,28 @@ const fetchOrCreateImageBitmap = async (
}
};
const fetchImageBitmap = async (enteFile: EnteFile) =>
fetchRenderableBlob(enteFile).then(createImageBitmap);
const fetchRenderableBlob = async (enteFile: EnteFile) => {
const fileStream = await DownloadManager.getFile(enteFile);
const fileBlob = await new Response(fileStream).blob();
if (enteFile.metadata.fileType === FILE_TYPE.IMAGE) {
return getRenderableImage(enteFile.metadata.title, fileBlob);
} else {
const { imageFileName, imageData } = await decodeLivePhoto(
enteFile.metadata.title,
fileBlob,
);
return getRenderableImage(imageFileName, new Blob([imageData]));
}
};
const getLocalFileImageBitmap = async (enteFile: EnteFile, localFile: File) =>
createImageBitmap(
await getRenderableImage(enteFile.metadata.title, localFile),
);
const indexFaces_ = async (enteFile: EnteFile, imageBitmap: ImageBitmap) => {
const fileID = enteFile.id;
const { width, height } = imageBitmap;

View File

@@ -1,37 +0,0 @@
import { FILE_TYPE } from "@/media/file-type";
import { decodeLivePhoto } from "@/media/live-photo";
import DownloadManager from "services/download";
import { getLocalFiles } from "services/fileService";
import { EnteFile } from "types/file";
import { getRenderableImage } from "utils/file";
export async function getLocalFile(fileId: number) {
const localFiles = await getLocalFiles();
return localFiles.find((f) => f.id === fileId);
}
export const fetchImageBitmap = async (file: EnteFile) =>
fetchRenderableBlob(file).then(createImageBitmap);
async function fetchRenderableBlob(file: EnteFile) {
const fileStream = await DownloadManager.getFile(file);
const fileBlob = await new Response(fileStream).blob();
if (file.metadata.fileType === FILE_TYPE.IMAGE) {
return await getRenderableImage(file.metadata.title, fileBlob);
} else {
const { imageFileName, imageData } = await decodeLivePhoto(
file.metadata.title,
fileBlob,
);
return await getRenderableImage(imageFileName, new Blob([imageData]));
}
}
export async function getLocalFileImageBitmap(
enteFile: EnteFile,
localFile: globalThis.File,
) {
let fileBlob = localFile as Blob;
fileBlob = await getRenderableImage(enteFile.metadata.title, fileBlob);
return createImageBitmap(fileBlob);
}

View File

@@ -84,6 +84,10 @@ export const syncPeopleIndex = async () => {
: best,
);
export async function getLocalFile(fileId: number) {
const localFiles = await getLocalFiles();
return localFiles.find((f) => f.id === fileId);
}
if (personFace && !personFace.crop?.cacheKey) {
const file = await getLocalFile(personFace.fileId);