mirror of
https://github.com/zen-browser/pdf.js.git
synced 2025-07-07 17:05:38 +02:00
Dispatch changes in prefs enableAltTextModelDownload and enableGuessAltText to the viewer (bug 1912024)
The user can change a setting in a tab and it must have an effect in the current viewer.
This commit is contained in:
parent
e099840100
commit
1d51c3e711
6 changed files with 164 additions and 53 deletions
|
@ -141,9 +141,11 @@ class StampEditor extends AnnotationEditor {
|
||||||
this._uiManager.useNewAltTextFlow &&
|
this._uiManager.useNewAltTextFlow &&
|
||||||
this.#bitmap
|
this.#bitmap
|
||||||
) {
|
) {
|
||||||
// The alt-text dialog isn't opened but we still want to guess the alt
|
try {
|
||||||
// text.
|
// The alt-text dialog isn't opened but we still want to guess the alt
|
||||||
this.mlGuessAltText();
|
// text.
|
||||||
|
this.mlGuessAltText();
|
||||||
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.div.focus();
|
this.div.focus();
|
||||||
|
@ -155,8 +157,11 @@ class StampEditor extends AnnotationEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { mlManager } = this._uiManager;
|
const { mlManager } = this._uiManager;
|
||||||
if (!mlManager || !(await mlManager.isEnabledFor("altText"))) {
|
if (!mlManager) {
|
||||||
return null;
|
throw new Error("No ML.");
|
||||||
|
}
|
||||||
|
if (!(await mlManager.isEnabledFor("altText"))) {
|
||||||
|
throw new Error("ML isn't enabled for alt text.");
|
||||||
}
|
}
|
||||||
const { data, width, height } =
|
const { data, width, height } =
|
||||||
imageData ||
|
imageData ||
|
||||||
|
@ -170,9 +175,18 @@ class StampEditor extends AnnotationEditor {
|
||||||
channels: data.length / (width * height),
|
channels: data.length / (width * height),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!response || response.error || !response.output) {
|
if (!response) {
|
||||||
|
throw new Error("No response from the AI service.");
|
||||||
|
}
|
||||||
|
if (response.error) {
|
||||||
|
throw new Error("Error from the AI service.");
|
||||||
|
}
|
||||||
|
if (response.cancel) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (!response.output) {
|
||||||
|
throw new Error("No valid response from the AI service.");
|
||||||
|
}
|
||||||
const altText = response.output;
|
const altText = response.output;
|
||||||
await this.setGuessedAltText(altText);
|
await this.setGuessedAltText(altText);
|
||||||
if (updateAltTextData && !this.hasAltTextData()) {
|
if (updateAltTextData && !this.hasAltTextData()) {
|
||||||
|
|
|
@ -404,9 +404,7 @@ const PDFViewerApplication = {
|
||||||
} else {
|
} else {
|
||||||
eventBus = new EventBus();
|
eventBus = new EventBus();
|
||||||
}
|
}
|
||||||
if (this.mlManager) {
|
this.mlManager?.setEventBus(eventBus, this._globalAbortController.signal);
|
||||||
this.mlManager.eventBus = eventBus;
|
|
||||||
}
|
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
|
||||||
this.overlayManager = new OverlayManager();
|
this.overlayManager = new OverlayManager();
|
||||||
|
|
|
@ -193,12 +193,12 @@ const defaultOptions = {
|
||||||
enableAltTextModelDownload: {
|
enableAltTextModelDownload: {
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
value: true,
|
value: true,
|
||||||
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH,
|
||||||
},
|
},
|
||||||
enableGuessAltText: {
|
enableGuessAltText: {
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
value: true,
|
value: true,
|
||||||
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH,
|
||||||
},
|
},
|
||||||
enableHighlightEditor: {
|
enableHighlightEditor: {
|
||||||
// We'll probably want to make some experiments before enabling this
|
// We'll probably want to make some experiments before enabling this
|
||||||
|
|
|
@ -307,11 +307,15 @@ class FirefoxScripting {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MLManager {
|
class MLManager {
|
||||||
|
#abortSignal = null;
|
||||||
|
|
||||||
#enabled = null;
|
#enabled = null;
|
||||||
|
|
||||||
|
#eventBus = null;
|
||||||
|
|
||||||
#ready = null;
|
#ready = null;
|
||||||
|
|
||||||
eventBus = null;
|
#requestResolvers = null;
|
||||||
|
|
||||||
hasProgress = false;
|
hasProgress = false;
|
||||||
|
|
||||||
|
@ -330,6 +334,32 @@ class MLManager {
|
||||||
this.enableGuessAltText = enableGuessAltText;
|
this.enableGuessAltText = enableGuessAltText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setEventBus(eventBus, abortSignal) {
|
||||||
|
this.#eventBus = eventBus;
|
||||||
|
this.#abortSignal = abortSignal;
|
||||||
|
eventBus._on(
|
||||||
|
"enablealttextmodeldownload",
|
||||||
|
({ value }) => {
|
||||||
|
if (this.enableAltTextModelDownload === value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
this.downloadModel("altText");
|
||||||
|
} else {
|
||||||
|
this.deleteModel("altText");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ signal: abortSignal }
|
||||||
|
);
|
||||||
|
eventBus._on(
|
||||||
|
"enableguessalttext",
|
||||||
|
({ value }) => {
|
||||||
|
this.toggleService("altText", value);
|
||||||
|
},
|
||||||
|
{ signal: abortSignal }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async isEnabledFor(name) {
|
async isEnabledFor(name) {
|
||||||
return this.enableGuessAltText && !!(await this.#enabled?.get(name));
|
return this.enableGuessAltText && !!(await this.#enabled?.get(name));
|
||||||
}
|
}
|
||||||
|
@ -339,16 +369,17 @@ class MLManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteModel(name) {
|
async deleteModel(name) {
|
||||||
if (name !== "altText") {
|
if (name !== "altText" || !this.enableAltTextModelDownload) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.enableAltTextModelDownload = false;
|
this.enableAltTextModelDownload = false;
|
||||||
this.#ready?.delete(name);
|
this.#ready?.delete(name);
|
||||||
this.#enabled?.delete(name);
|
this.#enabled?.delete(name);
|
||||||
await Promise.all([
|
await this.toggleService("altText", false);
|
||||||
this.toggleService("altText", false),
|
await FirefoxCom.requestAsync(
|
||||||
FirefoxCom.requestAsync("mlDelete", MLManager.#AI_ALT_TEXT_MODEL_NAME),
|
"mlDelete",
|
||||||
]);
|
MLManager.#AI_ALT_TEXT_MODEL_NAME
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadModel(name) {
|
async loadModel(name) {
|
||||||
|
@ -358,7 +389,7 @@ class MLManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadModel(name) {
|
async downloadModel(name) {
|
||||||
if (name !== "altText") {
|
if (name !== "altText" || this.enableAltTextModelDownload) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
this.enableAltTextModelDownload = true;
|
this.enableAltTextModelDownload = true;
|
||||||
|
@ -369,18 +400,52 @@ class MLManager {
|
||||||
if (data?.name !== "altText") {
|
if (data?.name !== "altText") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const resolvers = (this.#requestResolvers ||= new Set());
|
||||||
|
const resolver = Promise.withResolvers();
|
||||||
|
resolvers.add(resolver);
|
||||||
|
|
||||||
data.service = MLManager.#AI_ALT_TEXT_MODEL_NAME;
|
data.service = MLManager.#AI_ALT_TEXT_MODEL_NAME;
|
||||||
return FirefoxCom.requestAsync("mlGuess", data);
|
|
||||||
|
FirefoxCom.requestAsync("mlGuess", data)
|
||||||
|
.then(response => {
|
||||||
|
if (resolvers.has(resolver)) {
|
||||||
|
resolver.resolve(response);
|
||||||
|
resolvers.delete(resolver);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(reason => {
|
||||||
|
if (resolvers.has(resolver)) {
|
||||||
|
resolver.reject(reason);
|
||||||
|
resolvers.delete(resolver);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return resolver.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #cancelAllRequests() {
|
||||||
|
if (!this.#requestResolvers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const resolver of this.#requestResolvers) {
|
||||||
|
resolver.resolve({ cancel: true });
|
||||||
|
}
|
||||||
|
this.#requestResolvers.clear();
|
||||||
|
this.#requestResolvers = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleService(name, enabled) {
|
async toggleService(name, enabled) {
|
||||||
if (name !== "altText") {
|
if (name !== "altText" || this.enableGuessAltText === enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.enableGuessAltText = enabled;
|
this.enableGuessAltText = enabled;
|
||||||
if (enabled && this.enableAltTextModelDownload) {
|
if (enabled) {
|
||||||
await this.#loadAltTextEngine(false);
|
if (this.enableAltTextModelDownload) {
|
||||||
|
await this.#loadAltTextEngine(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.#cancelAllRequests();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +468,7 @@ class MLManager {
|
||||||
if (listenToProgress) {
|
if (listenToProgress) {
|
||||||
this.hasProgress = true;
|
this.hasProgress = true;
|
||||||
const callback = ({ detail }) => {
|
const callback = ({ detail }) => {
|
||||||
this.eventBus.dispatch("loadaiengineprogress", {
|
this.#eventBus.dispatch("loadaiengineprogress", {
|
||||||
source: this,
|
source: this,
|
||||||
detail,
|
detail,
|
||||||
});
|
});
|
||||||
|
@ -412,7 +477,9 @@ class MLManager {
|
||||||
window.removeEventListener("loadAIEngineProgress", callback);
|
window.removeEventListener("loadAIEngineProgress", callback);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener("loadAIEngineProgress", callback);
|
window.addEventListener("loadAIEngineProgress", callback, {
|
||||||
|
signal: this.#abortSignal,
|
||||||
|
});
|
||||||
promise.then(ok => {
|
promise.then(ok => {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
this.hasProgress = false;
|
this.hasProgress = false;
|
||||||
|
|
|
@ -79,6 +79,10 @@ class FakeMLManager {
|
||||||
this.enableAltTextModelDownload = enableAltTextModelDownload;
|
this.enableAltTextModelDownload = enableAltTextModelDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setEventBus(eventBus, abortSignal) {
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
}
|
||||||
|
|
||||||
async isEnabledFor(_name) {
|
async isEnabledFor(_name) {
|
||||||
return this.enableGuessAltText;
|
return this.enableGuessAltText;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,10 @@ class NewAltTextManager {
|
||||||
this.#toggleDisclaimer();
|
this.#toggleDisclaimer();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
eventBus._on("enableguessalttext", ({ value }) => {
|
||||||
|
this.#toggleGuessAltText(value, /* isInitial = */ false);
|
||||||
|
});
|
||||||
|
|
||||||
this.#overlayManager.register(dialog);
|
this.#overlayManager.register(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,13 +251,12 @@ class NewAltTextManager {
|
||||||
this.#imageData,
|
this.#imageData,
|
||||||
/* updateAltTextData = */ false
|
/* updateAltTextData = */ false
|
||||||
);
|
);
|
||||||
if (altText === null) {
|
if (altText) {
|
||||||
throw new Error("No valid response from the AI service.");
|
this.#guessedAltText = altText;
|
||||||
}
|
this.#wasAILoading = this.#isAILoading;
|
||||||
this.#guessedAltText = altText;
|
if (this.#isAILoading) {
|
||||||
this.#wasAILoading = this.#isAILoading;
|
this.#addAltText(altText);
|
||||||
if (this.#isAILoading) {
|
}
|
||||||
this.#addAltText(altText);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -458,6 +461,8 @@ class ImageAltTextSettings {
|
||||||
|
|
||||||
#createModelButton;
|
#createModelButton;
|
||||||
|
|
||||||
|
#downloadModelButton;
|
||||||
|
|
||||||
#dialog;
|
#dialog;
|
||||||
|
|
||||||
#eventBus;
|
#eventBus;
|
||||||
|
@ -486,6 +491,7 @@ class ImageAltTextSettings {
|
||||||
this.#dialog = dialog;
|
this.#dialog = dialog;
|
||||||
this.#aiModelSettings = aiModelSettings;
|
this.#aiModelSettings = aiModelSettings;
|
||||||
this.#createModelButton = createModelButton;
|
this.#createModelButton = createModelButton;
|
||||||
|
this.#downloadModelButton = downloadModelButton;
|
||||||
this.#showAltTextDialogButton = showAltTextDialogButton;
|
this.#showAltTextDialogButton = showAltTextDialogButton;
|
||||||
this.#overlayManager = overlayManager;
|
this.#overlayManager = overlayManager;
|
||||||
this.#eventBus = eventBus;
|
this.#eventBus = eventBus;
|
||||||
|
@ -508,40 +514,62 @@ class ImageAltTextSettings {
|
||||||
this.#togglePref.bind(this, "enableNewAltTextWhenAddingImage")
|
this.#togglePref.bind(this, "enableNewAltTextWhenAddingImage")
|
||||||
);
|
);
|
||||||
|
|
||||||
deleteModelButton.addEventListener("click", async () => {
|
deleteModelButton.addEventListener("click", this.#delete.bind(this, true));
|
||||||
await mlManager.deleteModel("altText");
|
downloadModelButton.addEventListener(
|
||||||
|
"click",
|
||||||
|
this.#download.bind(this, true)
|
||||||
|
);
|
||||||
|
|
||||||
aiModelSettings.classList.toggle("download", true);
|
closeButton.addEventListener("click", this.#finish.bind(this));
|
||||||
createModelButton.disabled = true;
|
|
||||||
createModelButton.setAttribute("aria-pressed", false);
|
eventBus._on("enablealttextmodeldownload", ({ value }) => {
|
||||||
this.#setPref("enableGuessAltText", false);
|
if (value) {
|
||||||
this.#setPref("enableAltTextModelDownload", false);
|
this.#download(false);
|
||||||
|
} else {
|
||||||
|
this.#delete(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
downloadModelButton.addEventListener("click", async () => {
|
this.#overlayManager.register(dialog);
|
||||||
downloadModelButton.disabled = true;
|
}
|
||||||
downloadModelButton.firstChild.setAttribute(
|
|
||||||
|
async #download(isFromUI = false) {
|
||||||
|
if (isFromUI) {
|
||||||
|
this.#downloadModelButton.disabled = true;
|
||||||
|
const span = this.#downloadModelButton.firstChild;
|
||||||
|
span.setAttribute(
|
||||||
"data-l10n-id",
|
"data-l10n-id",
|
||||||
"pdfjs-editor-alt-text-settings-downloading-model-button"
|
"pdfjs-editor-alt-text-settings-downloading-model-button"
|
||||||
);
|
);
|
||||||
|
|
||||||
await mlManager.downloadModel("altText");
|
await this.#mlManager.downloadModel("altText");
|
||||||
|
|
||||||
aiModelSettings.classList.toggle("download", false);
|
span.setAttribute(
|
||||||
downloadModelButton.firstChild.setAttribute(
|
|
||||||
"data-l10n-id",
|
"data-l10n-id",
|
||||||
"pdfjs-editor-alt-text-settings-download-model-button"
|
"pdfjs-editor-alt-text-settings-download-model-button"
|
||||||
);
|
);
|
||||||
createModelButton.disabled = false;
|
|
||||||
createModelButton.setAttribute("aria-pressed", true);
|
|
||||||
this.#setPref("enableGuessAltText", true);
|
|
||||||
mlManager.toggleService("altText", true);
|
|
||||||
this.#setPref("enableAltTextModelDownload", true);
|
|
||||||
downloadModelButton.disabled = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
closeButton.addEventListener("click", this.#finish.bind(this));
|
this.#createModelButton.disabled = false;
|
||||||
this.#overlayManager.register(dialog);
|
this.#setPref("enableGuessAltText", true);
|
||||||
|
this.#mlManager.toggleService("altText", true);
|
||||||
|
this.#setPref("enableAltTextModelDownload", true);
|
||||||
|
this.#downloadModelButton.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#aiModelSettings.classList.toggle("download", false);
|
||||||
|
this.#createModelButton.setAttribute("aria-pressed", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #delete(isFromUI = false) {
|
||||||
|
if (isFromUI) {
|
||||||
|
await this.#mlManager.deleteModel("altText");
|
||||||
|
this.#setPref("enableGuessAltText", false);
|
||||||
|
this.#setPref("enableAltTextModelDownload", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#aiModelSettings.classList.toggle("download", true);
|
||||||
|
this.#createModelButton.disabled = true;
|
||||||
|
this.#createModelButton.setAttribute("aria-pressed", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async open({ enableGuessAltText, enableNewAltTextWhenAddingImage }) {
|
async open({ enableGuessAltText, enableNewAltTextWhenAddingImage }) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue