使用 Summarizer API
Summarizer API
提供了一种异步(基于 Promise
)的机制,允许网站将一段文本输入到浏览器自身的内部 AI 模型中,并根据指定的选项请求该模型返回文本摘要。本文档将介绍如何使用 Summarizer API 的基础知识。
创建 summarizer
Summarizer API 的所有功能都通过一个单一的接口访问——Summarizer
。
让浏览器 AI 模型输出摘要的第一步是创建一个 Summarizer
对象实例。这通过调用 Summarizer.create()
静态方法完成,该方法接受一个选项对象作为参数,用于指定你想要的摘要类型等选项。
const summarizer = await Summarizer.create({
sharedContext:
"A general summary to help a user decide if the text is worth reading",
type: "tldr",
length: "short",
format: "markdown",
expectedInputLanguages: ["en-US"],
outputLanguage: "en-US",
});
sharedContext
选项提供了一个字符串,可以帮助 AI 模型为文本的使用场景生成更合适的摘要,而 type
则指定你想要的摘要类型,例如要点列表或“tl;dr”摘要。
我们还指定了所需的 length
(长度)、输出 format
(格式)、expectedInputLanguages
(预期输入语言)和所需的 outputLanguage
(输出语言)。如果未指定输入和输出语言,则会自动检测输入文本的语言,输出语言将与输入语言匹配。
如果浏览器的 AI 模型不支持指定的输入或输出语言,则会抛出错误。
注意: 有关可用选项的完整列表,请参阅 create()
参考页面。
检查配置支持情况
在创建 Summarizer
之前,可以使用 Summarizer.availability()
静态方法检查当前浏览器是否支持你所需的配置。例如:
const availability = await Summarizer.availability({
type: "tldr",
length: "short",
format: "markdown",
expectedInputLanguages: ["en-US"],
outputLanguage: "en-US",
});
此方法返回一个枚举值,指示是否支持指定的一组选项,或者将支持。
downloadable
表示浏览器支持请求的选项,但需要先下载 AI 模型或该模型的某些微调数据。downloading
表示浏览器支持请求的选项,但需要完成正在进行的下载才能继续。available
表示浏览器支持给定的配置,无需任何新下载。unavailable
表示浏览器不支持给定的配置。
如果需要下载,一旦使用 create()
方法创建了 Summarizer
实例,浏览器就会自动开始下载。你可以通过“监控下载进度”部分自动跟踪下载进度。
生成摘要
确定你所需的配置有效并创建了 Summarizer
实例后,可以通过在该实例上调用 Summarizer.summarize()
实例方法来生成摘要,并将要摘要的文本作为参数传递。
const summary = await summarizer.summarize(myTextString);
console.log(summary);
它还可以选择性地接受一个选项对象作为第二个参数,该对象可以接受特定于此摘要的 context
(上下文)字符串,以及一个 abort signal
(中止信号),允许摘要请求被中止(请参阅下一节)。
summarize()
方法有一个流式版本——Summarizer.summarizeStreaming()
——它允许你将摘要作为 ReadableStream
返回。
const stream = summarizer.summarizeStreaming(myTextString);
let summary = "";
for await (const chunk of stream) {
summary += chunk;
}
console.log("Stream complete");
summaryOutput.textContent = summary;
创建 Summarizer
实例后,可以使用 Summarizer.destroy()
实例方法将其移除。如果不再使用 Summarizer
对象,销毁它们是有意义的,因为它们在其处理过程中会占用大量资源。
取消摘要操作
你可以使用 AbortController
取消挂起的 create()
、summarize()
或 summarizeStreaming()
操作。
const controller = new AbortController();
const summary = await summarizer.summarize(myTextString, {
signal: controller.signal,
});
// ...
controller.abort();
监控下载进度
如果某个 summarizer 的 AI 模型正在下载(availability()
返回 downloadable
和 downloading
),提供反馈给用户,告知他们需要等待多久才能完成操作会很有帮助。
Summarizer.create()
方法可以接受一个 monitor
属性,其值是一个回调函数,该函数接受一个 CreateMonitor
实例作为参数。CreateMonitor
有一个可用的 downloadprogress
事件,当 AI 模型下载进度取得进展时会触发。你可以使用此事件来显示加载进度数据。
const summarizer = await Summarizer.create({
sharedContext:
"A general summary to help a user decide if the text is worth reading",
type: "tldr",
length: "short",
monitor(monitor) {
monitor.addEventListener("downloadprogress", (e) => {
console.log(`Downloaded ${Math.floor(e.loaded * 100)}%`);
});
},
});
使用配额
一些实现有一个输入配额,用于规定网站在给定时间段内可以请求的操作数量。总配额可以通过 Summarizer.inputQuota
属性访问,而特定摘要操作的配额使用情况可以通过 Summarizer.measureInputUsage()
方法返回。
例如,在下面的代码片段中,我们使用 create()
创建了一个新的 Summarizer
实例,然后通过 inputQuota
返回总输入配额,并通过 measureInputUsage()
返回摘要特定文本字符串的输入配额使用情况。
然后,我们测试该字符串的单个输入使用量是否大于总可用配额。如果是,则抛出适当的错误;否则,我们使用 summarize()
开始摘要该字符串。
const summarizer = await Summarizer.create({
sharedContext:
"A general summary to help a user decide if the text is worth reading",
type: "tldr",
length: "short",
});
const totalInputQuota = summarizer.inputQuota;
const inputUsage = await summarizer.measureInputUsage(myTextString);
if (inputUsage > totalInputQuota) {
throw new Error("Boo, insufficient quota to generate a summary.");
} else {
console.log("Yay, quota available to generate a summary.");
const summary = await summarizer.summarize(myTextString);
// ...
}
如果你尝试运行一个超出可用配额的摘要操作,将抛出一个 QuotaExceededError
DOMException
。
完整示例
让我们看一个完整的示例,演示 Summarizer API 的实际应用。
HTML
在我们的标记语言中,我们首先定义了一个输入 <form>
,允许用户设置要摘要的文本和配置选项。这包括一个用于输入要摘要文本的 <textarea>
,一个用于显示用户设置文本字符数的 <output>
元素,以及两个 <select>
元素,用于选择 summarizer 的 type
(类型)和 length
(长度)。
<h2>Input</h2>
<form>
<div>
<label for="summary-text">Enter text to summarize:</label>
<textarea id="summary-text" name="summaryText" rows="6"></textarea>
<output class="input-count">Input character count: </output>
</div>
<div>
<label for="summary-type">Summary type:</label>
<select id="summary-type" name="summaryType">
<option value="headline">Headline</option>
<option value="key-points">Key points</option>
<option value="teaser">Teaser</option>
<option value="tldr" selected>tldr</option>
</select>
</div>
<div>
<label for="summary-length">Summary length:</label>
<select id="summary-length" name="summaryLength">
<option value="short" selected>Short</option>
<option value="medium">Medium</option>
<option value="long">Long</option>
</select>
</div>
<button type="submit">Submit</button>
</form>
我们标记语言的后半部分包括一个 <p>
元素来显示生成的摘要,以及第二个 <output>
元素来显示摘要的字符数。
<h2>Summary output</h2>
<p class="summary-output"></p>
<output class="output-count">Output summary character count: 0</output>
请注意,我们不会展示此示例的 CSS,因为其中没有内容与理解 Summarizer API 相关。
JavaScript
在我们的脚本中,我们首先获取对 <form>
、<textarea>
、提交 <button>
、摘要输出 <p>
以及两个 <output>
元素的引用。
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");
const submitBtn = document.querySelector("button");
const summaryOutput = document.querySelector(".summary-output");
const inputCount = document.querySelector(".input-count");
const outputCount = document.querySelector(".output-count");
接下来,我们使用 EventTarget.addEventListener()
方法监听两组事件:
<form>
元素上的submit
事件;当单击提交按钮时,会调用handleSubmission()
函数。<textarea>
元素上的input
事件;当更改当前的<textarea>
值时,会调用updateInputCount()
函数。
form.addEventListener("submit", handleSubmission);
textarea.addEventListener("input", updateInputCount);
接下来定义的 updateInputCount()
函数将第一个 <output>
元素的 textContent
设置为一个包含 <textarea>
值长度的字符串。我们还定义了一个相应的 displayOutputCount()
函数,它对第二个 <output>
元素执行相同的操作。在 handleSubmission()
函数的接近尾声时,摘要返回后,才会调用此函数。
function updateInputCount() {
inputCount.textContent = `Input character count: ${textarea.value.length}`;
}
function displayOutputCount() {
outputCount.textContent = `Output summary character count: ${summaryOutput.textContent.length}`;
}
现在我们定义 handleSubmission()
函数本身。在阻止默认表单提交后,我们创建了一个新的 FormData
对象实例,其中包含我们所有的 <form>
数据名值对。然后,我们运行一些数据验证测试,检查 <textarea>
的内容(summaryText
)是否为空或太短而浪费资源,如果文本不满足要求,则在摘要输出 <p>
中打印错误消息。
如果文本通过了测试,我们就使用 create()
方法创建一个新的 Summarizer
对象,传递一个 sharedContext
字符串以及在表单中选择的 type
(summaryType
)和 length
(summaryLength
)值。然后,我们将输出摘要的 <p>
和 <output>
设置为“pending”(待处理)消息,并在运行 summarize()
操作时禁用 <submit>
按钮。
成功返回 summary
值后,我们将其设置为输出摘要 <p>
元素的 textContent
,调用 displayOutputCount()
在第二个 <output>
元素中显示输出字符数,并重新启用提交 <button>
。
async function handleSubmission(e) {
e.preventDefault();
const formData = new FormData(form);
if (formData.get("summaryText") === "") {
summaryOutput.innerHTML = `<span class="error">No text entered to summarize!</span>`;
return;
} else if (formData.get("summaryText").length < 100) {
summaryOutput.innerHTML = `<span class="error">I'm not trying to summarize something that short!</span>`;
return;
}
summaryOutput.innerHTML = "";
try {
const summarizer = await Summarizer.create({
sharedContext:
"A general summary to help a user decide if the text is worth reading",
type: formData.get("summaryType"),
length: formData.get("summaryLength"),
});
summaryOutput.textContent = "...generating summary...";
outputCount.textContent = "Output summary character count: -";
submitBtn.disabled = true;
const summary = await summarizer.summarize(formData.get("summaryText"));
summaryOutput.textContent = summary;
displayOutputCount();
submitBtn.disabled = false;
} catch (e) {
summaryOutput.innerHTML = `<span class="error">${e}</span>`;
}
}
最后一步是在脚本的顶层调用 updateInputCount()
函数,以确保包含输入计数的第一个 <output>
元素在页面加载时始终显示正确的值。
updateInputCount();
结果
渲染后的示例如下所示:
尝试在“Input”(输入)<textarea>
中输入一段文本,然后按提交按钮生成 AI 生成的摘要。你最喜欢的维基百科页面的文本是理想的选择。尝试使用不同的选项组合生成多个摘要,看看它们如何影响输出。