From cb86ab84f3835eb74b8064e5ffe35bf26a659a49 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 20 May 2024 14:28:27 +0530 Subject: [PATCH] Send user agent --- .../photos/src/services/face/face.worker.ts | 7 +-- web/apps/photos/src/services/face/remote.ts | 15 +++--- .../machineLearning/machineLearningService.ts | 49 ++++++++++++++----- .../services/machineLearning/mlWorkManager.ts | 21 +++++++- web/packages/shared/apps/constants.ts | 2 + 5 files changed, 70 insertions(+), 24 deletions(-) diff --git a/web/apps/photos/src/services/face/face.worker.ts b/web/apps/photos/src/services/face/face.worker.ts index f6b047b3cf..0ba2233e70 100644 --- a/web/apps/photos/src/services/face/face.worker.ts +++ b/web/apps/photos/src/services/face/face.worker.ts @@ -12,15 +12,16 @@ export class DedicatedMLWorker { public async syncLocalFile( token: string, userID: number, + userAgent: string, enteFile: EnteFile, localFile: globalThis.File, ) { - mlService.syncLocalFile(token, userID, enteFile, localFile); + mlService.syncLocalFile(token, userID, userAgent, enteFile, localFile); } - public async sync(token: string, userID: number) { + public async sync(token: string, userID: number, userAgent: string) { await downloadManager.init(APPS.PHOTOS, { token }); - return mlService.sync(token, userID); + return mlService.sync(token, userID, userAgent); } } diff --git a/web/apps/photos/src/services/face/remote.ts b/web/apps/photos/src/services/face/remote.ts index fc2169dd79..fcd8775a9e 100644 --- a/web/apps/photos/src/services/face/remote.ts +++ b/web/apps/photos/src/services/face/remote.ts @@ -8,8 +8,9 @@ import type { Face, FaceDetection, MlFileData } from "./types"; export const putFaceEmbedding = async ( enteFile: EnteFile, mlFileData: MlFileData, + userAgent: string, ) => { - const serverMl = LocalFileMlDataToServerFileMl(mlFileData); + const serverMl = LocalFileMlDataToServerFileMl(mlFileData, userAgent); log.debug(() => ({ t: "Local ML file data", mlFileData })); log.debug(() => ({ t: "Uploaded ML file data", @@ -57,13 +58,11 @@ class ServerFileMl { class ServerFaceEmbeddings { public faces: ServerFace[]; public version: number; - /* TODO - public client?: string; - public error?: boolean; - */ + public client: string; - public constructor(faces: ServerFace[], version: number) { + public constructor(faces: ServerFace[], client: string, version: number) { this.faces = faces; + this.client = client; this.version = version; } } @@ -121,6 +120,7 @@ class ServerFaceBox { function LocalFileMlDataToServerFileMl( localFileMlData: MlFileData, + userAgent: string, ): ServerFileMl { if (localFileMlData.errorCount > 0) { return null; @@ -139,7 +139,6 @@ function LocalFileMlDataToServerFileMl( const landmarks = detection.landmarks; const newBox = new ServerFaceBox(box.x, box.y, box.width, box.height); - // TODO-ML: Add client UA and version const newFaceObject = new ServerFace( faceID, Array.from(embedding), @@ -149,7 +148,7 @@ function LocalFileMlDataToServerFileMl( ); faces.push(newFaceObject); } - const faceEmbeddings = new ServerFaceEmbeddings(faces, 1); + const faceEmbeddings = new ServerFaceEmbeddings(faces, userAgent, 1); return new ServerFileMl( localFileMlData.fileId, faceEmbeddings, diff --git a/web/apps/photos/src/services/machineLearning/machineLearningService.ts b/web/apps/photos/src/services/machineLearning/machineLearningService.ts index 32980a2c04..954a88c66d 100644 --- a/web/apps/photos/src/services/machineLearning/machineLearningService.ts +++ b/web/apps/photos/src/services/machineLearning/machineLearningService.ts @@ -44,6 +44,7 @@ export async function updateMLSearchConfig(newConfig: MLSearchConfig) { class MLSyncContext { public token: string; public userID: number; + public userAgent: string; public localFilesMap: Map; public outOfSyncFiles: EnteFile[]; @@ -52,9 +53,10 @@ class MLSyncContext { public syncQueue: PQueue; - constructor(token: string, userID: number) { + constructor(token: string, userID: number, userAgent: string) { this.token = token; this.userID = userID; + this.userAgent = userAgent; this.outOfSyncFiles = []; this.nSyncedFiles = 0; @@ -77,12 +79,16 @@ class MachineLearningService { private localSyncContext: Promise; private syncContext: Promise; - public async sync(token: string, userID: number): Promise { + public async sync( + token: string, + userID: number, + userAgent: string, + ): Promise { if (!token) { throw Error("Token needed by ml service to sync file"); } - const syncContext = await this.getSyncContext(token, userID); + const syncContext = await this.getSyncContext(token, userID, userAgent); await this.syncLocalFiles(syncContext); @@ -214,13 +220,17 @@ class MachineLearningService { // await this.disposeMLModels(); } - private async getSyncContext(token: string, userID: number) { + private async getSyncContext( + token: string, + userID: number, + userAgent: string, + ) { if (!this.syncContext) { log.info("Creating syncContext"); // TODO-ML(MR): Keep as promise for now. this.syncContext = new Promise((resolve) => { - resolve(new MLSyncContext(token, userID)); + resolve(new MLSyncContext(token, userID, userAgent)); }); } else { log.info("reusing existing syncContext"); @@ -228,13 +238,17 @@ class MachineLearningService { return this.syncContext; } - private async getLocalSyncContext(token: string, userID: number) { + private async getLocalSyncContext( + token: string, + userID: number, + userAgent: string, + ) { // TODO-ML(MR): This is updating the file ML version. verify. if (!this.localSyncContext) { log.info("Creating localSyncContext"); // TODO-ML(MR): this.localSyncContext = new Promise((resolve) => { - resolve(new MLSyncContext(token, userID)); + resolve(new MLSyncContext(token, userID, userAgent)); }); } else { log.info("reusing existing localSyncContext"); @@ -254,10 +268,15 @@ class MachineLearningService { public async syncLocalFile( token: string, userID: number, + userAgent: string, enteFile: EnteFile, localFile?: globalThis.File, ) { - const syncContext = await this.getLocalSyncContext(token, userID); + const syncContext = await this.getLocalSyncContext( + token, + userID, + userAgent, + ); try { await this.syncFileWithErrorHandler( @@ -281,7 +300,11 @@ class MachineLearningService { localFile?: globalThis.File, ) { try { - const mlFileData = await this.syncFile(enteFile, localFile); + const mlFileData = await this.syncFile( + enteFile, + localFile, + syncContext.userAgent, + ); syncContext.nSyncedFiles += 1; return mlFileData; } catch (e) { @@ -313,14 +336,18 @@ class MachineLearningService { } } - private async syncFile(enteFile: EnteFile, localFile?: globalThis.File) { + private async syncFile( + enteFile: EnteFile, + localFile: globalThis.File | undefined, + userAgent: string, + ) { const oldMlFile = await mlIDbStorage.getFile(enteFile.id); if (oldMlFile && oldMlFile.mlVersion) { return oldMlFile; } const newMlFile = await indexFaces(enteFile, localFile); - await putFaceEmbedding(enteFile, newMlFile); + await putFaceEmbedding(enteFile, newMlFile, userAgent); await mlIDbStorage.putFile(newMlFile); return newMlFile; } diff --git a/web/apps/photos/src/services/machineLearning/mlWorkManager.ts b/web/apps/photos/src/services/machineLearning/mlWorkManager.ts index 42b2fe5b27..c1b2ef6a70 100644 --- a/web/apps/photos/src/services/machineLearning/mlWorkManager.ts +++ b/web/apps/photos/src/services/machineLearning/mlWorkManager.ts @@ -1,6 +1,8 @@ import { FILE_TYPE } from "@/media/file-type"; +import { ensureElectron } from "@/next/electron"; import log from "@/next/log"; import { ComlinkWorker } from "@/next/worker/comlink-worker"; +import { clientPackageNamePhotosDesktop } from "@ente/shared/apps/constants"; import { eventBus, Events } from "@ente/shared/events"; import { getToken, getUserID } from "@ente/shared/storage/localStorage/helpers"; import debounce from "debounce"; @@ -227,8 +229,15 @@ class MLWorkManager { this.stopSyncJob(); const token = getToken(); const userID = getUserID(); + const userAgent = await getUserAgent(); const mlWorker = await this.getLiveSyncWorker(); - return mlWorker.syncLocalFile(token, userID, enteFile, localFile); + return mlWorker.syncLocalFile( + token, + userID, + userAgent, + enteFile, + localFile, + ); }); } @@ -266,9 +275,10 @@ class MLWorkManager { const token = getToken(); const userID = getUserID(); + const userAgent = await getUserAgent(); const jobWorkerProxy = await this.getSyncJobWorker(); - return await jobWorkerProxy.sync(token, userID); + return await jobWorkerProxy.sync(token, userID, userAgent); // this.terminateSyncJobWorker(); // TODO: redirect/refresh to gallery in case of session_expired, stop ml sync job } catch (e) { @@ -320,3 +330,10 @@ export function logQueueStats(queue: PQueue, name: string) { console.error(`queuestats: ${name}: Error, `, error), ); } + +const getUserAgent = async () => { + const electron = ensureElectron(); + const name = clientPackageNamePhotosDesktop; + const version = await electron.appVersion(); + return `${name}/${version}`; +}; diff --git a/web/packages/shared/apps/constants.ts b/web/packages/shared/apps/constants.ts index d35a5e8c47..b679fb9123 100644 --- a/web/packages/shared/apps/constants.ts +++ b/web/packages/shared/apps/constants.ts @@ -14,6 +14,8 @@ export const CLIENT_PACKAGE_NAMES = new Map([ [APPS.ACCOUNTS, "io.ente.accounts.web"], ]); +export const clientPackageNamePhotosDesktop = "io.ente.photos.desktop"; + export const APP_TITLES = new Map([ [APPS.ALBUMS, "Ente Albums"], [APPS.PHOTOS, "Ente Photos"],