Update voice UI (#355)

This commit is contained in:
Paulus Schoutsen 2017-07-25 00:20:24 -07:00 committed by GitHub
parent 8bd0ab22f5
commit 19b903dfb7
2 changed files with 113 additions and 60 deletions

View File

@ -3,7 +3,7 @@
<link rel="import" href="../../bower_components/paper-dialog/paper-dialog.html"> <link rel="import" href="../../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html"> <link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../../bower_components/paper-spinner/paper-spinner.html"> <link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
<dom-module id="ha-voice-command-dialog"> <dom-module id="ha-voice-command-dialog">
<template> <template>
@ -13,28 +13,68 @@
} }
.content { .content {
width: 300px; width: 450px;
min-height: 80px; min-height: 80px;
font-size: 18px; font-size: 18px;
} }
.icon { .messages {
float: left; max-height: 50vh;
overflow: scroll;
} }
.text { .messages::after {
margin-left: 48px; content: "";
clear: both;
display: block;
}
.message {
clear: both;
margin: 8px 0;
padding: 8px;
border-radius: 15px;
}
.message.user {
margin-left: 24px;
float: right;
text-align: right;
border-bottom-right-radius: 0px;
background-color: var(--light-primary-color);
color: var(--primary-text-color);
}
.message.hass {
margin-right: 24px; margin-right: 24px;
float: left;
border-bottom-left-radius: 0px;
background-color: var(--primary-color);
color: var(--text-primary-color);
} }
.error { .message.error {
color: red; background-color: var(--google-red-500);
color: var(--text-primary-color);
}
.icon {
text-align: center;
}
.icon paper-icon-button {
height: 52px;
width: 52px;
} }
.interimTranscript { .interimTranscript {
color: darkgrey; color: darkgrey;
} }
[hidden] {
display: none;
}
@media all and (max-width: 450px) { @media all and (max-width: 450px) {
paper-dialog { paper-dialog {
margin: 0; margin: 0;
@ -47,22 +87,38 @@
right: 0px; right: 0px;
overflow: scroll; overflow: scroll;
} }
.content {
width: auto;
}
.messages {
max-height: 68vh;
}
} }
</style> </style>
<paper-dialog id="dialog" with-backdrop opened='{{dialogOpen}}'> <paper-dialog id="dialog" with-backdrop opened='{{dialogOpen}}'>
<div class='content'> <div class='content'>
<div class='icon'> <div class='messages' id='messages'>
<iron-icon icon="mdi:text-to-speech" hidden$="[[isTransmitting]]"></iron-icon> <template is='dom-repeat' items='[[_conversation]]' as='message'>
<paper-spinner active$="[[isTransmitting]]" hidden$="[[!isTransmitting]]"></paper-spinner> <div class$='[[_computeMessageClasses(message)]]'>[[message.text]]</div>
</template>
</div> </div>
<div class='text' hidden$='[[hasError]]'> <template is='dom-if' if='[[results]]'>
<span>{{results.final}}</span> <div class='messages'>
<span class='interimTranscript'>[[results.interim]]</span> <div class='message user'>
<span>{{results.final}}</span>
</div> <span class='interimTranscript'>[[results.interim]]</span>
<div class='text red' hidden$='[[!hasError]]'>
An error occurred. Unable to fulfill request. </div>
</div>
</template>
<div class='icon' hidden$="[[results]]">
<paper-icon-button
icon="mdi:text-to-speech"
on-tap='startListening'
></paper-icon-button>
</div> </div>
</div> </div>
</paper-dialog> </paper-dialog>
@ -87,28 +143,15 @@ Polymer({
results: { results: {
type: Object, type: Object,
value: null,
observer: '_scrollMessagesBottom',
}, },
isTransmitting: { _conversation: {
type: Boolean, type: Array,
value: false, value: function () { return []; },
}, observer: '_scrollMessagesBottom',
}
isListening: {
type: Boolean,
value: false,
},
hasError: {
type: Boolean,
value: false,
},
showListenInterface: {
type: Boolean,
computed: 'computeShowListenInterface(isListening, isTransmitting)',
observer: 'showListenInterfaceChanged',
},
}, },
initRecognition: function () { initRecognition: function () {
@ -117,9 +160,6 @@ Polymer({
/* eslint-enable new-cap */ /* eslint-enable new-cap */
this.recognition.onstart = function () { this.recognition.onstart = function () {
this.isListening = true;
this.isTransmitting = false;
this.hasError = false;
this.results = { this.results = {
final: '', final: '',
interim: '', interim: '',
@ -127,19 +167,24 @@ Polymer({
}.bind(this); }.bind(this);
this.recognition.onerror = function () { this.recognition.onerror = function () {
this.recognition.abort(); this.recognition.abort();
this.hasError = true; var text = this.results.final || this.results.interim;
this.results = null;
this.push('_conversation', { who: 'user', text: text, error: true });
}.bind(this); }.bind(this);
this.recognition.onend = function () { this.recognition.onend = function () {
this.isListening = false;
this.isTransmitting = true;
var text = this.results.final || this.results.interim; var text = this.results.final || this.results.interim;
this.results = null;
var listeningDone = function () { if (text === '') return;
this.isTransmitting = false;
}.bind(this);
this.hass.callService('conversation', 'process', { text: text }) this.push('_conversation', { who: 'user', text: text });
.then(listeningDone, listeningDone);
this.hass.callApi('post', 'conversation/process', { text: text })
.then(function (response) {
this.push('_conversation', { who: 'hass', text: response.speech.plain.speech });
}.bind(this), function () {
this.set(['_conversation', this._conversation.length - 1, 'error'], true);
}.bind(this));
}.bind(this); }.bind(this);
this.recognition.onresult = function (event) { this.recognition.onresult = function (event) {
@ -167,25 +212,33 @@ Polymer({
this.initRecognition(); this.initRecognition();
} }
this.results = {
interim: '',
final: '',
};
this.recognition.start(); this.recognition.start();
}, },
computeShowListenInterface: function (isListening, isTransmitting) { _scrollMessagesBottom: function () {
return isListening || isTransmitting; this.async(function () {
this.$.messages.scrollTop = this.$.messages.scrollHeight;
if (this.$.messages.scrollTop !== 0) {
this.$.dialog.fire('iron-resize');
}
}.bind(this), 10);
}, },
dialogOpenChanged: function (newVal) { dialogOpenChanged: function (newVal) {
if (!newVal && this.isListening) { if (newVal) {
this.startListening();
} else if (!newVal && this.results) {
this.recognition.abort(); this.recognition.abort();
} }
}, },
showListenInterfaceChanged: function (newVal) { _computeMessageClasses: function (message) {
if (!newVal && this.dialogOpen) { return 'message ' + message.who + (message.error ? ' error' : '');
this.dialogOpen = false; }
} else if (newVal) {
this.dialogOpen = true;
}
},
}); });
</script> </script>

View File

@ -133,7 +133,7 @@
handleStartVoice: function (ev) { handleStartVoice: function (ev) {
ev.stopPropagation(); ev.stopPropagation();
this.$.voiceDialog.startListening(); this.$.voiceDialog.dialogOpen = true;
}, },
handleOpenMenu: function () { handleOpenMenu: function () {