mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 19:26:36 +00:00
Add simple try tts dialog (#8245)
This commit is contained in:
parent
4f0bb9f6c3
commit
b22455d2a5
@ -23,12 +23,12 @@ import {
|
|||||||
updateCloudPref,
|
updateCloudPref,
|
||||||
} from "../../../../data/cloud";
|
} from "../../../../data/cloud";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import { convertTextToSpeech } from "../../../../data/tts";
|
|
||||||
import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
|
import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||||
import { translationMetadata } from "../../../../resources/translations-metadata";
|
import { translationMetadata } from "../../../../resources/translations-metadata";
|
||||||
import { caseInsensitiveCompare } from "../../../../common/string/compare";
|
import { caseInsensitiveCompare } from "../../../../common/string/compare";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { showTryTtsDialog } from "./show-dialog-cloud-tts-try";
|
||||||
|
|
||||||
@customElement("cloud-tts-pref")
|
@customElement("cloud-tts-pref")
|
||||||
export class CloudTTSPref extends LitElement {
|
export class CloudTTSPref extends LitElement {
|
||||||
@ -36,8 +36,6 @@ export class CloudTTSPref extends LitElement {
|
|||||||
|
|
||||||
@property() public cloudStatus?: CloudStatusLoggedIn;
|
@property() public cloudStatus?: CloudStatusLoggedIn;
|
||||||
|
|
||||||
@internalProperty() private loadingExample = false;
|
|
||||||
|
|
||||||
@internalProperty() private savingPreferences = false;
|
@internalProperty() private savingPreferences = false;
|
||||||
|
|
||||||
@internalProperty() private ttsInfo?: CloudTTSInfo;
|
@internalProperty() private ttsInfo?: CloudTTSInfo;
|
||||||
@ -62,12 +60,9 @@ export class CloudTTSPref extends LitElement {
|
|||||||
header=${this.hass.localize("ui.panel.config.cloud.account.tts.title")}
|
header=${this.hass.localize("ui.panel.config.cloud.account.tts.title")}
|
||||||
>
|
>
|
||||||
<div class="example">
|
<div class="example">
|
||||||
<mwc-button
|
<mwc-button @click=${this._openTryDialog}>
|
||||||
@click=${this._playExample}
|
|
||||||
.disabled=${this.loadingExample}
|
|
||||||
>
|
|
||||||
<ha-svg-icon .path=${mdiPlayCircleOutline}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiPlayCircleOutline}></ha-svg-icon>
|
||||||
Example
|
${this.hass.localize("ui.panel.config.cloud.account.tts.try")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@ -191,46 +186,9 @@ export class CloudTTSPref extends LitElement {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
async _playExample() {
|
private _openTryDialog() {
|
||||||
this.loadingExample = true;
|
showTryTtsDialog(this, {
|
||||||
const defaultVoice = this.cloudStatus!.prefs.tts_default_voice;
|
defaultVoice: this.cloudStatus!.prefs.tts_default_voice,
|
||||||
// Our example sentence is English. If user uses English voice, use that
|
|
||||||
// for example.
|
|
||||||
let language;
|
|
||||||
let gender;
|
|
||||||
if (defaultVoice[0].split("-")[0] === "en") {
|
|
||||||
language = defaultVoice[0];
|
|
||||||
gender = defaultVoice[1];
|
|
||||||
} else {
|
|
||||||
language = "en-US";
|
|
||||||
gender = "female";
|
|
||||||
}
|
|
||||||
|
|
||||||
let url;
|
|
||||||
try {
|
|
||||||
const result = await convertTextToSpeech(this.hass, {
|
|
||||||
platform: "cloud",
|
|
||||||
message: `Hello ${
|
|
||||||
this.hass.user!.name
|
|
||||||
}, you can play any text on any supported media player!`,
|
|
||||||
language,
|
|
||||||
options: { gender },
|
|
||||||
});
|
|
||||||
url = result.url;
|
|
||||||
} catch (err) {
|
|
||||||
this.loadingExample = false;
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(err);
|
|
||||||
showAlertDialog(this, {
|
|
||||||
text: `Unable to load example. ${err}`,
|
|
||||||
warning: true,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const audio = new Audio(url);
|
|
||||||
audio.play();
|
|
||||||
audio.addEventListener("playing", () => {
|
|
||||||
this.loadingExample = false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
201
src/panels/config/cloud/account/dialog-cloud-tts-try.ts
Normal file
201
src/panels/config/cloud/account/dialog-cloud-tts-try.ts
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import "@material/mwc-button";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import { TryTtsDialogParams } from "./show-dialog-cloud-tts-try";
|
||||||
|
import { haStyleDialog } from "../../../../resources/styles";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { convertTextToSpeech } from "../../../../data/tts";
|
||||||
|
import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||||
|
import "@polymer/paper-input/paper-textarea";
|
||||||
|
import "../../../../components/ha-paper-dropdown-menu";
|
||||||
|
import { computeStateDomain } from "../../../../common/entity/compute_state_domain";
|
||||||
|
import { computeStateName } from "../../../../common/entity/compute_state_name";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
|
import { supportsFeature } from "../../../../common/entity/supports-feature";
|
||||||
|
import { SUPPORT_PLAY_MEDIA } from "../../../../data/media-player";
|
||||||
|
import { createCloseHeading } from "../../../../components/ha-dialog";
|
||||||
|
import { mdiPlayCircleOutline } from "@mdi/js";
|
||||||
|
import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox";
|
||||||
|
import type { PaperTextareaElement } from "@polymer/paper-input/paper-textarea";
|
||||||
|
import { LocalStorage } from "../../../../common/decorators/local-storage";
|
||||||
|
|
||||||
|
@customElement("dialog-cloud-try-tts")
|
||||||
|
export class DialogTryTts extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@internalProperty() private _loadingExample = false;
|
||||||
|
|
||||||
|
@internalProperty() private _params?: TryTtsDialogParams;
|
||||||
|
|
||||||
|
@query("#target") private _targetInput?: PaperListboxElement;
|
||||||
|
|
||||||
|
@query("#message") private _messageInput?: PaperTextareaElement;
|
||||||
|
|
||||||
|
@LocalStorage("cloudTtsTryMessage") private _message?: string;
|
||||||
|
|
||||||
|
@LocalStorage("cloudTtsTryTarget") private _target?: string;
|
||||||
|
|
||||||
|
public showDialog(params: TryTtsDialogParams) {
|
||||||
|
this._params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog() {
|
||||||
|
this._params = undefined;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._params) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
scrimClickAction
|
||||||
|
escapeKeyAction
|
||||||
|
.heading=${createCloseHeading(
|
||||||
|
this.hass,
|
||||||
|
this.hass.localize("ui.panel.config.cloud.account.tts.dialog.header")
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<paper-textarea
|
||||||
|
id="message"
|
||||||
|
label="Message"
|
||||||
|
.value=${this._message ||
|
||||||
|
this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.account.tts.dialog.example_message",
|
||||||
|
"name",
|
||||||
|
this.hass.user!.name
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
</paper-textarea>
|
||||||
|
|
||||||
|
<ha-paper-dropdown-menu
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.account.tts.dialog.target"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
id="target"
|
||||||
|
slot="dropdown-content"
|
||||||
|
attr-for-selected="item-value"
|
||||||
|
.selected=${this._target || "browser"}
|
||||||
|
>
|
||||||
|
<paper-item item-value="browser">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.account.tts.dialog.target_browser"
|
||||||
|
)}
|
||||||
|
</paper-item>
|
||||||
|
${Object.values(this.hass.states)
|
||||||
|
.filter(
|
||||||
|
(entity) =>
|
||||||
|
computeStateDomain(entity) === "media_player" &&
|
||||||
|
supportsFeature(entity, SUPPORT_PLAY_MEDIA)
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
(entity) => html`
|
||||||
|
<paper-item .itemValue=${entity.entity_id}>
|
||||||
|
${computeStateName(entity)}
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</ha-paper-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${this._playExample}
|
||||||
|
.disabled=${this._loadingExample}
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiPlayCircleOutline}></ha-svg-icon>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.account.tts.dialog.play"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _playExample() {
|
||||||
|
const target = String(this._targetInput?.selected);
|
||||||
|
const message = this._messageInput?.value;
|
||||||
|
|
||||||
|
if (!message || !target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._message = message;
|
||||||
|
this._target = target;
|
||||||
|
|
||||||
|
if (target === "browser") {
|
||||||
|
this._playBrowser(message);
|
||||||
|
} else {
|
||||||
|
this.hass.callService("tts", "cloud_say", {
|
||||||
|
entity_id: target,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _playBrowser(message: string) {
|
||||||
|
this._loadingExample = true;
|
||||||
|
|
||||||
|
const language = this._params!.defaultVoice[0];
|
||||||
|
const gender = this._params!.defaultVoice[1];
|
||||||
|
|
||||||
|
let url;
|
||||||
|
try {
|
||||||
|
const result = await convertTextToSpeech(this.hass, {
|
||||||
|
platform: "cloud",
|
||||||
|
message,
|
||||||
|
language,
|
||||||
|
options: { gender },
|
||||||
|
});
|
||||||
|
url = result.url;
|
||||||
|
} catch (err) {
|
||||||
|
this._loadingExample = false;
|
||||||
|
showAlertDialog(this, {
|
||||||
|
text: `Unable to load example. ${err.error || err.body || err}`,
|
||||||
|
warning: true,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const audio = new Audio(url);
|
||||||
|
audio.addEventListener("canplaythrough", () => {
|
||||||
|
audio.play();
|
||||||
|
});
|
||||||
|
audio.addEventListener("playing", () => {
|
||||||
|
this._loadingExample = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
ha-dialog {
|
||||||
|
--mdc-dialog-max-width: 500px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-cloud-try-tts": DialogTryTts;
|
||||||
|
}
|
||||||
|
}
|
18
src/panels/config/cloud/account/show-dialog-cloud-tts-try.ts
Normal file
18
src/panels/config/cloud/account/show-dialog-cloud-tts-try.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
export interface TryTtsDialogParams {
|
||||||
|
defaultVoice: [string, string];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadTryTtsDialog = () => import("./dialog-cloud-tts-try");
|
||||||
|
|
||||||
|
export const showTryTtsDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
dialogParams: TryTtsDialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-cloud-try-tts",
|
||||||
|
dialogImport: loadTryTtsDialog,
|
||||||
|
dialogParams,
|
||||||
|
});
|
||||||
|
};
|
@ -1682,7 +1682,15 @@
|
|||||||
"info": "Bring personality to your home by having it speak to you by using our Text-to-Speech services. You can use this in automations and scripts by using the {service} service.",
|
"info": "Bring personality to your home by having it speak to you by using our Text-to-Speech services. You can use this in automations and scripts by using the {service} service.",
|
||||||
"default_language": "Default language to use",
|
"default_language": "Default language to use",
|
||||||
"male": "Male",
|
"male": "Male",
|
||||||
"female": "Female"
|
"female": "Female",
|
||||||
|
"try": "Try",
|
||||||
|
"dialog": {
|
||||||
|
"header": "Try Text to Speech",
|
||||||
|
"example_message": "Hello {name}, you can play any text on any supported media player!",
|
||||||
|
"target": "Target",
|
||||||
|
"target_browser": "Browser",
|
||||||
|
"play": "Play"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"remote": {
|
"remote": {
|
||||||
"title": "Remote Control",
|
"title": "Remote Control",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user