From 305f483b23981e72a68cb32f6cab772dfab6a548 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 27 Nov 2024 15:18:12 +0900 Subject: [PATCH 1/2] Specify summarization, destruction, and options This is most of the remaining normative text for the summarizer API. --- index.bs | 409 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 398 insertions(+), 11 deletions(-) diff --git a/index.bs b/index.bs index f57a590..bbe1fce 100644 --- a/index.bs +++ b/index.bs @@ -36,6 +36,8 @@ dl.props { display: grid; grid-template-columns: max-content auto; row-gap: 0.25 dl.props > dt { grid-column-start: 1; margin: 0; } dl.props > dd { grid-column-start: 2; margin: 0; } p + dl.props { margin-top: -0.5em; } + +.enum-table tbody th { white-space: nowrap; }

Introduction

@@ -145,7 +147,7 @@ dictionary AISummarizerSummarizeOptions { DOMString context; }; -enum AISummarizerType { "tl;dr", "key-points", "teaser", "headline" }; +enum AISummarizerType { "tl;dr", "teaser", "key-points", "headline" }; enum AISummarizerFormat { "plain-text", "markdown" }; enum AISummarizerLength { "short", "medium", "long" }; @@ -228,7 +230,7 @@ The summarizer getter steps are to return [=this=] :: 1. Initiate the download process for everything the user agent needs to summarize text according to |options|["{{AISummarizerCreateCoreOptions/type}}"], |options|["{{AISummarizerCreateCoreOptions/format}}"], or |options|["{{AISummarizerCreateCoreOptions/length}}"]. - 1. Run the following steps, by [=abort when=] |abortedDuringDownload| becomes true: + 1. Run the following steps, but [=abort when=] |abortedDuringDownload| becomes true: 1. Wait for the total number of bytes to be downloaded to become determined, and let that number be |totalBytes|. @@ -314,7 +316,7 @@ The summarizer getter steps are to return [=this=]
: [=AISummarizer/shared context=] - :: |options|["{{AISummarizerCreateOptions/sharedContext}}"] + :: |options|["{{AISummarizerCreateOptions/sharedContext}}"] if it [=map/exists=]; otherwise null : [=AISummarizer/summary type=] :: |options|["{{AISummarizerCreateCoreOptions/type}}"] @@ -380,9 +382,9 @@ The summarizer getter steps are to return [=this=] Every {{AISummarizerCapabilities}} has an available create options, a [=map=] from [=tuples=] of ({{AISummarizerType}}, {{AISummarizerFormat}}, {{AISummarizerLength}}) values to {{AICapabilityAvailability}} values, set during creation. -Every {{AISummarizerCapabilities}} has an readily available languages, [=set=] of strings representing BCP 47 language tags, set during creation. +Every {{AISummarizerCapabilities}} has an readily available languages, a [=set=] of strings representing BCP 47 language tags, set during creation. -Every {{AISummarizerCapabilities}} has an after-download available languages, [=set=] of strings representing BCP 47 language tags, set during creation. +Every {{AISummarizerCapabilities}} has an after-download available languages, a [=set=] of strings representing BCP 47 language tags, set during creation.
The available getter steps are: @@ -441,7 +443,7 @@ Every {{AISummarizerCapabilities}} has an af
- The current summarizer language availabilities are given by the following steps. They return a [=list=] containing two [=list/items=]; the items each are [=sets=] of strings representing [=Unicode canonicalized locale identifier=], or null. [[!ECMA-402]] + The current summarizer language availabilities are given by the following steps. They return a [=list=] containing two [=list/items=]; the items each are [=sets=] of strings representing [=Unicode canonicalized locale identifiers=], or null. [[!ECMA-402]] 1. [=Assert=]: this algorithm is running [=in parallel=]. @@ -503,9 +505,9 @@ Every {{AISummarizerCapabilities}} has an af
-

Summarization

+

The {{AISummarizer}} class

-Every {{AISummarizer}} has a shared context, a [=string=], set during creation. +Every {{AISummarizer}} has a shared context, a [=string=]-or-null, set during creation. Every {{AISummarizer}} has a summary type, an {{AISummarizerType}}, set during creation. @@ -513,6 +515,14 @@ Every {{AISummarizer}} has a summary format, an {{ Every {{AISummarizer}} has a summary length, an {{AISummarizerLength}}, set during creation. +Every {{AISummarizer}} has a destruction reason, a JavaScript value, initially undefined. + +Every {{AISummarizer}} has a destroyed boolean, initially false. + +

This value is separate from the [=AISummarizer/destruction reason=] so that it can be read from [=in parallel=] during the summarization process. + +


+ The sharedContext getter steps are to return [=this=]'s [=AISummarizer/shared context=]. The type getter steps are to return [=this=]'s [=AISummarizer/summary type=]. @@ -521,10 +531,387 @@ The format getter steps are to return [= The length getter steps are to return [=this=]'s [=AISummarizer/summary length=]. -The destroy() method steps are to [=AISummarizer/destroy=] [=this=] given a new "{{AbortError}}" {{DOMException}}. +
+ +
+ The summarize(|input|, |options|) method steps are: + + 1. If [=this=]'s [=relevant global object=] is a {{Window}} whose [=associated Document=] is not [=Document/fully active=], then return [=a promise rejected with=] an "{{InvalidStateError}}" {{DOMException}}. + + 1. If [=this=]'s [=AISummarizer/destroyed=] is true, then return [=a promise rejected with=] [=this=]'s [=AISummarizer/destruction reason=]. + + 1. If |options|["{{AISummarizerSummarizeOptions/signal}}"] [=map/exists=] and is [=AbortSignal/aborted=], then return [=a promise rejected with=] |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Let |abortedDuringSummarization| be false. + +

This variable will be written to from the [=event loop=], but read from [=in parallel=]. + + 1. If |options|["{{AISummarizerSummarizeOptions/signal}}"] [=map/exists=], then [=AbortSignal/add|add the following abort steps=] to |options|["{{AISummarizerSummarizeOptions/signal}}"]: + + 1. Set |abortedDuringSummarization| to true. + + 1. Let |promise| be [=a new promise=] created in [=this=]'s [=relevant realm=]. + + 1. Let |context| be |options|["{{AISummarizerSummarizeOptions/context}}"] if it [=map/exists=]; otherwise null. + + 1. [=In parallel=]: + + 1. Let |summary| be the empty string. + + 1. Let |chunkProduced| be the following steps given a [=string=] |chunk|: + + 1. [=Queue a global task=] on the [=AI task source=] given [=this=]'s [=relevant global object=] to perform the following steps: + + 1. If |abortedDuringSummarization| is true, then: + + 1. [=Reject=] |promise| with |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Abort these steps. + + 1. If [=this=]'s [=AISummarizer/destroyed=] is true, then: + + 1. [=Reject=] |promise| with [=this=]'s [=AISummarizer/destruction reason=]. + + 1. Abort these steps. + + 1. Append |chunk| to |summary|. + + 1. Let |done| be the following steps: + + 1. [=Queue a global task=] on the [=AI task source=] given [=this=]'s [=relevant global object=] to perform the following steps: + + 1. If |abortedDuringSummarization| is true, then: + + 1. [=Reject=] |promise| with |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Abort these steps. + + 1. If [=this=]'s [=AISummarizer/destroyed=] is true, then: + + 1. [=Reject=] |promise| with [=this=]'s [=AISummarizer/destruction reason=]. + + 1. Abort these steps. + + 1. [=Resolve=] |promise| with |summary|. + + 1. Let |error| be the following steps given [=summarization error information=] |errorInfo|: + + 1. [=Queue a global task=] on the [=AI task source=] given [=this=]'s [=relevant global object=] to perform the following steps: + + 1. If |abortedDuringSummarization| is true, then: + + 1. [=Reject=] |promise| with |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Abort these steps. + + 1. Let |exception| be the result of [=exception/creating=] a {{DOMException}} with name given by |errorInfo|'s [=summarization error information/error name=], using |errorInfo|'s [=summarization error information/error information=] to populate the message appropriately. + + 1. [=Reject=] |promise| with |exception|. + + 1. Let |stopProducing| be the following steps: + + 1. Return |abortedDuringSummarization|. + + 1. [=Summarize=] |input| given [=this=]'s [=AISummarizer/shared context=], |context|, [=this=]'s [=AISummarizer/summary type=], [=this=]'s [=AISummarizer/summary format=], [=this=]'s [=AISummarizer/summary length=], |chunkProduced|, |done|, |error|, and |stopProducing|. + + 1. Return |promise|. +

+ +
+ The summarizeStreaming(|input|, |options|) method steps are: + + 1. If [=this=]'s [=relevant global object=] is a {{Window}} whose [=associated Document=] is not [=Document/fully active=], then return [=a promise rejected with=] an "{{InvalidStateError}}" {{DOMException}}. + + 1. If [=this=]'s [=AISummarizer/destroyed=] is true, then return [=a promise rejected with=] [=this=]'s [=AISummarizer/destruction reason=]. + + 1. If |options|["{{AISummarizerSummarizeOptions/signal}}"] [=map/exists=] and is [=AbortSignal/aborted=], then return [=a promise rejected with=] |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Let |abortedDuringSummarization| be false. + +

This variable tracks web developer aborts via the |options|["{{AISummarizerSummarizeOptions/signal}}"] {{AbortSignal}}, which are surfaced as errors. It will be written to from the [=event loop=], but sometimes read from [=in parallel=]. + + 1. If |options|["{{AISummarizerSummarizeOptions/signal}}"] [=map/exists=], then [=AbortSignal/add|add the following abort steps=] to |options|["{{AISummarizerSummarizeOptions/signal}}"]: + + 1. Set |abortedDuringSummarization| to true. + + 1. Let |stream| be a [=new=] {{ReadableStream}} created in [=this=]'s [=relevant realm=]. + + 1. Let |canceledDuringSummarization| be false. + +

This variable tracks web developer [=ReadableStream/cancel|stream cancelations=] via {{ReadableStream/cancel()|stream.cancel()}}, which are not surfaced as errors. It will be written to from the [=event loop=], but sometimes read from [=in parallel=]. + + 1. [=ReadableStream/Set up=] |stream| with [=ReadableStream/set up/cancelAlgorithm=] set to the following steps (ignoring the reason argument): + + 1. Set |canceledDuringSummarization| to true. + + 1. Let |context| be |options|["{{AISummarizerSummarizeOptions/context}}"] if it [=map/exists=]; otherwise null. + + 1. [=In parallel=]: + + 1. Let |chunkProduced| be the following steps given a [=string=] |chunk|: + + 1. [=Queue a global task=] on the [=AI task source=] given [=this=]'s [=relevant global object=] to perform the following steps: + + 1. If |abortedDuringSummarization| is true, then: + + 1. [=ReadableStream/Error=] |stream| with |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Abort these steps. + + 1. If [=this=]'s [=AISummarizer/destroyed=] is true, then: + + 1. [=ReadableStream/Error=] |stream| with [=this=]'s [=AISummarizer/destruction reason=]. + + 1. Abort these steps. + + 1. [=ReadableStream/Enqueue=] |chunk| into |stream|. + + 1. Let |done| be the following steps: + + 1. [=Queue a global task=] on the [=AI task source=] given [=this=]'s [=relevant global object=] to perform the following steps: + + 1. If |abortedDuringSummarization| is true, then: + + 1. [=ReadableStream/Error=] |stream| with |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Abort these steps. + + 1. If [=this=]'s [=AISummarizer/destroyed=] is true, then: + + 1. [=ReadableStream/Error=] |stream| with [=this=]'s [=AISummarizer/destruction reason=]. + + 1. Abort these steps. + + 1. [=ReadableStream/Close=] |stream|. + + 1. Let |error| be the following steps given [=summarization error information=] |errorInfo|: + + 1. [=Queue a global task=] on the [=AI task source=] given [=this=]'s [=relevant global object=] to perform the following steps: + + 1. If |abortedDuringSummarization| is true, then: + + 1. [=ReadableStream/Error=] |stream| with |options|["{{AISummarizerSummarizeOptions/signal}}"]'s [=AbortSignal/abort reason=]. + + 1. Abort these steps. + + 1. If [=this=]'s [=AISummarizer/destroyed=] is true, then: + + 1. [=ReadableStream/Error=] |stream| with [=this=]'s [=AISummarizer/destruction reason=]. + + 1. Abort these steps. + + 1. Let |exception| be the result of [=exception/creating=] a {{DOMException}} with name given by |errorInfo|'s [=summarization error information/error name=], using |errorInfo|'s [=summarization error information/error information=] to populate the message appropriately. + + 1. [=ReadableStream/Error=] |stream| with |exception|. + + 1. Let |stopProducing| be the following steps: + + 1. If any of |abortedDuringSummarization|, |canceledDuringSummarization|, or [=this=]'s [=AISummarizer/destroyed=] are true, then return true. + + 1. Return false. + + 1. [=Summarize=] |input| given [=this=]'s [=AISummarizer/shared context=], |context|, [=this=]'s [=AISummarizer/summary type=], [=this=]'s [=AISummarizer/summary format=], [=this=]'s [=AISummarizer/summary length=], |chunkProduced|, |done|, |error|, and |stopProducing|. + + 1. Return |stream|. +

+ +
+ To summarize a string |input|, given a string-or-null |sharedContext|, a string-or-null |context|, an {{AISummarizerType}} |type|, an {{AISummarizerFormat}} |format|, an {{AISummarizerLength}} |length|, an algorithm |chunkProduced| that takes a string and returns nothing, an algorithm |done| that takes no arguments and returns nothing, an algorithm |error| that takes [=summarization error information=] and returns nothing, and an algorithm |stopProducing| that takes no arguments and returns a boolean: + + 1. [=Assert=]: this algorithm is running [=in parallel=]. + + 1. [=Assert=]: the [=current summarizer create options availability=] given |type|, |format|, and |length| is "{{AICapabilityAvailability/readily}}". + +

Otherwise, the {{AISummarizer}} object would not have been created. + + 1. In an [=implementation-defined=] manner, subject to the following guidelines, begin the processs of summarizing |input| into a string. + + If they are non-null, |sharedContext| and |context| should be used to aid in the summarization by providing context on how the web developer wishes the input to be summarized. + + The summarization should conform to the guidance given by |type|, |format|, and |length|, in the definitions of each of their enumeration values. + + 1. While true: + + 1. Wait for the next chunk of summarization data to be produced, for the summarization process to finish, or for the result of calling |stopProducing| to become true. + + 1. If such a chunk is successfully produced: + + 1. Let it be represented as a [=string=] |chunk|. + + 1. Perform |chunkProduced| given |chunk|. + + 1. Otherwise, if the summarization process has finished: + + 1. Perform |done|. + + 1. [=iteration/Break=]. + + 1. Otherwise, if |stopProducing| returns true, then [=iteration/break=]. + +

The caller will handle signaling cancelation or aborting as necessary. + + 1. Otherwise, if an error occurred during summarization: + + 1. Let the error be represented as [=summarization error information=] |errorInfo| according to the guidance in [[#summarizer-errors]]. + + 1. Perform |error| given |errorInfo|. + + 1. [=iteration/Break=]. +

+ +
+ +
+

The destroy() method steps are to [=AISummarizer/destroy=] [=this=] given a new "{{AbortError}}" {{DOMException}}. +

- To destroy an {{AISummarizer}} |summarizer|, given a JavaScript value |exception|: + To destroy an {{AISummarizer}} |summarizer|, given a JavaScript value |reason|: + + 1. Set |summarizer|'s [=AISummarizer/destroyed=] to true. - 1. TODO use |summarizer| and |exception|. + 1. Set |summarizer|'s [=AISummarizer/destruction reason=] to |reason|. + + 1. The user agent should release any resources associated with |summarizer|, such as AI models loaded during [=initialize the summarization model=], as long as those resources are not needed for other ongoing operations.
+ +

Options

+ +The [=summarize=] algorithm's details are [=implementation-defined=], as they are expected to be powered by an AI model. However, it is intended to be controllable by the web developer through the {{AISummarizerType}}, {{AISummarizerFormat}}, and {{AISummarizerLength}} enumerations. + +This section gives normative guidance on how the implementation of [=summarize=] should use each enumeration value to guide the summarization process. + + + + + + + + + + +
{{AISummarizerType}} values
Value + Meaning +
"tl;dr" + +

The summary should be short and to the point, providing a quick overview of the input, suitable for a busy reader. +

"teaser" + +

The summary should focus on the most interesting or intriguing parts of the input, designed to draw the the reader in to read more. +

"key-points" + +

The summary should extract the most important points from the input, presented as a bulleted list. +

"headline" + +

The summary should effectively containing the main point of the input in a single sentence, in the format of an article headline. +

+ + + + + + + + + +
{{AISummarizerLength}} values
Value + Meaning +
"short" + +

The guidance is dependent on the value of {{AISummarizerType}}: + +

+ : "{{AISummarizerType/tl;dr}}" + : "{{AISummarizerType/teaser}}" + :: The summary should fit within a one sentence. + : "{{AISummarizerType/key-points}}" + :: The summary should consist of no more than 3 bullet points. + : "{{AISummarizerType/headline}}" + :: The summary should use no more than 12 words. +
+
"medium" + +

The guidance is dependent on the value of {{AISummarizerType}}: + +

+ : "{{AISummarizerType/tl;dr}}" + : "{{AISummarizerType/teaser}}" + :: The summary should fit within a one short paragraph. + : "{{AISummarizerType/key-points}}" + :: The summary should consist of no more than 5 bullet points. + : "{{AISummarizerType/headline}}" + :: The summary should use no more than 17 words. +
+
"long" + +

The guidance is dependent on the value of {{AISummarizerType}}: + +

+ : "{{AISummarizerType/tl;dr}}" + : "{{AISummarizerType/teaser}}" + :: The summary should fit within a one paragraph. + : "{{AISummarizerType/key-points}}" + :: The summary should consist of no more than 7 bullet points. + : "{{AISummarizerType/headline}}" + :: The summary should use no more than 22 words. +
+
+ + + + + + + + +
{{AISummarizerFormat}} values
Value + Meaning +
"plain-text" + +

The summary should not contain any formatting or markup language. +

"markdown" + +

The summary should be formatted using the Markdown markup language, ideally as valid CommonMark. [[!COMMONMARK]] +

+ +

Errors

+ +A summarization error information is a [=struct=] with the following items: + +: error name +:: a [=string=] that will be used for the {{DOMException}}'s [=DOMException/name=]. +: error information +:: other information necessary to create a useful {{DOMException}} for the web developer. (Typically, just an exception message.) + +When summarization fails, the following possible reasons may be surfaced to the web developer. This table lists the possible {{DOMException}} [=DOMException/names=] and the cases in which an implementation should use them: + + + + + + + + + + +
{{DOMException}} [=DOMException/name=] + Scenarios +
"{{NotAllowedError}}" + +

Summarization is disabled by user choice or user agent policy. +

"{{NotReadableError}}" + +

The summarization output was filtered by the user agent, e.g., because it was detected to be harmful, inaccurate, or nonsensical. +

"{{NotSupportedError}}" + +

The input to be summarized was in a language that the user agent does not support summarizing. +

The summarization output was detected to be in a language that the user agent does not have sufficient quality control for and is not willing to support. +

"{{QuotaExceededError}}" + +

The input to be summarized was too large for the user agent to handle. +

"{{UnknownError}}" + +

All other scenarios, or if the user agent would prefer not to disclose the failure reason. +

+ +

This table does not give the complete list of exceptions that can be surfaced by {{AISummarizer/summarize()|summarizer.summarize()}} and {{AISummarizer/summarize()|summarizer.summarizeStreaming()}}. It only contains those which can come from the [=implementation-defined=] [=summarize=] algorithm. From a02c61180cd50729a120266a2a2b173c04006c29 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Fri, 29 Nov 2024 11:20:45 +0900 Subject: [PATCH 2/2] Respond to review comments --- index.bs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index bbe1fce..af15f00 100644 --- a/index.bs +++ b/index.bs @@ -488,7 +488,7 @@ Every {{AISummarizerCapabilities}} has an af One way this could be implemented would be for [=current summarizer language availabilities=] to return that « "`zh-Hant`" » is readily available, and « "`zh`", "`zh-Hans`" » is available after download. This return value conforms to the requirements of the [=language tag set completeness rules=], in ensuring that "`zh`" is present. Per the "should"-level guidance, the implementation has determined that "`zh`" belongs in the list of after-download available languages, with "`zh-Hans`", instead of in the list of readily available languages, with "`zh-Hant`". - Combined with the use of [$LookupMatchingLocaleByBestFit$], this means the the {{AISummarizerCapabilities/languageAvailable()}} will give the the following answers: + Combined with the use of [$LookupMatchingLocaleByBestFit$], this means {{AISummarizerCapabilities/languageAvailable()}} will give the following answers:

c.languageAvailable("zh") === "after-download"; @@ -795,7 +795,7 @@ This section gives normative guidance on how the implementation of [=summarize=] <tr> <th>"<dfn enum-value for="AISummarizerType">teaser</dfn>" <td> - <p>The summary should focus on the most interesting or intriguing parts of the input, designed to draw the the reader in to read more. + <p>The summary should focus on the most interesting or intriguing parts of the input, designed to draw the reader in to read more. <tr> <th>"<dfn enum-value for="AISummarizerType">key-points</dfn>" <td> @@ -803,7 +803,7 @@ This section gives normative guidance on how the implementation of [=summarize=] <tr> <th>"<dfn enum-value for="AISummarizerType">headline</dfn>" <td> - <p>The summary should effectively containing the main point of the input in a single sentence, in the format of an article headline. + <p>The summary should effectively contain the main point of the input in a single sentence, in the format of an article headline. </table> <table class="data enum-table"> @@ -821,7 +821,7 @@ This section gives normative guidance on how the implementation of [=summarize=] <dl class="switch"> : "{{AISummarizerType/tl;dr}}" : "{{AISummarizerType/teaser}}" - :: The summary should fit within a one sentence. + :: The summary should fit within 1 sentence. : "{{AISummarizerType/key-points}}" :: The summary should consist of no more than 3 bullet points. : "{{AISummarizerType/headline}}" @@ -835,7 +835,7 @@ This section gives normative guidance on how the implementation of [=summarize=] <dl class="switch"> : "{{AISummarizerType/tl;dr}}" : "{{AISummarizerType/teaser}}" - :: The summary should fit within a one short paragraph. + :: The summary should fit within 1 short paragraph. : "{{AISummarizerType/key-points}}" :: The summary should consist of no more than 5 bullet points. : "{{AISummarizerType/headline}}" @@ -849,7 +849,7 @@ This section gives normative guidance on how the implementation of [=summarize=] <dl class="switch"> : "{{AISummarizerType/tl;dr}}" : "{{AISummarizerType/teaser}}" - :: The summary should fit within a one paragraph. + :: The summary should fit within 1 paragraph. : "{{AISummarizerType/key-points}}" :: The summary should consist of no more than 7 bullet points. : "{{AISummarizerType/headline}}" @@ -857,6 +857,8 @@ This section gives normative guidance on how the implementation of [=summarize=] </dl> </table> +<p class="note">As with all "<span class="ignore-2119">should"-level guidance, user agents might not conform perfectly to these. Especially in the case of counting words, it's expected that language models might not conform perfectly. + <table class="data enum-table"> <caption>{{AISummarizerFormat}} values</caption> <thead>