Erweiterungsmöglichkeiten für Annotationen

Mit der Browser Annotation API kann Ihre Website anpassen, was Personen auswählen, welcher Kontext ihrem Feedback beigefügt wird und welche Steuerelemente sie zur Vorschau von Änderungen verwenden, bevor sie eine Annotation an ChatGPT senden.

Browserannotationen funktionieren auf Ihrer Website ohne Codeänderungen. Personen können einen Teil einer Seite auswählen, einen Kommentar hinzufügen und ihn als Kontext an Codex oder ChatGPT Work senden.

Als Entwickler können Sie mit der Browser Annotation API Kontext oder Steuerelemente bereitstellen, die auf Ihre Anwendung zugeschnitten sind. Sie können beispielsweise in einer Designsystem-Vorschau Vorschauen für Komponentenvarianten hinzufügen, damit Entwickler wissen, wie sie die Komponenten auf einer Website aktualisieren können.

Wenn Sie Hilfe beim Verständnis der Browser Annotation API oder beim Hinzufügen der Annotationsunterstützung zu Ihrer Website benötigen, installieren Sie das Plugin Annotations Extensibility.

Das Plugin Annotations Extensibility installieren

Ausprobieren

Erleben Sie die Browser Annotation API in dieser Anleitung in Aktion.

  1. Öffnen Sie diese Seite im integrierten Browser von ChatGPT.
  2. Öffnen Sie testweise den vorgeschlagenen Prompt, der in dieser Karte erscheint.
  3. Wechseln Sie in den Annotationsmodus und wählen Sie dann die folgende Tabelle oder ein Codebeispiel aus, um zwischen vordefinierten Layouts und Designs zu wechseln.
  4. Sie können weiterhin jedes Element auf der Seite annotieren und das standardmäßige Annotationsverhalten ausprobieren.

Öffnen Sie diese Seite im integrierten Browser von ChatGPT, um Anmerkungen auszuprobieren.

Im Browser von ChatGPT öffnen

Wählen Sie aus, was Sie anpassen möchten

Beginnen Sie mit der Integration, die zu Ihrer Website passt:

Ziel Integration
Eine Karte oder eine andere Elementgruppe als einzelnes Objekt auswählbar machen Auswahlziele
Personen die Auswahl einer Wortgruppe oder eines Satzes ermöglichen Textauswahlcontainer
Einer Auswahl zusätzlichen Kontext beifügen Auswahlmetadaten
Eine Annotation über eine eigene Schaltfläche mit einem vorgeschlagenen Kommentar öffnen Annotationsanfragen
Über die eigene Benutzeroberfläche Feedback zu einer bestimmten Textpassage anfordern Textbereichsanfragen
Beim Öffnen einer Annotation erweiterte Steuerelemente anzeigen Editor-Standardeinstellungen
Anwendungseigenschaften als Vorschau anzeigen oder Auswahlentscheidungen erfassen Benutzerdefinierte Steuerelemente
Einzelne Objekte auswählen, die in einem Canvas gezeichnet sind Annotationsflächen
Den Annotationsmodus über Ihre Website ein- oder ausschalten Steuerung des Annotationsmodus

Diese Anleitung bezieht sich auf die zur DevDay 2026 veröffentlichte Version der ChatGPT-Desktop-App und spätere Versionen. Die JavaScript-API ist über document.oai.annotation im integrierten Browser der App auf sicheren Seiten der obersten Ebene verfügbar, etwa über HTTPS oder localhost. Wenn sie aktiviert ist, installiert der Browser sie, bevor die Skripte Ihrer Seite ausgeführt werden. Prüfen Sie die Verfügbarkeit jeder Methode, um ältere oder nicht unterstützte Browser zu berücksichtigen, und initialisieren Sie Ihre Integration, sobald deren DOM-Elemente vorhanden sind. Weder ein Bereitschaftsereignis noch Polling ist erforderlich.

API-Methoden kehren synchron zurück, und Registrierungs-Handles können sofort verwendet werden. Der Browser kann den Annotationseditor anschließend fertig laden. Der hitTest-Callback einer Fläche kann ein Promise zurückgeben.

Auswahlziele anpassen

Standardmäßig wählt der Annotationsmodus Elemente aus dem DOM der Seite aus und bevorzugt dabei Ziele wie Text, Bilder und Steuerelemente. Um ein größeres Objekt auswählbar zu machen, kennzeichnen Sie seinen umschließenden Bereich mit oai-annotation-container und seine auswählbaren Nachfahren mit oai-annotatable.

Dieses Beispiel macht eine Diagrammkarte als einzelnes Objekt auswählbar:

<section oai-annotation-container>
  <article id="chart-card" oai-annotatable="Q3 Revenue">
    <h2>Q3 Revenue</h2>
    <p>$120,000 this quarter</p>
    <button type="button">More info</button>
  </article>
</section>

Wenn Sie auf eine beliebige Stelle innerhalb der Karte zeigen, wird die gesamte Karte hervorgehoben. Der optionale Wert oai-annotatable gibt dem Objekt einen Namen, der dem Benutzer und dem Modell angezeigt wird. Wählen Sie Namen, die benachbarte Objekte voneinander unterscheiden, oder lassen Sie den Wert weg.

Der Container legt fest, wo diese Auswahlregeln gelten. Ein oai-annotatable-Attribut allein ändert das Auswahlverhalten nicht. Innerhalb eines Containers wählt der Browser das nächstgelegene markierte Ziel aus, das das Element unter dem Zeiger enthält. Bei verschachtelten Containern wird der nächstgelegene Container verwendet. Nicht markierte Bereiche innerhalb eines Containers erzeugen eine Webseitenannotation; Bereiche außerhalb aller Container behalten das Standardverhalten bei.

Textauswahl aktivieren

Fügen Sie einem Bereich oai-annotation-container-text hinzu, damit Personen im Annotationsmodus Text durch Ziehen auswählen können. Das Attribut benötigt keinen Wert:

<article oai-annotation-container-text>
  <h2>Design guidelines</h2>
  <p>Use consistent spacing between related components.</p>
  <p>Leave more space between separate groups.</p>
</article>

Beim Loslassen einer nicht leeren Auswahl wird der Textannotationseditor mit dem ausgewählten Bereich und dessen Kontext geöffnet. Ein Klick ohne Textauswahl erstellt keine Annotation. Escape oder eine abgebrochene Geste bricht die Auswahl ab.

Der nächstgelegene Text- oder DOM-Auswahlcontainer bestimmt, wie eine Geste beginnt. Textcontainer verwenden keine oai-annotatable-Markierungen zur Elementauswahl. Verschachteln Sie einen oai-annotation-container, um die Elementauswahl wiederherzustellen, oder einen Textcontainer, um die Textauswahl wiederherzustellen. Wenn beide Attribute auf einem Element vorhanden sind, hat die Textauswahl Vorrang.

Die Textauswahl folgt den normalen Auswahlregeln der Seite und kann über den Ausgangscontainer hinausreichen. Ein Container begrenzt den Bereich nicht und ermöglicht keine Auswahl innerhalb eines iframe. Textfelder bleiben auswählbar, normale Seitenklicks und native Aktionen auf Steuerelementen bleiben im Annotationsmodus jedoch blockiert. Explizite request()-Aufrufe behalten ihr bisheriges Verhalten bei.

Einer Auswahl Kontext hinzufügen

Fügen Sie einem markierten Ziel oai-annotation-metadata hinzu, um Kontext einzubeziehen, der möglicherweise nicht auf der Seite sichtbar ist. Beispielsweise kann eine fiktive Kontaktzeile eine E-Mail-Adresse für eine Anfrage zum Verfassen einer E-Mail enthalten:

<section oai-annotation-container>
  <div
    id="contact-row"
    oai-annotatable="Alex Morgan"
    oai-annotation-metadata='{"email":"alex@example.com"}'
  >
    <div>Alex Morgan</div>
    <div>Project lead</div>
  </div>
</section>

Wenn eine der beiden Zeilen ausgewählt wird, wird die gesamte Kontaktzeile ausgewählt. Die Metadaten erscheinen mit der Annotation und werden ihr in der Unterhaltung beigefügt. Fügen Sie nur Kontext hinzu, den Sie sowohl mit dem Benutzer als auch mit dem Modell teilen möchten. Zum Senden einer E-Mail wäre weiterhin ein verbundenes E-Mail-Tool erforderlich.

Verwenden Sie ein kleines, flaches JSON-Objekt mit diesen Grenzen:

  • Bis zu sechs Eigenschaften mit Zeichenfolgen, endlichen Zahlen, booleschen Werten oder null als Werten.
  • Schlüssel mit bis zu 64 Zeichen und Zeichenfolgenwerte mit bis zu 256 Zeichen.
  • Bis zu 2.048 Byte für das serialisierte Objekt.

Schlüssel müssen mit einem ASCII-Buchstaben beginnen und dürfen nur ASCII-Buchstaben, Ziffern, Leerzeichen, Unterstriche oder Bindestriche enthalten. Verwenden Sie einzelne Leerzeichen zwischen Wörtern. Verschachtelte Objekte und Arrays werden nicht unterstützt. Der Browser ignoriert ungültige Metadaten.

Sie können Metadaten auch über request() oder das hitTest-Ergebnis einer Fläche bereitstellen.

Eine Annotation über Ihre Website öffnen

Rufen Sie document.oai.annotation.request(target, options) direkt aus einer Benutzerinteraktion auf, beispielsweise dem Betätigen einer Schaltfläche. Das Ziel kann ein mit dem DOM verbundenes HTML-Element im sichtbaren Bereich des aktuellen Dokuments oder ein DOM-Range sein. Es benötigt keine Annotationsattribute. Virtuelle Objekt-IDs werden nicht unterstützt.

Von der Website initiierte Anfragen können die Zustimmung des Benutzers erfordern; Benutzer können blockierte Annotationsfunktionen unter Site tools > Annotation features wieder aktivieren.

Fügen Sie diese Schaltfläche neben der Diagrammkarte aus dem Auswahlbeispiel hinzu und führen Sie das Skript aus, nachdem beide Elemente vorhanden sind:

<button id="discuss-chart" type="button" hidden>Explain more</button>
const card = document.getElementById("chart-card");
const button = document.getElementById("discuss-chart");

button.hidden = typeof document.oai?.annotation?.request !== "function";

button.addEventListener("click", () => {
  const annotation = document.oai?.annotation;
  if (typeof annotation?.request !== "function") return;

  annotation.request(card, {
    initialComment: "Explain the latest trend in this graph.",
  });
});

Die Auswahl von Explain more fordert den Browser auf, eine Annotation mit ausgewählter Karte und einem bearbeitbaren Kommentar zu öffnen. Die Person kann ihn bearbeiten, speichern und mit ihrer Nachricht senden. Das Öffnen einer Annotation sendet keine Nachricht an ChatGPT; nur der Benutzer kann sie absenden.

Führen Sie den Aufruf innerhalb der aktiven Benutzerinteraktion aus. Wenn Sie zuerst auf eine Netzwerkanfrage warten, kann der Bezug zu dieser Interaktion verloren gehen.

Das optionale zweite Argument unterstützt diese Felder:

Option Verhalten
mode Verwenden Sie "advanced", um erweiterte Steuerelemente für ein Element zu öffnen, oder "default" für das standardmäßige Editorverhalten. Der Standardwert ist "default". Benutzerdefinierte Steuerelemente können auch mit "default" geöffnet werden; siehe Editor-Standardeinstellungen. Textbereiche unterstützen nur "default".
enterAnnotationMode Setzen Sie den Wert auf true, um in den Annotationsmodus zu wechseln und nach dem Abbrechen oder Senden der Annotation darin zu bleiben.
metadata Gültige, nicht leere Metadaten ersetzen für diese Anfrage die HTML-Metadaten des Ziels. Diese Option wird bei Textbereichen und dann ignoriert, wenn sich das Zielelement innerhalb eines Shadow DOM befindet.
initialComment Stellt einen bearbeitbaren Kommentar mit bis zu 240 UTF-16-Codeeinheiten bereit.

request() gibt ein Objekt mit einem booleschen Wert accepted zurück. Prüfen Sie result.accepted, nicht das Ergebnisobjekt, um festzustellen, ob der Browser die Anfrage empfangen und validiert hat. Dies bestätigt weder, dass der Editor geöffnet wurde, noch, dass die Person eine Annotation gespeichert oder gesendet hat.

Während der Editor geladen wird, kann der Browser eine akzeptierte Anfrage vorhalten. Er kann eine weitere ablehnen, während eine Anfrage aussteht, ein Editor geöffnet ist oder ChatGPT den Browser steuert.

Eine Annotation für einen Textbereich anfordern

Übergeben Sie einen DOM-Range, um Feedback zu einer Passage anzufordern, ohne die Textauswahl des Browsers zu ändern. Dieses Beispiel wählt den Inhalt des Absatzes aus; es benötigt kein oai-annotation-container-text-Attribut:

<p id="draft-passage">Leave more space between separate groups.</p>
<button id="discuss-passage" type="button" hidden>Discuss this passage</button>

Führen Sie dieses Skript aus, nachdem beide Elemente vorhanden sind:

const passage = document.getElementById("draft-passage");
const button = document.getElementById("discuss-passage");

button.hidden = typeof document.oai?.annotation?.request !== "function";

button.addEventListener("click", () => {
  const annotation = document.oai?.annotation;
  if (typeof annotation?.request !== "function") return;

  const range = document.createRange();
  range.selectNodeContents(passage);
  annotation.request(range, {
    initialComment: "Suggest a clearer version of this guidance.",
  });
});

Der Bereich muss nicht leeren, sichtbaren Text im aktuellen Dokument enthalten, wobei sich mindestens ein Teil der Auswahl im sichtbaren Seitenbereich befinden muss. Er darf höchstens 20.000 UTF-16-Codeeinheiten enthalten. Auf einen Punkt reduzierte Textbereiche, Text ausschließlich aus Leerraum, ausgeblendeter ausgewählter Text und Bereiche in geschlossenen Shadow Roots werden nicht unterstützt.

Textbereichsanfragen verwenden ausschließlich den Standardtexteditor. Eine Anfrage mit mode: "advanced" wird abgelehnt, und Anfragemetadaten werden ignoriert. Halten Sie den Zieltext verfügbar, während eine akzeptierte Anfrage auf den Editor wartet: Der Browser prüft den Bereich erneut, bevor er ihn öffnet. Textauswahlcontainer ermöglichen unabhängig davon, dass Personen im Annotationsmodus Text durch Ziehen auswählen.

Den Standardmodus des Editors auswählen

Um erweiterte Steuerelemente bei Annotationen, die über die Auswahloberfläche des Browsers geöffnet werden, sofort anzuzeigen, fügen Sie dieses Tag zum <head> Ihrer Seite hinzu:

<meta name="oai-annotation-editor-default-mode" content="advanced" />

Für Annotationen, die über Ihre eigene Benutzeroberfläche geöffnet werden, übergeben Sie { mode: "advanced" } an request(). Verwenden Sie mode: "default" oder lassen Sie es weg, um das standardmäßige Editorverhalten zu erhalten. Die Metaeinstellung der Seite überschreibt diese Anfrageoption nicht. Der Standardmodus garantiert keinen reinen Kommentareditor: Benutzerdefinierte Steuerelemente mit vorgeschlagenen Anfangswerten oder Steuerelemente, bei denen currentValue weggelassen wird, können den Steuerelementeditor öffnen.

Manuelle Bedienelemente für Adjust, Einklappen und Wahltaste-Klick sind nur in Codex oder auf localhost verfügbar. Auf gehosteten Websites in ChatGPT erscheinen registrierte benutzerdefinierte Steuerelemente automatisch ohne Schaltfläche zum Adjust oder Einklappen. Der von der Seite angeforderte erweiterte Modus funktioniert dort weiterhin.

Benutzerdefinierte Steuerelemente hinzufügen

Verwenden Sie registerControls(), um Annotationssteuerelemente einem oder mehreren DOM-Elementen zuzuordnen. Steuerelemente können Anwendungseigenschaften wie ein Abstandstoken als Vorschau anzeigen oder Auswahlentscheidungen erfassen, die einer Anfrage beigefügt werden, etwa den Tonfall einer E-Mail.

Eine Vorschau für ein gemeinsam verwendetes Abstandstoken anzeigen

Beide Karten in diesem Beispiel verwenden dieselbe CSS-Eigenschaft:

<style>
  #component-preview {
    --card-padding: 16px;
  }

  .preview-card {
    padding: var(--card-padding);
    border: 1px solid #d1d5db;
  }
</style>

<section id="component-preview" oai-annotation-container>
  <article class="preview-card" oai-annotatable="Profile card">
    Profile card
  </article>
  <article class="preview-card" oai-annotatable="Summary card">
    Summary card
  </article>
</section>

Führen Sie dieses Skript aus, nachdem Sie die Vorschau erstellt haben:

const preview = document.getElementById("component-preview");
const annotation = document.oai?.annotation;

function previewSpacing(event) {
  const { callback, value } = event.detail;
  if (callback === "setCardPadding") {
    preview.style.setProperty("--card-padding", `${value}px`);
  }
}

let registration;
if (typeof annotation?.registerControls === "function") {
  preview.addEventListener("oaiannotationcontrolchange", previewSpacing);
  registration = annotation.registerControls({
    targets: preview.querySelectorAll(".preview-card"),
    controlsHeading: "Card spacing",
    controlsMode: "replace",
    controls: [
      {
        type: "range",
        label: "Card padding (pixels)",
        callback: "setCardPadding",
        reference: "--card-padding",
        min: 8,
        max: 32,
        step: 4,
        currentValue: 16,
      },
    ],
  });
}

function disposeAnnotationControls() {
  preview.style.removeProperty("--card-padding");
  registration?.dispose();
  preview.removeEventListener("oaiannotationcontrolchange", previewSpacing);
}

Annotieren Sie eine der beiden Karten und ändern Sie Card padding (pixels) von 16 auf 24. Auf gehosteten Websites in ChatGPT erscheinen die Steuerelemente automatisch; in Codex oder auf localhost wählen Sie bei Bedarf Adjust. Beide Karten werden aktualisiert. Die Annotation erfasst die Beschriftung, die Referenz sowie die alten und neuen Werte. Beim Löschen der Vorschau wird der ursprüngliche Innenabstand wiederhergestellt. Rufen Sie disposeAnnotationControls() auf, wenn Sie die Komponente entfernen.

Eine Auswahl ohne Vorschau erfassen

Verwenden Sie die Kontaktzeile aus dem Metadatenbeispiel, um einen E-Mail-Tonfall zur Auswahl anzubieten:

const contact = document.getElementById("contact-row");
const registration = document.oai?.annotation?.registerControls?.({
  targets: contact,
  controlsHeading: "Email options",
  controlsMode: "replace",
  controls: [
    {
      type: "select",
      label: "Email tone",
      callback: "emailTone",
      options: [
        { label: "Professional", value: "professional" },
        { label: "Friendly", value: "friendly" },
        { label: "Direct", value: "direct" },
      ],
      defaultValue: "professional",
    },
  ],
});

Dieses Steuerelement benötigt keinen Ereignishandler, da es keine Vorschau einer Seitenänderung anzeigt. Wenn Sie currentValue weglassen, weisen Sie den Browser an, den ausgewählten Tonfall einzubeziehen, auch wenn der Benutzer die anfängliche Option beibehält. Rufen Sie registration?.dispose() auf, wenn Sie die Zeile entfernen.

Bei Auswahlsteuerelementen erhalten Vorschau-Callbacks option.value, beispielsweise "professional". Der Annotationsverlauf und ChatGPT erhalten die sichtbare option.label, beispielsweise "Professional", sowohl für die vorherige als auch für die ausgewählte Option. Verwenden Sie Beschriftungen, die jede Auswahlmöglichkeit erklären; interne IDs in value werden nicht als Text der Auswahl gesendet.

Steuerelemente und Anfangswerte konfigurieren

Verwenden Sie controlsMode: "replace", um für die registrierten Ziele nur Ihre Steuerelemente anzuzeigen, oder "extend", um sie zusammen mit integrierten Steuerelementen anzuzeigen. Eine optionale controlsHeading benennt den Bereich. Der Browser entfernt umgebenden Leerraum und akzeptiert ein bis 80 Zeichen. Ohne Überschrift zeigt der Bereich das HTML-Tag des Elements an. Die Überschrift wird nicht in den an ChatGPT gesendeten Kontext aufgenommen.

Eine Registrierung unterstützt bis zu 12 Steuerelemente. Jedes benötigt einen type, eine sichtbare label und eine callback-Kennung:

Typ Wert Zusätzliche Felder
color Hexadezimale Farbe, etwa "#2563eb" Keine
range Zahl min, max und step
select Zeichenfolge options, ein Array aus { label, value }-Objekten
toggle Boolescher Wert Keine

callback ist eine Zeichenfolgenkennung, keine JavaScript-Funktion. Gestalten Sie sie innerhalb der Registrierung eindeutig, beginnen Sie mit einem ASCII-Buchstaben und verwenden Sie ASCII-Buchstaben, Ziffern, Unterstriche oder Bindestriche. Eine optionale reference identifiziert die Eigenschaft, die geändert wird, und wird der Beschriftung und dem Wert in der Annotation beigefügt.

Setzen Sie currentValue auf den gültigen regulären Wert der Eigenschaft, einschließlich nicht gespeicherter Änderungen. Verwenden Sie weder den Vorschauzustand noch unvollständige Eingaben als Ausgangswert. Der Browser verwendet ihn für Vorher-nachher-Änderungen und zum Zurücksetzen. Wenn sich der Anwendungszustand ändert, verwenden Sie registration.update({ controls }), um die currentValue-Werte der Steuerelemente zu aktualisieren. Aktualisierungen wirken sich auf künftige Annotationen aus; bestehende Annotationen behalten ihre erfassten Werte.

Setzen Sie defaultValue für einen vorgeschlagenen Anfangswert; dieser hat Vorrang vor currentValue für den anfänglichen Zustand des Steuerelements. Wenn Sie beide weglassen, beginnt das Steuerelement bei einer Farbe mit Weiß, bei einem Wertebereich mit dem Minimum, bei einer Auswahlliste mit der ersten Option oder bei einem Umschalter mit false.

Halten Sie vorgeschlagene Werte von regulären Entwürfen getrennt. Wenn eine Aktualisierung eine Ausnahme auslöst oder eine Anfrage fehlschlägt oder accepted: false zurückgibt, verwerfen Sie den versuchten Vorschlag und stellen Sie den vorherigen Zustand der Steuerelemente und Vorschläge wieder her. Behalten Sie Vorschläge bei, wenn eine Anfrage akzeptiert wird: Der Browser kann sie in eine Warteschlange stellen, bevor er die Steuerelemente erfasst.

Steuerelemente und Registrierungen validieren

Der Browser validiert Registrierungen und Aktualisierungen anhand dieser Grenzen:

Feld oder Ressource Einschränkung
Steuerelemente Bis zu 12 pro Registrierung mit eindeutigen callback-Kennungen. Verwenden Sie nur die für den Steuerelementtyp definierten Felder.
Beschriftungen und Überschriften Steuerelementbeschriftungen, Optionsbeschriftungen und controlsHeading dürfen nach dem Entfernen umgebenden Leerraums nicht leer sein und höchstens 80 UTF-16-Codeeinheiten umfassen. Steuerelementtexte dürfen keine Steuerzeichen oder Zeichen enthalten, die die Schreibrichtung ändern.
Kennungen callback umfasst nach dem Entfernen umgebenden Leerraums höchstens 80 UTF-16-Codeeinheiten und verwendet das oben beschriebene Format. reference umfasst 1–80 Zeichen und erlaubt ASCII-Buchstaben, Ziffern und _ . / : @ $ # -, ohne Leerzeichen.
Auswahloptionen 1–12 Optionen mit unterschiedlichen value-Zeichenfolgen mit jeweils höchstens 512 UTF-16-Codeeinheiten. Angegebene Werte für currentValue und defaultValue müssen dem Wert einer Option entsprechen.
Wertebereichswerte min, max, currentValue und defaultValue müssen endliche Zahlen zwischen −10.000 und 10.000 sein. Erforderlich sind min < max, ein step-Wert von 0,001 bis 10.000, der nicht größer als max - min ist, sowie Anfangswerte innerhalb des Bereichs. Anfangswerte müssen nicht an step ausgerichtet sein.
Farben und Umschalter Farben müssen 3, 4, 6 oder 8 Hexadezimalziffern nach # verwenden. Werte für Umschalter müssen true oder false sein.
Ziele 1–128 Zieleinträge bei der Registrierung, allesamt Elemente im aktuellen Dokument. Aktualisierungen können targets: [] übergeben, um die Zuordnung aufzuheben. Jedes Dokument unterstützt bis zu 64 Steuerelementregistrierungen und 1.024 Zuordnungen zwischen Registrierungen und Zielen.
Serialisierte Steuerelemente Die JSON-Nutzlast mit controls, controlsHeading und controlsMode darf höchstens 16.384 UTF-16-Codeeinheiten umfassen. Verwenden Sie Daten, die als JSON codiert werden können, ohne Funktionen, Symbole oder große Ganzzahlen.

registerControls() und registration.update() können bei ungültigen Definitionen, Zielen oder überschrittenen Grenzen synchron Ausnahmen auslösen. Eine Aktualisierung nach dispose() löst ebenfalls eine Ausnahme aus. Eine abgelehnte Aktualisierung erhält die vorherige Registrierung einschließlich ihrer Steuerelemente und Ziele. Behandeln Sie Fehler an der Aufrufstelle, halten Sie die reguläre Bearbeitung nutzbar und verwenden Sie eigene Registrierungen erneut oder geben Sie sie frei, um innerhalb der Grenzen zu bleiben.

Vorschauen und Zurücksetzungen verarbeiten

Das oaiannotationcontrolchange-Ereignis wird vom ausgewählten Element aus im DOM nach oben weitergereicht. Sein detail enthält callback, value und action:

Aktion Den bereitgestellten Wert anwenden, um
preview die angeforderte Änderung anzuzeigen.
preview-original vorübergehend den ursprünglichen Zustand zum Vergleich anzuzeigen.
reset beim Löschen der Vorschau den ursprünglichen Zustand wiederherzustellen.

Wenden Sie den bereitgestellten Wert bei jeder Aktion an, wie im Abstandsbeispiel. Gestalten Sie Handler reversibel und so, dass sie gefahrlos wiederholt aufgerufen werden können. Vorschauereignisse fordern keine dauerhafte Änderung an; speichern Sie über den normalen Speicherablauf Ihrer Anwendung. Halten Sie reguläre Entwürfe, unvollständige Eingaben und Vorschauen getrennt, damit unabhängige Änderungen keine Vorschau überschreiben. Wenn jemand dieselbe Einstellung bearbeitet, ersetzen Sie deren Vorschau und aktualisieren Sie den Ausgangswert für künftige Annotationen.

Bewahren Sie das Registrierungs-Handle für Aktualisierungen und die Bereinigung auf. update() akzeptiert jede Kombination aus targets, controls, controlsHeading und controlsMode. Weggelassene Felder behalten ihre bisherigen Werte. Verwenden Sie beispielsweise registration.update({ targets: newElement }), wenn Sie das DOM-Element einer Komponente ersetzen. Zielsammlungen erfassen vorhandene Elemente und verfolgen keine künftigen Selektortreffer.

Übergeben Sie targets: [], um die Zuordnung der Registrierung aufzuheben, oder controls: [], um ihre Steuerelemente zu löschen. Rufen Sie dispose() auf und entfernen Sie Ereignis-Listener, wenn Sie die Integration entfernen. Die Bereinigung muss auch die reguläre Darstellung wiederherstellen: dispose() entfernt nur die Steuerelementregistrierung und macht Ihre Vorschauänderungen nicht rückgängig. Das Abstandsbeispiel entfernt seine Inline-Überschreibung, um den ursprünglichen CSS-Wert wiederherzustellen. Beide Methoden kehren synchron ohne Wert zurück. Aktualisierungen wirken sich auf künftige Auswahlen aus; gespeicherte Annotationen behalten ihre erfassten Steuerelemente und ihr Ziel.

Steuerelementereignisse richten sich an das von der Annotation erfasste Element. Das Aktualisieren der Ziele einer Registrierung leitet bestehende Annotationen nicht um. Zurücksetzungsereignisse können weiterhin auf einem entfernten Element ausgelöst werden; ein Listener auf dessen früherem übergeordnetem Element empfängt sie daher nicht.

Canvas-Objekte auswählbar machen

Eine Annotationsfläche ermöglicht Ihrer Anwendung, einzelne Objekte zu identifizieren, die innerhalb eines Canvas gezeichnet sind. Registrieren Sie das Hostelement mit registerSurface() und stellen Sie eine hitTest-Funktion bereit, die ein Objekt mit einer stabilen id oder null für leere Bereiche zurückgibt.

Das Hostelement muss ein mit dem DOM verbundenes HTML-Element außerhalb des Shadow DOM in einem sicheren Dokument der obersten Ebene sein. Die Flächenregistrierung wird innerhalb eines iframe nicht unterstützt.

Dieses Beispiel zeichnet einen Umsatzbalken und macht ihn auswählbar. Platzieren Sie das Skript nach dem Canvas:

<canvas id="revenue-canvas" width="480" height="240">
  Revenue this quarter: $120,000.
</canvas>
const canvas = document.getElementById("revenue-canvas");
const context = canvas.getContext("2d");
const bar = { x: 40, y: 60, width: 320, height: 100 };

function drawRevenue(highlighted = false) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.fillStyle = "#2563eb";
  context.fillRect(bar.x, bar.y, bar.width, bar.height);
  if (highlighted) {
    context.strokeStyle = "#111827";
    context.lineWidth = 3;
    context.strokeRect(bar.x, bar.y, bar.width, bar.height);
  }
}

drawRevenue();

const surface = document.oai?.annotation?.registerSurface?.({
  element: canvas,
  hitTest({ clientX, clientY }) {
    const bounds = canvas.getBoundingClientRect();
    const scaleX = bounds.width / canvas.width;
    const scaleY = bounds.height / canvas.height;
    const rect = {
      x: bounds.left + bar.x * scaleX,
      y: bounds.top + bar.y * scaleY,
      width: bar.width * scaleX,
      height: bar.height * scaleY,
    };

    if (
      clientX < rect.x ||
      clientX > rect.x + rect.width ||
      clientY < rect.y ||
      clientY > rect.y + rect.height
    ) {
      return null;
    }

    return {
      id: "revenue-this-quarter",
      name: "Revenue this quarter",
      role: "chart-bar",
      metadata: { Metric: "Revenue", Value: 120000 },
      rect,
    };
  },
  renderSelection({ hoveredId, selectedId }) {
    drawRevenue(
      hoveredId === "revenue-this-quarter" ||
        selectedId === "revenue-this-quarter"
    );
  },
});

Wenn Sie im Annotationsmodus den Zeiger über den Balken bewegen, wird er hervorgehoben. Durch seine Auswahl wird eine Annotation mit dem Namen des Objekts, Metadaten und einem Screenshot der Auswahl geöffnet.

Halten Sie IDs innerhalb einer Fläche stabil. Der optionale name-Wert ist für den Benutzer sichtbar; role liefert eine kurze semantische Beschreibung. Die optionale Angabe rect verwendet CSS-Pixel relativ zum sichtbaren Seitenbereich, passend zu clientX und clientY. Rechnen Sie Szenenkoordinaten um und berücksichtigen Sie dabei Skalierung, Verschiebung und Zoom.

hitTest kann ein Promise zurückgeben und erhält ein AbortSignal als signal, um überholte Arbeit abzubrechen. Der Browser wartet 250 Millisekunden, bevor er auf die DOM-Auswahl zurückfällt. Auch bei Fehlern und ungültigen Ergebnissen fällt er darauf zurück. Geben Sie null explizit zurück, wenn die Trefferprüfung erfolgreich war, aber kein Objekt gefunden wurde.

Abgebrochene Arbeit muss ihr Promise trotzdem erfüllen oder ablehnen. Der Browser erlaubt nur einen gleichzeitig laufenden hitTest-Callback und hält diesen Platz belegt, bis das Promise abgeschlossen ist, auch nach einem Abbruch oder einer Zeitüberschreitung. Wenn ein Worker die Auswahl verarbeitet, schließen Sie das ausstehende Promise ab, wenn seine Arbeit abgebrochen wird; das Verwerfen einer abgebrochenen Worker-Antwort kann spätere Canvas-Auswahlen blockieren.

Verwenden Sie den optionalen renderSelection-Callback für anwendungsspezifische Rückmeldungen. Löschen Sie die Rückmeldung, wenn beide IDs null sind. Rufen Sie surface?.invalidate() nach dem Verschieben von Objekten oder dem Ändern des Zooms und surface?.dispose() beim Entfernen der Integration auf. Beide kehren synchron ohne Wert zurück.

Canvas-Objekten Steuerelemente hinzufügen

Registrieren Sie benutzerdefinierte Steuerelemente auf dem DOM-Element der Fläche. Gezeichnete Objekte, in der API als virtuelle Objekte bezeichnet, verwenden Ihre benutzerdefinierten Steuerelemente; integrierte CSS- und Textsteuerelemente gelten für sie nicht.

Verwenden Sie bei mehreren Objekten renderSelection, um die Steuerelemente des Hosts zu aktualisieren, wenn sich selectedId ändert, bevor der Browser die Annotation erfasst. Steuerelementereignisse enthalten detail.virtualTarget: { surfaceId, targetId }. Leiten Sie jedes Ereignis anhand dieser erfassten Identität und ihres callback weiter, nicht anhand der aktuellen Auswahl. targetId entspricht der id aus hitTest; surfaceId identifiziert die Flächenregistrierung des Browsers. Reguläre DOM-Ereignisse enthalten kein virtualTarget.

Vorschau-, Vergleichs- und Zurücksetzungsereignisse behalten die Identität des ursprünglichen Objekts bei, nachdem ein anderes Objekt ausgewählt wurde. Beim erneuten Öffnen einer gespeicherten Annotation wird keine erneute Trefferprüfung durchgeführt, um ihr erfasstes Objekt oder ihre Metadaten zu ersetzen.

Den Annotationsmodus steuern

Verwenden Sie toggle(), um einen Moduswechsel anzufordern, isActive(), um den bestätigten Zustand zu lesen, und das oaiannotationmodechange-Ereignis des Dokuments, um Ihre Benutzeroberfläche synchron zu halten. Prüfen Sie für ältere oder nicht unterstützte Browser die Verfügbarkeit beider Methoden. Fügen Sie diese Schaltfläche hinzu und führen Sie das Skript aus, nachdem sie vorhanden ist:

<button id="toggle-annotations" type="button" hidden>
  Enter annotation mode
</button>
const button = document.getElementById("toggle-annotations");
const annotation = document.oai?.annotation;

function renderMode(active) {
  button.textContent = active
    ? "Exit annotation mode"
    : "Enter annotation mode";
}

const onModeChange = (event) => renderMode(event.detail.active);
const onClick = () => annotation.toggle(!annotation.isActive());

if (
  typeof annotation?.toggle === "function" &&
  typeof annotation?.isActive === "function"
) {
  document.addEventListener("oaiannotationmodechange", onModeChange);
  button.addEventListener("click", onClick);
  renderMode(annotation.isActive());
  button.hidden = false;
}

function cleanupAnnotationButton() {
  document.removeEventListener("oaiannotationmodechange", onModeChange);
  button.removeEventListener("click", onClick);
  button.hidden = true;
}

toggle() kehrt den Modus um. Übergeben Sie true, um sicherzustellen, dass er aktiviert ist, oder false, um sicherzustellen, dass er deaktiviert ist. Wiederholte Anfragen mit demselben booleschen Wert sind idempotent. Die Übergabe von true erhält einen aktiven Editor oder eine ausstehende Aktivierung; false bricht eine ausstehende Aktivierung ab und verwendet den normalen Beendigungsablauf.

Rufen Sie toggle() aus einer laufenden Benutzerinteraktion auf. Sein synchrones { accepted }-Ergebnis bestätigt die Anfrage, nicht einen tatsächlich erfolgten Moduswechsel. Die Prüfungen der Voraussetzungen durch den Browser können die Änderung weiterhin verhindern. Lesen Sie den Zustand aus isActive() und dem Ereignis, wie im Beispiel gezeigt.

isActive() benötigt keine Benutzergeste. Der Browser aktualisiert den Wert, bevor er oaiannotationmodechange auslöst, dessen event.detail.active ein boolescher Wert ist. Der Browser sendet weder ein anfängliches Ereignis noch ein Duplikat, wenn das Erzwingen eines Zustands keine Änderung bewirkt. Initialisieren Sie Ihre Benutzeroberfläche daher über den Getter. Wird der Zugriff bei aktivem Modus widerrufen, meldet ein abschließendes Ereignis active: false, und ein beibehaltener Getter gibt false zurück.

Der Annotationsmodus fängt Seitenklicks ab. Halten Sie die Leertaste gedrückt, um Seitensteuerelemente zu verwenden, einschließlich Ihrer Schaltfläche zum Beenden, oder beenden Sie den Modus über die Annotationsoberfläche des Browsers. Das bloße Gedrückthalten der Leertaste lässt isActive() auf true. Die API unterstützt kein oai-annotation-ignore oder anderes Attribut, das Klicks durchlässt.

Beim Beenden wird der Editor geschlossen, und gespeicherte Annotationen bleiben erhalten, ohne abgesendet oder in das Eingabefeld verschoben zu werden. Rufen Sie cleanupAnnotationButton() auf, wenn Sie die Komponente entfernen. Die erfasste API-Referenz ermöglicht es der Bereinigung, Listener zu entfernen, auch wenn der Namensraum nicht mehr vorhanden ist.

Ihre Integration testen

Öffnen Sie Ihre Website im integrierten Browser der Desktop-App und testen Sie die Funktionen, die Sie hinzugefügt haben:

  1. Wechseln Sie in den Annotationsmodus und wählen Sie Objekte und Text aus. Prüfen Sie, ob Hervorhebungen, Namen, Bereiche und Metadaten den vorgesehenen Zielen entsprechen.
  2. Öffnen Sie eine Annotation über die Schaltfläche Ihrer Website. Prüfen Sie das ausgewählte Element oder den Textbereich, den anfänglichen Kommentar und den Editormodus.
  3. Ändern Sie ein benutzerdefiniertes Steuerelement, vergleichen Sie mit dem Original und löschen Sie die Vorschau. Prüfen Sie, ob Ihre Anwendung den ursprünglichen Zustand wiederherstellt.
  4. Testen Sie bei Canvas-Inhalten leere Bereiche, Größenänderungen und Szenenänderungen. Wechseln Sie zwischen Objekten und bestätigen Sie, dass Steuerelementereignisse weiterhin das erfasste Ziel aktualisieren. Brechen Sie eine asynchrone Trefferprüfung ab und bestätigen Sie, dass spätere Auswahlen weiterhin funktionieren.
  5. Speichern, öffnen und bearbeiten Sie eine Annotation über die Anhangsvorschau des Eingabefelds. Prüfen Sie, ob sie ihre Steuerelemente und ihr Ziel beibehält und ob durch ihr Entfernen jede Vorschau gelöscht wird.
  6. Senden Sie eine Annotation mit einer Nachricht. Bestätigen Sie, dass ChatGPT den ausgewählten Inhalt, die Metadaten und die angeforderten Werte erhält, einschließlich sichtbarer Auswahlbeschriftungen und unveränderter Auswahlentscheidungen bei Steuerelementen, die currentValue weglassen.
  7. Öffnen Sie die Website in einem Browser ohne die API und überprüfen Sie, ob normale Interaktionen weiterhin funktionieren.

Um Aktionen bereitzustellen, die ChatGPT auf Ihrer Website ausführen kann, fügen Sie Website-Tools (WebMCP) hinzu. Annotationen bringen die Auswahl und das Feedback der Person in die Unterhaltung; Website-Tools ermöglichen es dem Agenten, auf Grundlage dieses Kontexts über die vorhandenen Funktionen Ihrer Anwendung zu handeln.