mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-17 22:36:35 +00:00
Add add-on installation to voice setup flow (#23018)
This commit is contained in:
parent
2782b2fb1b
commit
0a954cf1c7
@ -93,7 +93,7 @@ export class CloudStepIntro extends LitElement {
|
|||||||
<a
|
<a
|
||||||
href="https://www.nabucasa.com"
|
href="https://www.nabucasa.com"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer noopenner"
|
rel="noreferrer noopener"
|
||||||
>
|
>
|
||||||
<ha-button>
|
<ha-button>
|
||||||
<ha-svg-icon .path=${mdiOpenInNew} slot="icon"></ha-svg-icon>
|
<ha-svg-icon .path=${mdiOpenInNew} slot="icon"></ha-svg-icon>
|
||||||
|
@ -22,6 +22,7 @@ import "./voice-assistant-setup-step-pipeline";
|
|||||||
import "./voice-assistant-setup-step-success";
|
import "./voice-assistant-setup-step-success";
|
||||||
import "./voice-assistant-setup-step-update";
|
import "./voice-assistant-setup-step-update";
|
||||||
import "./voice-assistant-setup-step-wake-word";
|
import "./voice-assistant-setup-step-wake-word";
|
||||||
|
import "./voice-assistant-setup-step-local";
|
||||||
|
|
||||||
export const enum STEP {
|
export const enum STEP {
|
||||||
INIT,
|
INIT,
|
||||||
@ -32,6 +33,7 @@ export const enum STEP {
|
|||||||
PIPELINE,
|
PIPELINE,
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
CLOUD,
|
CLOUD,
|
||||||
|
LOCAL,
|
||||||
CHANGE_WAKEWORD,
|
CHANGE_WAKEWORD,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,22 +120,24 @@ export class HaVoiceAssistantSetupDialog extends LitElement {
|
|||||||
scrimClickAction
|
scrimClickAction
|
||||||
>
|
>
|
||||||
<ha-dialog-header slot="heading">
|
<ha-dialog-header slot="heading">
|
||||||
${this._previousSteps.length
|
${this._step === STEP.LOCAL
|
||||||
? html`<ha-icon-button
|
? nothing
|
||||||
slot="navigationIcon"
|
: this._previousSteps.length
|
||||||
.label=${this.hass.localize("ui.common.back") ?? "Back"}
|
|
||||||
.path=${mdiChevronLeft}
|
|
||||||
@click=${this._goToPreviousStep}
|
|
||||||
></ha-icon-button>`
|
|
||||||
: this._step !== STEP.UPDATE
|
|
||||||
? html`<ha-icon-button
|
? html`<ha-icon-button
|
||||||
slot="navigationIcon"
|
slot="navigationIcon"
|
||||||
.label=${this.hass.localize("ui.dialogs.generic.close") ??
|
.label=${this.hass.localize("ui.common.back") ?? "Back"}
|
||||||
"Close"}
|
.path=${mdiChevronLeft}
|
||||||
.path=${mdiClose}
|
@click=${this._goToPreviousStep}
|
||||||
@click=${this.closeDialog}
|
|
||||||
></ha-icon-button>`
|
></ha-icon-button>`
|
||||||
: nothing}
|
: this._step !== STEP.UPDATE
|
||||||
|
? html`<ha-icon-button
|
||||||
|
slot="navigationIcon"
|
||||||
|
.label=${this.hass.localize("ui.dialogs.generic.close") ??
|
||||||
|
"Close"}
|
||||||
|
.path=${mdiClose}
|
||||||
|
@click=${this.closeDialog}
|
||||||
|
></ha-icon-button>`
|
||||||
|
: nothing}
|
||||||
${this._step === STEP.WAKEWORD ||
|
${this._step === STEP.WAKEWORD ||
|
||||||
this._step === STEP.AREA ||
|
this._step === STEP.AREA ||
|
||||||
this._step === STEP.PIPELINE
|
this._step === STEP.PIPELINE
|
||||||
@ -145,7 +149,11 @@ export class HaVoiceAssistantSetupDialog extends LitElement {
|
|||||||
>`
|
>`
|
||||||
: nothing}
|
: nothing}
|
||||||
</ha-dialog-header>
|
</ha-dialog-header>
|
||||||
<div class="content" @next-step=${this._goToNextStep}>
|
<div
|
||||||
|
class="content"
|
||||||
|
@next-step=${this._goToNextStep}
|
||||||
|
@prev-step=${this._goToPreviousStep}
|
||||||
|
>
|
||||||
${this._step === STEP.UPDATE
|
${this._step === STEP.UPDATE
|
||||||
? html`<ha-voice-assistant-setup-step-update
|
? html`<ha-voice-assistant-setup-step-update
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -197,14 +205,20 @@ export class HaVoiceAssistantSetupDialog extends LitElement {
|
|||||||
? html`<ha-voice-assistant-setup-step-cloud
|
? html`<ha-voice-assistant-setup-step-cloud
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
></ha-voice-assistant-setup-step-cloud>`
|
></ha-voice-assistant-setup-step-cloud>`
|
||||||
: this._step === STEP.SUCCESS
|
: this._step === STEP.LOCAL
|
||||||
? html`<ha-voice-assistant-setup-step-success
|
? html`<ha-voice-assistant-setup-step-local
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.assistConfiguration=${this
|
.assistConfiguration=${this
|
||||||
._assistConfiguration}
|
._assistConfiguration}
|
||||||
.assistEntityId=${assistSatelliteEntityId}
|
></ha-voice-assistant-setup-step-local>`
|
||||||
></ha-voice-assistant-setup-step-success>`
|
: this._step === STEP.SUCCESS
|
||||||
: nothing}
|
? html`<ha-voice-assistant-setup-step-success
|
||||||
|
.hass=${this.hass}
|
||||||
|
.assistConfiguration=${this
|
||||||
|
._assistConfiguration}
|
||||||
|
.assistEntityId=${assistSatelliteEntityId}
|
||||||
|
></ha-voice-assistant-setup-step-success>`
|
||||||
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
@ -229,17 +243,17 @@ export class HaVoiceAssistantSetupDialog extends LitElement {
|
|||||||
this._step = this._previousSteps.pop()!;
|
this._step = this._previousSteps.pop()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _goToNextStep(ev) {
|
private _goToNextStep(ev?: CustomEvent) {
|
||||||
if (ev.detail?.updateConfig) {
|
if (ev?.detail?.updateConfig) {
|
||||||
this._fetchAssistConfiguration();
|
this._fetchAssistConfiguration();
|
||||||
}
|
}
|
||||||
if (ev.detail?.nextStep) {
|
if (ev?.detail?.nextStep) {
|
||||||
this._nextStep = ev.detail.nextStep;
|
this._nextStep = ev.detail.nextStep;
|
||||||
}
|
}
|
||||||
if (!ev.detail?.noPrevious) {
|
if (!ev?.detail?.noPrevious) {
|
||||||
this._previousSteps.push(this._step);
|
this._previousSteps.push(this._step);
|
||||||
}
|
}
|
||||||
if (ev.detail?.step) {
|
if (ev?.detail?.step) {
|
||||||
this._step = ev.detail.step;
|
this._step = ev.detail.step;
|
||||||
} else if (this._nextStep) {
|
} else if (this._nextStep) {
|
||||||
this._step = this._nextStep;
|
this._step = this._nextStep;
|
||||||
@ -294,5 +308,6 @@ declare global {
|
|||||||
nextStep?: STEP;
|
nextStep?: STEP;
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
|
"prev-step": undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,350 @@
|
|||||||
|
import { mdiOpenInNew } from "@mdi/js";
|
||||||
|
import type { PropertyValues } from "lit";
|
||||||
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
|
import "../../components/ha-circular-progress";
|
||||||
|
import {
|
||||||
|
createAssistPipeline,
|
||||||
|
listAssistPipelines,
|
||||||
|
} from "../../data/assist_pipeline";
|
||||||
|
import type { AssistSatelliteConfiguration } from "../../data/assist_satellite";
|
||||||
|
import { createConfigFlow, handleConfigFlowStep } from "../../data/config_flow";
|
||||||
|
import type { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
||||||
|
import {
|
||||||
|
fetchHassioAddonsInfo,
|
||||||
|
installHassioAddon,
|
||||||
|
startHassioAddon,
|
||||||
|
} from "../../data/hassio/addon";
|
||||||
|
import { listSTTEngines } from "../../data/stt";
|
||||||
|
import { listTTSEngines, listTTSVoices } from "../../data/tts";
|
||||||
|
import type { HomeAssistant } from "../../types";
|
||||||
|
import { documentationUrl } from "../../util/documentation-url";
|
||||||
|
import { AssistantSetupStyles } from "./styles";
|
||||||
|
import { STEP } from "./voice-assistant-setup-dialog";
|
||||||
|
|
||||||
|
@customElement("ha-voice-assistant-setup-step-local")
|
||||||
|
export class HaVoiceAssistantSetupStepLocal extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public assistConfiguration?: AssistSatelliteConfiguration;
|
||||||
|
|
||||||
|
@state() private _state: "INSTALLING" | "NOT_SUPPORTED" | "ERROR" | "INTRO" =
|
||||||
|
"INTRO";
|
||||||
|
|
||||||
|
@state() private _detailState?: string;
|
||||||
|
|
||||||
|
@state() private _localTts?: EntityRegistryDisplayEntry[];
|
||||||
|
|
||||||
|
@state() private _localStt?: EntityRegistryDisplayEntry[];
|
||||||
|
|
||||||
|
protected override render() {
|
||||||
|
return html`<div class="content">
|
||||||
|
${this._state === "INSTALLING"
|
||||||
|
? html`<img src="/static/images/voice-assistant/update.png" />
|
||||||
|
<h1>Installing add-ons</h1>
|
||||||
|
<p>
|
||||||
|
The Whisper and Piper add-ons are being installed and configured.
|
||||||
|
</p>
|
||||||
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
|
<p>
|
||||||
|
${this._detailState || "Installation can take several minutes"}
|
||||||
|
</p>`
|
||||||
|
: this._state === "ERROR"
|
||||||
|
? html` <img src="/static/images/voice-assistant/error.png" />
|
||||||
|
<h1>Failed to install add-ons</h1>
|
||||||
|
<p>
|
||||||
|
We could not automatically install a local TTS and STT provider
|
||||||
|
for you. Read the documentation to learn how to install them.
|
||||||
|
</p>
|
||||||
|
<ha-button @click=${this._prevStep}>Go back</ha-button>
|
||||||
|
<a
|
||||||
|
href=${documentationUrl(
|
||||||
|
this.hass,
|
||||||
|
"/voice_control/voice_remote_local_assistant/"
|
||||||
|
)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
>
|
||||||
|
<ha-button>
|
||||||
|
<ha-svg-icon .path=${mdiOpenInNew} slot="icon"></ha-svg-icon>
|
||||||
|
Learn more</ha-button
|
||||||
|
>
|
||||||
|
</a>`
|
||||||
|
: this._state === "NOT_SUPPORTED"
|
||||||
|
? html`<img src="/static/images/voice-assistant/error.png" />
|
||||||
|
<h1>Installation of add-ons is not supported on your system</h1>
|
||||||
|
<p>
|
||||||
|
Your system is not supported to automatically install a local
|
||||||
|
TTS and STT provider. Learn how to set up local TTS and STT
|
||||||
|
providers in the documentation.
|
||||||
|
</p>
|
||||||
|
<ha-button @click=${this._prevStep}>Go back</ha-button>
|
||||||
|
<a
|
||||||
|
href=${documentationUrl(
|
||||||
|
this.hass,
|
||||||
|
"/voice_control/voice_remote_local_assistant/"
|
||||||
|
)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
>
|
||||||
|
<ha-button>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${mdiOpenInNew}
|
||||||
|
slot="icon"
|
||||||
|
></ha-svg-icon>
|
||||||
|
Learn more</ha-button
|
||||||
|
>
|
||||||
|
</a>`
|
||||||
|
: nothing}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override willUpdate(changedProperties: PropertyValues): void {
|
||||||
|
super.willUpdate(changedProperties);
|
||||||
|
|
||||||
|
if (!this.hasUpdated) {
|
||||||
|
this._checkLocal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _prevStep() {
|
||||||
|
fireEvent(this, "prev-step");
|
||||||
|
}
|
||||||
|
|
||||||
|
private _nextStep() {
|
||||||
|
fireEvent(this, "next-step", { step: STEP.SUCCESS, noPrevious: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _checkLocal() {
|
||||||
|
this._findLocalEntities();
|
||||||
|
if (!this._localTts || !this._localStt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._localTts.length && this._localStt.length) {
|
||||||
|
this._pickOrCreatePipelineExists();
|
||||||
|
}
|
||||||
|
if (!isComponentLoaded(this.hass, "hassio")) {
|
||||||
|
this._state = "NOT_SUPPORTED";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._state = "INSTALLING";
|
||||||
|
try {
|
||||||
|
const { addons } = await fetchHassioAddonsInfo(this.hass);
|
||||||
|
const whisper = addons.find((addon) => addon.slug === "core_whisper");
|
||||||
|
const piper = addons.find((addon) => addon.slug === "core_piper");
|
||||||
|
if (piper && !this._localTts.length) {
|
||||||
|
if (piper.state !== "started") {
|
||||||
|
this._detailState = "Starting Piper add-on";
|
||||||
|
await startHassioAddon(this.hass, "core_piper");
|
||||||
|
}
|
||||||
|
this._detailState = "Setting up Piper";
|
||||||
|
await this._setupConfigEntry("piper");
|
||||||
|
}
|
||||||
|
if (whisper && !this._localStt.length) {
|
||||||
|
if (whisper.state !== "started") {
|
||||||
|
this._detailState = "Starting Whisper add-on";
|
||||||
|
await startHassioAddon(this.hass, "core_whisper");
|
||||||
|
}
|
||||||
|
this._detailState = "Setting up Whisper";
|
||||||
|
await this._setupConfigEntry("whisper");
|
||||||
|
}
|
||||||
|
if (!piper) {
|
||||||
|
this._detailState = "Installing Piper add-on";
|
||||||
|
await installHassioAddon(this.hass, "core_piper");
|
||||||
|
this._detailState = "Starting Piper add-on";
|
||||||
|
await startHassioAddon(this.hass, "core_piper");
|
||||||
|
this._detailState = "Setting up Piper";
|
||||||
|
await this._setupConfigEntry("piper");
|
||||||
|
}
|
||||||
|
if (!whisper) {
|
||||||
|
this._detailState = "Installing Whisper add-on";
|
||||||
|
await installHassioAddon(this.hass, "core_whisper");
|
||||||
|
this._detailState = "Starting Whisper add-on";
|
||||||
|
await startHassioAddon(this.hass, "core_whisper");
|
||||||
|
this._detailState = "Setting up Whisper";
|
||||||
|
await this._setupConfigEntry("whisper");
|
||||||
|
}
|
||||||
|
this._detailState = "Creating assistant";
|
||||||
|
this._findEntitiesAndCreatePipeline();
|
||||||
|
} catch (e) {
|
||||||
|
this._state = "ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _findLocalEntities() {
|
||||||
|
const wyomingEntities = Object.values(this.hass.entities).filter(
|
||||||
|
(entity) => entity.platform === "wyoming"
|
||||||
|
);
|
||||||
|
this._localTts = wyomingEntities.filter(
|
||||||
|
(ent) => computeDomain(ent.entity_id) === "tts"
|
||||||
|
);
|
||||||
|
this._localStt = wyomingEntities.filter(
|
||||||
|
(ent) => computeDomain(ent.entity_id) === "stt"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _setupConfigEntry(addon: string) {
|
||||||
|
const configFlow = await createConfigFlow(this.hass, "wyoming");
|
||||||
|
const step = await handleConfigFlowStep(this.hass, configFlow.flow_id, {
|
||||||
|
host: `core_${addon}`,
|
||||||
|
port: addon === "piper" ? 10200 : 10300,
|
||||||
|
});
|
||||||
|
if (step.type !== "create_entry") {
|
||||||
|
throw new Error("Failed to create entry");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _pickOrCreatePipelineExists() {
|
||||||
|
// Check if a pipeline already exists with local TTS and STT
|
||||||
|
|
||||||
|
if (!this._localStt?.length || !this._localTts?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipelines = await listAssistPipelines(this.hass);
|
||||||
|
const preferredPipeline = pipelines.pipelines.find(
|
||||||
|
(pipeline) => pipeline.id === pipelines.preferred_pipeline
|
||||||
|
);
|
||||||
|
|
||||||
|
const ttsEntityIds = this._localTts.map((ent) => ent.entity_id);
|
||||||
|
const sttEntityIds = this._localStt.map((ent) => ent.entity_id);
|
||||||
|
|
||||||
|
if (preferredPipeline) {
|
||||||
|
if (
|
||||||
|
preferredPipeline.tts_engine &&
|
||||||
|
ttsEntityIds.includes(preferredPipeline.tts_engine) &&
|
||||||
|
preferredPipeline.stt_engine &&
|
||||||
|
sttEntityIds.includes(preferredPipeline.stt_engine)
|
||||||
|
) {
|
||||||
|
await this.hass.callService(
|
||||||
|
"select",
|
||||||
|
"select_option",
|
||||||
|
{ option: "preferred" },
|
||||||
|
{ entity_id: this.assistConfiguration?.pipeline_entity_id }
|
||||||
|
);
|
||||||
|
this._nextStep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let localPipeline = pipelines.pipelines.find(
|
||||||
|
(pipeline) =>
|
||||||
|
pipeline.tts_engine &&
|
||||||
|
ttsEntityIds.includes(pipeline.tts_engine) &&
|
||||||
|
pipeline.stt_engine &&
|
||||||
|
sttEntityIds.includes(pipeline.stt_engine)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!localPipeline) {
|
||||||
|
localPipeline = await this._createPipeline(
|
||||||
|
this._localTts[0].entity_id,
|
||||||
|
this._localStt[0].entity_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.hass.callService(
|
||||||
|
"select",
|
||||||
|
"select_option",
|
||||||
|
{ option: localPipeline.name },
|
||||||
|
{ entity_id: this.assistConfiguration?.pipeline_entity_id }
|
||||||
|
);
|
||||||
|
this._nextStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _createPipeline(ttsEntityId: string, sttEntityId: string) {
|
||||||
|
// Create a pipeline with local TTS and STT
|
||||||
|
|
||||||
|
const pipelines = await listAssistPipelines(this.hass);
|
||||||
|
|
||||||
|
const ttsEngine = (
|
||||||
|
await listTTSEngines(
|
||||||
|
this.hass,
|
||||||
|
this.hass.config.language,
|
||||||
|
this.hass.config.country || undefined
|
||||||
|
)
|
||||||
|
).providers.find((provider) => provider.engine_id === ttsEntityId);
|
||||||
|
const ttsVoices = await listTTSVoices(
|
||||||
|
this.hass,
|
||||||
|
ttsEntityId,
|
||||||
|
ttsEngine?.supported_languages![0] || this.hass.config.language
|
||||||
|
);
|
||||||
|
|
||||||
|
const sttEngine = (
|
||||||
|
await listSTTEngines(
|
||||||
|
this.hass,
|
||||||
|
this.hass.config.language,
|
||||||
|
this.hass.config.country || undefined
|
||||||
|
)
|
||||||
|
).providers.find((provider) => provider.engine_id === sttEntityId);
|
||||||
|
|
||||||
|
let pipelineName = "Local Assistant";
|
||||||
|
let i = 1;
|
||||||
|
while (
|
||||||
|
pipelines.pipelines.find(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||||
|
(pipeline) => pipeline.name === pipelineName
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
pipelineName = `Local Assistant ${i}`;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createAssistPipeline(this.hass, {
|
||||||
|
name: pipelineName,
|
||||||
|
language: this.hass.config.language.split("-")[0],
|
||||||
|
conversation_engine: "conversation.home_assistant",
|
||||||
|
conversation_language: this.hass.config.language.split("-")[0],
|
||||||
|
stt_engine: sttEntityId,
|
||||||
|
stt_language: sttEngine!.supported_languages![0],
|
||||||
|
tts_engine: ttsEntityId,
|
||||||
|
tts_language: ttsEngine!.supported_languages![0],
|
||||||
|
tts_voice: ttsVoices.voices![0].voice_id,
|
||||||
|
wake_word_entity: null,
|
||||||
|
wake_word_id: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _findEntitiesAndCreatePipeline(tryNo: number = 0) {
|
||||||
|
this._findLocalEntities();
|
||||||
|
if (!this._localTts?.length || !this._localStt?.length) {
|
||||||
|
if (tryNo > 3) {
|
||||||
|
throw new Error("Timeout searching for local TTS and STT entities");
|
||||||
|
}
|
||||||
|
setTimeout(() => this._findEntitiesAndCreatePipeline(tryNo + 1), 2000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localPipeline = await this._createPipeline(
|
||||||
|
this._localTts[0].entity_id,
|
||||||
|
this._localStt[0].entity_id
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.hass.callService(
|
||||||
|
"select",
|
||||||
|
"select_option",
|
||||||
|
{ option: localPipeline.name },
|
||||||
|
{ entity_id: this.assistConfiguration?.pipeline_entity_id }
|
||||||
|
);
|
||||||
|
this._nextStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
AssistantSetupStyles,
|
||||||
|
css`
|
||||||
|
ha-circular-progress {
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-voice-assistant-setup-step-local": HaVoiceAssistantSetupStepLocal;
|
||||||
|
}
|
||||||
|
}
|
@ -14,9 +14,9 @@ import { fetchCloudStatus } from "../../data/cloud";
|
|||||||
import { listSTTEngines } from "../../data/stt";
|
import { listSTTEngines } from "../../data/stt";
|
||||||
import { listTTSEngines, listTTSVoices } from "../../data/tts";
|
import { listTTSEngines, listTTSVoices } from "../../data/tts";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { documentationUrl } from "../../util/documentation-url";
|
|
||||||
import { AssistantSetupStyles } from "./styles";
|
import { AssistantSetupStyles } from "./styles";
|
||||||
import { STEP } from "./voice-assistant-setup-dialog";
|
import { STEP } from "./voice-assistant-setup-dialog";
|
||||||
|
import { documentationUrl } from "../../util/documentation-url";
|
||||||
|
|
||||||
@customElement("ha-voice-assistant-setup-step-pipeline")
|
@customElement("ha-voice-assistant-setup-step-pipeline")
|
||||||
export class HaVoiceAssistantSetupStepPipeline extends LitElement {
|
export class HaVoiceAssistantSetupStepPipeline extends LitElement {
|
||||||
@ -93,7 +93,7 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
<h2>Home Assistant Cloud</h2>
|
<h2>Home Assistant Cloud</h2>
|
||||||
<p>Ideal if you don't have a powerful system at home.</p>
|
<p>Ideal if you don't have a powerful system at home.</p>
|
||||||
<ha-button @click=${this._setupCloud}>Learn more</ha-button>
|
<ha-button @click=${this._setupCloud} unelevated>Learn more</ha-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="messages-container rpi">
|
<div class="messages-container rpi">
|
||||||
@ -117,19 +117,24 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
|
|||||||
Install add-ons or containers to run it on your own system. Powerful
|
Install add-ons or containers to run it on your own system. Powerful
|
||||||
hardware is needed for fast responses.
|
hardware is needed for fast responses.
|
||||||
</p>
|
</p>
|
||||||
<a
|
<div class="row">
|
||||||
href=${documentationUrl(
|
<a
|
||||||
this.hass,
|
href=${documentationUrl(
|
||||||
"/voice_control/voice_remote_local_assistant/"
|
this.hass,
|
||||||
)}
|
"/voice_control/voice_remote_local_assistant/"
|
||||||
target="_blank"
|
)}
|
||||||
rel="noreferrer noopenner"
|
target="_blank"
|
||||||
>
|
rel="noreferrer noopener"
|
||||||
<ha-button @click=${this._skip}>
|
|
||||||
<ha-svg-icon .path=${mdiOpenInNew} slot="icon"></ha-svg-icon>
|
|
||||||
Learn more</ha-button
|
|
||||||
>
|
>
|
||||||
</a>
|
<ha-button>
|
||||||
|
<ha-svg-icon .path=${mdiOpenInNew} slot="icon"></ha-svg-icon>
|
||||||
|
Learn more</ha-button
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
<ha-button @click=${this._setupLocal} unelevated
|
||||||
|
>Setup with add-ons</ha-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
@ -218,15 +223,15 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
|
|||||||
(pipeline) => pipeline.name === pipelineName
|
(pipeline) => pipeline.name === pipelineName
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
pipelineName = `${pipelineName} ${i}`;
|
pipelineName = `Home Assistant Cloud ${i}`;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cloudPipeline = await createAssistPipeline(this.hass, {
|
cloudPipeline = await createAssistPipeline(this.hass, {
|
||||||
name: pipelineName,
|
name: pipelineName,
|
||||||
language: this.hass.config.language,
|
language: this.hass.config.language.split("-")[0],
|
||||||
conversation_engine: "conversation.home_assistant",
|
conversation_engine: "conversation.home_assistant",
|
||||||
conversation_language: this.hass.config.language,
|
conversation_language: this.hass.config.language.split("-")[0],
|
||||||
stt_engine: cloudSttEntityId,
|
stt_engine: cloudSttEntityId,
|
||||||
stt_language: sttEngine!.supported_languages![0],
|
stt_language: sttEngine!.supported_languages![0],
|
||||||
tts_engine: cloudTtsEntityId,
|
tts_engine: cloudTtsEntityId,
|
||||||
@ -250,8 +255,8 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
|
|||||||
this._nextStep(STEP.CLOUD);
|
this._nextStep(STEP.CLOUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _skip() {
|
private async _setupLocal() {
|
||||||
this._nextStep(STEP.SUCCESS);
|
this._nextStep(STEP.LOCAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _nextStep(step?: STEP) {
|
private _nextStep(step?: STEP) {
|
||||||
@ -334,6 +339,11 @@ export class HaVoiceAssistantSetupStepPipeline extends LitElement {
|
|||||||
.message.hass.show {
|
.message.hass.show {
|
||||||
width: 184px;
|
width: 184px;
|
||||||
}
|
}
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 0 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user