Screenreader-Plugin mit dem Robot /text/speak erstellen

Hinweis zu historischen Preisen: Die Preise und Kontingente unten beschreiben das Angebot zum Zeitpunkt der Veröffentlichung dieses Artikels. Die heutigen Tarife finden Sie unter aktuellen Preisen.
Wir haben kürzlich ein Update für einen unserer beliebten KI-Robots besprochen, und heute nutzen wir diesen Schwung und erweitern die KI-Robot-Familie um ein weiteres Mitglied. Begrüßen Sie unseren neuen Robot /text/speak! Wie schon beim letzten KI-Robot, den wir vorgestellt haben, dem Robot /speech/transcribe, dreht sich auch bei diesem Robot die Kernfunktion um Sprache. Statt jedoch Text aus Sprache zu schreiben, können Sie damit Text zu Sprache verarbeiten (TTS).
Da dies eine so spannende Ergänzung ist, haben mein Kollege Joseph und ich beschlossen, dass wir beide ein Projekt entwickeln, bei dem dieser Robot im Mittelpunkt des Designs steht, und anschließend einen Blogbeitrag über unseren Design-Prozess schreiben, um zu zeigen, wie vielseitig dieser Robot ist. Wenn Ihnen dieser Beitrag also gefällt, halten Sie Ausschau nach Josephs Beitrag, der bald erscheint!
Für mein Projekt erstelle ich einen Screenreader, der sich leicht in Ihre Website einbinden lässt und den Text einer ganzen Seite per Knopfdruck in Sprache umwandelt.
Dies ist ein Text-to-Speech-Experiment und kein Ersatz für einen assistiven Screenreader mit Navigations- und Interaktionsunterstützung. Wenn Sie die Schaltfläche drücken, sendet die Demo den nachfolgenden Tutorial-Text an Transloadit, ausgenommen die Code-Beispiele. Die Audioausgabe folgt der Sprache, die im Sprachmenü der Website angezeigt wird; nutzen Sie die Audiosteuerung, um das Ergebnis abzuspielen. Das eigenständige Beispiel unten wählt seine Stimme stattdessen anhand des Sprachattributs seines ersten markierten Textblocks aus.

Voraussetzungen
Bevor Sie loslegen, müssen Sie einen üblichen Website-Ordner anlegen. Erstellen Sie die folgenden
Dateien: index.html, index.js und optional style.css. Um diesen Beitrag nicht
aufzublähen, besprechen wir nur den Inhalt der JS-Datei und die Stellen, an denen sie mit unserer
HTML-Datei zusammenspielt. Wenn Sie dennoch den vollständigen Inhalt unserer übrigen Dateien samt
dem GIF der Ladeanimation kopieren möchten, das später in dieser Vorstellung verwendet wird, finden
Sie alles im folgenden Repository.
HTML
Legen wir zunächst das HTML-Element unserer Anwendung an. Wie oben erwähnt, gehen wir nicht auf das Erstellen einer Webseite ein, sondern nur auf die Elemente, die für das Zusammenspiel mit unserer JavaScript-Datei nötig sind. Erstellen Sie also eine HTML-Grundgerüstdatei mit den folgenden Elementen innerhalb des body-Tags:
<button id="button_event" onclick="runScript()">Generate</button>
<p id="status" role="status"></p>
<div data-screenreaderlanguage="en-US">
<p>Sample Text</p>
</div>
<script src="index.js"></script>
Damit steht das UI-Element unserer Anwendung. Der Button, den wir erstellt haben, löst unsere Assembly-Anfrage für /text/speak aus und verwendet dafür den Text innerhalb unseres div-Tags. Um auf dieses div-Tag zu verweisen, weisen wir ihm einen Dataset-Wert zu, den der Back-End-Entwickler außerdem nutzt, um für den Robot die angegebene Zielsprache anhand der Optionen auszuwählen, die in unserer Dokumentation aufgeführt sind. Zum Schluss binden wir unsere JavaScript-Datei am Ende des body ein.
Für die Anbindung an die Transloadit-API verwenden wir Robodog, eine abgespeckte Version unseres kostenlosen Dateiuploaders Uppy.
Hinweis: Robodog ist veraltet. Verwenden Sie für neue Integrationen das Transloadit-Plugin von Uppy (Dashboard-UI oder eine eigene UI).
Fügen Sie im Header Ihrer HTML-Seite die folgende Zeile ein:
<script src="https://releases.transloadit.com/uppy/robodog/v1.10.7/robodog.min.js"></script>
JavaScript
Fügen Sie die folgenden JavaScript-Snippets der Reihe nach in index.js zusammen. Die Snippets
teilen ein einziges Programm auf mehrere Erklärungen auf; es handelt sich nicht um separate Module.
Das historische Robodog-Bundle ist unten fest eingebunden; die Live-Demo oben verwendet das
gepflegte Transloadit-Plugin von Uppy.
Verwenden Sie nur öffentlichen Text, für dessen Übermittlung die Nutzer ihre Zustimmung gegeben haben. Erzeugen Sie für den Produktivbetrieb kurzlebige signierte Parameter auf Ihrem Server mithilfe der Signature Authentication, beschränken Sie die zulässigen Instructions und die Eingabegröße und geben Sie ein Auth Secret niemals im Browser-Code preis.
Unseren Text auslesen
In unserer JavaScript-Datei können wir nun mit dem Schreiben unseres Programms beginnen. Als Erstes müssen wir den lesbaren Text unserer Website auslesen und ihn für die spätere Verwendung einer Variablen zuweisen.
// …
const result = document.querySelectorAll('[data-screenreaderlanguage]')
const textArray = []
for (const element of result) textArray.push(element.innerText)
const language = document.querySelector('[data-screenreaderlanguage]').dataset.screenreaderlanguage
// …
In diesem Code verwenden wir die Methode Document.querySelectorAll(), um ein Array mit allen
Informationselementen zu erstellen, die mit dem Dataset screenreaderlanguage verknüpft sind. Wir
verwenden ein Dataset, damit wir, wenn wir lesbaren Text von der Ausgabe unseres Screenreaders
ausschließen möchten (etwa Text innerhalb eines Tags wie <code>), unser div-Tag vor diesem
unerwünschten Text schließen und dort, wo unser Screenreader die Textverarbeitung fortsetzen soll,
ein neues div-Tag unter demselben Dataset erstellen können.
Nachdem diese Basisinformationen gesammelt sind, müssen wir noch den lesbaren Text aus unseren
gesammelten Daten auslesen. Zuerst initialisieren wir daher eine Array-Variable zum Speichern
unseres lesbaren Textes, bevor wir mit der Schleife
for...of jedes ausgewählte Element durchgehen und seinen
innerText-Wert speichern.
Zum Abschluss dieses Abschnitts legen wir eine Sprachvariable fest, damit unser
Robot /text/speak später in unserem Programm
unsere Zielsprache kennt. Dazu deklarieren wir unsere Sprachvariable mit dem Wert screenreaderlanguage
aus unserem Dataset.
Für Uppy aufbereiten
Da unsere Daten nun bereitstehen, müssen wir sie so aufbereiten, dass unsere Robodog-Instanz sie verarbeiten kann.
// …
const mytextfile = new File([textArray.join('\n\n')], 'mytextfile.txt', { type: 'text/plain' })
// …
Damit wird eine Textdatei mit Absatzumbrüchen zwischen den gesammelten Textblöcken erzeugt. Markieren Sie nur Inhalte in derselben Sprache; das Beispiel liest die Sprache des ersten markierten Blocks aus.
Ladeanimation
Damit Nutzer merken, dass gerade verarbeitet wird, soll eine Ladeanimation laufen, während unser Robot /text/speak arbeitet. Dazu brauchen wir einige Platzhaltervariablen, um unser Button-Element durch ein GIF zu ersetzen. Wenn unsere Textverarbeitung erfolgreich ist, ersetzen wir dieses GIF-Element anschließend durch einen Audioplayer.
// …
const buttonEl = document.getElementById('button_event')
const statusEl = document.getElementById('status')
const tmpGif = document.createElement('img')
const audioPlayer = document.createElement('AUDIO')
tmpGif.src = 'loader.gif'
tmpGif.width = 100
tmpGif.height = 100
tmpGif.id = 'tmpGif'
tmpGif.alt = 'Generating speech'
// …
Hier haben wir drei Variablen deklariert, um Elemente unseres HTML-Dokuments zu speichern; die
erste Variable, buttonEl, verweist auf ein vorhandenes Element, während die beiden anderen
Variablen neue Elemente erzeugen. Darunter weisen wir unserem ersetzenden GIF-Element mehrere
Attribute zu. Schließlich legen wir eine Quell-GIF-Datei aus unserem Arbeitsverzeichnis fest,
setzen die Abmessungen und vergeben eine ID, auf die wir uns später in unserem Programm beziehen.
Auslösendes Skript
Da diese vorbereitenden Steps nun erledigt sind, können wir die Hauptfunktionalität unseres Programms einbauen. Definieren wir den Click-Handler für den Button Generate.
Deklarieren Sie zu Beginn eine Funktion mit demselben Namen wie die Funktion, auf die wir zuvor in unserer HTML-Seite verwiesen haben.
// …
function runScript() {
if (!buttonEl.isConnected) return
statusEl.textContent = 'Generating speech.'
buttonEl.parentNode.replaceChild(tmpGif, buttonEl)
// …
Nachdem unsere Funktion eingerichtet ist, können wir unsere erste Methode zur DOM-Manipulation
nutzen, parentNode.replaceChild(). Sie ersetzt den Button unserer Seite durch das neue GIF-Element, sobald unsere
Funktion ausgeführt wird.
Da das GIF nun eingebunden ist und signalisiert, dass Daten verarbeitet werden, können wir die Transloadit-API nutzen, um die Sprache für unser Programm zu synthetisieren. Dafür verwenden wir das Robodog-Skript, das wir in unsere HTML-Datei importiert haben.
// …
window.Robodog.upload([mytextfile], {
waitForEncoding: true,
params: {
auth: { key: 'TRANSLOADIT_AUTH_KEY' },
steps: {
':original': {
robot: '/upload/handle',
},
speech: {
use: ':original',
robot: '/text/speak',
provider: 'aws',
target_language: language,
},
},
},
})
// …
In unserer neuen Robodog-Instanz müssen wir zwei Parameter einrichten. Der erste ist für unsere hochgeladene Datei, die wir als die Textdatei-Variable deklarieren, die wir zuvor in unserem Programm erstellt haben. Der andere Parameter ist ein Objekt, das alle weiteren zusätzlichen Optionen enthält.
In unserem Objektparameter müssen wir einige Steps einrichten. Zuerst muss waitForEncoding
auf true gesetzt werden, damit wir unsere Assembly-Ergebnisse später in unserem
Programm abrufen können. Als Nächstes müssen wir außerdem unseren Authentifizierungsschlüssel in
den Parameter auth eintragen. Diesen Schlüssel finden Sie in Ihrer Transloadit-Konsole im
Tab „Zugangsdaten“. Zuletzt müssen wir unsere Steps für das
Template einfügen: einen für den Upload und einen für die Sprachsynthese.
Der Step für die Sprachsynthese besteht aus einigen Parametern. Zuerst müssen wir diesem
Step mitteilen, dass wir die hochgeladene Textdatei verwenden wollen; das erreichen wir
mit dem Parameter "use". Als Nächstes müssen wir mit dem Parameter "robot" angeben, dass
unser Robot /text/speak verwendet werden soll. Mit dem
folgenden Parameter "provider" legen wir die Backend-API für die Sprachsynthese fest. Die
verfügbaren Werte sind „gcp“ und „aws“. Jeder Anbieter bietet eine Vielzahl unterschiedlicher
Stimmen, wir bleiben hier jedoch bei der Standardeinstellung. Der letzte Parameter, den wir
verwenden, "target_language", teilt unserer API mit, in welcher Sprache unser Text ausgesprochen werden
soll. Dieser Wert stammt aus der Variablen language, die wir zu Beginn unseres Programms
eingerichtet haben.
Sobald diese Funktionalität steht, verwenden wir die Methode then() von JavaScript, um ein
Promise mit unseren Sprachdaten zurückzugeben, auf das wir uns später beziehen können.
Das Ergebnis verwenden
Da Robodog nun vollständig eingerichtet ist, können wir die erzeugte Sprachausgabe speichern, um sie später im Browser abzuspielen.
// …
.then((bundle) => {
const audio_url = bundle.results?.find((result) => result.stepName === 'speech')?.ssl_url
if (!audio_url) throw new Error('No speech result returned')
audioPlayer.setAttribute('src', audio_url)
audioPlayer.setAttribute('controls', 'controls')
audioPlayer.setAttribute('aria-label', 'Generated speech')
audioPlayer.setAttribute('lang', language)
audioPlayer.setAttribute('style', 'width: 100%;')
tmpGif.parentNode.replaceChild(audioPlayer, tmpGif)
statusEl.textContent = 'Speech is ready. Use the audio controls to play it.'
})
// …
In unserer Methode then() können wir mithilfe des von Robodog bereitgestellten Promise die
JSON-Ergebnisse der Assembly auslesen und die Ergebnis-URL in einer neuen Variablen
speichern. Mit dieser neuen Variablen, audio_url, können wir dieselbe Methode zum Ersetzen von
Elementen verwenden, die wir zuvor in dieser Vorstellung genutzt haben. Um den Audioplayer
anschließend zum Laufen zu bringen, setzen wir einige Attribute, die die Quelle des Audios angeben
und die Wiedergabesteuerung sichtbar machen. Die Wiedergabe wird von der nutzenden Person gestartet
und hängt daher nicht von einer Autoplay-Berechtigung ab. Damit ist nun ein Text-to-Speech-Player
erzeugt und in Ihre Website integriert!
Eine Absicherung dürfen wir aber nicht vergessen. Hier verwenden wir die Methode catch() von
JavaScript, um eventuelle Fehler zu behandeln.
// …
.catch(() => {
statusEl.textContent = 'Could not generate speech. Please try again.'
tmpGif.parentNode.replaceChild(buttonEl, tmpGif)
})
}
// …
Fehler erzeugen einen lesbaren Status, und unser Verarbeitungs-GIF wird wieder durch das ursprüngliche Button-Element ersetzt. Das bedeutet: Wenn Sie kurzzeitig die Netzwerkverbindung verlieren und sie danach wiedererlangen, können Sie auf den Button Generate klicken, damit die Sprachgenerierung erneut abläuft.
Und damit endet diese Vorstellung! Wir hoffen, Sie stimmen uns zu, dass sie die schiere Vielseitigkeit unserer API einmal mehr gezeigt hat. Natürlich können Sie das Programm, das wir erstellt haben, einfach zu jeder beliebigen Website hinzufügen und erhalten so schnell und unkompliziert einen Screenreader – aber hören Sie damit nicht auf! Nutzen Sie diesen Beitrag stattdessen als Bausteine, um Ihre eigenen Projekte zu erweitern, und erzählen Sie uns unbedingt von den Ergebnissen :) Unser Robot /text/speak steht allen unseren zahlenden Kunden zur Verfügung; wenn dieser Beitrag für Sie interessant war, sollten Sie daher ein Upgrade Ihres Kontos in Erwägung ziehen. Unser erster kostenpflichtiger Tarif beginnt bei 49 $/Monat mit 10 GB Encoding-Daten!