Skip to content

Commit

Permalink
Merge pull request #31 from Azure-Samples/speech
Browse files Browse the repository at this point in the history
Adding keyboard shortcuts to input/output
  • Loading branch information
pamelafox authored Dec 17, 2024
2 parents 0e2f386 + de2504c commit 2736f17
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 11 deletions.
43 changes: 36 additions & 7 deletions src/quartapp/static/speech-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,31 @@ class SpeechInputButton extends HTMLElement {
this.speechRecognition = new SpeechRecognition();
this.speechRecognition.lang = navigator.language || navigator.userLanguage;
this.speechRecognition.interimResults = false;
this.speechRecognition.continuous = true;
this.speechRecognition.maxAlternatives = 1;
}

connectedCallback() {
this.innerHTML = `
<button class="btn btn-outline-secondary" type="button">
<button class="btn btn-outline-secondary" type="button" title="Start recording (Shift + Space)">
<i class="bi bi-mic"></i>
</button>`;
this.recordButton = this.querySelector("button");
this.recordButton.addEventListener("click", () => this.toggleRecording());
document.addEventListener('keydown', this.handleKeydown.bind(this));
}

disconnectedCallback() {
document.removeEventListener('keydown', this.handleKeydown.bind(this));
}

handleKeydown(event) {
if (event.key === 'Escape') {
this.abortRecording();
} else if (event.key === ' ' && event.shiftKey) { // Shift + Space
event.preventDefault(); // Prevent default action
this.toggleRecording();
}
}

renderButtonOn() {
Expand All @@ -37,6 +52,15 @@ class SpeechInputButton extends HTMLElement {
this.recordButton.innerHTML = '<i class="bi bi-mic"></i>';
}


toggleRecording() {
if (this.isRecording) {
this.stopRecording();
} else {
this.startRecording();
}
}

startRecording() {
if (this.speechRecognition == null) {
this.dispatchEvent(
Expand Down Expand Up @@ -86,11 +110,11 @@ class SpeechInputButton extends HTMLElement {
},
})
);
} else {
} else if (event.error != "aborted") {
this.dispatchEvent(
new CustomEvent("speech-input-error", {
detail: {
error: "An error occurred while recording. Please try again.",
error: "An error occurred while recording. Please try again: " + event.error,
},
})
);
Expand All @@ -103,13 +127,18 @@ class SpeechInputButton extends HTMLElement {
this.renderButtonOn();
}

toggleRecording() {
if (this.isRecording) {
stopRecording() {
if (this.speechRecognition) {
this.speechRecognition.stop();
} else {
this.startRecording();
}
}

abortRecording() {
if (this.speechRecognition) {
this.speechRecognition.abort();
}
}

}

customElements.define("speech-input-button", SpeechInputButton);
23 changes: 20 additions & 3 deletions src/quartapp/static/speech-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ class SpeechOutputButton extends HTMLElement {
this.speechButton.addEventListener("click", () =>
this.toggleSpeechOutput()
);
document.addEventListener('keydown', this.handleKeydown.bind(this));
}

disconnectedCallback() {
document.removeEventListener('keydown', this.handleKeydown.bind(this));
}

handleKeydown(event) {
if (event.key === 'Escape') {
this.stopSpeech();
}
}

renderButtonOn() {
Expand All @@ -46,9 +57,7 @@ class SpeechOutputButton extends HTMLElement {
const text = this.getAttribute("text");
if (this.synth != null) {
if (this.isPlaying || text === "") {
this.synth.cancel(); // removes all utterances from the utterance queue.
this.isPlaying = false;
this.renderButtonOff();
this.stopSpeech();
return;
}

Expand Down Expand Up @@ -86,6 +95,14 @@ class SpeechOutputButton extends HTMLElement {
};
}
}

stopSpeech() {
if (this.synth) {
this.synth.cancel();
this.isPlaying = false;
this.renderButtonOff();
}
}
}

customElements.define("speech-output-button", SpeechOutputButton);
2 changes: 1 addition & 1 deletion src/quartapp/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ <h2 id="no-messages-heading" class="text-center">Chat with your uploaded images<
const speechOutput = document.createElement("speech-output-button");
speechOutput.setAttribute("text", answer);
messageDiv.appendChild(speechOutput);
messageDiv.focus();
messageInput.focus();
} catch (error) {
messageDiv.innerHTML = "Error: " + error;
}
Expand Down

0 comments on commit 2736f17

Please sign in to comment.