Documentation

Le plugin fonctionne d'emblée. Une ligne de HTML met un microphone à côté d'un champ, et tout le reste de cette page est facultatif.

Installation rapide

Vous travaillez avec Claude, Codex ou un autre agent ? Copiez-collez simplement le prompt ci-dessous et confiez-lui l'installation de bout en bout.

Install AddSpeech on this site by following https://addspeech.com/skill.md

Ces instructions sont une page ordinaire que vous pouvez ouvrir et lire avant de coller quoi que ce soit. Elle détermine elle-même avec quoi votre projet est construit, demande avant d'écrire, et aucune partie de votre projet ne nous est envoyée.

En enregistrant cette même page comme skill, à ~/.claude/skills/addspeech/SKILL.md, vous pourrez l'appeler par son nom sur le site suivant au lieu de recoller un lien. C'est le même fichier dans les deux cas.

Installation

Tout ce qui suit change avec ce choix : l'étape d'installation, les exemples et la façon dont chaque option s'écrit. Il est retenu dans ce navigateur, la page suivante s'ouvrira donc déjà au bon endroit.

Quelques lignes dans nuxt.config.ts, pour que la balise fasse partie du head de votre application sur chaque page, sans composant à ne pas oublier.

nuxt.config.ts

export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: 'https://cdn.addspeech.com/widget.js',
          'data-key': 'as_pub_your_key_here',
          defer: true,
        },
      ],
    },
  },
});

Elle figure dans le source de la page, comme une publishable key de Stripe ou une key de Google Maps. Une key par domaine, et dans cette installation elle y est lisible à dessein. Elle ne fonctionne que sur les domaines listés dans votre compte, donc celui qui la copie sur son propre site n'en tire rien.

Si vous préférez qu'elle n'y figure jamais, votre propre serveur peut la garder et remettre à chaque page un jeton de courte durée par enregistrement. C'est l'option session ci-dessous, et c'est l'installation que nous recommandons à quiconque a un serveur où la mettre.

Rien d'autre n'est nécessaire. Laissé tel quel, le microphone remplit la textarea de la page - celle dans laquelle on tapait en dernier, s'il y en a plusieurs - donc un formulaire avec une seule zone de message n'a besoin d'aucune target. Ajoutez data-target, un sélecteur CSS comme celui que vous passeriez à querySelector, quand le champ est un input plutôt qu'une textarea, ou quand une seule de plusieurs textareas vous appartient. Sur une page où rien ne correspond, le bouton n'apparaît pas du tout - la balise script peut donc rester dans le gabarit utilisé par toutes les pages, et le microphone ne se montre que là où il y a un formulaire.

Prérequis

Une courte liste, à laquelle un site ordinaire répond déjà en grande partie.

La page doit être servie en HTTPS.

Les navigateurs ne donnent pas de microphone à une page qui ne l'est pas, et nous n'y pouvons rien de notre côté. Localhost fait exception, donc le développement local fonctionne normalement.

Le champ doit exister dans la page au moment où le script s'exécute, et ce doit être un véritable input ou textarea.

Un élément éditable qui n'est pas un champ de formulaire - un éditeur de texte riche fait de divs - n'est pas encore pris en charge.

Le champ a besoin de place pour quelques milliers de caractères.

Les gens parlent en phrases bien plus longues qu'ils n'en tapent, et une minute de parole ordinaire fait environ mille caractères - un maxlength de 255 ou 500 mange donc silencieusement la fin de chaque réponse. Retirez l'attribut ou portez-le à environ 3000. Le widget examine le champ vers lequel il est pointé et le signale dans la console du navigateur, ainsi que sur votre page de compte, quand il en trouve un trop petit.

La colonne derrière ce champ a besoin de la même place.

C'est la moitié qu'on oublie généralement : un formulaire qui accepte neuf cents caractères dans le navigateur, devant un VARCHAR(255), jette la fin à la dernière étape, après que la personne a déjà parlé. Utilisez TEXT, ou un VARCHAR assez long pour être sérieux, et vérifiez toute règle de validation côté serveur qui reflète encore l'ancienne longueur.

N'importe quel navigateur de ces dernières années.

Chrome, Edge, Firefox et Safari enregistrent tous ; sur iOS cela fonctionne dans Safari et dans tous les autres navigateurs du téléphone, puisqu'en dessous ils sont tous Safari.

Le visiteur se voit demander le microphone une fois, par son propre navigateur, et la réponse est retenue pour votre domaine.

Nous ne voyons jamais cette fenêtre et ne pouvons pas la devancer.

Quand le quota du mois est épuisé, le bouton se retire de vos pages jusqu'au premier du mois suivant.

C'est voulu et non une panne. Vos formulaires et vos zones de texte continuent de fonctionner exactement comme avant l'ajout du widget, de sorte qu'un visiteur ne voit pas de microphone plutôt qu'un microphone qui refuse. Votre page de compte montre ce qui a été consommé et quand le quota se remet à zéro.

React, Vue, Livewire, WordPress, une simple page HTML - cela ne change rien.

Le widget écrit dans le champ comme le ferait une personne qui tape et déclenche ensuite les événements input et change, donc un framework qui surveille ce champ voit exactement ce qu'il attend.

Utilisation

Tout ce qu'on peut dire au widget, dit sous forme d'attributs sur la balise script. Seule la key est obligatoire ; les autres ont une valeur par défaut choisie pour qu'en omettre un vous donne quelque chose de sensé plutôt que quelque chose de cassé.

Les lignes ci-dessous nomment chaque option comme une balise script la nomme. Sur Nuxt, la même option s'écrit ainsi :

'data-theme': 'spotlight',
data-keyObligatoire

Votre key, depuis votre compte. Elle dit de quel site il s'agit, et donc sur quel quota l'enregistrement est décompté.

data-targettextarea

Un sélecteur CSS pour le champ à remplir. Toute textarea de la page, sauf indication contraire.

data-themeglow

Le widget montre qu'il écoute : glow fait monter une lumière colorée depuis le bas de la fenêtre, spotlight assombrit la page, subtle le bouton seul.

data-accentLe nôtre

Votre couleur, sous n'importe quelle forme acceptée par CSS. Tout le reste en découle : ce seul attribut passe le widget à votre charte graphique.

data-backgroundL'accent

Le fond du bouton lui-même, votre accent sauf indication contraire. Transparent le supprime entièrement.

data-foreground#fff

La couleur du pictogramme et du mot sur le bouton. Blanc, ce qui est juste sur un bouton coloré et invisible sur un bouton clair.

data-radius999

L'arrondi des coins du bouton, en pixels. Zéro donne un carré net ; omis, les coins s'arrondissent au maximum - un cercle sans mot, une pilule avec.

data-sizemedium

La taille du bouton : small, medium ou large. Un cinquième plus petit ou plus grand que par défaut, pictogramme, mot et espace allant ensemble.

data-positionright

Dans quel coin le bouton se place : top (en haut à droite), right (en bas à droite) ou left (en bas à gauche). Mesuré sur le champ, ou sur la fenêtre.

data-anchorfield

Où se loge le bouton : dans le coin du champ qu'il remplit, ou window pour le faire flotter au bord de l'écran - préférable sur une page à six champs.

data-showalways

Si le bouton est là dès le départ. Always, c'est le bouton que vous avez toujours eu, focus attend le curseur dans le champ, never n'ajoute rien.

data-devicealways

Sur quels appareils le bouton est proposé : always, mobile ou desktop. Mobile, c'est pointer du doigt : une tablette oui, un portable tactile non.

data-appendtrue

Chaque pression ajoute un paragraphe sous ce qui se trouve déjà dans le champ. Réglez sur false si une pression doit remplacer la réponse précédente.

data-growfalse

Laisse un textarea grandir à mesure qu'il se remplit, pour ne pas avoir à remonter dans un paragraphe dicté. Désactivé sauf demande.

data-labelAucun

Un mot à côté du microphone, que le bouton ne porte pas sauf demande. Auto donne notre propre formulation ; autre chose, jusqu'à vingt caractères.

data-languageVotre page

Deux lettres : un indice sur ce qui va être dit, et la langue que le widget parle lui-même. Lu depuis l'attribut lang de votre page.

data-fontAucun

Mettez-le sur inherit et le bouton emprunte la typographie de la page où il se trouve. Omis, il utilise une police système arrondie et discrète.

data-shortcuton

Ctrl+Maj+Espace démarre et arrête le microphone depuis n'importe où sur la page. Désactivez-le si votre page utilise déjà cette combinaison.

data-soundoff

Un bref son au démarrage de l'enregistrement : chime, pop ou beep, ou votre propre fichier. Désactivé sauf demande - mais sur un téléphone, il arrive.

data-confettifalse

Une petite volée de papier quand les mots arrivent dans le champ. Désactivée sauf demande, et jamais après un enregistrement revenu vide.

data-counterring

Le temps restant : ring autour du bouton, bar en travers de la fenêtre, ou fill qui monte dedans. Orange à dix secondes, rouge à cinq. Actif par défaut.

data-shadowfalse

Une ombre sous le bouton. Désactivée : la hauteur à laquelle un bouton flotte au-dessus de la page, votre site y a déjà répondu - true pour clair sur clair.

data-sessionAucun

L'adresse, sur votre propre site, qui délivre les autorisations d'enregistrement, pour que la key qui dépense votre quota reste hors de votre code source.

Des réglages différents sur un champ

Tout ce qui figure ci-dessus peut aussi se dire sur un champ lui-même, en mettant data-speech- devant le nom. Le champ est interrogé en premier et la balise script sert de repli : une exception coûte donc exactement un attribut, et tout ce que vous ne mentionnez pas continue de suivre la page. Un formulaire avec une ligne d'objet au-dessus d'une zone de message peut les libeller différemment, ou poser le compte à rebours le long du bord du champ long et laisser un anneau au champ court.

<input
  id="subject"
  data-speech-label="Dictate"
  data-speech-counter="ring"
/>

<textarea
  id="message"
  data-speech-anchor="field"
  data-speech-counter="bar"
  data-speech-grow="true"
></textarea>

Le widget s'habille pour le champ dans lequel on écrit à cet instant : cela reste donc un seul micro, et non un par case. La key est le seul attribut qui n'a pas sa place ici - une deuxième key sur une page, c'est un deuxième compte.

À régler sur le champ lui-même

Deux attributs sur votre propre champ plutôt que sur la balise script. Une transcription est un paragraphe que personne n'a relu : laissez donc le correcteur orthographique du navigateur activé, car le soulignement rouge est le moyen le plus rapide, pour celui qui vient de parler, de retrouver le nom mal entendu, et le corriger tient en un double-clic. La plupart des navigateurs le font déjà pour un textarea, mais pas tous, et le régler explicitement le rend vrai partout. Autocapitalize garde les phrases tapées à la main ensuite, sur un téléphone, cohérentes avec celles qui ont été dictées.

<textarea
  id="message"
  spellcheck="true"
  autocapitalize="sentences"
  rows="4"
></textarea>

Mise en forme

Le widget vit dans un shadow root, seule manière fiable de survivre à un dépôt dans une feuille de style écrite par quelqu'un d'autre : rien de chez vous n'y entre, et rien de chez nous ne déborde sur votre page. Cette même protection rendrait la personnalisation impossible, donc deux portes y ont été volontairement laissées ouvertes.

Custom properties

Posez l'une d'elles sur le widget depuis votre propre feuille de style et elle l'emporte sur ce que la balise script demandait. C'est ce qui rend possibles un mode sombre, une couleur différente par section du site ou une règle d'impression.

--as-accent
La couleur unique dont tout le reste découle.
--as-face
Le fond du bouton lui-même, normalement l'accent.
--as-ink
Le pictogramme et le mot sur le bouton, normalement blancs.
--as-deep
L'ombre sous le bouton, normalement une version plus foncée de l'accent.
--as-lift
Le bouton sous le pointeur, normalement une version plus claire de l'accent.
--as-radius
L'arrondi des coins du bouton.
--as-scale
La taille du bouton, comme simple multiple de sa taille normale - 0.8 est le réglage small, 1.2 le réglage large. Que ce soit une property et pas seulement un attribut est tout l'intérêt : elle peut être posée à l'intérieur d'une media query, donc le bouton peut avoir une taille sur un ordinateur et une autre sous un pouce.
--as-font
La typographie du bouton et de la ligne d'état.
--as-hot
La couleur d'un enregistrement en cours, qui suit votre accent sauf indication contraire. Qu'un enregistrement soit en cours est dit par le halo qui bat, par le compte à rebours et par le mot qui l'arrête, et non par la couleur - mettez donc du rouge ici si vous voulez retrouver l'ancienne convention.
addspeech-microphone {
  --as-accent: #7c3aed;
  --as-radius: 12px;
}

@media (prefers-color-scheme: dark) {
  addspeech-microphone {
    --as-accent: #a78bfa;
  }
}

Parts

Pour ce qu'une custom property ne peut pas exprimer : un bouton plus lourd, une ligne d'état assortie à vos propres notifications. Chaque nom ci-dessous est une promesse - le nom interne d'un élément dans le widget peut changer à chaque version, ce que vous écrivez dans votre feuille de style non.

::part(button)
Le bouton lui-même, icône et mot compris.
::part(label)
Uniquement le mot sur le bouton.
::part(icon)
Uniquement le microphone.
::part(status)
La ligne qui dit ce qui se passe - écoute, transcription, ou ce qui a échoué.
::part(countdown)
La pastille sous le bouton qui décompte en toutes lettres les dix dernières secondes.
::part(hint)
Le petit rappel de raccourci clavier montré pendant un enregistrement.
::part(tip)
La petite bulle au-dessus du bouton qui nomme le raccourci clavier, sur un appareil avec pointeur.
::part(backdrop)
La lueur, ou la page assombrie derrière, selon le thème.
::part(bar)
Le trait de décompte le long du bord inférieur de la fenêtre, quand c'est le décompte que vous avez choisi.
::part(badge)
Le petit lien AddSpeech sous le bouton, sur le plan gratuit.
addspeech-microphone::part(button) {
  box-shadow: none;
  font-weight: 600;
}

addspeech-microphone::part(status) {
  font-family: "Your Face", sans-serif;
}

Le widget porte aussi son propre état sur lui-même, sous forme d'attributs ordinaires, pour que vous puissiez mettre en forme un moment aussi bien qu'un élément.

addspeech-microphone[data-state="listening"]::part(label) {
  text-transform: uppercase;
}

Tout ce qui bouge est déjà désactivé pour qui demande moins d'animations à son système. Chaque thème garde la partie qui dit que le microphone est allumé et ne perd que la partie qui bouge. Ce comportement ne doit pas être surchargé.

Exemples

Quatre exemples complets. Chacun est tout ce qui doit se trouver sur la page.

Chacun est dessiné en dessous. Ce sont des images et non des microphones en état de marche - une page qui vous demanderait quatre autorisations d'enregistrement pendant votre lecture serait une drôle de façon de défendre une seule ligne de script. Celui qui fonctionne est sur la page d'accueil.

Le plus petit qui fonctionne

Un microphone dans le coin inférieur du champ qu'il remplit, dans notre couleur, sur l'unique textarea de la page. Rien de réglé, rien de choisi.

nuxt.config.ts

script: [
  {
    src: 'https://cdn.addspeech.com/widget.js',
    'data-key': 'as_pub_your_key_here',
    defer: true,
  },
],
Un petit microphone rond posé dans le coin inférieur droit du champ de message.

À vos couleurs, au bord de la fenêtre

Flottant au bord de l'écran plutôt que posé dans le champ, dans votre propre couleur, avec des coins plus nets et votre propre mot à côté du microphone. Un bouton qui se tient seul est le seul qui puisse porter un mot : ancré dans un champ, il est déjà à côté de ce qu'il remplit, et le mot disparaît.

nuxt.config.ts

script: [
  {
    src: 'https://cdn.addspeech.com/widget.js',
    'data-key': 'as_pub_your_key_here',
    'data-anchor': 'window',
    'data-accent': '#7c3aed',
    'data-radius': '12',
    'data-label': 'Dictate',
    'data-sound': 'chime',
    defer: true,
  },
],
Une pastille violette en bas à droite de la fenêtre, portant Dictate à côté d'un microphone, avec le formulaire derrière.

Sur un tableau de bord

Rien ne bouge sur la page à part le bouton sur lequel on a appuyé, le raccourci clavier est rendu à la page, et la typographie est celle déjà chargée.

nuxt.config.ts

script: [
  {
    src: 'https://cdn.addspeech.com/widget.js',
    'data-key': 'as_pub_your_key_here',
    'data-theme': 'subtle',
    'data-position': 'left',
    'data-font': 'inherit',
    'data-shortcut': 'off',
    defer: true,
  },
],
En pleine dictée : le microphone est en bas à gauche du champ avec un halo discret, et le reste de la page est exactement comme avant.

Une seule réponse parlée

Pour une page dont tout le rôle est de récolter ce que quelqu'un dit : la page s'efface, le microphone vient au centre, et le champ s'agrandit pour accueillir le paragraphe qui y arrive.

nuxt.config.ts

script: [
  {
    src: 'https://cdn.addspeech.com/widget.js',
    'data-key': 'as_pub_your_key_here',
    'data-theme': 'spotlight',
    'data-grow': 'true',
    defer: true,
  },
],
En pleine dictée : la page est assombrie derrière un grand microphone au centre, la réponse déjà donnée transparaissant au travers.

Nommer vos formulaires

Votre page de compte découpe le mois par formulaire : combien de réponses chacun a récoltées, et quelle était la longueur d'une réponse typique. Cela ne se lit bien que si vos formulaires ont un nom, et voici comment ils en reçoivent un.

Un formulaire est nommé par le premier de ces éléments qui existe : un data-speech-name sur le champ ou sur le formulaire, l'id du formulaire, le name du formulaire, le name du champ, et à défaut de tout cela l'adresse vers laquelle le formulaire poste. La plupart des sites obtiennent donc des noms sensés sans rien changer - mais le haut de cette liste est celui que vous maîtrisez.

<form action="/customer-support/refund" data-speech-name="Refund Form">
  <textarea name="reason"></textarea>
</form>

Cela vaut la peine dès qu'une page porte plusieurs formulaires, ou quand l'id est quelque chose qu'un constructeur de pages a généré. « Retours » et « Réclamation » vous disent quelque chose d'un coup d'œil ; « form-7ab » non.

Pour ce dernier recours, seul le chemin est utilisé, et seulement ses deux derniers segments. La query string est retirée, et tout segment qui ressemble à un identifiant - un numéro de commande, un ULID, un hash - est remplacé par :id avant d'être enregistré. Un même modèle de formulaire sur huit mille pages produit reste un seul formulaire, et aucun numéro de commande n'est jamais noté.

Rien de tout cela ne concerne la personne qui remplit le formulaire. Ce qui est enregistré, c'est le nom du formulaire et l'heure qu'il était à l'horloge du visiteur, deux choses qui décrivent votre site web plutôt que votre visiteur. Il n'y a toujours pas de colonne pour ce que quelqu'un a dit.

Savoir que cela a été dicté

S'il vous est utile de savoir quels envois ont été dictés plutôt que tapés, donnez au formulaire un champ caché nommé _mic. Le widget remplit ce champ ; il ne l'ajoute jamais. Un formulaire qui n'en a pas se comporte exactement comme aujourd'hui.

<form method="post" action="/contact">
  <textarea name="message"></textarea>

  <input type="hidden" name="_mic">
</form>

Il passe à true au moment où les mots atterrissent dans le champ, et à aucun moment plus tôt. Quelqu'un qui ouvre le microphone puis se ravise, ou dont l'enregistrement revient vide, envoie le formulaire avec ce champ encore vide - ce qui vous parvient est donc soit « true », soit rien du tout.

Ce que cela vaut est réel mais modeste. Cela dit qu'un audio a été enregistré dans ce navigateur, envoyé chez nous, et revenu avec des mots dedans, ce qui représente bien plus de peine qu'un script remplissant un formulaire ne s'en donne. Cela mérite donc d'être pesé, à côté de ce que vous regardez déjà.

Ce n'est pas la preuve qu'une personne a rempli le formulaire, et nous préférons le dire plutôt que de le vendre comme tel. Un audio peut être joué dans un microphone depuis un haut-parleur, ou carrément synthétisé par quiconque est prêt à y consacrer un après-midi. Traitez-le comme vous traiteriez un pot de miel : un signal bon marché qui vaut la peine d'être là, jamais ce qui se dresse entre votre formulaire et le monde.

Ce qu'il advient de l'enregistrement

  • Rien n'est conservé. L'audio est transcrit et jeté dans la même requête, à chaque fois - il n'y a pas de seau où il atterrit d'abord, ni de réglage qui change cela.
  • Rien ne circule en clair. Un navigateur ne donne pas de microphone à une page qui n'est pas en HTTPS, et l'enregistrement nous parvient par cette même connexion chiffrée - l'audio n'est donc jamais lisible sur le fil entre la personne qui parle et le texte qui revient.
  • Une key est refusée en HTTP simple, même si l'adresse a été ajoutée de cette façon à la liste des domaines autorisés, et aucun réglage ne désactive cela. La seule exception est localhost, où le trafic ne quitte pas la machine et où les gens développent.
  • Rien n'est entraîné sur ce qui passe par là. Ni nos modèles, ni ceux de qui que ce soit d'autre.
  • Le silence n'est pas facturé, et une requête qui a échoué de notre côté non plus.
  • Si l'un de ces points change un jour, ce sera écrit sur cette page avant que cela n'arrive.

Parrainer quelqu'un

Chaque compte contient un lien. Toute personne qui s'inscrit par votre lien vous rapporte des fills, que vous affectez au mois de votre choix.

  • Payé en fills, pas en argent. Aucune facture à envoyer, aucun seuil à atteindre et aucun versement à attendre - la récompense, c'est le produit lui-même, et elle apparaît simplement dans votre compte.
  • Une inscription gratuite vaut 25 fills, un Freelancer 300 et une Agency 750. Ce sont des nombres fixes et non un pourcentage : un changement de prix ne modifie donc jamais en douce ce que vaut un parrainage.
  • Un crédit est retenu un mois avant de pouvoir être dépensé, et le compte qui l'a produit doit avoir créé un domaine et réellement utilisé le microphone au moins une fois. Cela vaut pour les inscriptions gratuites comme payantes ; sur une formule payante, l'abonnement doit en outre avoir survécu au mois, car un paiement par carte peut encore être annulé.
  • C'est vous qui décidez du mois où ils atterrissent. Mettez-les tous sur le mois prochain si vous l'attendez chargé, ou répartissez-les. Ce qu'un mois n'a pas consommé revient à votre solde quand il se termine : viser large ne vous coûte rien.
  • La cagnotte passe en dernier. Un site épuise d'abord son propre quota mensuel et ne puise dans vos fills qu'ensuite, ce qui fait qu'une affectation ne peut jamais rendre un mois moins cher qu'il ne l'était déjà.
  • Suivre votre lien ne pose aucun nouveau cookie. Le code est retenu dans la session qui existe déjà et disparaît à la fermeture du navigateur - une mémoire plus courte que l'usage du secteur, et la seule que nous puissions décrire honnêtement. Vous voyez combien de personnes sont venues et combien se sont inscrites ; vous ne voyez jamais qui.

Votre lien, vos clics et vos conversions sont sur votre page de compte, sous Refer someone.

Quand cela ne marche pas

Le widget n'affiche jamais d'erreur sur votre page. Si quelque chose ne va pas dans la ligne que vous avez collée, cela est signalé dans la console du navigateur, précédé de notre nom ; sinon, rien n'est écrit. Un site en production n'est pas l'endroit pour nos messages d'erreur.

Un microphone qui n'apparaît pas du tout, c'est presque toujours l'une de trois choses : la page n'est pas en HTTPS, le sélecteur ne correspond à rien, ou la key n'est pas autorisée sur ce domaine. La console dira laquelle.

Pour tout le reste, écrivez à [email protected]. Pour tout ce qui ressemble à un problème de sécurité, écrivez-y d'abord et donnez-nous la chance de le corriger avant que ce ne soit public.