Add more info dialog for conversation agent (#23682)

* Add more info dialog for conversation agent

* Fixes

* Disable speech option for LLM testing

* Address comments

* New style more info

* Also reset errors on loading pipeline
This commit is contained in:
Paulus Schoutsen 2025-01-15 04:57:49 -05:00 committed by GitHub
parent e54f178b02
commit d112872eb2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 143 additions and 18 deletions

View File

@ -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

View File

@ -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",

View File

@ -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`<ha-alert alert-type="error">
${this.hass.localize(
`ui.dialogs.voice_command.${this._errorLoadAssist}_error_load_assist`
)}
</ha-alert>`
: this._pipeline
? html`
<ha-assist-chat
.hass=${this.hass}
.pipeline=${this._pipeline}
disable-speech
></ha-assist-chat>
`
: html`<div class="pipelines-loading">
<ha-circular-progress
indeterminate
size="large"
></ha-circular-progress>
</div>`}
`;
}
static styles = css`
:host {
display: flex;
flex: 1;
}
ha-assist-chat {
flex: 1;
min-height: 400px;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"more-info-conversation": MoreInfoConversation;
}
}

View File

@ -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"),

View File

@ -164,28 +164,27 @@ export class HaVoiceCommandDialog extends LitElement {
</a>
</ha-dialog-header>
${this._pipeline
? html`
<ha-assist-chat
.hass=${this.hass}
.pipeline=${this._pipeline}
.startListening=${this._startListening}
>
</ha-assist-chat>
`
: html`<div class="pipelines-loading">
<ha-circular-progress
indeterminate
size="large"
></ha-circular-progress>
</div>`}
${this._errorLoadAssist
? html`<ha-alert alert-type="error">
${this.hass.localize(
`ui.dialogs.voice_command.${this._errorLoadAssist}_error_load_assist`
)}
</ha-alert>`
: nothing}
: this._pipeline
? html`
<ha-assist-chat
.hass=${this.hass}
.pipeline=${this._pipeline}
.startListening=${this._startListening}
>
</ha-assist-chat>
`
: html`<div class="pipelines-loading">
<ha-circular-progress
indeterminate
size="large"
></ha-circular-progress>
</div>`}
</ha-dialog>
`;
}
@ -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 {