diff --git a/src/components/ha-conversation-agent-picker.ts b/src/components/ha-conversation-agent-picker.ts index 5175e99f35..b87f75f151 100644 --- a/src/components/ha-conversation-agent-picker.ts +++ b/src/components/ha-conversation-agent-picker.ts @@ -15,7 +15,7 @@ import "./ha-list-item"; import "./ha-select"; import type { HaSelect } from "./ha-select"; -const DEFAULT = "default_agent_option"; +const NONE = "__NONE_OPTION__"; @customElement("ha-conversation-agent-picker") export class HaConversationAgentPicker extends LitElement { @property() public value?: string; @@ -36,7 +36,7 @@ export class HaConversationAgentPicker extends LitElement { if (!this._agents) { return nothing; } - const value = this.value ?? DEFAULT; + const value = this.value ?? (this.required ? this._defaultAgent : NONE); return html` - - ${this.hass!.localize( - "ui.components.coversation-agent-picker.default", - { - default: this._agents.find( - (agent) => agent.id === this._defaultAgent - )?.name, - } - )} - + ${!this.required + ? html` + ${this.hass!.localize( + "ui.components.coversation-agent-picker.none" + )} + ` + : nothing} ${this._agents.map( (agent) => html`${agent.name}` @@ -93,11 +90,11 @@ export class HaConversationAgentPicker extends LitElement { !this.hass || target.value === "" || target.value === this.value || - (this.value === undefined && target.value === DEFAULT) + (this.value === undefined && target.value === NONE) ) { return; } - this.value = target.value === DEFAULT ? undefined : target.value; + this.value = target.value === NONE ? undefined : target.value; fireEvent(this, "value-changed", { value: this.value }); } } diff --git a/src/components/ha-stt-picker.ts b/src/components/ha-stt-picker.ts index bbaab72be4..b7e998fb92 100644 --- a/src/components/ha-stt-picker.ts +++ b/src/components/ha-stt-picker.ts @@ -3,20 +3,22 @@ import { CSSResultGroup, html, LitElement, - PropertyValueMap, + nothing, + PropertyValues, TemplateResult, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { stopPropagation } from "../common/dom/stop_propagation"; import { computeStateName } from "../common/entity/compute_state_name"; +import { debounce } from "../common/util/debounce"; import { listSTTEngines, STTEngine } from "../data/stt"; import { HomeAssistant } from "../types"; import "./ha-list-item"; import "./ha-select"; import type { HaSelect } from "./ha-select"; -const DEFAULT = "default_engine_option"; +const NONE = "__NONE_OPTION__"; @customElement("ha-stt-picker") export class HaSTTPicker extends LitElement { @@ -35,7 +37,11 @@ export class HaSTTPicker extends LitElement { @state() _engines: STTEngine[] = []; protected render(): TemplateResult { - const value = this.value ?? DEFAULT; + const value = + this.value ?? + (this.required + ? this._engines.find((engine) => engine.language_supported) + : NONE); return html` - - ${this.hass!.localize("ui.components.stt-picker.default")} - + ${!this.required + ? html` + ${this.hass!.localize("ui.components.stt-picker.none")} + ` + : nothing} ${this._engines.map((engine) => { const stateObj = this.hass!.states[engine.engine_id]; return html` | Map - ): void { + protected willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); - if (!this.hasUpdated || changedProperties.has("language")) { - listSTTEngines(this.hass, this.language).then((engines) => { - this._engines = engines.providers; - }); + if (!this.hasUpdated) { + this._updateEngines(); + } else if (changedProperties.has("language")) { + this._debouncedUpdateEngines(); + } + } + + private _debouncedUpdateEngines = debounce(() => this._updateEngines(), 500); + + private async _updateEngines() { + this._engines = (await listSTTEngines(this.hass, this.language)).providers; + + if ( + this.value && + !this._engines.find((engine) => engine.engine_id === this.value) + ?.language_supported + ) { + this.value = undefined; + fireEvent(this, "value-changed", { value: this.value }); } } @@ -89,11 +110,11 @@ export class HaSTTPicker extends LitElement { !this.hass || target.value === "" || target.value === this.value || - (this.value === undefined && target.value === DEFAULT) + (this.value === undefined && target.value === NONE) ) { return; } - this.value = target.value === DEFAULT ? undefined : target.value; + this.value = target.value === NONE ? undefined : target.value; fireEvent(this, "value-changed", { value: this.value }); } } diff --git a/src/components/ha-tts-picker.ts b/src/components/ha-tts-picker.ts index c0d5916a4d..fe671b3bea 100644 --- a/src/components/ha-tts-picker.ts +++ b/src/components/ha-tts-picker.ts @@ -1,22 +1,24 @@ +import { debounce } from "chart.js/helpers"; import { css, CSSResultGroup, html, LitElement, - PropertyValueMap, + nothing, + PropertyValues, TemplateResult, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { stopPropagation } from "../common/dom/stop_propagation"; import { computeStateName } from "../common/entity/compute_state_name"; -import { TTSEngine, listTTSEngines } from "../data/tts"; +import { listTTSEngines, TTSEngine } from "../data/tts"; import { HomeAssistant } from "../types"; -import "./ha-select"; import "./ha-list-item"; +import "./ha-select"; import type { HaSelect } from "./ha-select"; -const DEFAULT = "default_engine_option"; +const NONE = "__NONE_OPTION__"; @customElement("ha-tts-picker") export class HaTTSPicker extends LitElement { @@ -35,7 +37,11 @@ export class HaTTSPicker extends LitElement { @state() _engines: TTSEngine[] = []; protected render(): TemplateResult { - const value = this.value ?? DEFAULT; + const value = + this.value ?? + (this.required + ? this._engines.find((engine) => engine.language_supported) + : NONE); return html` - - ${this.hass!.localize("ui.components.tts-picker.default")} - + ${!this.required + ? html` + ${this.hass!.localize("ui.components.tts-picker.none")} + ` + : nothing} ${this._engines.map((engine) => { const stateObj = this.hass!.states[engine.engine_id]; return html` | Map - ): void { + protected willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); - if (!this.hasUpdated || changedProperties.has("language")) { - listTTSEngines(this.hass, this.language).then((engines) => { - this._engines = engines.providers; - }); + if (!this.hasUpdated) { + this._updateEngines(); + } else if (changedProperties.has("language")) { + this._debouncedUpdateEngines(); + } + } + + private _debouncedUpdateEngines = debounce(() => this._updateEngines(), 500); + + private async _updateEngines() { + this._engines = (await listTTSEngines(this.hass, this.language)).providers; + + if ( + this.value && + !this._engines.find((engine) => engine.engine_id === this.value) + ?.language_supported + ) { + this.value = undefined; + fireEvent(this, "value-changed", { value: this.value }); } } @@ -89,11 +110,11 @@ export class HaTTSPicker extends LitElement { !this.hass || target.value === "" || target.value === this.value || - (this.value === undefined && target.value === DEFAULT) + (this.value === undefined && target.value === NONE) ) { return; } - this.value = target.value === DEFAULT ? undefined : target.value; + this.value = target.value === NONE ? undefined : target.value; fireEvent(this, "value-changed", { value: this.value }); } } diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts index 66e5cefa56..3bd1bd00c4 100644 --- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts +++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts @@ -131,6 +131,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement { }, { name: "conversation_engine", + required: true, selector: { conversation_agent: {}, }, diff --git a/src/translations/en.json b/src/translations/en.json index ffc8b1fd16..6034c59a02 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -403,7 +403,7 @@ }, "coversation-agent-picker": { "conversation_agent": "Conversation agent", - "default": "Default agent ({default})" + "none": "None" }, "theme-picker": { "theme": "Theme", @@ -411,7 +411,7 @@ }, "tts-picker": { "tts": "Text to Speech", - "default": "Default" + "none": "None" }, "user-picker": { "no_user": "No user", @@ -466,7 +466,7 @@ } } }, - "stt-picker": { "stt": "Speech to text", "default": "Default" }, + "stt-picker": { "stt": "Speech to text", "none": "None" }, "related-filter-menu": { "filter": "Filter", "filter_by_entity": "Filter by entity",