Vorlesen
Ein „Diese Seite anhören“-Player, der jede Seite vorliest und den gerade gelesenen Satz hervorhebt – mit den Browserstimmen deiner Leser oder mit neuronalen Stimmen, die beim Build erzeugt werden.
Die Vorlesefunktion fügt unter der Beschreibung jeder Seite einen Player Diese Seite anhören hinzu. Deine Leser drücken auf Play, und die Seite wird vom Titel an vorgelesen. Der gerade gelesene Satz wird dabei hervorgehoben und bleibt immer sichtbar. Die Funktion ist standardmäßig aus und du schaltest sie so ein:
export default defineConfig({
narration: true,
});
Mit true werden Seiten mit den Browserstimmen deiner Leser vorgelesen. Du brauchst keinen Schlüssel und keinen Build-Schritt, und es funktioniert auf jedem Host, ob statisch oder nicht. Wenn du stattdessen generierte Stimmen nutzen willst, füge einen provider hinzu.
Was vorgelesen wird
Vorgelesen werden der Reihe nach der Seitentitel, die Beschreibung, Überschriften, Absätze, Listeneinträge und Kartentexte. Vor manchen Komponenten kommt ein kurzer gesprochener Hinweis, damit Zuhörende wissen, welche Art von Inhalt als Nächstes folgt:
| Komponente | Hinweis |
|---|---|
| Callouts | „Hinweis.“, „Tipp.“, „Warnung.“ usw. |
| Steps | „Schritt 1.“, „Schritt 2.“ |
| Tabs | „macOS-Tab.“ Jeder Tab wird vorgelesen, nicht nur der geöffnete |
| Accordions und Expandable | „Ausklappbarer Abschnitt.“ |
Kommt das Vorlesen bei einem geschlossenen Abschnitt oder einem ausgeblendeten Tab an, wird er geöffnet. So landet die Hervorhebung immer auf Text, den deine Leser auch sehen.
Codeblöcke, Tabellen, Bilder, Videos, Diagramme, mathematische Formeln, Typtabellen, Dateibäume und Live-Vorschauen von Komponenten werden übersprungen, weil sie vorgelesen keinen Sinn ergeben.
Der Player erscheint nur auf Seiten mit so viel Fließtext, dass sich das Zuhören lohnt, also etwa ab 50 Wörtern. Sehr kurze Seiten und Seiten, die vor allem aus Code oder API-Feldern bestehen, bekommen keinen Player.
Zuhören
Während eine Seite abgespielt wird, bleibt der Player unter dem Header fixiert. Er hat Play und Pause, Tasten für den vorherigen und nächsten Satz, einen Fortschrittsregler, die bisher gelesene Zeit neben der Gesamtlänge der Seite und eine Geschwindigkeitsregelung von 0,8× bis 2×. Die Geschwindigkeit wird für die nächste Seite gespeichert.
Die Seite scrollt mit, damit der gerade gelesene Satz sichtbar bleibt. Scrollen deine Leser weg, hört die Seite auf mitzuscrollen, aber der Ton läuft weiter. Wer zum Satz zurückscrollt oder auf Mitlesen drückt, schaltet das Mitscrollen wieder ein. Wird eine andere Seite geöffnet, stoppt das Vorlesen.
Browserstimmen
narration: true liest die Seite mit der Web Speech API und den Stimmen auf dem Gerät deiner Leser vor und wählt eine Stimme für die Sprache der Seite. Hat ein Browser keine Stimme für diese Sprache, bleibt der Player ausgeblendet, statt die Seite mit falschem Akzent vorzulesen.
Dafür musst du nichts tun und es kostet nichts. Wie es klingt, hängt aber vom Gerät ab. Die Systemstimmen unter macOS, iOS und Windows klingen gut, während manche Linux-Browser nur wenige oder gar keine Stimmen mitbringen.
Generierte Stimmen
Übergib einen provider, um beim Build Audio mit einem neuronalen Sprachsynthesemodell zu erzeugen. Der Provider ist derselbe gateway()-Adapter, den auch der Assistent verwendet, nur mit einem Sprachsynthesemodell:
import { defineConfig } from "blume";
import { gateway } from "blume/ai";
export default defineConfig({
narration: {
provider: gateway({
model: "openai/tts-1-hd",
voice: "alloy",
}),
},
});
blume build liest jede gebaute Seite genau so, wie der Player sie vorlesen wird, und teilt sie in Sätze auf. Dann erzeugt es über das Vercel AI Gateway einen Clip pro Satz. Die Clips und ein kleines Manifest pro Seite landen als statische Dateien unter /blume-narration/ in deinem Build. Erneutes Abspielen kostet also nichts, und auf keinem Server läuft etwas.
Bevor etwas generiert wird, gibt der Build aus, wie viele neue Clips er braucht und wie viele Zeichen sie umfassen. So siehst du die Kosten schon vorher:
Generating narration: 214 new clip(s), 15,880 characters, with openai/tts-1-hd
| Option | Standard | Beschreibung |
|---|---|---|
model |
openai/tts-1-hd |
Ein Sprachsynthesemodell aus dem Gateway: openai/tts-1, openai/tts-1-hd, fish-audio/s2.1-pro, spacexai/grok-tts und weitere Modelle, die das Gateway anbietet. |
voice |
alloy |
Die Stimme des Modells. |
instructions |
Wie die Stimme klingen soll, bei Modellen, die Anweisungen annehmen („Lies ruhig vor, wie eine Lehrkraft“). | |
apiKeyEnv |
AI_GATEWAY_API_KEY |
Die Umgebungsvariable mit dem Gateway-Schlüssel. Auf Vercel funktioniert auch das OIDC-Token des Builds. |
headers |
Statische Header, die mit jeder Anfrage gesendet werden. | |
providerOptions |
Wird unverändert an generateSpeech aus dem AI SDK weitergegeben, für Modelleinstellungen, die Blume nicht selbst kennt. |
Caching
Clips werden in node_modules/.cache/blume/narration gecacht. Der Cache-Schlüssel besteht aus allem, was ihren Klang bestimmt: dem Satz, seiner Sprache, dem Modell, der Stimme und den Anweisungen. Bei einem neuen Build zahlst du nur für geänderte Sätze, und ein Satz, der auf vielen Seiten steht, wird nur einmal generiert. Vercel und Netlify stellen node_modules aus ihrem Build-Cache wieder her, deshalb wird dort bei einem Deployment nur neu generiert, was sich geändert hat. Bei anderen CI-Systemen cachest du das Verzeichnis zwischen den Läufen selbst.
Fallbacks
Wo es keine Clips gibt, greifen generierte Stimmen auf Browserstimmen zurück:
- In
blume dev, weil dort nie Audio generiert wird. Führeblume buildundblume previewaus, um die generierte Stimme lokal zu hören. - Wenn der Schlüssel beim Build nicht gesetzt ist. Der Build gibt dann eine Warnung aus und überspringt die Generierung.
- Wenn die Generierung fehlschlägt. Der Build bricht beim ersten fehlgeschlagenen Clip ab, weil das AI SDK ihn schon erneut versucht hat, und behält alle bereits gecachten Clips.
Sprachen
Jede Seite wird in ihrer Inhaltssprache vorgelesen. Auf einer internationalisierten Site bekommt so jede Locale ihre eigene Stimme. Die gesprochenen Hinweise und die Beschriftungen des Players sind in alle integrierten UI-Sprachen übersetzt. Du kannst sie pro Locale unter narration in i18n.ui überschreiben.
Für eine Seite ausschalten
Setze narration: false im Frontmatter einer Seite, wenn diese Seite keinen Player bekommen soll:
---
title: Changelog
narration: false
---
Inhalte ausschließen
Mit data-blume-narration="skip" schließt du ein Element samt seinem gesamten Inhalt vom Vorlesen aus. Genau so überspringt Blume seine eigenen Typtabellen und Vorschauen, und es funktioniert genauso bei deinen eigenen Komponenten und Islands:
<div data-blume-narration="skip">
<PricingCalculator />
</div>
Analytics
Wenn jemand mit dem Zuhören beginnt, sendet der Player ein narration_play-Event mit der engine (audio oder browser) und dem path der Seite. Läuft eine Seite bis zum Ende durch, sendet er narration_complete. Beide Events laufen wie die anderen benutzerdefinierten Events über deine Analytics-Adapter.