Crea APK gratis

API del bridge JavaScript

Sintesi vocale

Le voci del dispositivo, pronunciate dalla pagina.

SpeechRecognition standard web#

webkitSpeechRecognition / SpeechRecognition — speech to text

Esempio

La Web Speech API standard per la dettatura: l'utente parla, la pagina riceve il testo. Chrome su Android ce l'ha e la WebView di Android no, quindi l'app la fornisce sopra il riconoscitore vocale di Android. Il codice scritto per Chrome funziona senza modifiche.

Restituisce: start() inizia ad ascoltare; gli eventi result portano event.results[i][0].transcript (e .confidence, .isFinal); gli eventi error portano event.error (not-allowed, no-speech, audio-capture, network, aborted, language-not-supported, service-not-allowed); end arriva sempre per ultimo. Richiede: il microfono. La build lo attiva da sola quando il tuo codice nomina SpeechRecognition, e Android lo chiede all'utente la prima volta che start() viene eseguito.

<button id="mic">Dictate</button>
<textarea id="note"></textarea>
<script>
const Rec = window.SpeechRecognition || window.webkitSpeechRecognition;
const mic = document.getElementById('mic');
if (!Rec) {
  mic.hidden = true;                       // no speech recogniser on this phone
} else {
  mic.addEventListener('click', () => {
    const rec = new Rec();
    rec.lang = 'en-IN';                    // leave empty for the page / phone language
    rec.interimResults = true;             // live text while the user speaks
    rec.onresult = (e) => {
      let text = '';
      for (const r of e.results) text += r[0].transcript;
      document.getElementById('note').value = text;
    };
    rec.onerror = (e) => {
      if (e.error === 'not-allowed') alert('Allow the microphone to dictate.');
    };
    rec.onend = () => { mic.disabled = false; };
    mic.disabled = true;
    rec.start();
  });
}
</script>

Dettatura continua che si ferma a richiesta e segnala ogni errore:

const Rec = window.SpeechRecognition || window.webkitSpeechRecognition;
let rec = null;
function toggleDictation() {
  if (!Rec) return showMessage('Voice typing is not available on this phone.');
  if (rec) { rec.stop(); return; }                   // stop() delivers what was heard
  rec = new Rec();
  rec.continuous = true;
  rec.onresult = (e) => {
    for (let i = e.resultIndex; i < e.results.length; i++) {
      if (e.results[i].isFinal) appendToNote(e.results[i][0].transcript);
    }
  };
  rec.onerror = (e) => {
    const msg = { 'not-allowed': 'Allow the microphone first.', 'no-speech': 'Nothing was heard.',
                  'audio-capture': 'No microphone found.', 'network': 'Speech service unreachable.' }[e.error];
    if (msg) showMessage(msg);
  };
  rec.onend = () => { rec = null; };
  rec.start();
}

Pronuncia un comando ed eseguilo, nella lingua del telefono:

const Rec = window.SpeechRecognition || window.webkitSpeechRecognition;
function listenForCommand() {
  if (!Rec) return;
  const rec = new Rec();
  rec.lang = navigator.language;
  rec.onresult = (e) => {
    const said = e.results[0][0].transcript.toLowerCase();
    if (said.includes('next')) goNext();
    else if (said.includes('back')) goBack();
    else showMessage('Heard: ' + said);
  };
  rec.onerror = (e) => {
    if (e.error === 'language-not-supported') showMessage('This language is not supported here.');
  };
  rec.start();
}

Note: continuous = true continua ad ascoltare attraverso piĂč frasi finchĂ© non chiami stop(); dopo tre cicli di silenzio termina con no-speech, cosĂŹ un riconoscitore dimenticato non resta in ascolto per sempre. stop() consegna ciĂČ che Ăš stato sentito; abort() lo scarta. Il riconoscimento si ferma quando l'app va in secondo piano, come quando una scheda di Chrome viene nascosta. Solo le pagine che appartengono all'app (i suoi file o il sito del creatore) possono usare il microfono in questo modo; qualsiasi altro sito ottiene not-allowed. L'API manca quando il telefono non ha un servizio di riconoscimento vocale, quindi verificane la presenza come sopra. Trasporti interni: __srStart, __srStop, __srAbort, __srAvailable; i risultati arrivano come appmint:sr. Le app create con l'AI usano speech.start() da @/lib/appmintNative.

speechSynthesis standard web#

window.speechSynthesis + SpeechSynthesisUtterance

Esempio

Legge il testo ad alta voce con il motore di sintesi vocale del telefono, usando la normale Web Speech API.

Restituisce: speechSynthesis.speak(u) non restituisce nulla; gli eventi start / boundary / end / error / pause / resume dell'enunciato (come proprietĂ onstart … o con addEventListener) ti dicono cosa Ăš successo. getVoices() restituisce in modo sincrono un array di { voiceURI, name, lang, localService, default }. Richiede: niente. La WebView di Android non ha una propria API vocale funzionante; l'app installa questa all'avvio del documento in ogni frame.

Pronuncia una frase e sappi quando ha finito:

function say(text) {
  if (!('speechSynthesis' in window)) { alert('Speech is not available here'); return; }
  var u = new SpeechSynthesisUtterance(text);
  u.lang = 'en-US';   // BCP-47 tag: 'ta-IN', 'hi-IN', 'fr-FR' ...
  u.rate = 1.2;       // 0.1 .. 4 (1 = normal)
  u.pitch = 1;        // 0.1 .. 4 (1 = normal)
  u.onstart = function () { document.body.classList.add('speaking'); };
  u.onend = function () { document.body.classList.remove('speaking'); };
  u.onerror = function (e) {
    document.body.classList.remove('speaking');
    console.log('Speech failed:', e.error);   // 'synthesis-failed'
  };
  speechSynthesis.speak(u);   // queues after anything already speaking
}

document.getElementById('stop').onclick = function () {
  if ('speechSynthesis' in window) speechSynthesis.cancel();   // stops now, clears the queue
};

Le voci arrivano un attimo dopo l'avvio. Rileggile quando scatta voiceschanged:

var voices = [];
function loadVoices() {
  voices = speechSynthesis.getVoices();   // [] until the engine is ready
  var tamil = voices.filter(function (v) { return v.lang.indexOf('ta') === 0; });
  document.getElementById('tamil-btn').hidden = tamil.length === 0;
}
if ('speechSynthesis' in window) {
  loadVoices();
  speechSynthesis.addEventListener('voiceschanged', loadVoices);
}

function sayWithVoice(text, voice) {
  var u = new SpeechSynthesisUtterance(text);
  u.voice = voice;           // a voice from getVoices(): that exact voice is used
  u.volume = 0.8;            // 0 .. 1
  speechSynthesis.speak(u);
}

Un lettore di articoli con un solo pulsante Pausa / Riprendi che evidenzia il paragrafo in lettura:

var toggle = document.getElementById('pause-toggle');

toggle.onclick = function () {
  if (!('speechSynthesis' in window) || !speechSynthesis.speaking) return;
  if (speechSynthesis.paused) speechSynthesis.resume();   // continues from the last word
  else speechSynthesis.pause();
};

function readArticle() {
  if (!('speechSynthesis' in window)) return;
  speechSynthesis.cancel();                               // start over
  document.querySelectorAll('article p').forEach(function (p) {
    var u = new SpeechSynthesisUtterance(p.textContent);
    u.onstart = function () { p.classList.add('reading'); };
    u.onend = u.onerror = function () { p.classList.remove('reading'); };
    u.onpause = function () { toggle.textContent = 'Resume'; };
    u.onresume = function () { toggle.textContent = 'Pause'; };
    speechSynthesis.speak(u);                             // paragraphs queue in order
  });
  toggle.textContent = 'Pause';
}

Note:

  • volume (0-1), voice (la voce esatta di getVoices()), rate, pitch e lang arrivano tutti al motore del telefono. Con voice e lang, vince la voce; con nessuno dei due, parla la voce predefinita del motore.
  • boundary scatta prima di ogni parola con charIndex / charLength (Android 8+; i motori che non riportano le posizioni delle parole non ne inviano).
  • pause() / resume(): il motore di Android non puĂČ mettere in pausa a metĂ parola, quindi pause() lo ferma e resume() legge il resto della frase dall'ultima parola riportata dal motore (scattano gli eventi pause / resume). Su un motore che non riporta le posizioni delle parole, resume() fa ripartire quell'enunciato dall'inizio. speaking resta true durante la pausa; pending Ăš true mentre gli enunciati in coda attendono.
  • cancel() scatta error con error: 'interrupted' sull'enunciato in lettura e 'canceled' su quelli in coda, come dice lo standard: non mostrarli come errori.
  • Se il telefono non ha i dati vocali per la lingua, il motore puĂČ comunque parlare nella sua lingua predefinita. Controlla prima getVoices() per la lingua.
  • Gli eventi grezzi dietro questo sono appmint:tts (vedi ttsSpeak). Non ti servono quando usi questa API.

__srAbort bridge#

window.WebToApk.__srAbort(id: String)

SpeechRecognition.abort(): si ferma subito e scarta tutto.

Esempio

Documentato insieme a WebToApk.__srStart - l'esempio lì mostra anche questo.

Trasporto interno dietro webkitSpeechRecognition / SpeechRecognition (avvio, stop, interruzione e presenza di un riconoscitore sul telefono). Le pagine usano l'API standard; non chiamare mai questi direttamente, perché i metodi __ possono cambiare senza preavviso.

Restituisce: __srStart(id, options) restituisce "" quando inizia l'ascolto, oppure un nome di errore Web Speech (not-allowed, service-not-allowed). Tutto il resto arriva come eventi appmint:sr: {id, type} per start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]} e {id, type:'error', error}. Richiede: il microfono (attivato in base alla forma della chiamata).

Usa l'API pubblica:

const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();

Dettatura continua con testo in tempo reale e una lingua:

const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
  const rec = new SR();
  rec.lang = 'en-US';
  rec.continuous = true;
  rec.interimResults = true;
  rec.onresult = (e) => {
    const r = e.results[e.results.length - 1];
    note.value = r[0].transcript + (r.isFinal ? '\n' : '');
  };
  micBtn.onclick = () => rec.start();
  stopBtn.onclick = () => rec.stop();
}

Segnala errori come un microfono rifiutato:

rec.onerror = (e) => {
  if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
  else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');

Note: Implementato nella shell dell'app (SpeechRecognitionBridge.kt) sopra il SpeechRecognizer di Android. __srStart viene rifiutato per le pagine che non appartengono all'app.

__srAvailable bridge#

window.WebToApk.__srAvailable(): Boolean

Se Ăš installato un servizio di riconoscimento vocale (webkitSpeechRecognition esiste solo in quel caso).

Esempio

Documentato insieme a WebToApk.__srStart - l'esempio lì mostra anche questo.

Trasporto interno dietro webkitSpeechRecognition / SpeechRecognition (avvio, stop, interruzione e presenza di un riconoscitore sul telefono). Le pagine usano l'API standard; non chiamare mai questi direttamente, perché i metodi __ possono cambiare senza preavviso.

Restituisce: __srStart(id, options) restituisce "" quando inizia l'ascolto, oppure un nome di errore Web Speech (not-allowed, service-not-allowed). Tutto il resto arriva come eventi appmint:sr: {id, type} per start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]} e {id, type:'error', error}. Richiede: il microfono (attivato in base alla forma della chiamata).

Usa l'API pubblica:

const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();

Dettatura continua con testo in tempo reale e una lingua:

const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
  const rec = new SR();
  rec.lang = 'en-US';
  rec.continuous = true;
  rec.interimResults = true;
  rec.onresult = (e) => {
    const r = e.results[e.results.length - 1];
    note.value = r[0].transcript + (r.isFinal ? '\n' : '');
  };
  micBtn.onclick = () => rec.start();
  stopBtn.onclick = () => rec.stop();
}

Segnala errori come un microfono rifiutato:

rec.onerror = (e) => {
  if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
  else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');

Note: Implementato nella shell dell'app (SpeechRecognitionBridge.kt) sopra il SpeechRecognizer di Android. __srStart viene rifiutato per le pagine che non appartengono all'app.

__srStart bridge#

window.WebToApk.__srStart(id: String, optionsJson: String): String

SpeechRecognition.start(): "" all'avvio (gli eventi arrivano come `appmint:sr`), altrimenti il nome dell'errore Web Speech. Protetta dall'origine: ciĂČ che l'utente dice Ăš un dato dell'utente.

Esempio

Trasporto interno dietro webkitSpeechRecognition / SpeechRecognition (avvio, stop, interruzione e presenza di un riconoscitore sul telefono). Le pagine usano l'API standard; non chiamare mai questi direttamente, perché i metodi __ possono cambiare senza preavviso.

Restituisce: __srStart(id, options) restituisce "" quando inizia l'ascolto, oppure un nome di errore Web Speech (not-allowed, service-not-allowed). Tutto il resto arriva come eventi appmint:sr: {id, type} per start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]} e {id, type:'error', error}. Richiede: il microfono (attivato in base alla forma della chiamata).

Usa l'API pubblica:

const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();

Dettatura continua con testo in tempo reale e una lingua:

const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
  const rec = new SR();
  rec.lang = 'en-US';
  rec.continuous = true;
  rec.interimResults = true;
  rec.onresult = (e) => {
    const r = e.results[e.results.length - 1];
    note.value = r[0].transcript + (r.isFinal ? '\n' : '');
  };
  micBtn.onclick = () => rec.start();
  stopBtn.onclick = () => rec.stop();
}

Segnala errori come un microfono rifiutato:

rec.onerror = (e) => {
  if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
  else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');

Note: Implementato nella shell dell'app (SpeechRecognitionBridge.kt) sopra il SpeechRecognizer di Android. __srStart viene rifiutato per le pagine che non appartengono all'app.

__srStop bridge#

window.WebToApk.__srStop(id: String)

SpeechRecognition.stop(): smette di ascoltare e consegna ciĂČ che Ăš stato sentito.

Esempio

Documentato insieme a WebToApk.__srStart - l'esempio lì mostra anche questo.

Trasporto interno dietro webkitSpeechRecognition / SpeechRecognition (avvio, stop, interruzione e presenza di un riconoscitore sul telefono). Le pagine usano l'API standard; non chiamare mai questi direttamente, perché i metodi __ possono cambiare senza preavviso.

Restituisce: __srStart(id, options) restituisce "" quando inizia l'ascolto, oppure un nome di errore Web Speech (not-allowed, service-not-allowed). Tutto il resto arriva come eventi appmint:sr: {id, type} per start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]} e {id, type:'error', error}. Richiede: il microfono (attivato in base alla forma della chiamata).

Usa l'API pubblica:

const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
rec.onresult = (e) => console.log(e.results[0][0].transcript);
rec.start();

Dettatura continua con testo in tempo reale e una lingua:

const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SR) {
  const rec = new SR();
  rec.lang = 'en-US';
  rec.continuous = true;
  rec.interimResults = true;
  rec.onresult = (e) => {
    const r = e.results[e.results.length - 1];
    note.value = r[0].transcript + (r.isFinal ? '\n' : '');
  };
  micBtn.onclick = () => rec.start();
  stopBtn.onclick = () => rec.stop();
}

Segnala errori come un microfono rifiutato:

rec.onerror = (e) => {
  if (e.error === 'not-allowed' || e.error === 'service-not-allowed') showMessage('Allow the microphone to dictate.');
  else showMessage('Speech error: ' + e.error);
};
rec.onend = () => micBtn.classList.remove('live');

Note: Implementato nella shell dell'app (SpeechRecognitionBridge.kt) sopra il SpeechRecognizer di Android. __srStart viene rifiutato per le pagine che non appartengono all'app.

__ttsSpeak bridge#

window.WebToApk.__ttsSpeak(json: String)

Lo speak completo del polyfill speechSynthesis: `{text, lang, rate, pitch, volume (0-1), voice (un nome di getVoices(), oppure ''), id}`. [ttsSpeak] rimane per le pagine che chiamano direttamente il bridge; non ha volume né voce.

Esempio

Trasporto interno dietro speechSynthesis.speak(utterance): l'enunciato completo (testo, lingua, velocitĂ , tono, volume e voce scelta) come unica stringa JSON. Le pagine usano l'API standard speechSynthesis; non chiamare mai questo direttamente.

Restituisce: niente. I progressi arrivano come eventi appmint:tts, che il livello speechSynthesis trasforma negli eventi start / boundary / end / error dell'enunciato. Richiede: niente.

L'API standard che questo fornisce:

function readAloud(text) {
  if (!('speechSynthesis' in window)) return;
  var voice = speechSynthesis.getVoices().filter(function (v) { return v.lang === 'en-GB'; })[0];
  var u = new SpeechSynthesisUtterance(text);
  if (voice) u.voice = voice;   // that exact voice
  u.volume = 0.6;               // 0 .. 1
  u.addEventListener('boundary', function (e) { highlightWordAt(e.charIndex, e.charLength); });
  u.addEventListener('end', function () { clearHighlight(); });
  speechSynthesis.speak(u);
}

Un selettore di voce che l'utente sceglie una volta; ogni enunciato successivo porta quella voce esatta:

var picker = document.getElementById('voice-picker');

function listVoices() {
  var saved = localStorage.getItem('voiceName') || '';
  picker.innerHTML = '';
  speechSynthesis.getVoices().forEach(function (v) {
    picker.add(new Option(v.name + ' (' + v.lang + ')', v.name, false, v.name === saved));
  });
}
if ('speechSynthesis' in window) {
  listVoices();                                   // [] until the engine is ready
  speechSynthesis.onvoiceschanged = listVoices;
}
picker.onchange = function () { localStorage.setItem('voiceName', picker.value); };

function speakWithSavedVoice(text) {
  var name = localStorage.getItem('voiceName');
  var voice = speechSynthesis.getVoices().filter(function (v) { return v.name === name; })[0];
  var u = new SpeechSynthesisUtterance(text);
  if (voice) u.voice = voice;                     // its language is used too when u.lang is empty
  speechSynthesis.speak(u);
}

Indicazioni per l'allenamento: discrete e rapide per i conti alla rovescia, a tutto volume e piĂč acute per il cambio:

function cue(text, loud) {
  if (!('speechSynthesis' in window)) return;
  var u = new SpeechSynthesisUtterance(text);
  u.lang = 'en-US';
  u.rate = 1.4;                  // 0.1 .. 4
  u.pitch = loud ? 1.3 : 1;      // 0.1 .. 4
  u.volume = loud ? 1 : 0.4;     // 0 .. 1
  u.onerror = function (e) {
    if (e.error === 'synthesis-failed') console.log('Cue not spoken:', text);
  };
  speechSynthesis.speak(u);      // queues after the previous cue
}

cue('Ten seconds left', false);
cue('Switch sides!', true);

Note: Il JSON Ú {text, lang, rate, pitch, volume, voice, id} (voice Ú un nome di getVoices() oppure ''). Il vecchio ttsSpeak(text, lang, rate, pitch, id) rimane per le pagine che chiamano direttamente il bridge; non ha volume né voce.

ttsCancel bridge#

window.WebToApk.ttsCancel()

Sostiene il polyfill window.speechSynthesis, installato all'avvio del documento in ogni frame: le pagine devono usare l'API STANDARD speechSynthesis e queste funzioni verranno chiamate per loro. La WebView di Android non ha un proprio speechSynthesis funzionante, ed Ăš per questo che esiste il reindirizzamento.

Descritta dal suo gruppo, Sintesi vocale, e non singolarmente.

Esempio

Ferma subito la lettura e scarta tutto ciĂČ che era ancora in attesa. Le pagine chiamano normalmente lo standard speechSynthesis.cancel(), che chiama questo per te.

Restituisce: niente. Richiede: niente.

Il metodo pubblico (usa questo):

document.getElementById('stop-reading').addEventListener('click', function () {
  if ('speechSynthesis' in window) speechSynthesis.cancel();
});

La chiamata grezza:

if (window.WebToApk && typeof window.WebToApk.ttsCancel === 'function') {
  window.WebToApk.ttsCancel();
}

Pronuncia solo lo stato piĂč recente e scarta tutto ciĂČ che Ăš ancora in coda e piĂč vecchio (un tracciamento consegne, un punteggio in diretta):

function announceLatest(text) {
  if (!('speechSynthesis' in window)) return;
  speechSynthesis.cancel();   // the old line gets error 'interrupted', queued ones 'canceled'
  var u = new SpeechSynthesisUtterance(text);
  u.onerror = function (e) {
    if (e.error === 'interrupted' || e.error === 'canceled') return;   // replaced, not a failure
    showToast('Could not read that aloud');
  };
  speechSynthesis.speak(u);
}

announceLatest('Your driver is 5 minutes away');
announceLatest('Your driver has arrived');   // cuts the first one off

Note: Una lettura interrotta o scartata non invia alcun evento appmint:tts end o error, quindi l'onend di un enunciato non viene eseguito dopo un annullamento. Se tieni traccia tu degli id grezzi di ttsSpeak, dimenticali quando chiami ttsCancel().

ttsGetVoices bridge#

window.WebToApk.ttsGetVoices(): String

Array JSON delle voci installate: [{name, lang, default}]. Vuoto finché il motore non ha finito l'inizializzazione: la pagina riceve allora 'voiceschanged' e le richiede di nuovo, esattamente come il contratto asincrono di getVoices() di Chrome.

Esempio

Elenca le voci di sintesi vocale installate sul telefono. Le pagine usano normalmente lo standard speechSynthesis.getVoices(), che chiama questo per te.

Restituisce: una stringa JSON, in modo sincrono: [{ "name": "en-us-x-sfg-local", "lang": "en-US", "default": false }, ...]. Ăˆ "[]" finchĂ© il motore non si Ăš avviato. Richiede: niente.

Il metodo pubblico (usa questo):

function fillLanguages() {
  var langs = {};
  speechSynthesis.getVoices().forEach(function (v) { langs[v.lang] = true; });
  document.getElementById('langs').textContent = Object.keys(langs).join(', ');
}
if ('speechSynthesis' in window) {
  fillLanguages();
  speechSynthesis.onvoiceschanged = fillLanguages;
}

La chiamata diretta (ricorda JSON.parse):

function nativeVoices() {
  if (!(window.WebToApk && typeof window.WebToApk.ttsGetVoices === 'function')) return [];
  try { return JSON.parse(window.WebToApk.ttsGetVoices()); } catch (e) { return []; }
}

window.addEventListener('appmint:tts', function (e) {
  if (e.detail && e.detail.event === 'voiceschanged') {
    var hindi = nativeVoices().filter(function (v) { return v.lang.indexOf('hi') === 0; });
    document.getElementById('hindi-btn').hidden = hindi.length === 0;
  }
});

Parla nella lingua del telefono quando Ăš installata una voce per essa, altrimenti lascia che il motore usi la sua voce predefinita:

function bestSpeechLang() {
  if (!(window.WebToApk && typeof window.WebToApk.ttsGetVoices === 'function')) return '';
  var voices;
  try { voices = JSON.parse(window.WebToApk.ttsGetVoices()); } catch (e) { return ''; }
  var want = navigator.language || 'en-US';            // e.g. 'ta-IN'
  var exact = voices.filter(function (v) { return v.lang === want; })[0];
  if (exact) return exact.lang;
  var base = want.split('-')[0];
  var near = voices.filter(function (v) { return v.lang.split('-')[0] === base; })[0];
  return near ? near.lang : '';                        // '' = the engine's default voice
}

if (window.WebToApk && typeof window.WebToApk.ttsSpeak === 'function') {
  window.WebToApk.ttsSpeak(greetingText(), bestSpeechLang(), 1.0, 1.0, 'greeting');
}

Note: lang Ăš un tag BCP-47 come en-US o ta-IN. Il name di una voce Ăš l'id del motore e non puĂČ essere scelto per nome quando si parla; viene usata solo la sua lingua.

ttsIsSpeaking bridge#

window.WebToApk.ttsIsSpeaking(): Boolean

Sostiene il polyfill window.speechSynthesis, installato all'avvio del documento in ogni frame: le pagine devono usare l'API STANDARD speechSynthesis e queste funzioni verranno chiamate per loro. La WebView di Android non ha un proprio speechSynthesis funzionante, ed Ăš per questo che esiste il reindirizzamento.

Descritta dal suo gruppo, Sintesi vocale, e non singolarmente.

Esempio

Ti dice se il motore di sintesi vocale del telefono sta parlando in questo momento. Le pagine usano normalmente speechSynthesis.speaking o l'onend dell'enunciato.

Restituisce: true / false, in modo sincrono. false prima che il motore si sia avviato. Richiede: niente.

Il metodo pubblico (usa questo):

if ('speechSynthesis' in window && speechSynthesis.speaking) {
  speechSynthesis.cancel();
}

La chiamata diretta interroga il motore stesso, quindi Ăš esatta anche se la lettura Ăš stata avviata con la chiamata diretta ttsSpeak:

function isSpeaking() {
  if (window.WebToApk && typeof window.WebToApk.ttsIsSpeaking === 'function') {
    return window.WebToApk.ttsIsSpeaking() === true;
  }
  return false;
}

var btn = document.getElementById('read-btn');
setInterval(function () {
  btn.textContent = isSpeaking() ? 'Stop' : 'Read aloud';
}, 500);

Aspetta che l'app abbia finito di parlare prima di iniziare a registrare, cosĂŹ il microfono non capta la sua stessa voce:

function whenQuiet(fn) {
  if (!(window.WebToApk && typeof window.WebToApk.ttsIsSpeaking === 'function')) { fn(); return; }
  (function check() {
    if (window.WebToApk.ttsIsSpeaking()) setTimeout(check, 300);
    else fn();
  })();
}

document.getElementById('answer-btn').addEventListener('click', function () {
  whenQuiet(startRecordingAnswer);   // e.g. after the question was read aloud
});

Note: Non fare polling rapido; un evento (onend, oppure appmint:tts con event: 'end') Ăš meglio quando hai avviato tu la lettura.

ttsSpeak bridge#

window.WebToApk.ttsSpeak(text: String, lang: String, rate: Double, pitch: Double, utteranceId: String)

Sostiene il polyfill window.speechSynthesis, installato all'avvio del documento in ogni frame: le pagine devono usare l'API STANDARD speechSynthesis e queste funzioni verranno chiamate per loro. La WebView di Android non ha un proprio speechSynthesis funzionante, ed Ăš per questo che esiste il reindirizzamento.

Descritta dal suo gruppo, Sintesi vocale, e non singolarmente.

Esempio

Inizia a leggere il testo con il motore di sintesi vocale del telefono. Le pagine usano normalmente l'API standard speechSynthesis, che chiama questo per te.

Restituisce: niente. I progressi arrivano dopo come evento appmint:tts (e hook window.onAppMintTts(detail)) con detail = { id, event }, dove event Ăš 'start', 'end' o 'error', e id Ăš l'utteranceId che hai passato. Richiede: niente.

Il metodo pubblico (usa questo):

if ('speechSynthesis' in window) {
  var u = new SpeechSynthesisUtterance('Your order is ready');
  u.lang = 'en-GB';
  u.onend = function () { console.log('done'); };
  speechSynthesis.speak(u);
}

La chiamata diretta, se vuoi i tuoi id. Argomenti: text, lang, rate, pitch, utteranceId:

var ttsWaiting = {};

window.addEventListener('appmint:tts', function (e) {
  var d = e.detail || {};
  if (d.event === 'voiceschanged') return;        // engine ready, id is ''
  var done = ttsWaiting[d.id];
  if (!done || d.event === 'start') return;
  delete ttsWaiting[d.id];
  done(d.event === 'end');                         // 'end' = spoke it, 'error' = failed
});

function speakRaw(text) {
  return new Promise(function (resolve) {
    if (!(window.WebToApk && typeof window.WebToApk.ttsSpeak === 'function')) { resolve(false); return; }
    var id = 'mine_' + Date.now();
    ttsWaiting[id] = resolve;
    window.WebToApk.ttsSpeak(String(text), 'en-US', 1.0, 1.0, id);
  });
}

speakRaw('Hello').then(function (ok) { console.log(ok ? 'spoken' : 'could not speak'); });

Leggi un elenco di passaggi in ordine con id tuoi, ed evidenzia il passaggio in lettura:

var steps = Array.prototype.slice.call(document.querySelectorAll('.recipe-step'));

window.addEventListener('appmint:tts', function (e) {
  var d = e.detail || {};
  var m = /^recipe_(\d+)$/.exec(d.id || '');
  if (!m) return;                                  // not one of ours
  var el = steps[Number(m[1])];
  if (d.event === 'start') el.classList.add('reading');
  if (d.event === 'end' || d.event === 'error') el.classList.remove('reading');
});

document.getElementById('read-recipe').addEventListener('click', function () {
  if (!(window.WebToApk && typeof window.WebToApk.ttsSpeak === 'function')) return;
  steps.forEach(function (el, i) {
    // '' = the engine's default voice; 0.9 = a little slower for cooking
    window.WebToApk.ttsSpeak(el.textContent, '', 0.9, 1.0, 'recipe_' + i);
  });
});

Note: Gli enunciati si mettono in coda uno dopo l'altro. lang puĂČ essere '' (la voce predefinita del motore); rate e pitch sono limitati a 0,1-4. Se il motore si sta ancora avviando, il testo attende e viene letto quando Ăš pronto; se il motore non riesce ad avviarsi, ogni enunciato in attesa riceve 'error'. Usa un tuo prefisso per gli id; gli id che iniziano con wta_u appartengono al livello speechSynthesis. Su Android 8+ appmint:tts porta anche {id, event: 'boundary', charIndex, charLength} prima di ogni parola. Questa chiamata diretta non ha volume nĂ© voce: speechSynthesis ha entrambi.

ttsWarmUp bridge#

window.WebToApk.ttsWarmUp()

Sostiene il polyfill window.speechSynthesis, installato all'avvio del documento in ogni frame: le pagine devono usare l'API STANDARD speechSynthesis e queste funzioni verranno chiamate per loro. La WebView di Android non ha un proprio speechSynthesis funzionante, ed Ăš per questo che esiste il reindirizzamento.

Descritta dal suo gruppo, Sintesi vocale, e non singolarmente.

Esempio

Avvia in anticipo il motore di sintesi vocale del telefono, cosĂŹ il primo speak() non ha ritardi e getVoices() si popola. Il livello speechSynthesis dell'app lo chiama giĂ all'avvio della pagina, quindi le pagine non ne hanno quasi mai bisogno.

Restituisce: niente. Quando il motore Ăš pronto, scatta l'evento appmint:tts con detail = { id: '', event: 'voiceschanged' } (e viene eseguito speechSynthesis.onvoiceschanged). Richiede: niente.

Il modo pubblico (usa questo): leggi semplicemente le voci quando sono pronte.

if ('speechSynthesis' in window) {
  speechSynthesis.onvoiceschanged = function () {
    console.log('voices:', speechSynthesis.getVoices().length);
  };
}

La chiamata diretta, poi attendi l'evento ready:

window.addEventListener('appmint:tts', function (e) {
  if (e.detail && e.detail.event === 'voiceschanged') {
    var list = JSON.parse(window.WebToApk.ttsGetVoices());
    console.log('engine ready,', list.length, 'voices');
  }
});

if (window.WebToApk && typeof window.WebToApk.ttsWarmUp === 'function') {
  window.WebToApk.ttsWarmUp();   // safe to call many times
}

Avvia il motore quando si apre una schermata "Leggi ad alta voce" e abilita il suo pulsante quando il motore Ăš pronto:

var readBtn = document.getElementById('read-aloud');

function engineReady() {
  try { return JSON.parse(window.WebToApk.ttsGetVoices()).length > 0; } catch (e) { return false; }
}

function openReaderScreen() {
  showReaderScreen();
  if (!(window.WebToApk && typeof window.WebToApk.ttsWarmUp === 'function')) return;
  readBtn.disabled = !engineReady();       // already started earlier? enable right away
  window.WebToApk.ttsWarmUp();             // no-op when the engine is already running
}

window.addEventListener('appmint:tts', function (e) {
  if (e.detail && e.detail.event === 'voiceschanged') readBtn.disabled = false;
});

Note: voiceschanged scatta una volta, quando il motore ha finito di avviarsi. Se era già avviato (per esempio perché lo ha preparato il livello speechSynthesis), non lo riceverai di nuovo; chiama direttamente ttsGetVoices().

Generato dal runtime dell'app e dai suoi file di esempio a ogni build della documentazione. Leggilo in Markdown · Tutte le famiglie.

Verificato rispetto al bridge distribuito il 22/10/2026.