mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add basic assist dev tools (#17062)
This commit is contained in:
parent
cbe8be1573
commit
73e1b4b1d1
@ -1,3 +1,4 @@
|
||||
import { ensureArray } from "../common/array/ensure-array";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
interface IntentTarget {
|
||||
@ -58,6 +59,24 @@ export interface Agent {
|
||||
supported_languages: "*" | string[];
|
||||
}
|
||||
|
||||
export interface AssitDebugResult {
|
||||
intent: {
|
||||
name: string;
|
||||
};
|
||||
entities: Record<
|
||||
string,
|
||||
{
|
||||
name: string;
|
||||
value: string;
|
||||
text: string;
|
||||
}
|
||||
>;
|
||||
}
|
||||
|
||||
export interface AssistDebugResponse {
|
||||
results: (AssitDebugResult | null)[];
|
||||
}
|
||||
|
||||
export const processConversationInput = (
|
||||
hass: HomeAssistant,
|
||||
text: string,
|
||||
@ -91,3 +110,16 @@ export const prepareConversation = (
|
||||
type: "conversation/prepare",
|
||||
language,
|
||||
});
|
||||
|
||||
export const debugAgent = (
|
||||
hass: HomeAssistant,
|
||||
sentences: string[] | string,
|
||||
language: string,
|
||||
device_id?: string
|
||||
): Promise<AssistDebugResponse> =>
|
||||
hass.callWS({
|
||||
type: "conversation/agent/homeassistant/debug",
|
||||
sentences: ensureArray(sentences),
|
||||
language,
|
||||
device_id,
|
||||
});
|
||||
|
240
src/panels/developer-tools/assist/developer-tools-assist.ts
Normal file
240
src/panels/developer-tools/assist/developer-tools-assist.ts
Normal file
@ -0,0 +1,240 @@
|
||||
import { dump } from "js-yaml";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-code-editor";
|
||||
import "../../../components/ha-language-picker";
|
||||
import "../../../components/ha-textarea";
|
||||
import "../../../components/ha-absolute-time";
|
||||
import type { HaTextArea } from "../../../components/ha-textarea";
|
||||
import {
|
||||
AssitDebugResult,
|
||||
debugAgent,
|
||||
listAgents,
|
||||
} from "../../../data/conversation";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { formatLanguageCode } from "../../../common/language/format_language";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
|
||||
type SentenceParsingResult = {
|
||||
sentence: string;
|
||||
language: string;
|
||||
result: AssitDebugResult | null;
|
||||
time: Date;
|
||||
};
|
||||
|
||||
@customElement("developer-tools-assist")
|
||||
class HaPanelDevAssist extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@state() supportedLanguages?: string[];
|
||||
|
||||
@storage({
|
||||
key: "assist_debug_language",
|
||||
state: true,
|
||||
subscribe: false,
|
||||
storage: "localStorage",
|
||||
})
|
||||
_language?: string;
|
||||
|
||||
@state() _results: SentenceParsingResult[] = [];
|
||||
|
||||
@query("#sentences-input") _sentencesInput!: HaTextArea;
|
||||
|
||||
@state() _validInput = false;
|
||||
|
||||
private _languageChanged(ev) {
|
||||
this._language = ev.detail.value;
|
||||
}
|
||||
|
||||
private _textAreaInput(ev) {
|
||||
const value = ev.target.value;
|
||||
const valid = Boolean(value);
|
||||
if (valid !== this._validInput) {
|
||||
this._validInput = valid;
|
||||
}
|
||||
}
|
||||
|
||||
private async _parse() {
|
||||
const sentences = this._sentencesInput.value
|
||||
.split("\n")
|
||||
.filter((a) => a !== "");
|
||||
const { results } = await debugAgent(this.hass, sentences, this._language!);
|
||||
|
||||
this._sentencesInput.value = "";
|
||||
|
||||
const now = new Date();
|
||||
|
||||
const newResults: SentenceParsingResult[] = [];
|
||||
sentences.forEach((sentence, index) => {
|
||||
const result = results[index];
|
||||
|
||||
newResults.push({
|
||||
sentence,
|
||||
language: this._language!,
|
||||
result,
|
||||
time: now,
|
||||
});
|
||||
});
|
||||
this._results = [...newResults, ...this._results];
|
||||
}
|
||||
|
||||
private async _fetchLanguages() {
|
||||
const { agents } = await listAgents(this.hass);
|
||||
const assistAgent = agents.find((agent) => agent.id === "homeassistant");
|
||||
this.supportedLanguages =
|
||||
assistAgent?.supported_languages === "*"
|
||||
? undefined
|
||||
: assistAgent?.supported_languages;
|
||||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
this._fetchLanguages();
|
||||
}
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<div class="content">
|
||||
<ha-card header="Sentences parser" class="form">
|
||||
<div class="card-content">
|
||||
<p class="description">
|
||||
Enter sentences and see how they will be parsed by Home Assistant.
|
||||
Each line will be processed as individual sentence. Intents will
|
||||
not be executed on your instance.
|
||||
</p>
|
||||
${this.supportedLanguages
|
||||
? html`
|
||||
<ha-language-picker
|
||||
.languages=${this.supportedLanguages}
|
||||
.hass=${this.hass}
|
||||
.value=${this._language ?? "en"}
|
||||
@value-changed=${this._languageChanged}
|
||||
></ha-language-picker>
|
||||
`
|
||||
: nothing}
|
||||
<ha-textarea
|
||||
autogrow
|
||||
label="Sentences"
|
||||
id="sentences-input"
|
||||
@input=${this._textAreaInput}
|
||||
></ha-textarea>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-button
|
||||
@click=${this._parse}
|
||||
.disabled=${!this._language || !this._validInput}
|
||||
>
|
||||
Parse sentences
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
|
||||
${this._results.map((r) => {
|
||||
const { sentence, result, language, time } = r;
|
||||
const matched = result != null;
|
||||
|
||||
return html`
|
||||
<ha-card class="result">
|
||||
<div class="card-content">
|
||||
<div class="sentence">
|
||||
<p>${sentence}</p>
|
||||
<p>${matched ? "✅" : "❌"}</p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<p>
|
||||
Language: ${formatLanguageCode(
|
||||
language,
|
||||
this.hass.locale
|
||||
)} (${language})
|
||||
</p>
|
||||
<p>Execution time:
|
||||
<ha-absolute-time .hass=${this.hass} .datetime=${time}>
|
||||
</ha-absolute-time>
|
||||
</p>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
${
|
||||
result
|
||||
? html`
|
||||
<ha-code-editor
|
||||
mode="yaml"
|
||||
.hass=${this.hass}
|
||||
.value=${dump(result).trimRight()}
|
||||
read-only
|
||||
dir="ltr"
|
||||
></ha-code-editor>
|
||||
`
|
||||
: html`<ha-alert alert-type="error"
|
||||
>No intent matched</ha-alert
|
||||
>`
|
||||
}
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.content {
|
||||
padding: 28px 20px 16px;
|
||||
padding: max(28px, calc(12px + env(safe-area-inset-top)))
|
||||
max(20px, calc(4px + env(safe-area-inset-right)))
|
||||
max(16px, env(safe-area-inset-bottom))
|
||||
max(20px, calc(4px + env(safe-area-inset-left)));
|
||||
max-width: 1040px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.description {
|
||||
margin: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
ha-textarea {
|
||||
width: 100%;
|
||||
}
|
||||
.card-actions {
|
||||
text-align: right;
|
||||
}
|
||||
.form {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.result {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.sentence {
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.sentence p {
|
||||
margin: 0;
|
||||
}
|
||||
.info p {
|
||||
margin: 0;
|
||||
}
|
||||
ha-code-editor,
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin-top: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-assist": HaPanelDevAssist;
|
||||
}
|
||||
}
|
@ -45,6 +45,10 @@ class DeveloperToolsRouter extends HassRouterPage {
|
||||
tag: "developer-yaml-config",
|
||||
load: () => import("./yaml_configuration/developer-yaml-config"),
|
||||
},
|
||||
assist: {
|
||||
tag: "developer-tools-assist",
|
||||
load: () => import("./assist/developer-tools-assist"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -65,6 +65,7 @@ class PanelDeveloperTools extends LitElement {
|
||||
"ui.panel.developer-tools.tabs.statistics.title"
|
||||
)}
|
||||
</paper-tab>
|
||||
<paper-tab page-name="assist">Assist</paper-tab>
|
||||
</paper-tabs>
|
||||
</div>
|
||||
<developer-tools-router
|
||||
|
Loading…
x
Reference in New Issue
Block a user