Blume中文文档

配置

朗读

为每个页面加一个「收听本页」播放器,可用读者设备自带的浏览器语音,也可在构建时生成语音

朗读会在每个页面的描述下方加一个 收听本页播放器。读者按下播放,页面就从标题开始逐句朗读,被读到的句子会高亮并保持在视野内。它需要手动启用:

export default defineConfig({
  narration: true,
});

设为 true 时,页面使用读者设备自带的浏览器语音朗读:无需密钥,无需构建步骤,在任何托管平台上都能工作,静态的或非静态的都可以。加上一个 provider 则改用生成的语音。

它朗读哪些内容#

朗读会按顺序读出页面标题、描述、各级标题、段落、列表项和卡片文字。有些组件前面会加一句简短的语音提示,让听者知道接下来是什么内容:

组件 提示
提示框 「注意。」「提示。」「警告。」等等
Steps 「第 1 步。」「第 2 步。」
Tabs 「macOS 标签页。」每个标签页都会被朗读,不只是当前打开的那个
Accordion 和 Expandable 「可展开区块。」

当朗读遇到折叠起来的区块或未显示的标签页时,会把它展开,这样高亮总能落在读者看得见的文字上。

代码块、表格、图片、视频、图表、公式、类型展示、文件树和实时组件预览都会被跳过 —— 它们读出来没有意义。

只有正文足够多、值得一听的页面才会出现播放器,大约 50 词以上。很短的页面,以及大部分由代码或 API 字段构成的页面,都不会出现播放器。

收听#

页面播放时,播放器会固定在页头下方,包含播放与暂停、上一句与下一句、进度条、已读时间与页面总长度的对比,以及 0.8× 到 2× 的倍速控制。这个倍速会被记住,下一页继续沿用。

页面会自动滚动,让正在朗读的句子保持在视野内。如果读者自己滚走了,跟随就会停止而音频继续播放;滚回那个句子,或者按下 跟随朗读,就会重新跟上。打开另一个页面会停止朗读。

浏览器语音#

narration: true 使用 Web Speech API 和读者设备上的语音来朗读页面,并按页面语言挑选一个合适的声音。如果浏览器没有该语言的声音,播放器会保持隐藏,而不是用错误的口音把页面念出来。

这不需要你提供任何东西,也不产生任何费用,但效果取决于设备:macOS、iOS 和 Windows 上的系统语音都不错,而某些 Linux 浏览器自带的语音很少,甚至一个都没有。

生成的语音#

传入一个 provider,就能在构建时用神经语音模型生成音频。这个 provider 就是 assistant 使用的同一个 gateway()适配器,只是指向一个语音模型:

import { defineConfig } from "blume";
import { gateway } from "blume/ai";

export default defineConfig({
  narration: {
    provider: gateway({
      model: "openai/tts-1-hd",
      voice: "alloy",
    }),
  },
});

blume build 会完全按播放器的方式读取每个构建好的页面,把它拆成句子,并通过 Vercel AI Gateway 为每个句子生成一段音频。这些音频和每页一份的小清单会作为静态文件写入你的构建产物,放在 /blume-narration/ 下,因此重播不花任何代价,也没有任何东西在服务器上运行。

在生成任何东西之前,构建会先打印它需要多少段新音频、总共覆盖多少字符,让成本一目了然:

Generating narration: 214 new clip(s), 15,880 characters, with openai/tts-1-hd
选项 默认值 说明
model openai/tts-1-hd gateway 的语音模型:openai/tts-1、openai/tts-1-hd、fish-audio/s2.1-pro、spacexai/grok-tts,以及 gateway 列出的其它模型。
voice alloy 模型使用的声音。
instructions 指定声音该如何朗读,适用于接受指令的模型(「像一位老师那样,平静地朗读」)。
apiKeyEnv AI_GATEWAY_API_KEY 保存 gateway 密钥的环境变量。在 Vercel 上,构建的 OIDC token 同样可用。
headers 随每次请求发送的静态响应头。
providerOptions 原样传给 AI SDK 的 generateSpeech,用于 Blume 没有具名列出的模型设置。

缓存#

音频会按决定其声音的那些条件缓存在 node_modules/.cache/blume/narration 下:句子本身、它的语言、模型、声音和指令。重新构建时只需为发生变化的句子付费,被多个页面共用的句子只生成一次。Vercel 和 Netlify 会从各自的构建缓存中恢复 node_modules,所以在那里部署只会重新生成变化的部分。在其它 CI 上,请在两次运行之间缓存这个目录。

回退#

在没有音频的地方,生成的语音会回退到浏览器语音:

  • 在 blume dev 中,它从不生成音频。运行 blume build 和 blume preview 就能在本地听到生成的语音。
  • 构建时未设置密钥。构建会发出警告并跳过生成。
  • 生成失败时。由于 AI SDK 已经重试过,构建会在第一段失败的音频处停下,并保留所有已缓存的音频。

语言#

朗读会用每个页面自身的内容语言进行,因此在一个国际化的站点上,每个 locale 都用自己对应的声音朗读。这些语音提示和播放器标签在每个内置 UI 语言中都已翻译。要按 locale 覆盖它们,在 i18n.ui 中改写 narration 下的内容。

为单个页面关闭它#

在页面的 frontmatter 中设置 narration: false,就能让该页面不出现播放器:

---
title: Changelog
narration: false
---

让内容不被朗读#

给某个元素加上 data-blume-narration="skip",就能让它及其内部的一切都不参与朗读。Blume 就是靠它跳过自己的类型展示和预览的,对你自己的组件和交互岛同样有效:

<div data-blume-narration="skip">
  <PricingCalculator />
</div>

分析#

读者开始收听时,播放器会发送一个 narration_play 事件,附带 engine(audio 或 browser)和页面的 path;页面播放到结尾时再发送 narration_complete。这两个事件和其它自定义事件一样,都会经过你的分析适配器。