Sprache in Dokumenten mit Ruby synthetisieren
Die Umwandlung von Textdokumenten in Sprache kann die Barrierefreiheit verbessern und Nutzern neue Möglichkeiten bieten, sich mit Ihren Inhalten zu befassen. In diesem DevTip zeigen wir, wie Sie Sprache in Dokumenten mit Ruby und der Google Cloud Text-to-Speech-Bibliothek synthetisieren, samt praktischen Beispielen und bewährten Verfahren.
Google Cloud Text-to-Speech einrichten
Google Cloud Text-to-Speech bietet hochwertige Stimmen, umfangreiche Sprachunterstützung und eine nahtlose Integration. Verwenden Sie Ruby 3.2 oder neuer, aktivieren Sie die Text-to-Speech-API und die Abrechnung in Ihrem Google-Cloud-Projekt und fügen Sie dann diese Abhängigkeiten zu Ihrem Gemfile hinzu:
gem 'google-cloud-text_to_speech', '2.2.0'
gem 'nokogiri', '1.19.4'
Installieren Sie das Bundle und committen Sie dessen Lockfile, damit der getestete Abhängigkeitsgraph reproduzierbar bleibt:
bundle install
Verwenden Sie Application Default Credentials. Für die lokale Entwicklung kann die Google Cloud CLI Zugangsdaten für die Entwicklung erstellen:
gcloud auth application-default login
Ziehen Sie bei gehosteten Workloads eine angehängte Dienstidentität einem heruntergeladenen, langlebigen Schlüssel vor. Committen Sie niemals Zugangsdaten und nehmen Sie keinen Dokumenttext in Diagnoseprotokolle auf. Tatsächliche Syntheseanfragen verwenden das konfigurierte Konto und können Kosten verursachen.
Einfaches Skript zur Dokumentvertonung
Speichern Sie diese Klasse als document_narrator.rb. Sie unterstützt UTF-8-Klartext und
HTML-Dokumente, begrenzt die Größe der Quelldatei, entfernt nicht inhaltstragende HTML-Elemente und
prüft den extrahierten Text gegen das Inhaltslimit von 5.000 Byte der Standard-Synthese-API. Das
Limit bezieht sich auf Bytes, nicht auf Zeichen.
require "google/cloud/text_to_speech"
require "nokogiri"
require "tempfile"
class DocumentNarrator
def initialize(client: Google::Cloud::TextToSpeech.text_to_speech)
@client = client
end
def narrate_text(text, output_path, language_code: "en-US")
unless text.is_a?(String) && text.encoding == Encoding::UTF_8 && text.valid_encoding?
raise ArgumentError, "Text must be valid UTF-8"
end
raise ArgumentError, "Text cannot be empty" if text.strip.empty?
raise ArgumentError, "Text exceeds 5,000 bytes" if text.bytesize > 5000
if File.exist?(output_path) || File.symlink?(output_path)
raise ArgumentError, "Output must not exist"
end
input = { text: text }
voice = { language_code: language_code, ssml_gender: :FEMALE }
audio_config = { audio_encoding: :MP3, speaking_rate: 1.0, pitch: 0.0 }
# Create the candidate on the destination filesystem before making a paid request.
Tempfile.create([".narration-", ".mp3"], File.dirname(output_path)) do |file|
file.binmode
response = @client.synthesize_speech(
input: input, voice: voice, audio_config: audio_config
)
raise IOError, "Synthesis returned empty audio" if response.audio_content.empty?
file.write(response.audio_content)
file.flush
# Publication must not replace a file created while synthesis was running.
File.link(file.path, output_path)
end
end
def narrate_file(input_path, output_path, language_code: "en-US")
text = extract_text(input_path)
narrate_text(text, output_path, language_code: language_code)
end
private
def extract_text(file_path)
raise ArgumentError, "Input must be a regular file" unless File.file?(file_path)
source = File.binread(file_path, 1024 * 1024 + 1)
raise ArgumentError, "Source exceeds 1 MiB" if source.bytesize > 1024 * 1024
source.force_encoding(Encoding::UTF_8)
raise ArgumentError, "Source must be valid UTF-8" unless source.valid_encoding?
case File.extname(file_path).downcase
when ".txt"
source
when ".html", ".htm"
doc = Nokogiri::HTML5(source)
doc.css("script, style, template, noscript").remove
doc.at_css("body").xpath(".//text()").map(&:text).join(" ").strip
else
raise ArgumentError, "Unsupported file format"
end
end
end
Erweiterte Funktionen und Fehlerbehandlung
Behalten Sie eine einzige Implementierung von DocumentNarrator bei und bauen Sie ein
kleines CLI darum herum. Speichern Sie das Folgende als narrate.rb im selben
Verzeichnis. Es beendet sich mit einem Fehlerstatus bei ungültiger Eingabe, einem Fehler des
Anbieters oder einer Kollision der Ausgabe, ohne Anbieterfehler mit Zugangsdaten oder Dokumenttext
auszugeben.
require_relative "document_narrator"
unless (2..3).cover?(ARGV.length)
abort "Usage: bundle exec ruby narrate.rb <input.txt|input.html> <new-output.mp3> [language-code]"
end
begin
DocumentNarrator.new.narrate_file(ARGV[0], ARGV[1], language_code: ARGV[2] || "en-US")
puts "Narration saved"
rescue StandardError
warn "Narration failed. Check the input, destination, credentials, and provider configuration."
exit 1
end
Führen Sie bundle exec ruby narrate.rb document.html narration.mp3 en-US aus. Wählen Sie einen Sprachcode, der zu Ihrem Dokument
passt, und eine vom Anbieter unterstützte Stimmkonfiguration. Die Stimmeinstellung übersetzt die
Eingabe nicht. Die HTML-Extraktion ist hier bewusst einfach gehalten; sie bildet weder das
Browser-Layout noch die CSS-Sichtbarkeit oder die barrierefreie Lesereihenfolge nach. Prüfen Sie den
extrahierten Inhalt vor der Vertonung.
Bewährte Verfahren für die Sprachsynthese
Beachten Sie diese bewährten Verfahren, wenn Sie Text-to-Speech-Funktionalität implementieren:
-
Textvorverarbeitung:
- Teilen Sie langen Text an Satzgrenzen auf und prüfen Sie die UTF-8-Bytegröße jeder Anfrage.
- Halten Sie sich an die aktuellen Inhaltslimits.
- Entfernen Sie unnötige Leerzeichen und Sonderzeichen.
- Schreiben Sie Abkürzungen und Zahlen aus, um die Aussprache zu verbessern.
-
Stimmkonfiguration:
- Wählen Sie die passende Sprache und Stimme für Ihre Inhalte.
- Passen Sie Sprechgeschwindigkeit und Tonhöhe an, damit das Audio natürlich klingt.
- Nutzen Sie SSML-Markup für feingranulare Kontrolle, einschließlich Pausen und Betonungen.
-
Performance-Optimierung:
- Implementieren Sie Caching, um redundante API-Aufrufe zu reduzieren.
- Nutzen Sie Batch-Verarbeitung für große Dokumente, um die Effizienz zu steigern.
- Nutzen Sie den dokumentierten Long-Audio-Workflow des Anbieters für Material, das die synchronen Limits überschreitet.
-
Sicherheitsaspekte:
- Speichern und verwalten Sie Ihre API-Zugangsdaten sicher.
- Implementieren Sie Rate Limiting und Eingabevalidierung, um Missbrauch zu verhindern.
- Überwachen Sie die API-Nutzung und richten Sie Benachrichtigungen ein, um die Kosten zu kontrollieren.
Alternative Lösungen
Google Cloud Text-to-Speech ist zwar eine robuste Lösung, dennoch kommen auch andere Optionen infrage:
- Das Ruby-SDK von Amazon Polly bietet einen eigenen Client. Seine Regeln für Stimme, Engine und Inhaltslimits unterscheiden sich von denen bei Google.
- Die Text-to-Speech-REST-API von Azure lässt sich aus Ruby heraus aufrufen. Gehen Sie nicht davon aus, dass ein SDK für eine andere Sprache ein Ruby-Äquivalent hat; halten Sie sich an die REST-Verträge für Authentifizierung, SSML, Ausgabeformat, Timeout und HTTP-Fehler.
- Selbst gehostete Sprachmodelle können die Dokumentenverarbeitung in Ihrer eigenen Infrastruktur halten. Prüfen Sie Lizenzierung und Wartung der Modelle, planen Sie Worker-Ressourcen ein und nutzen Sie die dokumentierte HTTP-API des gewählten Servers, statt anzunehmen, dass alle TTS-Server dieselbe JSON-Nutzlast akzeptieren.
Fazit
Moderne Text-to-Speech-Lösungen ermöglichen es Ihnen, mit Ruby ansprechende, barrierefreie Audioinhalte aus Dokumenten zu erstellen. Google Cloud Text-to-Speech bietet ebenso wie andere Alternativen hochwertige Stimmen und Unterstützung für mehrere Sprachen. Für verwaltete Sprachsynthese siehe den Text to Speech Robot von Transloadit.
