From 5934eefa44c91a6e6532c10b14d05df6dafdcf71 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Fri, 9 Aug 2024 19:16:07 +0200 Subject: [PATCH] [Editor] Add the telemetry for the new alt text (bug 1912500) --- src/display/editor/alt_text.js | 14 ++++ src/display/editor/stamp.js | 25 ++++++++ web/annotation_editor_params.js | 9 +++ web/new_alt_text_manager.js | 109 +++++++++++++++++++++++++------- web/pdf_viewer.js | 8 ++- web/toolbar.js | 14 +++- 6 files changed, 153 insertions(+), 26 deletions(-) diff --git a/src/display/editor/alt_text.js b/src/display/editor/alt_text.js index fc346b4d5b51c2..8466a2b8a7c6a2 100644 --- a/src/display/editor/alt_text.js +++ b/src/display/editor/alt_text.js @@ -75,6 +75,16 @@ class AltText { const onClick = event => { event.preventDefault(); this.#editor._uiManager.editAltText(this.#editor); + if (this.#useNewAltTextFlow) { + const label = + (this.#altText && "added") || + (this.#altText === null && this.guessedText && "review") || + "missing"; + this.#editor._reportTelemetry({ + action: "pdfjs.image.alt_text.image_status_label_clicked", + label, + }); + } }; altText.addEventListener("click", onClick, { capture: true, signal }); altText.addEventListener( @@ -222,6 +232,10 @@ class AltText { (this.#altText && "added") || (this.#altText === null && this.guessedText && "to-review") || "missing"; + this.#editor._reportTelemetry({ + action: "pdfjs.image.alt_text.image_status_label_displayed", + label: type === "to-review" ? "review" : type, + }); button.classList.toggle("done", !!this.#altText); AltText._l10nPromise .get(`pdfjs-editor-new-alt-text-${type}-button-label`) diff --git a/src/display/editor/stamp.js b/src/display/editor/stamp.js index fc15ea7270b791..c1609e372c433d 100644 --- a/src/display/editor/stamp.js +++ b/src/display/editor/stamp.js @@ -104,6 +104,22 @@ class StampEditor extends AnnotationEditor { super.altTextFinish(); } + /** @inheritdoc */ + get telemetryFinalData() { + return { + type: "stamp", + hasAltText: this.hasAltTextData(), + }; + } + + static computeTelemetryFinalData(data) { + const hasAltTextStats = data.get("hasAltText"); + return { + hasAltText: hasAltTextStats.get(true) ?? 0, + hasNoAltText: hasAltTextStats.get(false) ?? 0, + }; + } + #getBitmapFetched(data, fromId = false) { if (!data) { this.remove(); @@ -141,6 +157,12 @@ class StampEditor extends AnnotationEditor { this._uiManager.useNewAltTextFlow && this.#bitmap ) { + this._reportTelemetry({ + action: "pdfjs.image.image_added", + data: { + alt_text_modal: false, + }, + }); try { // The alt-text dialog isn't opened but we still want to guess the alt // text. @@ -247,6 +269,9 @@ class StampEditor extends AnnotationEditor { const data = await this._uiManager.imageManager.getFromFile( input.files[0] ); + this._reportTelemetry({ + action: "pdfjs.image.image_selected", + }); this.#getBitmapFetched(data); } if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) { diff --git a/web/annotation_editor_params.js b/web/annotation_editor_params.js index 22f453a1b9d709..110a24fb3175e6 100644 --- a/web/annotation_editor_params.js +++ b/web/annotation_editor_params.js @@ -75,6 +75,15 @@ class AnnotationEditorParams { dispatchEvent("INK_OPACITY", this.valueAsNumber); }); editorStampAddImage.addEventListener("click", () => { + this.eventBus.dispatch("reporttelemetry", { + source: this, + details: { + type: "editing", + data: { + action: "pdfjs.image.add_image_click", + }, + }, + }); dispatchEvent("CREATE"); }); editorFreeHighlightThickness.addEventListener("input", function () { diff --git a/web/new_alt_text_manager.js b/web/new_alt_text_manager.js index e13b47f0fb29ab..6f5cf4b7f77b44 100644 --- a/web/new_alt_text_manager.js +++ b/web/new_alt_text_manager.js @@ -64,8 +64,6 @@ class NewAltTextManager { #previousAltText = null; - #telemetryData = null; - constructor( { descriptionContainer, @@ -142,6 +140,15 @@ class NewAltTextManager { }); this.#overlayManager.register(dialog); + + this.#learnMore.addEventListener("click", () => { + this.#currentEditor._reportTelemetry({ + action: "pdfjs.image.alt_text.info", + data: { + topic: "alt_text", + }, + }); + }); } #toggleLoading(value) { @@ -401,6 +408,20 @@ class NewAltTextManager { this.#currentEditor.altTextData = { cancel: true, }; + const altText = this.#textarea.value.trim(); + this.#currentEditor._reportTelemetry({ + action: "pdfjs.image.alt_text.dismiss", + data: { + alt_text_type: altText ? "present" : "empty", + flow: this.#firstTime ? "image_add" : "alt_text_edit", + }, + }); + this.#currentEditor._reportTelemetry({ + action: "pdfjs.image.image_added", + data: { + alt_text_modal: false, + }, + }); this.#finish(); } @@ -416,13 +437,6 @@ class NewAltTextManager { canvas.width = canvas.height = 0; this.#imageData = null; - this.#currentEditor._reportTelemetry( - this.#telemetryData || { - action: "alt_text_cancel", - } - ); - - this.#telemetryData = null; this.#toggleLoading(false); this.#uiManager?.addEditListeners(); @@ -438,15 +452,35 @@ class NewAltTextManager { altText, decorative: false, }; - this.#telemetryData = { - action: "alt_text_save", - alt_text_description: !!altText, - alt_text_edit: - !!this.#previousAltText && this.#previousAltText !== altText, - alt_text_decorative: false, - alt_text_altered: - this.#guessedAltText && this.#guessedAltText !== altText, - }; + this.#currentEditor.altTextData.guessedAltText = this.#guessedAltText; + + if (this.#guessedAltText && this.#guessedAltText !== altText) { + const guessedWords = new Set(this.#guessedAltText.split(/\s+/)); + const words = new Set(altText.split(/\s+/)); + this.#currentEditor._reportTelemetry({ + action: "pdfjs.image.alt_text.user_edit", + data: { + total_words: guessedWords.size, + words_removed: guessedWords.difference(words).size, + words_added: words.difference(guessedWords).size, + }, + }); + } + this.#currentEditor._reportTelemetry({ + action: "pdfjs.image.image_added", + data: { + alt_text_modal: true, + }, + }); + + this.#currentEditor._reportTelemetry({ + action: "pdfjs.image.alt_text.save", + data: { + alt_text_type: altText ? "present" : "empty", + flow: this.#firstTime ? "image_add" : "alt_text_edit", + }, + }); + this.#finish(); } @@ -507,12 +541,21 @@ class ImageAltTextSettings { createModelButton.addEventListener("click", async e => { const checked = this.#togglePref("enableGuessAltText", e); await mlManager.toggleService("altText", checked); + this.#reportTelemetry({ + type: "stamp", + action: "pdfjs.image.alt_text.settings_ai_generation_check", + data: { status: checked }, + }); }); - showAltTextDialogButton.addEventListener( - "click", - this.#togglePref.bind(this, "enableNewAltTextWhenAddingImage") - ); + showAltTextDialogButton.addEventListener("click", e => { + const checked = this.#togglePref("enableNewAltTextWhenAddingImage", e); + this.#reportTelemetry({ + type: "stamp", + action: "pdfjs.image.alt_text.settings_edit_alt_text_check", + data: { status: checked }, + }); + }); deleteModelButton.addEventListener("click", this.#delete.bind(this, true)); downloadModelButton.addEventListener( @@ -522,6 +565,14 @@ class ImageAltTextSettings { closeButton.addEventListener("click", this.#finish.bind(this)); + learnMore.addEventListener("click", () => { + this.#reportTelemetry({ + type: "stamp", + action: "pdfjs.image.alt_text.info", + data: { topic: "ai_generation" }, + }); + }); + eventBus._on("enablealttextmodeldownload", ({ value }) => { if (value) { this.#download(false); @@ -533,6 +584,16 @@ class ImageAltTextSettings { this.#overlayManager.register(dialog); } + #reportTelemetry(data) { + this.#eventBus.dispatch("reporttelemetry", { + source: this, + details: { + type: "editing", + data, + }, + }); + } + async #download(isFromUI = false) { if (isFromUI) { this.#downloadModelButton.disabled = true; @@ -589,6 +650,10 @@ class ImageAltTextSettings { ); await this.#overlayManager.open(this.#dialog); + this.#reportTelemetry({ + type: "stamp", + action: "pdfjs.image.alt_text.settings_displayed", + }); } #togglePref(name, { target }) { diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index c53678ba365d32..2d1d7c7e4714be 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -2316,11 +2316,13 @@ class PDFViewer { if (!this.pdfDocument) { return; } - if (mode === AnnotationEditorType.STAMP) { - this.#mlManager?.loadModel("altText"); - } const { eventBus } = this; + + if (mode === AnnotationEditorType.STAMP && this.#mlManager) { + this.#mlManager.loadModel("altText"); + } + const updater = () => { this.#cleanupSwitchAnnotationEditorMode(); this.#annotationEditorMode = mode; diff --git a/web/toolbar.js b/web/toolbar.js index b17e0d6cfe7e0d..eebd245d668d6a 100644 --- a/web/toolbar.js +++ b/web/toolbar.js @@ -112,6 +112,17 @@ class Toolbar { : AnnotationEditorType.STAMP; }, }, + telemetry: () => { + eventBus.dispatch("reporttelemetry", { + source: this, + details: { + type: "editing", + data: { + action: "pdfjs.image.icon_click", + }, + }, + }); + }, }, ]; @@ -173,7 +184,7 @@ class Toolbar { const self = this; // The buttons within the toolbar. - for (const { element, eventName, eventDetails } of buttons) { + for (const { element, eventName, eventDetails, telemetry } of buttons) { element.addEventListener("click", evt => { if (eventName !== null) { eventBus.dispatch(eventName, { @@ -183,6 +194,7 @@ class Toolbar { isFromKeyboard: evt.detail === 0, }); } + telemetry?.(); }); } // The non-button elements within the toolbar.