diff --git a/src/components/ha-assist-chat.ts b/src/components/ha-assist-chat.ts index b6e894fa5d..2fca50c4ae 100644 --- a/src/components/ha-assist-chat.ts +++ b/src/components/ha-assist-chat.ts @@ -29,6 +29,9 @@ export class HaAssistChat extends LitElement { @property({ attribute: false }) public pipeline?: AssistPipeline; + @property({ type: Boolean, attribute: "disable-speech" }) + public disableSpeech = false; + @property({ type: Boolean, attribute: false }) public startListening?: boolean; @@ -103,7 +106,7 @@ export class HaAssistChat extends LitElement { ) : true); const supportsMicrophone = AudioRecorder.isSupported; - const supportsSTT = this.pipeline?.stt_engine; + const supportsSTT = this.pipeline?.stt_engine && !this.disableSpeech; return html` ${controlHA diff --git a/src/dialogs/more-info/const.ts b/src/dialogs/more-info/const.ts index 76b51ae791..7c77de80ce 100644 --- a/src/dialogs/more-info/const.ts +++ b/src/dialogs/more-info/const.ts @@ -22,6 +22,7 @@ export const DOMAINS_WITH_NEW_MORE_INFO = [ "alarm_control_panel", "cover", "climate", + "conversation", "fan", "humidifier", "input_boolean", @@ -43,6 +44,7 @@ export const DOMAINS_WITH_MORE_INFO = [ "camera", "climate", "configurator", + "conversation", "counter", "cover", "date", diff --git a/src/dialogs/more-info/controls/more-info-conversation.ts b/src/dialogs/more-info/controls/more-info-conversation.ts new file mode 100644 index 0000000000..6fe8e20c56 --- /dev/null +++ b/src/dialogs/more-info/controls/more-info-conversation.ts @@ -0,0 +1,109 @@ +import type { HassEntity } from "home-assistant-js-websocket"; +import type { PropertyValues } from "lit"; +import { css, html, LitElement, nothing } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import "../../../components/ha-attributes"; +import type { HomeAssistant } from "../../../types"; +import "../../../components/ha-assist-chat"; +import "../../../components/ha-circular-progress"; +import "../../../components/ha-alert"; +import type { AssistPipeline } from "../../../data/assist_pipeline"; +import { getAssistPipeline } from "../../../data/assist_pipeline"; + +@customElement("more-info-conversation") +class MoreInfoConversation extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public stateObj?: HassEntity; + + @state() public _pipeline?: AssistPipeline; + + @state() private _errorLoadAssist?: "not_found" | "unknown"; + + protected willUpdate(changedProperties: PropertyValues): void { + super.willUpdate(changedProperties); + + if (!changedProperties.has("stateObj") || !this.stateObj) { + return; + } + + const oldStateObj = changedProperties.get("stateObj") as + | HassEntity + | undefined; + + if (!oldStateObj || oldStateObj.entity_id !== this.stateObj.entity_id) { + this._getPipeline(); + } + } + + private async _getPipeline() { + this._pipeline = undefined; + this._errorLoadAssist = undefined; + const pipelineId = this.stateObj!.entity_id; + try { + const pipeline = await getAssistPipeline(this.hass, pipelineId); + // Verify the pipeline is still the same. + if (this.stateObj && pipelineId === this.stateObj.entity_id) { + this._pipeline = pipeline; + } + } catch (e: any) { + if (this.stateObj && pipelineId !== this.stateObj.entity_id) { + return; + } + + if (e.code === "not_found") { + this._errorLoadAssist = "not_found"; + } else { + this._errorLoadAssist = "unknown"; + // eslint-disable-next-line no-console + console.error(e); + } + } + } + + protected render() { + if (!this.hass || !this.stateObj) { + return nothing; + } + + return html` + ${this._errorLoadAssist + ? html` + ${this.hass.localize( + `ui.dialogs.voice_command.${this._errorLoadAssist}_error_load_assist` + )} + ` + : this._pipeline + ? html` + + ` + : html`
+ +
`} + `; + } + + static styles = css` + :host { + display: flex; + flex: 1; + } + ha-assist-chat { + flex: 1; + min-height: 400px; + } + `; +} + +declare global { + interface HTMLElementTagNameMap { + "more-info-conversation": MoreInfoConversation; + } +} diff --git a/src/dialogs/more-info/state_more_info_control.ts b/src/dialogs/more-info/state_more_info_control.ts index 2be9b0877b..4b7949b7f0 100644 --- a/src/dialogs/more-info/state_more_info_control.ts +++ b/src/dialogs/more-info/state_more_info_control.ts @@ -11,6 +11,7 @@ const LAZY_LOADED_MORE_INFO_CONTROL = { camera: () => import("./controls/more-info-camera"), climate: () => import("./controls/more-info-climate"), configurator: () => import("./controls/more-info-configurator"), + conversation: () => import("./controls/more-info-conversation"), counter: () => import("./controls/more-info-counter"), cover: () => import("./controls/more-info-cover"), date: () => import("./controls/more-info-date"), diff --git a/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts b/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts index cdd2c02ae5..f6c4f0a187 100644 --- a/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts +++ b/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts @@ -164,28 +164,27 @@ export class HaVoiceCommandDialog extends LitElement { - ${this._pipeline - ? html` - - - ` - : html`
- -
`} ${this._errorLoadAssist ? html` ${this.hass.localize( `ui.dialogs.voice_command.${this._errorLoadAssist}_error_load_assist` )} ` - : nothing} + : this._pipeline + ? html` + + + ` + : html`
+ +
`} `; } @@ -218,9 +217,20 @@ export class HaVoiceCommandDialog extends LitElement { } private async _getPipeline() { + this._pipeline = undefined; + this._errorLoadAssist = undefined; + const pipelineId = this._pipelineId!; try { - this._pipeline = await getAssistPipeline(this.hass, this._pipelineId); + const pipeline = await getAssistPipeline(this.hass, pipelineId); + // Verify the pipeline is still the same. + if (pipelineId === this._pipelineId) { + this._pipeline = pipeline; + } } catch (e: any) { + if (pipelineId !== this._pipelineId) { + return; + } + if (e.code === "not_found") { this._errorLoadAssist = "not_found"; } else {