diff --git a/src/display/editor/stamp.js b/src/display/editor/stamp.js index f4f1387a6..c84078336 100644 --- a/src/display/editor/stamp.js +++ b/src/display/editor/stamp.js @@ -430,7 +430,8 @@ class StampEditor extends AnnotationEditor { return; } this.#hasMLBeenQueried = true; - if (!this._uiManager.isMLEnabledFor("altText") || this.hasAltText()) { + const isMLEnabled = await this._uiManager.isMLEnabledFor("altText"); + if (!isMLEnabled || this.hasAltText()) { return; } const offscreen = new OffscreenCanvas(width, height); @@ -447,7 +448,7 @@ class StampEditor extends AnnotationEditor { height ); const response = await this._uiManager.mlGuess({ - service: "image-to-text", + service: "moz-image-to-text", request: { data: ctx.getImageData(0, 0, width, height).data, width, diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index 61e7f7e8c..fa4be1fd1 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -855,8 +855,8 @@ class AnnotationEditorUIManager { return this.#mlManager?.guess(data) || null; } - isMLEnabledFor(name) { - return !!this.#mlManager?.isEnabledFor(name); + async isMLEnabledFor(name) { + return !!(await this.#mlManager?.isEnabledFor(name)); } get useNewAltTextFlow() { diff --git a/web/app.js b/web/app.js index b4f57301c..012cb3159 100644 --- a/web/app.js +++ b/web/app.js @@ -155,6 +155,7 @@ const PDFViewerApplication = { isViewerEmbedded: window.parent !== window, url: "", baseUrl: "", + mlManager: null, _downloadUrl: "", _eventBusAbortController: null, _windowAbortController: null, @@ -205,6 +206,11 @@ const PDFViewerApplication = { if (mode) { document.documentElement.classList.add(mode); } + } else { + // We want to load the image-to-text AI engine as soon as possible. + this.mlManager = new MLManager({ + enableAltText: AppOptions.get("enableAltText"), + }); } // Ensure that the `L10n`-instance has been initialized before creating @@ -370,11 +376,14 @@ const PDFViewerApplication = { let eventBus; if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) { - eventBus = AppOptions.eventBus = new FirefoxEventBus( - AppOptions.get("allowedGlobalEvents"), - externalServices, - AppOptions.get("isInAutomation") - ); + eventBus = + AppOptions.eventBus = + this.mlManager.eventBus = + new FirefoxEventBus( + AppOptions.get("allowedGlobalEvents"), + externalServices, + AppOptions.get("isInAutomation") + ); } else { eventBus = new EventBus(); } @@ -731,15 +740,6 @@ const PDFViewerApplication = { return shadow(this, "externalServices", new ExternalServices()); }, - get mlManager() { - const enableAltText = AppOptions.get("enableAltText"); - return shadow( - this, - "mlManager", - enableAltText === true ? new MLManager({ enableAltText }) : null - ); - }, - get initialized() { return this._initializedCapability.settled; }, diff --git a/web/firefoxcom.js b/web/firefoxcom.js index 0e8154f9f..af2e8ee4b 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -308,19 +308,56 @@ class FirefoxScripting { } class MLManager { - #enabled = new Map(); + #enabled = null; - constructor({ enableAltText }) { - this.#enabled.set("altText", enableAltText); + eventBus = null; + + constructor(options) { + this.enable({ ...options, listenToProgress: false }); } - isEnabledFor(name) { - return this.#enabled.get(name); + async isEnabledFor(name) { + return !!(await this.#enabled?.get(name)); } guess(data) { return FirefoxCom.requestAsync("mlGuess", data); } + + enable({ enableAltText, listenToProgress }) { + if (enableAltText) { + this.#loadAltTextEngine(listenToProgress); + } + } + + async #loadAltTextEngine(listenToProgress) { + if (this.#enabled?.has("altText")) { + // We already have a promise for the "altText" service. + return; + } + const promise = FirefoxCom.requestAsync("loadAIEngine", { + service: "moz-image-to-text", + listenToProgress, + }); + (this.#enabled ||= new Map()).set("altText", promise); + if (listenToProgress) { + const callback = ({ detail }) => { + this.eventBus.dispatch("loadaiengineprogress", { + source: this, + detail, + }); + if (detail.finished) { + window.removeEventListener("loadAIEngineProgress", callback); + } + }; + window.addEventListener("loadAIEngineProgress", callback); + promise.then(ok => { + if (!ok) { + window.removeEventListener("loadAIEngineProgress", callback); + } + }); + } + } } class ExternalServices extends BaseExternalServices { diff --git a/web/genericcom.js b/web/genericcom.js index 6ab2766ef..9c646099e 100644 --- a/web/genericcom.js +++ b/web/genericcom.js @@ -48,7 +48,7 @@ class ExternalServices extends BaseExternalServices { } class MLManager { - isEnabledFor(_name) { + async isEnabledFor(_name) { return false; }