Buat APK Gratis

API jembatan JavaScript

Teks ke ucapan

Suara perangkat, diucapkan dari halaman.

SpeechRecognition standar web#

webkitSpeechRecognition / SpeechRecognition — speech to text

Contoh

Web Speech API standar untuk dikte: pengguna berbicara, halaman mendapat teks. Chrome di Android memilikinya dan WebView Android tidak, jadi aplikasi menyediakannya di atas pengenal suara Android sendiri. Kode yang ditulis untuk Chrome berfungsi tanpa perubahan.

Hasil: start() mulai mendengarkan; event result membawa event.results[i][0].transcript (dan .confidence, .isFinal); event error membawa event.error (not-allowed, no-speech, audio-capture, network, aborted, language-not-supported, service-not-allowed); end selalu datang terakhir. Membutuhkan: mikrofon. Build mengaktifkannya sendiri bila kode Anda menyebut SpeechRecognition, dan Android meminta pengguna saat pertama kali start() berjalan.

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

Dikte berkelanjutan yang berhenti sesuai permintaan dan melaporkan setiap kesalahan:

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();
}

Ucapkan perintah dan lakukan, dalam bahasa ponsel:

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();
}

Catatan: continuous = true terus mendengarkan di antara kalimat sampai Anda memanggil stop(); setelah tiga putaran hening ia berakhir dengan no-speech, agar pengenal yang terlupa tidak mendengarkan selamanya. stop() menyerahkan apa yang terdengar; abort() membuangnya. Pengenalan berhenti saat aplikasi masuk latar belakang, seperti saat tab Chrome disembunyikan. Hanya halaman milik aplikasi (file-nya sendiri, atau situs pembuat) yang dapat memakai mikrofon dengan cara ini; situs lain mendapat not-allowed. API tidak ada bila ponsel tidak punya layanan pengenalan suara, jadi periksa seperti di atas. Transport internal: __srStart, __srStop, __srAbort, __srAvailable; hasil tiba sebagai appmint:sr. Aplikasi buatan AI memakai speech.start() dari @/lib/appmintNative.

speechSynthesis standar web#

window.speechSynthesis + SpeechSynthesisUtterance

Contoh

Membacakan teks dengan mesin text-to-speech ponsel sendiri, memakai Web Speech API biasa.

Hasil: speechSynthesis.speak(u) tidak mengembalikan apa pun; event start / boundary / end / error / pause / resume milik ucapan (sebagai properti onstart ... atau dengan addEventListener) memberi tahu apa yang terjadi. getVoices() mengembalikan array { voiceURI, name, lang, localService, default } secara sinkron. Membutuhkan: tidak ada. Android WebView tidak punya API ucapan yang berfungsi sendiri; aplikasi memasang yang ini saat dokumen dimulai di setiap frame.

Ucapkan sebuah kalimat dan ketahui kapan selesai:

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

Suara tiba beberapa saat setelah startup. Baca lagi saat voiceschanged terpicu:

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

Pembaca artikel dengan satu tombol Jeda / Lanjutkan yang menyorot paragraf yang sedang dibacakan:

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';
}

Catatan:

  • volume (0-1), voice (suara persis dari getVoices()), rate, pitch, dan lang semuanya sampai ke mesin ponsel. Dengan voice dan lang, suara yang menang; tanpa keduanya, suara bawaan mesin yang berbicara.
  • boundary terpicu sebelum setiap kata dengan charIndex / charLength (Android 8+; mesin yang tidak melaporkan posisi kata tidak mengirimnya).
  • pause() / resume(): Mesin Android tidak bisa menjeda di tengah kata, jadi pause() menghentikannya dan resume() mengucapkan sisa kalimat dari kata terakhir yang dilaporkan mesin (event pause / resume terpicu). Pada mesin yang tidak melaporkan posisi kata, resume() memulai ucapan itu lagi dari awal. speaking tetap true saat dijeda; pending bernilai true saat ucapan yang mengantre menunggu.
  • cancel() terpicu error dengan error: 'interrupted' pada ucapan yang sedang diucapkan dan 'canceled' pada yang mengantre, sesuai standar - jangan tampilkan itu sebagai kegagalan.
  • Jika ponsel tidak memiliki data suara untuk bahasa tersebut, mesin mungkin tetap berbicara dalam bahasa bawaannya. Periksa getVoices() untuk bahasa itu lebih dulu.
  • Event mentah di balik ini adalah appmint:tts (lihat ttsSpeak). Anda tidak membutuhkannya saat memakai API ini.

__srAbort jembatan#

window.WebToApk.__srAbort(id: String)

SpeechRecognition.abort(): berhenti seketika, buang.

Contoh

Didokumentasikan bersama WebToApk.__srStart - contoh di sana menunjukkan yang ini juga.

Transport internal di balik webkitSpeechRecognition / SpeechRecognition (mulai, berhenti, batalkan, dan apakah ada pengenal di ponsel). Halaman memakai API standar; jangan panggil ini secara langsung, karena metode __ dapat berubah tanpa pemberitahuan.

Hasil: __srStart(id, options) mengembalikan "" saat mulai mendengarkan, atau nama kesalahan Web Speech (not-allowed, service-not-allowed). Semua setelah itu tiba sebagai event appmint:sr: {id, type} untuk start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, dan {id, type:'error', error}. Membutuhkan: mikrofon (diaktifkan dari bentuk panggilan).

Gunakan API publik:

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

Dikte berkelanjutan dengan teks langsung dan bahasa:

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();
}

Laporkan kesalahan seperti mikrofon yang ditolak:

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');

Catatan: Diimplementasikan di shell aplikasi (SpeechRecognitionBridge.kt) di atas SpeechRecognizer Android. __srStart ditolak untuk halaman yang bukan milik aplikasi.

__srAvailable jembatan#

window.WebToApk.__srAvailable(): Boolean

Apakah layanan pengenalan suara terpasang (webkitSpeechRecognition hanya ada bila demikian).

Contoh

Didokumentasikan bersama WebToApk.__srStart - contoh di sana menunjukkan yang ini juga.

Transport internal di balik webkitSpeechRecognition / SpeechRecognition (mulai, berhenti, batalkan, dan apakah ada pengenal di ponsel). Halaman memakai API standar; jangan panggil ini secara langsung, karena metode __ dapat berubah tanpa pemberitahuan.

Hasil: __srStart(id, options) mengembalikan "" saat mulai mendengarkan, atau nama kesalahan Web Speech (not-allowed, service-not-allowed). Semua setelah itu tiba sebagai event appmint:sr: {id, type} untuk start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, dan {id, type:'error', error}. Membutuhkan: mikrofon (diaktifkan dari bentuk panggilan).

Gunakan API publik:

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

Dikte berkelanjutan dengan teks langsung dan bahasa:

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();
}

Laporkan kesalahan seperti mikrofon yang ditolak:

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');

Catatan: Diimplementasikan di shell aplikasi (SpeechRecognitionBridge.kt) di atas SpeechRecognizer Android. __srStart ditolak untuk halaman yang bukan milik aplikasi.

__srStart jembatan#

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

SpeechRecognition.start(): "" saat dimulai (event tiba sebagai `appmint:sr`), jika tidak nama kesalahan Web Speech. Dibatasi origin: apa yang diucapkan pengguna adalah data pengguna.

Contoh

Transport internal di balik webkitSpeechRecognition / SpeechRecognition (mulai, berhenti, batalkan, dan apakah ada pengenal di ponsel). Halaman memakai API standar; jangan panggil ini secara langsung, karena metode __ dapat berubah tanpa pemberitahuan.

Hasil: __srStart(id, options) mengembalikan "" saat mulai mendengarkan, atau nama kesalahan Web Speech (not-allowed, service-not-allowed). Semua setelah itu tiba sebagai event appmint:sr: {id, type} untuk start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, dan {id, type:'error', error}. Membutuhkan: mikrofon (diaktifkan dari bentuk panggilan).

Gunakan API publik:

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

Dikte berkelanjutan dengan teks langsung dan bahasa:

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();
}

Laporkan kesalahan seperti mikrofon yang ditolak:

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');

Catatan: Diimplementasikan di shell aplikasi (SpeechRecognitionBridge.kt) di atas SpeechRecognizer Android. __srStart ditolak untuk halaman yang bukan milik aplikasi.

__srStop jembatan#

window.WebToApk.__srStop(id: String)

SpeechRecognition.stop(): berhenti mendengarkan, serahkan apa yang terdengar.

Contoh

Didokumentasikan bersama WebToApk.__srStart - contoh di sana menunjukkan yang ini juga.

Transport internal di balik webkitSpeechRecognition / SpeechRecognition (mulai, berhenti, batalkan, dan apakah ada pengenal di ponsel). Halaman memakai API standar; jangan panggil ini secara langsung, karena metode __ dapat berubah tanpa pemberitahuan.

Hasil: __srStart(id, options) mengembalikan "" saat mulai mendengarkan, atau nama kesalahan Web Speech (not-allowed, service-not-allowed). Semua setelah itu tiba sebagai event appmint:sr: {id, type} untuk start/audiostart/speechstart/speechend/audioend/end, {id, type:'result', final, alternatives:[{transcript, confidence}]}, dan {id, type:'error', error}. Membutuhkan: mikrofon (diaktifkan dari bentuk panggilan).

Gunakan API publik:

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

Dikte berkelanjutan dengan teks langsung dan bahasa:

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();
}

Laporkan kesalahan seperti mikrofon yang ditolak:

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');

Catatan: Diimplementasikan di shell aplikasi (SpeechRecognitionBridge.kt) di atas SpeechRecognizer Android. __srStart ditolak untuk halaman yang bukan milik aplikasi.

__ttsSpeak jembatan#

window.WebToApk.__ttsSpeak(json: String)

Fungsi speak lengkap dari polyfill speechSynthesis: `{text, lang, rate, pitch, volume (0-1), voice (nama dari getVoices(), atau ''), id}`. [ttsSpeak] tetap ada untuk halaman yang memanggil bridge secara langsung; tidak memiliki volume atau suara.

Contoh

Transport internal di balik speechSynthesis.speak(utterance): ucapan lengkap - teks, bahasa, kecepatan, nada, volume, dan suara yang dipilih - sebagai satu string JSON. Halaman memakai API speechSynthesis standar; jangan panggil ini secara langsung.

Hasil: tidak ada. Kemajuan tiba sebagai event appmint:tts, yang diubah lapisan speechSynthesis menjadi event start / boundary / end / error milik ucapan. Membutuhkan: tidak ada.

API standar yang dibawa ini:

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

Pemilih suara yang dipilih pengguna sekali; setiap ucapan berikutnya memakai suara persis itu:

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

Aba-aba latihan: pelan dan cepat untuk hitung mundur, volume penuh dan lebih tinggi untuk pergantian:

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);

Catatan: JSON-nya adalah {text, lang, rate, pitch, volume, voice, id} (voice adalah nama dari getVoices() atau ''). ttsSpeak(text, lang, rate, pitch, id) yang lebih lama tetap ada untuk halaman yang memanggil bridge secara langsung; tidak memiliki volume atau suara.

ttsCancel jembatan#

window.WebToApk.ttsCancel()

Mendukung polyfill window.speechSynthesis, yang dipasang saat dokumen dimulai di setiap frame - halaman harus memakai API speechSynthesis STANDAR dan ini akan dipanggil untuk mereka. Android WebView tidak menyertakan speechSynthesis yang berfungsi, itulah sebabnya pengalihan ini ada.

Dijelaskan oleh grupnya, Text-to-speech, bukan secara terpisah.

Contoh

Menghentikan ucapan saat itu juga dan membuang semua yang masih menunggu untuk diucapkan. Halaman biasanya memanggil speechSynthesis.cancel() standar, yang memanggil ini untuk Anda.

Mengembalikan: tidak ada. Membutuhkan: tidak ada.

Cara publik (gunakan ini):

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

Panggilan mentah:

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

Ucapkan hanya status terbaru dan buang yang lebih lama yang masih mengantre (pelacak pengiriman, skor langsung):

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

Catatan: Ucapan yang terpotong atau dibatalkan tidak mengirim event appmint:tts end atau error, jadi onend sebuah ucapan tidak berjalan setelah dibatalkan. Jika Anda melacak id ttsSpeak mentah sendiri, lupakan id itu saat Anda memanggil ttsCancel().

ttsGetVoices jembatan#

window.WebToApk.ttsGetVoices(): String

Array JSON suara yang terpasang: [{name, lang, default}]. Kosong sampai mesin selesai inisialisasi - halaman mendapat 'voiceschanged' saat itu dan mengueri ulang, persis seperti kontrak getVoices() asinkron Chrome.

Contoh

Mendaftar suara text-to-speech yang terpasang di ponsel. Halaman biasanya memakai speechSynthesis.getVoices() standar, yang memanggil ini untuk Anda.

Hasil: string JSON, sinkron: [{ "name": "en-us-x-sfg-local", "lang": "en-US", "default": false }, ...]. Nilainya "[]" sampai mesin dimulai. Membutuhkan: tidak ada.

Cara publik (gunakan ini):

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

Panggilan mentah (ingat 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;
  }
});

Berbicara dalam bahasa ponsel bila suara untuknya terpasang, jika tidak biarkan mesin memakai suara bawaannya:

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');
}

Catatan: lang adalah tag BCP-47 seperti en-US atau ta-IN. name sebuah suara adalah id milik mesin dan tidak dapat dipilih menurut nama saat berbicara; hanya bahasanya yang dipakai.

ttsIsSpeaking jembatan#

window.WebToApk.ttsIsSpeaking(): Boolean

Mendukung polyfill window.speechSynthesis, yang dipasang saat dokumen dimulai di setiap frame - halaman harus memakai API speechSynthesis STANDAR dan ini akan dipanggil untuk mereka. Android WebView tidak menyertakan speechSynthesis yang berfungsi, itulah sebabnya pengalihan ini ada.

Dijelaskan oleh grupnya, Text-to-speech, bukan secara terpisah.

Contoh

Memberi tahu apakah mesin text-to-speech ponsel sedang berbicara saat ini. Halaman biasanya memakai speechSynthesis.speaking atau onend milik ucapan sebagai gantinya.

Hasil: true / false, sinkron. false sebelum mesin dimulai. Membutuhkan: tidak ada.

Cara publik (gunakan ini):

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

Panggilan mentah menanyakan langsung ke mesin, jadi akurat meskipun ucapan dimulai dengan mentah 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);

Tunggu sampai aplikasi berhenti berbicara sebelum Anda mulai merekam, agar mikrofon tidak menangkap suaranya sendiri:

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

Catatan: Jangan melakukan polling cepat; event (onend, atau appmint:tts dengan event: 'end') lebih baik bila Anda memulai ucapan sendiri.

ttsSpeak jembatan#

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

Mendukung polyfill window.speechSynthesis, yang dipasang saat dokumen dimulai di setiap frame - halaman harus memakai API speechSynthesis STANDAR dan ini akan dipanggil untuk mereka. Android WebView tidak menyertakan speechSynthesis yang berfungsi, itulah sebabnya pengalihan ini ada.

Dijelaskan oleh grupnya, Text-to-speech, bukan secara terpisah.

Contoh

Mulai mengucapkan teks dengan mesin text-to-speech ponsel. Halaman biasanya memakai API speechSynthesis standar, yang memanggil ini untuk Anda.

Hasil: tidak ada. Kemajuan tiba kemudian sebagai event appmint:tts (dan hook window.onAppMintTts(detail)) dengan detail = { id, event }, di mana event adalah 'start', 'end' atau 'error', dan id adalah utteranceId yang Anda berikan. Membutuhkan: tidak ada.

Cara publik (gunakan ini):

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

Panggilan mentah, bila Anda ingin id sendiri. Argumen: 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'); });

Bacakan daftar langkah secara berurutan dengan id Anda sendiri, dan sorot langkah yang sedang diucapkan:

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

Catatan: Ucapan mengantre satu demi satu. lang boleh '' (suara bawaan mesin); rate dan pitch dibatasi ke 0,1-4. Jika mesin masih dimulai, teks menunggu dan diucapkan saat siap; jika mesin tidak bisa dimulai, setiap ucapan yang menunggu mendapat 'error'. Gunakan awalan id Anda sendiri; id yang diawali wta_u milik lapisan speechSynthesis. Di Android 8+ appmint:tts juga membawa {id, event: 'boundary', charIndex, charLength} sebelum setiap kata. Panggilan mentah ini tidak punya volume atau suara - speechSynthesis punya keduanya.

ttsWarmUp jembatan#

window.WebToApk.ttsWarmUp()

Mendukung polyfill window.speechSynthesis, yang dipasang saat dokumen dimulai di setiap frame - halaman harus memakai API speechSynthesis STANDAR dan ini akan dipanggil untuk mereka. Android WebView tidak menyertakan speechSynthesis yang berfungsi, itulah sebabnya pengalihan ini ada.

Dijelaskan oleh grupnya, Text-to-speech, bukan secara terpisah.

Contoh

Memulai mesin text-to-speech ponsel lebih awal, agar speak() pertama tanpa jeda dan getVoices() terisi. Lapisan speechSynthesis aplikasi sudah memanggil ini saat halaman dimulai, jadi halaman hampir tidak pernah membutuhkannya.

Hasil: tidak ada. Saat mesin siap, event appmint:tts terpicu dengan detail = { id: '', event: 'voiceschanged' } (dan speechSynthesis.onvoiceschanged berjalan). Membutuhkan: tidak ada.

Cara publik (gunakan ini): cukup baca suara saat sudah siap.

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

Panggilan mentah, lalu tunggu event siap:

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
}

Mulai mesin saat layar "Baca dengan suara" terbuka dan aktifkan tombolnya setelah mesin siap:

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

Catatan: voiceschanged terpicu sekali, saat mesin selesai dimulai. Jika sudah dimulai (misalnya karena lapisan speechSynthesis memanaskannya), Anda tidak akan mendapatkannya lagi; panggil ttsGetVoices() secara langsung.

Dibuat dari runtime aplikasi dan file contohnya pada setiap build dokumentasi. Baca sebagai Markdown · Semua keluarga.

Diperiksa terhadap jembatan yang dirilis pada 2026-10-22.