Comment faire un éditeur de synthèse vocale

Publié: 2022-03-10
Résumé rapide ↬ Les assistants vocaux sont en route vers les maisons, les poignets et les poches des gens. Cela signifie qu'une partie de notre contenu sera prononcée à haute voix à l'aide de la synthèse vocale numérique. Dans ce didacticiel, vous apprendrez à créer un éditeur WYGIWYH (What You Get Is What You Hear) pour la synthèse vocale à l'aide de l'éditeur Sanity.io pour Portable Text.

Lorsque Steve Jobs a dévoilé le Macintosh en 1984, il nous a dit « bonjour » depuis la scène. Même à ce moment-là, la synthèse vocale n'était pas vraiment une nouvelle technologie : les Bell Labs ont développé le vocodeur dès la fin des années 30, et le concept d'un ordinateur à assistant vocal a fait son chemin lorsque Stanley Kubrick a fait du vocodeur la voix de HAL9000 en 2001 : L'Odyssée de l'espace (1968).

Ce n'est pas avant l'introduction de Siri, d'Amazon Echo et de Google Assistant d'Apple au milieu des années 2015 que les interfaces vocales ont trouvé leur place dans les maisons, les poignets et les poches d'un public plus large. Nous sommes encore dans une phase d'adoption, mais il semble que ces assistants vocaux soient là pour rester.

En d'autres termes, le Web n'est plus seulement du texte passif sur un écran . Les éditeurs Web et les concepteurs UX doivent s'habituer à créer des contenus et des services qui doivent être prononcés à haute voix.

Nous nous dirigeons déjà rapidement vers l'utilisation de systèmes de gestion de contenu qui nous permettent de travailler avec notre contenu sans tête et via des API. Le dernier élément consiste à créer des interfaces éditoriales qui facilitent l'adaptation du contenu à la voix. Alors faisons juste ça !

Plus après saut! Continuez à lire ci-dessous ↓

Qu'est-ce que SSML

Alors que les navigateurs Web utilisent la spécification du W3C pour le langage HTML (HyperText Markup Language) pour rendre visuellement les documents, la plupart des assistants vocaux utilisent le langage SSML (Speech Synthesis Markup Language) lors de la génération de la parole.

Un exemple minimal utilisant l'élément racine <speak> et les balises de paragraphe ( <p> ) et de phrase ( <s> ) :

 <speak> <p> <s>This is the first sentence of the paragraph.</s> <s>Here's another sentence.</s> </p> </speak>
Appuyez sur lecture pour écouter l'extrait :

Là où SSML devient existant, c'est lorsque nous introduisons des balises pour <emphasis> et <prosody> (hauteur) :

 <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>
Appuyez sur lecture pour écouter l'extrait :

SSML a plus de fonctionnalités, mais cela suffit pour avoir une idée des bases. Maintenant, regardons de plus près l'éditeur que nous allons utiliser pour créer l'interface d'édition de la synthèse vocale.

L'éditeur de texte portable

Pour créer cet éditeur, nous utiliserons l'éditeur de texte portable qui figure dans Sanity.io. Portable Text est une spécification JSON pour l'édition de texte enrichi, qui peut être sérialisée dans n'importe quel langage de balisage, tel que SSML. Cela signifie que vous pouvez facilement utiliser le même extrait de texte à plusieurs endroits en utilisant différents langages de balisage.

L'éditeur par défaut de Sanity.io pour Portable Text
Éditeur par défaut de Sanity.io pour Portable Text ( Grand aperçu )

Installer Sanity

Sanity.io est une plate-forme de contenu structuré fournie avec un environnement d'édition open source construit avec React.js. Il faut deux minutes pour que tout soit opérationnel.

Tapez npm i -g @sanity/cli && sanity init dans votre terminal et suivez les instructions. Choisissez "vide", lorsque vous êtes invité à entrer un modèle de projet.

Si vous ne souhaitez pas suivre ce didacticiel et créer cet éditeur à partir de rien, vous pouvez également cloner le code de ce didacticiel et suivre les instructions du README.md .

Lorsque l'éditeur est téléchargé, vous exécutez sanity start dans le dossier du projet pour le démarrer. Il démarrera un serveur de développement qui utilise le rechargement de module à chaud pour mettre à jour les modifications lorsque vous modifiez ses fichiers.

Comment configurer des schémas dans Sanity Studio

Création des fichiers de l'éditeur

Nous allons commencer par créer un dossier appelé ssml-editor dans le dossier /schemas . Dans ce dossier, nous mettrons quelques fichiers vides :

 /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

Nous pouvons maintenant ajouter des schémas de contenu dans ces fichiers. Les schémas de contenu définissent la structure des données pour le texte enrichi et ce que Sanity Studio utilise pour générer l'interface éditoriale. Ce sont de simples objets JavaScript qui ne nécessitent généralement qu'un name et un type .

Nous pouvons également ajouter un title et une description pour rendre un peu plus agréable pour les éditeurs. Par exemple, voici un schéma pour un champ texte simple pour un title :

 export default { name: 'title', type: 'string', title: 'Title', description: 'Titles should be short and descriptive' } 
Sanity Studio avec un champ de titre et un éditeur pour Portable Text
Le studio avec notre champ de titre et l'éditeur par défaut ( Grand aperçu )

Portable Text est construit sur l'idée du texte enrichi en tant que données. Ceci est puissant car il vous permet d'interroger votre texte enrichi et de le convertir en pratiquement n'importe quel balisage de votre choix.

Il s'agit d'un tableau d'objets appelés "blocs" que vous pouvez considérer comme des "paragraphes". Dans un bloc, il y a un tableau d'étendues enfants. Chaque bloc peut avoir un style et un ensemble de définitions de marques, qui décrivent les structures de données distribuées sur les étendues enfants.

Sanity.io est livré avec un éditeur qui peut lire et écrire dans Portable Text, et est activé en plaçant le type de block dans un champ array , comme ceci :

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

Un tableau peut être de plusieurs types. Pour un éditeur SSML, il peut s'agir de blocs pour les fichiers audio, mais cela n'entre pas dans le cadre de ce didacticiel.

La dernière chose que nous voulons faire est d'ajouter un type de contenu où cet éditeur peut être utilisé. La plupart des assistants utilisent un modèle de contenu simple d'« intentions » et de « réalisations » :

  • Intentions
    Généralement une liste de chaînes utilisées par le modèle d'IA pour délimiter ce que l'utilisateur veut faire.
  • Accomplissements
    Cela se produit lorsqu'une « intention » est identifiée. Un accomplissement est souvent - ou du moins - vient avec une sorte de réponse.

Créons donc un type de contenu simple appelé fulfillment qui utilise l'éditeur de synthèse vocale. Créez un nouveau fichier appelé fillment.js et enregistrez-le dans le dossier /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' } ] }

Enregistrez le fichier et ouvrez schema.js . Ajoutez-le à votre studio comme ceci :

 // 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, ]) })

Si vous exécutez maintenant sanity start dans votre interface de ligne de commande dans le dossier racine du projet, le studio démarrera localement et vous pourrez ajouter des entrées pour les réalisations. Vous pouvez continuer à faire fonctionner le studio pendant que nous continuons, car il se rechargera automatiquement avec de nouvelles modifications lorsque vous enregistrerez les fichiers.

Ajout de SSML à l'éditeur

Par défaut, le type de block vous donnera un éditeur standard pour le texte riche orienté visuellement avec des styles de titre, des styles de décorateur pour l'emphase et la force, des annotations pour les liens et des listes. Maintenant, nous voulons remplacer ceux avec les concepts auditifs trouvés dans SSML.

Nous commençons par définir les différentes structures de contenu, avec des descriptions utiles pour les éditeurs, que nous ajouterons au block dans SSMLeditorSchema.js en tant que configurations pour les annotations . Ce sont "emphase", "alias", "prosodie" et "dire comme".

Accent

Nous commençons par "emphase", qui contrôle le poids accordé au texte marqué. Nous le définissons comme une chaîne avec une liste de valeurs prédéfinies parmi lesquelles l'utilisateur peut choisir :

 // 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

Parfois, le terme écrit et le terme parlé diffèrent. Par exemple, vous voulez utiliser l'abréviation d'une phrase dans un texte écrit, mais faire lire la phrase entière à haute voix. Par exemple:

 <s>This is a <sub alias="Speech Synthesis Markup Language">SSML</sub> tutorial</s>
Appuyez sur lecture pour écouter l'extrait :

Le champ de saisie de l'alias est une simple chaîne :

 // 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', } ] }

Prosodie

Avec la propriété de prosodie, nous pouvons contrôler différents aspects de la façon dont le texte doit être prononcé, comme la hauteur, le débit et le volume. Le balisage pour cela peut ressembler à ceci :

 <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>
Appuyez sur lecture pour écouter l'extrait :

Cette entrée aura trois champs avec des options de chaîne prédéfinies :

 // 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' } ] } } ] }

Dire comme

Le dernier que nous voulons inclure est <say-as> . Cette balise nous permet d'exercer un peu plus de contrôle sur la façon dont certaines informations sont prononcées. Nous pouvons même l'utiliser pour faire biper des mots si vous avez besoin de rédiger quelque chose dans les interfaces vocales. C'est @!%& utile !

 <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>
Appuyez sur lecture pour écouter l'extrait :
 // 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' } ] } ] }

Nous pouvons maintenant les importer dans un fichier annotations.js , ce qui rend les choses un peu plus ordonnées.

 // 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'

Nous pouvons maintenant importer ces types d'annotations dans nos schémas principaux :

 // 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 ]) })

Enfin, nous pouvons maintenant les ajouter à l'éditeur comme ceci :

 // 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'} ] } } ] }

Notez que nous avons également ajouté des tableaux vides aux styles et aux decorators . Cela désactive les styles et les décorateurs par défaut (comme le gras et l'emphase) car ils n'ont pas beaucoup de sens dans ce cas spécifique.

Personnalisation de l'apparence et de la convivialité

Nous avons maintenant la fonctionnalité en place, mais comme nous n'avons spécifié aucune icône, chaque annotation utilisera l'icône par défaut, ce qui rend l'éditeur difficile à utiliser pour les auteurs. Alors réparons ça !

Avec l'éditeur pour Portable Text, il est possible d'injecter des composants React à la fois pour les icônes et pour la façon dont le texte marqué doit être rendu. Ici, nous allons simplement laisser quelques emoji faire le travail pour nous, mais vous pouvez évidemment aller loin avec cela, en les rendant dynamiques, etc. Pour prosody nous ferons même changer l'icône en fonction du volume sélectionné. Notez que j'ai omis les champs dans ces extraits par souci de concision, vous ne devriez pas les supprimer dans vos fichiers locaux.

 // 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>, }, }; 
L'éditeur SSML personnalisé
L'éditeur avec nos marques SSML personnalisées ( Grand aperçu )

Vous avez maintenant un éditeur pour éditer du texte qui peut être utilisé par des assistants vocaux. Mais ne serait-il pas utile que les éditeurs puissent également prévisualiser le son du texte ?

Ajout d'un bouton de prévisualisation à l'aide de la synthèse vocale de Google

La prise en charge de la synthèse vocale native est en cours pour les navigateurs. Mais dans ce didacticiel, nous utiliserons l'API Text-to-Speech de Google qui prend en charge SSML. La création de cette fonctionnalité d'aperçu sera également une démonstration de la façon dont vous sérialisez le texte portable en SSML dans le service pour lequel vous souhaitez l'utiliser.

Envelopper l'éditeur dans un composant React

Nous commençons par ouvrir le fichier SSMLeditor.js et ajoutons le code suivant :

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

Nous avons maintenant enveloppé l'éditeur dans notre propre composant React. Tous les accessoires dont il a besoin, y compris les données qu'il contient, sont transmis en temps réel. Pour utiliser réellement ce composant, vous devez l'importer dans votre fichier 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' }, ], }, }, ], }

Lorsque vous enregistrez ceci et que le studio se recharge, cela devrait ressembler à peu près exactement au même, mais c'est parce que nous n'avons pas encore commencé à peaufiner l'éditeur.

Convertir du texte portable en SSML

L'éditeur enregistrera le contenu en tant que texte portable, un tableau d'objets au format JSON qui facilite la conversion de texte enrichi dans le format dont vous avez besoin. Lorsque vous convertissez Portable Text dans une autre syntaxe ou un autre format, nous appelons cette « sérialisation ». Par conséquent, les "sérialiseurs" sont les recettes de la façon dont le texte enrichi doit être converti. Dans cette section, nous allons ajouter des sérialiseurs pour la synthèse vocale.

Vous avez déjà créé le fichier blocksToSSML.js . Maintenant, nous allons devoir ajouter notre première dépendance. Commencez par exécuter la commande de terminal npm init -y dans le dossier ssml-editor . Cela ajoutera un package.json où les dépendances de l'éditeur seront listées.

Une fois cela fait, vous pouvez exécuter npm install @sanity/block-content-to-html pour obtenir une bibliothèque qui facilite la sérialisation de Portable Text. Nous utilisons la bibliothèque HTML car SSML a la même syntaxe XML avec des balises et des attributs.

C'est un tas de code, alors n'hésitez pas à le copier-coller. Je vais expliquer le modèle juste en dessous de l'extrait :

 // 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 })

Ce code exportera une fonction qui prend le tableau de blocs et les parcourt en boucle. Chaque fois qu'un bloc contient une mark , il recherchera un sérialiseur pour le type. Si vous avez marqué du texte pour qu'il soit mis en emphasis , utilisez cette fonction à partir de l'objet sérialiseurs :

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

Peut-être reconnaissez-vous le paramètre à partir duquel nous avons défini le schéma ? La fonction h() permet de définir un élément HTML, c'est-à-dire qu'ici on « triche » et lui fait retourner un élément SSML nommé <emphasis> . Nous lui donnons également le level d'attribut si celui-ci est défini, et y plaçons les éléments children — qui dans la plupart des cas seront le texte que vous avez marqué avec 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" ] } ] }

C'est ainsi que la structure ci-dessus dans Portable Text est sérialisée dans ce SSML :

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

Si vous souhaitez prendre en charge davantage de balises SSML, vous pouvez ajouter davantage d'annotations dans le schéma et ajouter les types d'annotation à la section des marks dans les sérialiseurs.

Nous avons maintenant une fonction qui renvoie le balisage SSML à partir de notre texte enrichi balisé. La dernière partie consiste à créer un bouton qui nous permet d'envoyer ce balisage à un service de synthèse vocale.

Ajout d'un bouton de prévisualisation qui vous parle

Idéalement, nous aurions dû utiliser les capacités de synthèse vocale du navigateur dans l'API Web. De cette façon, nous aurions pu nous en sortir avec moins de code et de dépendances.

Au début de 2019, cependant, la prise en charge native du navigateur pour la synthèse vocale en est encore à ses débuts. Il semble que la prise en charge de SSML soit en cours, et il existe une preuve de concepts d'implémentations JavaScript côté client pour cela.

Il y a de fortes chances que vous utilisiez ce contenu avec un assistant vocal de toute façon. Google Assistant et Amazon Echo (Alexa) prennent en charge SSML en tant que réponses dans une exécution. Dans ce didacticiel, nous utiliserons l'API de synthèse vocale de Google, qui sonne également bien et prend en charge plusieurs langues.

Commencez par obtenir une clé API en vous inscrivant à Google Cloud Platform (elle sera gratuite pour le premier million de caractères que vous traiterez). Une fois inscrit, vous pouvez créer une nouvelle clé API sur cette page.

Vous pouvez maintenant ouvrir votre fichier PreviewButton.js et y ajouter ce code :

 // 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> }

J'ai réduit ce code de bouton de prévisualisation au minimum pour faciliter le suivi de ce didacticiel. Bien sûr, vous pouvez le créer en ajoutant un état pour indiquer si l'aperçu est en cours de traitement ou permettre de prévisualiser avec les différentes voix prises en charge par l'API de Google.

Ajoutez le bouton à 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> ); }

Vous devriez maintenant pouvoir baliser votre texte avec les différentes annotations et entendre le résultat lorsque vous appuyez sur "Prononcer le texte". Cool, n'est-ce pas ?

Vous avez créé un éditeur de synthèse vocale, et maintenant ?

Si vous avez suivi ce didacticiel, vous savez comment utiliser l'éditeur de texte portable dans Sanity Studio pour créer des annotations personnalisées et personnaliser l'éditeur. Vous pouvez utiliser ces compétences pour toutes sortes de choses, pas seulement pour créer un éditeur de synthèse vocale. Vous avez également appris à sérialiser Portable Text dans la syntaxe dont vous avez besoin. Évidemment, c'est également pratique si vous construisez des interfaces dans React ou Vue. Vous pouvez même utiliser ces compétences pour générer Markdown à partir de Portable Text.

Nous n'avons pas expliqué comment vous l'utilisez réellement avec un assistant vocal. Si vous voulez essayer, vous pouvez utiliser une grande partie de la même logique qu'avec le bouton de prévisualisation dans une fonction sans serveur et le définir comme point de terminaison API pour une réalisation à l'aide de webhooks, par exemple avec Dialogflow.

Si vous souhaitez que j'écrive un tutoriel sur l'utilisation de l'éditeur de synthèse vocale avec un assistant vocal, n'hésitez pas à me donner un indice sur Twitter ou à partager dans la section des commentaires ci-dessous.

Lectures complémentaires sur SmashingMag :

  • Expérimenter la synthèse vocale
  • Améliorer l'expérience utilisateur avec l'API Web Speech
  • API d'accessibilité : clé de l'accessibilité Web
  • Construire un chatbot AI simple avec l'API Web Speech et Node.js