Skip to content
12 changes: 6 additions & 6 deletions web-speech-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ Code for demos illustrating features of the Web Speech API. See [Web_Speech_API]

[Run recognition demo live](https://mdn.github.io/dom-examples/web-speech-api/speech-color-changer/)

Tap the screen then say a colour — the grammar string contains a large number of HTML keywords to choose from, although we've removed most of the multiple word colors to remove ambiguity. We did keep goldenrod, cos, well.
Tap the screen then say a color — the grammar string contains a large number of HTML named color keywords to choose from.

This current works only on Chrome/Chrome Mobile. To get this code running successfully, you'll need to run the code through a web server (localhost will work.)
## On-device speech color changer demo

[Run on-device recognition demo live](https://mdn.github.io/dom-examples/web-speech-api/on-device-speech-color-changer/)

This version of the color changer demo uses the new on-device color changer functionality, which at the time of writing works in Chrome 139+ desktop only.

## Phrase matcher demo

Speak the phrase and then see if the recognition engine successfully recognises it — this is another demo that relies on speech recognition, written for a research team at the University of Nebraska at Kearney.

This current works only on Chrome/Chrome Mobile. To get this code running successfully, you'll need to run the code through a web server (localhost will work.)

[Run phrase matcher demo live](https://mdn.github.io/dom-examples/web-speech-api/phrase-matcher/)

## Speak easy synthesis demo

[Run synthesis demo live](https://mdn.github.io/dom-examples/web-speech-api/speak-easy-synthesis/)

Type words in the input then submit the form to hear it spoken. You can also select the different voices available on the system, and alter the rate and pitch.

This currently works in Chrome, Firefox and Safari.
5 changes: 5 additions & 0 deletions web-speech-api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ <h1>Pick your test</h1>
<li>
<a href="speech-color-changer/index.html">Speech color changer</a>
</li>
<li>
<a href="on-device-speech-color-changer/index.html"
>On-device-speech color changer</a
>
</li>
</ul>
<h2>More information</h2>
<ul>
Expand Down
24 changes: 24 additions & 0 deletions web-speech-api/on-device-speech-color-changer/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />

<title>On-device speech color changer</title>

<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>

<body>
<h1>On-device speech color changer</h1>

<p>This demo works in Chrome 142+ on desktop and equivalent Chromiums.</p>

<p class="hints"></p>

<button>Start recognition</button>

<p class="output"><em>...diagnostic messages</em></p>
</body>
</html>
131 changes: 131 additions & 0 deletions web-speech-api/on-device-speech-color-changer/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
const colors = [
"aqua",
"azure",
"bisque",
"blue",
"brown",
"chocolate",
"coral",
"cornflowerblue",
"crimson",
"cyan",
"deepskyblue",
"fuchsia",
"ghostwhite",
"gold",
"goldenrod",
"gray",
"green",
"greenyellow",
"hotpink",
"indigo",
"ivory",
"khaki",
"lavender",
"lightseagreen",
"lime",
"linen",
"magenta",
"maroon",
"moccasin",
"navy",
"olive",
"orange",
"orchid",
"peru",
"pink",
"plum",
"purple",
"rebeccapurple",
"red",
"salmon",
"sienna",
"silver",
"snow",
"steelblue",
"tan",
"teal",
"thistle",
"tomato",
"turquoise",
"violet",
"yellow",
];

const phraseData = [
{ phrase: "azure", boost: 10.0 },
{ phrase: "khaki", boost: 3.0 },
{ phrase: "tan", boost: 2.0 },
];

const phraseObjects = phraseData.map(
(p) => new SpeechRecognitionPhrase(p.phrase, p.boost)
);

const recognition = new SpeechRecognition();
recognition.continuous = false;
recognition.lang = "en-US";
recognition.interimResults = false;
recognition.processLocally = true;
recognition.phrases = phraseObjects;

recognition.phrases.push(new SpeechRecognitionPhrase("thistle", 5.0));

const diagnostic = document.querySelector(".output");
const bg = document.querySelector("html");
const hints = document.querySelector(".hints");
const startBtn = document.querySelector("button");

let colorHTML = "";
colors.forEach(function (v, i, a) {
console.log(v, i);
colorHTML += `<span style="background-color: ${v};">${v}</span> `;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest using buttons to make the demo accessible for keyboard users.

Suggested change
colorHTML += `<span style="background-color: ${v};">${v}</span> `;
colorHTML += `<button style="background-color: ${v};">${v}</button> `;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to change all of these into buttons; they are supposed to be hint text, not controls. I've fixed the keyboard accessibility issue by instead adding a single button to the DOM, and then starting the speech recognition when that is pressed. I've also updated the text description to suit.

I've done this in both versions of the color changer demo.

});
hints.innerHTML = `Press the button then say a color to change the background color of the app. For example, you could try ${colorHTML}`;

startBtn.addEventListener("click", () => {
// check availability of target language
SpeechRecognition.available({ langs: ["en-US"], processLocally: true }).then(
(result) => {
if (result === "unavailable") {
diagnostic.textContent = `en-US not available to download at this time. Sorry!`;
} else if (result === "available") {
recognition.start();
console.log("Ready to receive a color command.");
} else {
diagnostic.textContent = `en-US language pack downloading`;
SpeechRecognition.install({
langs: ["en-US"],
processLocally: true,
}).then((result) => {
if (result) {
diagnostic.textContent = `en-US language pack downloaded. Try again.`;
} else {
diagnostic.textContent = `en-US language pack failed to download. Try again later.`;
}
});
}
}
);
});

recognition.addEventListener("result", (event) => {
let color = event.results[0][0].transcript;
// Remove whitespace from recognized speech
color = color.replace(/\s+/g, "");
diagnostic.textContent = `Result received: ${color}.`;
bg.style.backgroundColor = color;
console.log(`Confidence: ${event.results[0][0].confidence}`);
});

recognition.addEventListener("speechend", () => {
recognition.stop();
});

recognition.addEventListener("nomatch", (event) => {
diagnostic.textContent = "I didn't recognise that color.";
});

recognition.addEventListener("error", (event) => {
diagnostic.textContent = `Error occurred in recognition: ${event.error}`;
});
39 changes: 39 additions & 0 deletions web-speech-api/on-device-speech-color-changer/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
body,
html {
margin: 0;
}

html {
height: 100%;
}

body {
height: inherit;
overflow: hidden;
max-width: 800px;
margin: 0 auto;
font-family: system-ui;
text-align: center;
}

.output {
height: 100px;
margin: 0;
overflow: auto;
position: absolute;
bottom: 0;
right: 0;
left: 0;
background-color: rgba(255 255 255 / 0.2);
display: flex;
justify-content: center;
align-items: center;
}

ul {
margin: 0;
}

.hints span {
text-shadow: 0px 0px 6px rgba(255 255 255 / 0.7);
}
Comment on lines +37 to +39
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.hints span {
text-shadow: 0px 0px 6px rgba(255 255 255 / 0.7);
}
.hints button {
border: none;
text-shadow: 0px 0px 6px rgba(255 255 255 / 0.7);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comment.

7 changes: 4 additions & 3 deletions web-speech-api/speech-color-changer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
<h1>Speech color changer</h1>

<p class="hints"></p>
<div>
<p class="output"><em>...diagnostic messages</em></p>
</div>

<button>Start recognition</button>

<p class="output"><em>...diagnostic messages</em></p>

<script src="script.js"></script>
</body>
Expand Down
130 changes: 83 additions & 47 deletions web-speech-api/speech-color-changer/script.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,98 @@
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition
var SpeechGrammarList = SpeechGrammarList || window.webkitSpeechGrammarList
var SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent

var colors = [ 'aqua' , 'azure' , 'beige', 'bisque', 'black', 'blue', 'brown', 'chocolate', 'coral', 'crimson', 'cyan', 'fuchsia', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'indigo', 'ivory', 'khaki', 'lavender', 'lime', 'linen', 'magenta', 'maroon', 'moccasin', 'navy', 'olive', 'orange', 'orchid', 'peru', 'pink', 'plum', 'purple', 'red', 'salmon', 'sienna', 'silver', 'snow', 'tan', 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'white', 'yellow'];

var recognition = new SpeechRecognition();
if (SpeechGrammarList) {
// SpeechGrammarList is not currently available in Safari, and does not have any effect in any other browser.
// This code is provided as a demonstration of possible capability. You may choose not to use it.
var speechRecognitionList = new SpeechGrammarList();
var grammar = '#JSGF V1.0; grammar colors; public <color> = ' + colors.join(' | ') + ' ;'
speechRecognitionList.addFromString(grammar, 1);
recognition.grammars = speechRecognitionList;
}
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
var SpeechRecognitionEvent =
SpeechRecognitionEvent || webkitSpeechRecognitionEvent;

var colors = [
"aqua",
"azure",
"beige",
"bisque",
"black",
"blue",
"brown",
"chocolate",
"coral",
"crimson",
"cyan",
"fuchsia",
"ghostwhite",
"gold",
"goldenrod",
"gray",
"green",
"indigo",
"ivory",
"khaki",
"lavender",
"lime",
"linen",
"magenta",
"maroon",
"moccasin",
"navy",
"olive",
"orange",
"orchid",
"peru",
"pink",
"plum",
"purple",
"red",
"salmon",
"sienna",
"silver",
"snow",
"tan",
"teal",
"thistle",
"tomato",
"turquoise",
"violet",
"white",
"yellow",
];

const recognition = new SpeechRecognition();
recognition.continuous = false;
recognition.lang = 'en-US';
recognition.lang = "en-US";
recognition.interimResults = false;
recognition.maxAlternatives = 1;

var diagnostic = document.querySelector('.output');
var bg = document.querySelector('html');
var hints = document.querySelector('.hints');
const diagnostic = document.querySelector(".output");
const bg = document.querySelector("html");
const hints = document.querySelector(".hints");
const startBtn = document.querySelector("button");

var colorHTML= '';
colors.forEach(function(v, i, a){
let colorHTML = "";
colors.forEach(function (v, i, a) {
console.log(v, i);
colorHTML += '<span style="background-color:' + v + ';"> ' + v + ' </span>';
colorHTML += '<span style="background-color:' + v + ';"> ' + v + " </span>";
});
hints.innerHTML = 'Tap/click then say a color to change the background color of the app. Try ' + colorHTML + '.';
hints.innerHTML =
"Press the button then say a color to change the background color of the app. Try " +
colorHTML +
".";

document.body.onclick = function() {
startBtn.onclick = function () {
recognition.start();
console.log('Ready to receive a color command.');
}

recognition.onresult = function(event) {
// The SpeechRecognitionEvent results property returns a SpeechRecognitionResultList object
// The SpeechRecognitionResultList object contains SpeechRecognitionResult objects.
// It has a getter so it can be accessed like an array
// The first [0] returns the SpeechRecognitionResult at the last position.
// Each SpeechRecognitionResult object contains SpeechRecognitionAlternative objects that contain individual results.
// These also have getters so they can be accessed like arrays.
// The second [0] returns the SpeechRecognitionAlternative at position 0.
// We then return the transcript property of the SpeechRecognitionAlternative object
var color = event.results[0][0].transcript;
diagnostic.textContent = 'Result received: ' + color + '.';
console.log("Ready to receive a color command.");
};

recognition.onresult = function (event) {
const color = event.results[0][0].transcript;
diagnostic.textContent = "Result received: " + color + ".";
bg.style.backgroundColor = color;
console.log('Confidence: ' + event.results[0][0].confidence);
}
console.log("Confidence: " + event.results[0][0].confidence);
};

recognition.onspeechend = function() {
recognition.onspeechend = function () {
recognition.stop();
}
};

recognition.onnomatch = function(event) {
recognition.onnomatch = function (event) {
diagnostic.textContent = "I didn't recognise that color.";
}
};

recognition.onerror = function(event) {
diagnostic.textContent = 'Error occurred in recognition: ' + event.error;
}
recognition.onerror = function (event) {
diagnostic.textContent = "Error occurred in recognition: " + event.error;
};
Loading