Skip to content

Commit 9c41b57

Browse files
Add on-device speech recognition demo (#332)
1 parent 750873d commit 9c41b57

File tree

8 files changed

+300
-65
lines changed

8 files changed

+300
-65
lines changed

web-speech-api/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@ Code for demos illustrating features of the Web Speech API. See [Web_Speech_API]
88

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

11-
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.
11+
Tap the screen then say a color — the grammar string contains a large number of HTML named color keywords to choose from.
1212

13-
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.)
13+
## On-device speech color changer demo
14+
15+
[Run on-device recognition demo live](https://mdn.github.io/dom-examples/web-speech-api/on-device-speech-color-changer/)
16+
17+
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.
1418

1519
## Phrase matcher demo
1620

1721
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.
1822

19-
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.)
20-
2123
[Run phrase matcher demo live](https://mdn.github.io/dom-examples/web-speech-api/phrase-matcher/)
2224

2325
## Speak easy synthesis demo
2426

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

2729
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.
28-
29-
This currently works in Chrome, Firefox and Safari.

web-speech-api/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ <h1>Pick your test</h1>
2020
<li>
2121
<a href="speech-color-changer/index.html">Speech color changer</a>
2222
</li>
23+
<li>
24+
<a href="on-device-speech-color-changer/index.html"
25+
>On-device-speech color changer</a
26+
>
27+
</li>
2328
</ul>
2429
<h2>More information</h2>
2530
<ul>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width" />
6+
7+
<title>On-device speech color changer</title>
8+
9+
<link rel="stylesheet" href="style.css" />
10+
<script src="script.js" defer></script>
11+
</head>
12+
13+
<body>
14+
<h1>On-device speech color changer</h1>
15+
16+
<p>This demo works in Chrome 142+ on desktop and equivalent Chromiums.</p>
17+
18+
<p class="hints"></p>
19+
20+
<button>Start recognition</button>
21+
22+
<p class="output"><em>...diagnostic messages</em></p>
23+
</body>
24+
</html>
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
const colors = [
2+
"aqua",
3+
"azure",
4+
"bisque",
5+
"blue",
6+
"brown",
7+
"chocolate",
8+
"coral",
9+
"cornflowerblue",
10+
"crimson",
11+
"cyan",
12+
"deepskyblue",
13+
"fuchsia",
14+
"ghostwhite",
15+
"gold",
16+
"goldenrod",
17+
"gray",
18+
"green",
19+
"greenyellow",
20+
"hotpink",
21+
"indigo",
22+
"ivory",
23+
"khaki",
24+
"lavender",
25+
"lightseagreen",
26+
"lime",
27+
"linen",
28+
"magenta",
29+
"maroon",
30+
"moccasin",
31+
"navy",
32+
"olive",
33+
"orange",
34+
"orchid",
35+
"peru",
36+
"pink",
37+
"plum",
38+
"purple",
39+
"rebeccapurple",
40+
"red",
41+
"salmon",
42+
"sienna",
43+
"silver",
44+
"snow",
45+
"steelblue",
46+
"tan",
47+
"teal",
48+
"thistle",
49+
"tomato",
50+
"turquoise",
51+
"violet",
52+
"yellow",
53+
];
54+
55+
const phraseData = [
56+
{ phrase: "azure", boost: 10.0 },
57+
{ phrase: "khaki", boost: 3.0 },
58+
{ phrase: "tan", boost: 2.0 },
59+
];
60+
61+
const phraseObjects = phraseData.map(
62+
(p) => new SpeechRecognitionPhrase(p.phrase, p.boost)
63+
);
64+
65+
const recognition = new SpeechRecognition();
66+
recognition.continuous = false;
67+
recognition.lang = "en-US";
68+
recognition.interimResults = false;
69+
recognition.processLocally = true;
70+
recognition.phrases = phraseObjects;
71+
72+
recognition.phrases.push(new SpeechRecognitionPhrase("thistle", 5.0));
73+
74+
const diagnostic = document.querySelector(".output");
75+
const bg = document.querySelector("html");
76+
const hints = document.querySelector(".hints");
77+
const startBtn = document.querySelector("button");
78+
79+
let colorHTML = "";
80+
colors.forEach(function (v, i, a) {
81+
console.log(v, i);
82+
colorHTML += `<span style="background-color: ${v};">${v}</span> `;
83+
});
84+
hints.innerHTML = `Press the button then say a color to change the background color of the app. For example, you could try ${colorHTML}`;
85+
86+
startBtn.addEventListener("click", () => {
87+
// check availability of target language
88+
SpeechRecognition.available({ langs: ["en-US"], processLocally: true }).then(
89+
(result) => {
90+
if (result === "unavailable") {
91+
diagnostic.textContent = `en-US not available to download at this time. Sorry!`;
92+
} else if (result === "available") {
93+
recognition.start();
94+
console.log("Ready to receive a color command.");
95+
} else {
96+
diagnostic.textContent = `en-US language pack downloading`;
97+
SpeechRecognition.install({
98+
langs: ["en-US"],
99+
processLocally: true,
100+
}).then((result) => {
101+
if (result) {
102+
diagnostic.textContent = `en-US language pack downloaded. Try again.`;
103+
} else {
104+
diagnostic.textContent = `en-US language pack failed to download. Try again later.`;
105+
}
106+
});
107+
}
108+
}
109+
);
110+
});
111+
112+
recognition.addEventListener("result", (event) => {
113+
let color = event.results[0][0].transcript;
114+
// Remove whitespace from recognized speech
115+
color = color.replace(/\s+/g, "");
116+
diagnostic.textContent = `Result received: ${color}.`;
117+
bg.style.backgroundColor = color;
118+
console.log(`Confidence: ${event.results[0][0].confidence}`);
119+
});
120+
121+
recognition.addEventListener("speechend", () => {
122+
recognition.stop();
123+
});
124+
125+
recognition.addEventListener("nomatch", (event) => {
126+
diagnostic.textContent = "I didn't recognise that color.";
127+
});
128+
129+
recognition.addEventListener("error", (event) => {
130+
diagnostic.textContent = `Error occurred in recognition: ${event.error}`;
131+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
body,
2+
html {
3+
margin: 0;
4+
}
5+
6+
html {
7+
height: 100%;
8+
}
9+
10+
body {
11+
height: inherit;
12+
overflow: hidden;
13+
max-width: 800px;
14+
margin: 0 auto;
15+
font-family: system-ui;
16+
text-align: center;
17+
}
18+
19+
.output {
20+
height: 100px;
21+
margin: 0;
22+
overflow: auto;
23+
position: absolute;
24+
bottom: 0;
25+
right: 0;
26+
left: 0;
27+
background-color: rgba(255 255 255 / 0.2);
28+
display: flex;
29+
justify-content: center;
30+
align-items: center;
31+
}
32+
33+
ul {
34+
margin: 0;
35+
}
36+
37+
.hints span {
38+
text-shadow: 0px 0px 6px rgba(255 255 255 / 0.7);
39+
}

web-speech-api/speech-color-changer/index.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
<h1>Speech color changer</h1>
1515

1616
<p class="hints"></p>
17-
<div>
18-
<p class="output"><em>...diagnostic messages</em></p>
19-
</div>
17+
18+
<button>Start recognition</button>
19+
20+
<p class="output"><em>...diagnostic messages</em></p>
2021

2122
<script src="script.js"></script>
2223
</body>
Lines changed: 83 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,98 @@
1-
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition
2-
var SpeechGrammarList = SpeechGrammarList || window.webkitSpeechGrammarList
3-
var SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent
4-
5-
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'];
6-
7-
var recognition = new SpeechRecognition();
8-
if (SpeechGrammarList) {
9-
// SpeechGrammarList is not currently available in Safari, and does not have any effect in any other browser.
10-
// This code is provided as a demonstration of possible capability. You may choose not to use it.
11-
var speechRecognitionList = new SpeechGrammarList();
12-
var grammar = '#JSGF V1.0; grammar colors; public <color> = ' + colors.join(' | ') + ' ;'
13-
speechRecognitionList.addFromString(grammar, 1);
14-
recognition.grammars = speechRecognitionList;
15-
}
1+
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
2+
var SpeechRecognitionEvent =
3+
SpeechRecognitionEvent || webkitSpeechRecognitionEvent;
4+
5+
var colors = [
6+
"aqua",
7+
"azure",
8+
"beige",
9+
"bisque",
10+
"black",
11+
"blue",
12+
"brown",
13+
"chocolate",
14+
"coral",
15+
"crimson",
16+
"cyan",
17+
"fuchsia",
18+
"ghostwhite",
19+
"gold",
20+
"goldenrod",
21+
"gray",
22+
"green",
23+
"indigo",
24+
"ivory",
25+
"khaki",
26+
"lavender",
27+
"lime",
28+
"linen",
29+
"magenta",
30+
"maroon",
31+
"moccasin",
32+
"navy",
33+
"olive",
34+
"orange",
35+
"orchid",
36+
"peru",
37+
"pink",
38+
"plum",
39+
"purple",
40+
"red",
41+
"salmon",
42+
"sienna",
43+
"silver",
44+
"snow",
45+
"tan",
46+
"teal",
47+
"thistle",
48+
"tomato",
49+
"turquoise",
50+
"violet",
51+
"white",
52+
"yellow",
53+
];
54+
55+
const recognition = new SpeechRecognition();
1656
recognition.continuous = false;
17-
recognition.lang = 'en-US';
57+
recognition.lang = "en-US";
1858
recognition.interimResults = false;
1959
recognition.maxAlternatives = 1;
2060

21-
var diagnostic = document.querySelector('.output');
22-
var bg = document.querySelector('html');
23-
var hints = document.querySelector('.hints');
61+
const diagnostic = document.querySelector(".output");
62+
const bg = document.querySelector("html");
63+
const hints = document.querySelector(".hints");
64+
const startBtn = document.querySelector("button");
2465

25-
var colorHTML= '';
26-
colors.forEach(function(v, i, a){
66+
let colorHTML = "";
67+
colors.forEach(function (v, i, a) {
2768
console.log(v, i);
28-
colorHTML += '<span style="background-color:' + v + ';"> ' + v + ' </span>';
69+
colorHTML += '<span style="background-color:' + v + ';"> ' + v + " </span>";
2970
});
30-
hints.innerHTML = 'Tap/click then say a color to change the background color of the app. Try ' + colorHTML + '.';
71+
hints.innerHTML =
72+
"Press the button then say a color to change the background color of the app. Try " +
73+
colorHTML +
74+
".";
3175

32-
document.body.onclick = function() {
76+
startBtn.onclick = function () {
3377
recognition.start();
34-
console.log('Ready to receive a color command.');
35-
}
36-
37-
recognition.onresult = function(event) {
38-
// The SpeechRecognitionEvent results property returns a SpeechRecognitionResultList object
39-
// The SpeechRecognitionResultList object contains SpeechRecognitionResult objects.
40-
// It has a getter so it can be accessed like an array
41-
// The first [0] returns the SpeechRecognitionResult at the last position.
42-
// Each SpeechRecognitionResult object contains SpeechRecognitionAlternative objects that contain individual results.
43-
// These also have getters so they can be accessed like arrays.
44-
// The second [0] returns the SpeechRecognitionAlternative at position 0.
45-
// We then return the transcript property of the SpeechRecognitionAlternative object
46-
var color = event.results[0][0].transcript;
47-
diagnostic.textContent = 'Result received: ' + color + '.';
78+
console.log("Ready to receive a color command.");
79+
};
80+
81+
recognition.onresult = function (event) {
82+
const color = event.results[0][0].transcript;
83+
diagnostic.textContent = "Result received: " + color + ".";
4884
bg.style.backgroundColor = color;
49-
console.log('Confidence: ' + event.results[0][0].confidence);
50-
}
85+
console.log("Confidence: " + event.results[0][0].confidence);
86+
};
5187

52-
recognition.onspeechend = function() {
88+
recognition.onspeechend = function () {
5389
recognition.stop();
54-
}
90+
};
5591

56-
recognition.onnomatch = function(event) {
92+
recognition.onnomatch = function (event) {
5793
diagnostic.textContent = "I didn't recognise that color.";
58-
}
94+
};
5995

60-
recognition.onerror = function(event) {
61-
diagnostic.textContent = 'Error occurred in recognition: ' + event.error;
62-
}
96+
recognition.onerror = function (event) {
97+
diagnostic.textContent = "Error occurred in recognition: " + event.error;
98+
};

0 commit comments

Comments
 (0)