mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-12 20:06:33 +00:00
Update voice UI (#355)
This commit is contained in:
parent
8bd0ab22f5
commit
19b903dfb7
@ -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]]'>
|
||||||
|
<div class='messages'>
|
||||||
|
<div class='message user'>
|
||||||
<span>{{results.final}}</span>
|
<span>{{results.final}}</span>
|
||||||
<span class='interimTranscript'>[[results.interim]]</span>
|
<span class='interimTranscript'>[[results.interim]]</span>
|
||||||
…
|
…
|
||||||
</div>
|
</div>
|
||||||
<div class='text red' hidden$='[[!hasError]]'>
|
</div>
|
||||||
An error occurred. Unable to fulfill request.
|
</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>
|
||||||
|
@ -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 () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user