Jak zrobić edytor syntezy mowy

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ Asystenci głosowi są w drodze do domów, nadgarstków i kieszeni. Oznacza to, że niektóre z naszych treści będą wypowiadane na głos za pomocą cyfrowej syntezy mowy. W tym samouczku dowiesz się, jak stworzyć edytor „What You Get Is What You Hear” (WYGIWYH) do syntezy mowy przy użyciu edytora Sanity.io dla Portable Text.

Kiedy Steve Jobs zaprezentował Macintosha w 1984 roku, powiedział nam „Cześć” ze sceny. Nawet w tym momencie synteza mowy nie była tak naprawdę nową technologią: Bell Labs opracował wokoder już pod koniec lat 30., a koncepcja komputera z asystentem głosowym weszła do świadomości ludzi, gdy Stanley Kubrick uczynił wokoder głosem HAL9000 w 2001: Odyseja kosmiczna (1968).

Dopiero wprowadzenie Siri, Amazon Echo i Asystenta Google firmy Apple w połowie 2015 roku sprawiło, że interfejsy głosowe trafiły do ​​domów, nadgarstków i kieszeni szerszej publiczności. Nadal jesteśmy w fazie adopcji, ale wydaje się, że ci asystenci głosowi zostaną tutaj.

Innymi słowy, sieć nie jest już tylko pasywnym tekstem na ekranie . Redaktorzy stron internetowych i projektanci UX muszą przyzwyczaić się do tworzenia treści i usług, o których należy mówić głośno.

Już teraz szybko zmierzamy w kierunku korzystania z systemów zarządzania treścią, które pozwalają nam pracować z naszymi treściami bez głowy i za pośrednictwem interfejsów API. Ostatnim elementem jest stworzenie interfejsów redakcyjnych, które ułatwią dostosowywanie treści do głosu. Więc zróbmy właśnie to!

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Co to jest SSML

Podczas gdy przeglądarki internetowe używają specyfikacji W3C dla HyperText Markup Language (HTML) do wizualnego renderowania dokumentów, większość asystentów głosowych używa języka syntezy mowy (SSML) podczas generowania mowy.

Minimalny przykład wykorzystujący element główny <speak> oraz znaczniki akapitu ( <p> ) i zdania ( <s> ):

 <speak> <p> <s>This is the first sentence of the paragraph.</s> <s>Here's another sentence.</s> </p> </speak>
Naciśnij Odtwórz, aby posłuchać fragmentu:

SSML zaczyna istnieć, gdy wprowadzamy tagi dla <emphasis> i <prosody> (pitch):

 <speak> <p> <s>Put some <emphasis strength="strong">extra weight on these words</emphasis></s> <s>And say <prosody pitch="high" rate="fast">this a bit higher and faster</prosody>!</s> </p> </speak>
Naciśnij Odtwórz, aby posłuchać fragmentu:

SSML ma więcej funkcji, ale to wystarczy, aby poznać podstawy. Teraz przyjrzyjmy się bliżej edytorowi, którego użyjemy do stworzenia interfejsu edycji syntezy mowy.

Edytor przenośnego tekstu

Aby stworzyć ten edytor, użyjemy edytora Portable Text, który jest dostępny w Sanity.io. Portable Text to specyfikacja JSON do edycji tekstu sformatowanego, którą można serializować do dowolnego języka znaczników, takiego jak SSML. Oznacza to, że możesz z łatwością używać tego samego fragmentu tekstu w wielu miejscach, używając różnych języków znaczników.

Domyślny edytor Sanity.io dla przenośnego tekstu
Domyślny edytor Sanity.io dla przenośnego tekstu (duży podgląd)

Instalowanie Poczytalności

Sanity.io to platforma dla ustrukturyzowanych treści, która jest dostarczana ze środowiskiem edycji open source zbudowanym za pomocą React.js. Rozpoczęcie pracy zajmuje dwie minuty.

Wpisz npm i -g @sanity/cli && sanity init w swoim terminalu i postępuj zgodnie z instrukcjami. Wybierz „pusty”, gdy pojawi się monit o szablon projektu.

Jeśli nie chcesz śledzić tego samouczka i tworzyć tego edytora od zera, możesz również sklonować kod tego samouczka i postępować zgodnie z instrukcjami w README.md .

Po pobraniu edytora uruchamiasz program sanity start w folderze projektu, aby go uruchomić. Uruchomi serwer programistyczny, który używa funkcji Hot Module Reloading do aktualizacji zmian podczas edytowania jego plików.

Jak skonfigurować schematy w Sanity Studio

Tworzenie plików edytora

Zaczniemy od utworzenia folderu o nazwie ssml-editor w folderze /schemas . W tym folderze umieścimy kilka pustych plików:

 /ssml-tutorial/schemas/ssml-editor ├── alias.js ├── emphasis.js ├── annotations.js ├── preview.js ├── prosody.js ├── sayAs.js ├── blocksToSSML.js ├── speech.js ├── SSMLeditor.css └── SSMLeditor.js

Teraz możemy dodać schematy treści w tych plikach. Schematy treści definiują strukturę danych dla tekstu sformatowanego oraz to, czego Sanity Studio używa do generowania interfejsu redakcyjnego. Są to proste obiekty JavaScript, które w większości wymagają tylko name i type .

Możemy również dodać title i description , aby uatrakcyjnić redaktorom. Na przykład jest to schemat prostego pola tekstowego dla title :

 export default { name: 'title', type: 'string', title: 'Title', description: 'Titles should be short and descriptive' } 
Sanity Studio z polem tytułowym i edytorem Portable Text
Studio z naszym polem tytułowym i domyślnym edytorem (duży podgląd)

Portable Text opiera się na idei tekstu sformatowanego jako danych. Jest to potężne, ponieważ umożliwia wysyłanie zapytań do tekstu sformatowanego i konwertowanie go na praktycznie dowolny znacznik.

Jest to zbiór obiektów zwanych „blokami”, o których można myśleć jako o „akapitach”. W bloku znajduje się tablica przęseł potomnych. Każdy blok może mieć styl i zestaw definicji znaczników, które opisują struktury danych rozmieszczone w rozpiętościach potomnych.

Sanity.io jest dostarczany z edytorem, który może czytać i zapisywać tekst przenośny, i jest aktywowany przez umieszczenie typu block w polu array , w następujący sposób:

 // speech.js export default { name: 'speech', type: 'array', title: 'SSML Editor', of: [ { type: 'block' } ] }

Tablica może być wielu typów. W przypadku edytora SSML mogą to być bloki dla plików audio, ale wykracza to poza zakres tego samouczka.

Ostatnią rzeczą, jaką chcemy zrobić, jest dodanie typu zawartości, w którym ten edytor może być używany. Większość asystentów korzysta z prostego modelu treści „zamiarów” i „spełnień”:

  • Intencje
    Zwykle lista ciągów używanych przez model AI do wytyczenia tego, co użytkownik chce zrobić.
  • Spełnienia
    Dzieje się tak, gdy zostanie zidentyfikowany „zamiar”. Spełnienie często wiąże się – a przynajmniej – z jakąś odpowiedzią.

Stwórzmy więc prosty typ treści zwany fulfillment , który korzysta z edytora syntezy mowy. Utwórz nowy plik o nazwie wypełnienie.js i zapisz go w folderze /schema :

 // fulfillment.js export default { name: 'fulfillment', type: 'document', title: 'Fulfillment', of: [ { name: 'title', type: 'string', title: 'Title', description: 'Titles should be short and descriptive' }, { name: 'response', type: 'speech' } ] }

Zapisz plik i otwórz schema.js . Dodaj go do swojego studia w ten sposób:

 // schema.js import createSchema from 'part:@sanity/base/schema-creator' import schemaTypes from 'all:part:@sanity/base/schema-type' import fullfillment from './fullfillment' import speech from './speech' export default createSchema({ name: 'default', types: schemaTypes.concat([ fullfillment, speech, ]) })

Jeśli teraz uruchomisz sanity start w interfejsie wiersza poleceń w folderze głównym projektu, studio uruchomi się lokalnie i będziesz mógł dodawać wpisy dotyczące realizacji. Możesz utrzymać studio uruchomione, gdy będziemy kontynuować, ponieważ zostanie ono automatycznie ponownie załadowane z nowymi zmianami, gdy zapiszesz pliki.

Dodawanie SSML do edytora

Domyślnie typ block zapewnia standardowy edytor zorientowanego wizualnie tekstu sformatowanego ze stylami nagłówków, stylami dekoratorów dla podkreślenia i wzmocnienia, adnotacjami dla linków i listami. Teraz chcemy zastąpić te z koncepcjami dźwiękowymi znalezionymi w SSML.

Zaczynamy od zdefiniowania różnych struktur treści, z pomocnymi opisami dla edytorów, które dodamy do block w SSMLeditorSchema.js jako konfiguracje dla annotations . Są to „podkreślenie”, „alias”, „prozodia” i „powiedz jak”.

Podkreślenie

Zaczynamy od „podkreślenia”, które kontroluje wagę zaznaczonego tekstu. Definiujemy go jako string z listą predefiniowanych wartości, z których użytkownik może wybrać:

 // emphasis.js export default { name: 'emphasis', type: 'object', title: 'Emphasis', description: 'The strength of the emphasis put on the contained text', fields: [ { name: 'level', type: 'string', options: { list: [ { value: 'strong', title: 'Strong' }, { value: 'moderate', title: 'Moderate' }, { value: 'none', title: 'None' }, { value: 'reduced', title: 'Reduced' } ] } } ] }

Alias

Czasami pisemny i mówiony termin różnią się. Na przykład chcesz użyć skrótu frazy w tekście pisanym, ale całą frazę przeczytać na głos. Na przykład:

 <s>This is a <sub alias="Speech Synthesis Markup Language">SSML</sub> tutorial</s>
Naciśnij Odtwórz, aby posłuchać fragmentu:

Pole wejściowe dla aliasu to prosty ciąg:

 // alias.js export default { name: 'alias', type: 'object', title: 'Alias (sub)', description: 'Replaces the contained text for pronunciation. This allows a document to contain both a spoken and written form.', fields: [ { name: 'text', type: 'string', title: 'Replacement text', } ] }

Prozodia

Dzięki właściwości prozodii możemy kontrolować różne aspekty wypowiadania tekstu, takie jak wysokość, szybkość i głośność. Znacznik tego może wyglądać tak:

 <s>Say this with an <prosody pitch="x-low">extra low pitch</prosody>, and this <prosody rate="fast" volume="loud">loudly with a fast rate</prosody></s>
Naciśnij Odtwórz, aby posłuchać fragmentu:

To wejście będzie miało trzy pola z predefiniowanymi opcjami ciągu:

 // prosody.js export default { name: 'prosody', type: 'object', title: 'Prosody', description: 'Control of the pitch, speaking rate, and volume', fields: [ { name: 'pitch', type: 'string', title: 'Pitch', description: 'The baseline pitch for the contained text', options: { list: [ { value: 'x-low', title: 'Extra low' }, { value: 'low', title: 'Low' }, { value: 'medium', title: 'Medium' }, { value: 'high', title: 'High' }, { value: 'x-high', title: 'Extra high' }, { value: 'default', title: 'Default' } ] } }, { name: 'rate', type: 'string', title: 'Rate', description: 'A change in the speaking rate for the contained text', options: { list: [ { value: 'x-slow', title: 'Extra slow' }, { value: 'slow', title: 'Slow' }, { value: 'medium', title: 'Medium' }, { value: 'fast', title: 'Fast' }, { value: 'x-fast', title: 'Extra fast' }, { value: 'default', title: 'Default' } ] } }, { name: 'volume', type: 'string', title: 'Volume', description: 'The volume for the contained text.', options: { list: [ { value: 'silent', title: 'Silent' }, { value: 'x-soft', title: 'Extra soft' }, { value: 'medium', title: 'Medium' }, { value: 'loud', title: 'Loud' }, { value: 'x-loud', title: 'Extra loud' }, { value: 'default', title: 'Default' } ] } } ] }

Powiedz jako

Ostatnią, którą chcemy uwzględnić, jest <say-as> . Ten tag pozwala nam sprawować nieco większą kontrolę nad wymawianiem niektórych informacji. Możemy go nawet użyć do wygaszenia słów, jeśli musisz coś zredagować w interfejsach głosowych. To @!%& przydatne!

 <s>Do I have to <say-as interpret-as="expletive">frakking</say-as> <say-as interpret-as="verbatim">spell</say-as> it out for you!?</s>
Naciśnij Odtwórz, aby posłuchać fragmentu:
 // sayAs.js export default { name: 'sayAs', type: 'object', title: 'Say as...', description: 'Lets you indicate information about the type of text construct that is contained within the element. It also helps specify the level of detail for rendering the contained text.', fields: [ { name: 'interpretAs', type: 'string', title: 'Interpret as...', options: { list: [ { value: 'cardinal', title: 'Cardinal numbers' }, { value: 'ordinal', title: 'Ordinal numbers (1st, 2nd, 3th...)' }, { value: 'characters', title: 'Spell out characters' }, { value: 'fraction', title: 'Say numbers as fractions' }, { value: 'expletive', title: 'Blip out this word' }, { value: 'unit', title: 'Adapt unit to singular or plural' }, { value: 'verbatim', title: 'Spell out letter by letter (verbatim)' }, { value: 'date', title: 'Say as a date' }, { value: 'telephone', title: 'Say as a telephone number' } ] } }, { name: 'date', type: 'object', title: 'Date', fields: [ { name: 'format', type: 'string', description: 'The format attribute is a sequence of date field character codes. Supported field character codes in format are {y, m, d} for year, month, and day (of the month) respectively. If the field code appears once for year, month, or day then the number of digits expected are 4, 2, and 2 respectively. If the field code is repeated then the number of expected digits is the number of times the code is repeated. Fields in the date text may be separated by punctuation and/or spaces.' }, { name: 'detail', type: 'number', validation: Rule => Rule.required() .min(0) .max(2), description: 'The detail attribute controls the spoken form of the date. For detail='1' only the day fields and one of month or year fields are required, although both may be supplied' } ] } ] }

Teraz możemy je zaimportować do pliku annotations.js , dzięki czemu wszystko jest nieco bardziej uporządkowane.

 // annotations.js export {default as alias} from './alias' export {default as emphasis} from './emphasis' export {default as prosody} from './prosody' export {default as sayAs} from './sayAs'

Teraz możemy zaimportować te typy adnotacji do naszych głównych schematów:

 // schema.js import createSchema from "part:@sanity/base/schema-creator" import schemaTypes from "all:part:@sanity/base/schema-type" import fulfillment from './fulfillment' import speech from './ssml-editor/speech' import { alias, emphasis, prosody, sayAs } from './annotations' export default createSchema({ name: "default", types: schemaTypes.concat([ fulfillment, speech, alias, emphasis, prosody, sayAs ]) })

Na koniec możemy teraz dodać je do edytora w ten sposób:

 // speech.js export default { name: 'speech', type: 'array', title: 'SSML Editor', of: [ { type: 'block', styles: [], lists: [], marks: { decorators: [], annotations: [ {type: 'alias'}, {type: 'emphasis'}, {type: 'prosody'}, {type: 'sayAs'} ] } } ] }

Zauważ, że dodaliśmy także puste tablice do styles i decorators . Powoduje to wyłączenie domyślnych stylów i dekoratorów (takich jak pogrubienie i podkreślenie), ponieważ w tym konkretnym przypadku nie mają one większego sensu.

Dostosowywanie wyglądu i odczucia

Teraz mamy tę funkcjonalność, ale ponieważ nie określiliśmy żadnych ikon, każda adnotacja będzie używać domyślnej ikony, co sprawia, że ​​edytor jest trudny w użyciu dla autorów. Więc naprawmy to!

Za pomocą edytora Portable Text można wstrzykiwać komponenty React zarówno dla ikon, jak i sposobu renderowania zaznaczonego tekstu. Tutaj po prostu pozwolimy, aby niektóre emoji wykonały za nas pracę, ale oczywiście możesz posunąć się z tym daleko, czyniąc je dynamicznymi i tak dalej. W przypadku prosody zmienimy nawet ikonę w zależności od wybranej głośności. Zauważ, że pominąłem pola w tych fragmentach dla zwięzłości, nie powinieneś ich usuwać z plików lokalnych.

 // alias.js import React from 'react' export default { name: 'alias', type: 'object', title: 'Alias (sub)', description: 'Replaces the contained text for pronunciation. This allows a document to contain both a spoken and written form.', fields: [ /* all the fields */ ], blockEditor: { icon: () => '', render: ({ children }) => <span>{children} </span>, }, };
 // emphasis.js import React from 'react' export default { name: 'emphasis', type: 'object', title: 'Emphasis', description: 'The strength of the emphasis put on the contained text', fields: [ /* all the fields */ ], blockEditor: { icon: () => '', render: ({ children }) => <span>{children} </span>, }, };
 // prosody.js import React from 'react' export default { name: 'prosody', type: 'object', title: 'Prosody', description: 'Control of the pitch, speaking rate, and volume', fields: [ /* all the fields */ ], blockEditor: { icon: () => '', render: ({ children, volume }) => ( <span> {children} {['x-loud', 'loud'].includes(volume) ? '' : ''} </span> ), }, };
 // sayAs.js import React from 'react' export default { name: 'sayAs', type: 'object', title: 'Say as...', description: 'Lets you indicate information about the type of text construct that is contained within the element. It also helps specify the level of detail for rendering the contained text.', fields: [ /* all the fields */ ], blockEditor: { icon: () => '', render: props => <span>{props.children} </span>, }, }; 
Dostosowany edytor SSML
Edytor z naszymi niestandardowymi znakami SSML (duży podgląd)

Teraz masz edytor do edycji tekstu, z którego mogą korzystać asystenci głosowi. Ale czy nie byłoby przydatne, gdyby redaktorzy mogli również podejrzeć, jak faktycznie będzie brzmiał tekst?

Dodawanie przycisku podglądu za pomocą funkcji zamiany tekstu na mowę firmy Google

Obsługa natywnej syntezy mowy jest już w drodze dla przeglądarek. Ale w tym samouczku użyjemy Google Text-to-Speech API, który obsługuje SSML. Budowanie tej funkcji w wersji zapoznawczej będzie również demonstracją sposobu serializacji przenośnego tekstu do formatu SSML w dowolnej usłudze, w której chcesz tego użyć.

Zawijanie edytora w komponent React

Zaczynamy od otwarcia pliku SSMLeditor.js i dodania następującego kodu:

 // SSMLeditor.js import React, { Fragment } from 'react'; import { BlockEditor } from 'part:@sanity/form-builder'; export default function SSMLeditor(props) { return ( <Fragment> <BlockEditor {...props} /> </Fragment> ); }

Otoczyliśmy edytor w naszym własnym komponencie React. Wszystkie potrzebne rekwizyty, w tym zawarte w nim dane, są przekazywane w czasie rzeczywistym. Aby faktycznie użyć tego komponentu, musisz zaimportować go do swojego pliku speech.js :

 // speech.js import React from 'react' import SSMLeditor from './SSMLeditor.js' export default { name: 'speech', type: 'array', title: 'SSML Editor', inputComponent: SSMLeditor, of: [ { type: 'block', styles: [], lists: [], marks: { decorators: [], annotations: [ { type: 'alias' }, { type: 'emphasis' }, { type: 'prosody' }, { type: 'sayAs' }, ], }, }, ], }

Kiedy to zapiszesz, a studio przeładuje się, powinno wyglądać prawie tak samo, ale to dlatego, że nie zaczęliśmy jeszcze poprawiać edytora.

Konwertuj przenośny tekst na SSML

Edytor zapisze zawartość jako Portable Text, tablicę obiektów w formacie JSON, która ułatwia konwersję tekstu sformatowanego do dowolnego formatu. Kiedy konwertujesz Portable Text na inną składnię lub format, nazywamy to „serializacją”. Dlatego „serializatory” to przepisy na konwersję tekstu sformatowanego. W tej sekcji dodamy serializatory do syntezy mowy.

Utworzyłeś już plik blocksToSSML.js . Teraz musimy dodać naszą pierwszą zależność. Zacznij od uruchomienia polecenia terminala npm init -y w folderze ssml-editor . Spowoduje to dodanie pliku package.json , w którym zostaną wymienione zależności edytora.

Gdy to zrobisz, możesz uruchomić npm install @sanity/block-content-to-html , aby uzyskać bibliotekę, która ułatwia serializację przenośnego tekstu. Używamy biblioteki HTML, ponieważ SSML ma tę samą składnię XML z tagami i atrybutami.

To jest trochę kodu, więc możesz go skopiować i wkleić. Wyjaśnię wzór tuż pod fragmentem:

 // blocksToSSML.js import blocksToHTML, { h } from '@sanity/block-content-to-html' const serializers = { marks: { prosody: ({ children, mark: { rate, pitch, volume } }) => h('prosody', { attrs: { rate, pitch, volume } }, children), alias: ({ children, mark: { text } }) => h('sub', { attrs: { alias: text } }, children), sayAs: ({ children, mark: { interpretAs } }) => h('say-as', { attrs: { 'interpret-as': interpretAs } }, children), break: ({ children, mark: { time, strength } }) => h('break', { attrs: { time: '${time}ms', strength } }, children), emphasis: ({ children, mark: { level } }) => h('emphasis', { attrs: { level } }, children) } } export const blocksToSSML = blocks => blocksToHTML({ blocks, serializers })

Ten kod wyeksportuje funkcję, która pobiera tablicę bloków i przechodzi przez nie w pętli. Za każdym razem, gdy blok zawiera mark , będzie szukał serializatora dla typu. Jeśli zaznaczyłeś jakiś tekst do emphasis , to ta funkcja z obiektu serializatorów:

 emphasis: ({ children, mark: { level } }) => h('emphasis', { attrs: { level } }, children)

Może rozpoznajesz parametr, z którego zdefiniowaliśmy schemat? Funkcja h() pozwala nam zdefiniować element HTML, czyli tutaj „oszukujemy” i sprawia, że ​​zwraca on element SSML o nazwie <emphasis> . Nadajemy mu również level atrybutu, jeśli jest zdefiniowany, i umieszczamy w nim elementy children — w większości przypadków będzie to tekst, który został zaznaczony z emphasis .

 { "_type": "block", "_key": "f2c4cf1ab4e0", "style": "normal", "markDefs": [ { "_type": "emphasis", "_key": "99b28ed3fa58", "level": "strong" } ], "children": [ { "_type": "span", "_key": "f2c4cf1ab4e01", "text": "Say this strongly!", "marks": [ "99b28ed3fa58" ] } ] }

W ten sposób powyższa struktura w Portable Text zostaje zserializowana do tego SSML:

 <emphasis level="strong">Say this strongly</emphasis>

Jeśli potrzebujesz obsługi większej liczby tagów SSML, możesz dodać więcej adnotacji w schemacie i dodać typy adnotacji do sekcji marks w serializatorach.

Teraz mamy funkcję, która zwraca znaczniki SSML z naszego oznaczonego tekstu sformatowanego. Ostatnią częścią jest stworzenie przycisku, który pozwoli nam wysłać ten znacznik do usługi zamiany tekstu na mowę.

Dodawanie przycisku podglądu, który mówi do ciebie

W idealnym przypadku powinniśmy użyć możliwości syntezy mowy przeglądarki w internetowym interfejsie API. W ten sposób uszłoby nam na sucho mniej kodu i zależności.

Jednak od początku 2019 r. natywna obsługa syntezy mowy w przeglądarkach jest nadal na wczesnym etapie. Wygląda na to, że wsparcie dla SSML jest w drodze i istnieje dowód koncepcji implementacji JavaScript po stronie klienta.

Są szanse, że i tak będziesz używać tej zawartości z asystentem głosowym. Zarówno Asystent Google, jak i Amazon Echo (Alexa) obsługują SSML jako odpowiedzi w realizacji. W tym samouczku użyjemy interfejsu Google do zamiany tekstu na mowę, który również dobrze brzmi i obsługuje kilka języków.

Zacznij od uzyskania klucza API, rejestrując się w Google Cloud Platform (będzie on bezpłatny dla pierwszego przetworzonego 1 miliona znaków). Po zarejestrowaniu się na tej stronie możesz utworzyć nowy klucz API.

Teraz możesz otworzyć plik PreviewButton.js i dodać do niego ten kod:

 // PreviewButton.js import React from 'react' import Button from 'part:@sanity/components/buttons/default' import { blocksToSSML } from './blocksToSSML' // You should be careful with sharing this key // I put it here to keep the code simple const API_KEY = '<yourAPIkey>' const GOOGLE_TEXT_TO_SPEECH_URL = 'https://texttospeech.googleapis.com/v1beta1/text:synthesize?key=' + API_KEY const speak = async blocks => { // Serialize blocks to SSML const ssml = blocksToSSML(blocks) // Prepare the Google Text-to-Speech configuration const body = JSON.stringify({ input: { ssml }, // Select the language code and voice name (AF) voice: { languageCode: 'en-US', name: 'en-US-Wavenet-A' }, // Use MP3 in order to play in browser audioConfig: { audioEncoding: 'MP3' } }) // Send the SSML string to the API const res = await fetch(GOOGLE_TEXT_TO_SPEECH_URL, { method: 'POST', body }).then(res => res.json()) // Play the returned audio with the Browser's Audo API const audio = new Audio('data:audio/wav;base64,' + res.audioContent) audio.play() } export default function PreviewButton (props) { return <Button style={{ marginTop: '1em' }} onClick={() => speak(props.blocks)}>Speak text</Button> }

Ograniczyłem kod przycisku podglądu do minimum, aby ułatwić śledzenie tego samouczka. Oczywiście możesz go zbudować, dodając stan, aby pokazać, czy podgląd jest przetwarzany, lub umożliwić podgląd za pomocą różnych głosów obsługiwanych przez interfejs API Google.

Dodaj przycisk do SSMLeditor.js :

 // SSMLeditor.js import React, { Fragment } from 'react'; import { BlockEditor } from 'part:@sanity/form-builder'; import PreviewButton from './PreviewButton'; export default function SSMLeditor(props) { return ( <Fragment> <BlockEditor {...props} /> <PreviewButton blocks={props.value} /> </Fragment> ); }

Teraz powinieneś być w stanie oznaczyć swój tekst różnymi adnotacjami i usłyszeć wynik po naciśnięciu „Mów tekst”. Fajne, prawda?

Stworzyłeś edytor syntezy mowy i co teraz?

Jeśli postępowałeś zgodnie z tym samouczkiem, wiesz już, jak używać edytora Portable Text w Sanity Studio do tworzenia niestandardowych adnotacji i dostosowywania edytora. Możesz używać tych umiejętności do różnych rzeczy, nie tylko do tworzenia edytora syntezy mowy. Przeszedłeś również przez proces serializacji przenośnego tekstu do potrzebnej składni. Oczywiście jest to również przydatne, jeśli budujesz nakładki w React lub Vue. Możesz nawet użyć tych umiejętności, aby wygenerować Markdown z przenośnego tekstu.

Nie omówiliśmy, jak faktycznie używasz tego razem z asystentem głosowym. Jeśli chcesz spróbować, możesz użyć w dużej mierze tej samej logiki, co w przypadku przycisku podglądu w funkcji bezserwerowej i ustawić go jako punkt końcowy API dla realizacji za pomocą webhooków, np. z Dialogflow.

Jeśli chcesz, abym napisał samouczek dotyczący korzystania z edytora syntezy mowy z asystentem głosowym, daj mi wskazówkę na Twitterze lub udostępnij w sekcji komentarzy poniżej.

Dalsze czytanie na SmashingMag:

  • Eksperymentowanie z mowąSynteza
  • Poprawa doświadczenia użytkownika dzięki interfejsowi Web Speech API
  • Interfejsy API ułatwień dostępu: klucz do ułatwień dostępu w sieci
  • Tworzenie prostego chatbota AI z Web Speech API i Node.js