UNPKG

iobroker.lovelace

Version:

With this adapter you can build visualization for ioBroker with Home Assistant Lovelace UI

3 lines 19.6 kB
"use strict";(self.rspackChunkhome_assistant_frontend=self.rspackChunkhome_assistant_frontend||[]).push([[28845],{85404:function(t,e,s){s.a(t,async function(t,e){try{s(44114),s(54743),s(11745),s(16573),s(78100),s(77936),s(18111),s(61701),s(33110),s(3362),s(42762),s(72107),s(21489),s(48140),s(75044),s(21903),s(91134),s(28845),s(373),s(37467),s(44732),s(79577),s(16632),s(34226),s(9486),s(20456),s(62953);var a=s(40445),i=s(5124),o=s(67576),n=s(6412),r=s(82286),l=s(69150),d=s(88433),c=s(65063),h=s(14503),u=s(74209),p=s(36918),g=s(38962),_=(s(3587),s(91485)),v=t([g,_]);[g,_]=v.then?(await v)():v;let m,f,b,y,k,x,w,M,C,A,$,L,H,S,B,q,z,V=t=>t;const U="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z",R="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z",E="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z",I="M9,22A1,1 0 0,1 8,21V18H4A2,2 0 0,1 2,16V4C2,2.89 2.9,2 4,2H20A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H13.9L10.2,21.71C10,21.9 9.75,22 9.5,22V22H9M10,16V19.08L13.08,16H20V4H4V16H10M17,11H15V9H17V11M13,11H11V9H13V11M9,11H7V9H9V11Z",T="M12,2A3,3 0 0,1 15,5V11A3,3 0 0,1 12,14A3,3 0 0,1 9,11V5A3,3 0 0,1 12,2M19,11C19,14.53 16.39,17.44 13,17.93V21H11V17.93C7.61,17.44 5,14.53 5,11H7A5,5 0 0,0 12,16A5,5 0 0,0 17,11H19Z",O="M2,21L23,12L2,3V10L17,12L2,14V21Z";class N extends i.WF{willUpdate(t){this.hasUpdated&&!t.has("pipeline")||(this._conversation=[{who:"hass",text:this.hass.localize("ui.dialogs.voice_command.how_can_i_help"),thinking:"",tool_calls:{}}])}firstUpdated(t){super.firstUpdated(t),this.startListening&&this.pipeline&&this.pipeline.stt_engine&&u.N.isSupported&&this._toggleListening(),setTimeout(()=>this._messageInput.focus(),0)}updated(t){super.updated(t),t.has("_conversation")&&this._scrollMessagesBottom()}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this._audioRecorder)||void 0===t||t.close(),this._unloadAudio()}render(){var t,e;const s=!!this.pipeline&&(this.pipeline.prefer_local_intents||!this.hass.states[this.pipeline.conversation_engine]||(0,r.$)(this.hass.states[this.pipeline.conversation_engine],d.ZE.CONTROL)),a=u.N.isSupported,o=(null===(t=this.pipeline)||void 0===t?void 0:t.stt_engine)&&!this.disableSpeech;return(0,i.qy)(m||(m=V` <div class="messages ha-scrollbar"> ${0} <div class="spacer"></div> ${0} </div> <div class="input" slot="primaryAction"> <ha-input id="message-input" @keyup="${0}" @input="${0}" .label="${0}"> <div slot="end"> ${0} </div> </ha-input> </div> `),s?i.s6:(0,i.qy)(f||(f=V` <ha-alert> ${0} </ha-alert> `),this.hass.localize("ui.dialogs.voice_command.conversation_no_control")),this._conversation.map((t,e)=>(0,i.qy)(b||(b=V` <div class="message-container ${0}"> ${0} </div> `),(0,n.H)({[t.who]:!0}),t.text||t.error||t.thinking||t.tool_calls&&Object.keys(t.tool_calls).length>0?(0,i.qy)(y||(y=V` <div class="message ${0}"> ${0} ${0} </div> `),(0,n.H)({error:!!t.error,[t.who]:!0}),t.thinking||t.tool_calls&&Object.keys(t.tool_calls).length>0?(0,i.qy)(k||(k=V` <div class="thinking-wrapper ${0}"> <button class="thinking-header" .index="${0}" @click="${0}" aria-expanded="${0}"> <ha-svg-icon .path="${0}"></ha-svg-icon> <span class="thinking-label"> ${0} </span> <ha-svg-icon .path="${0}"></ha-svg-icon> </button> <div class="thinking-content"> ${0} ${0} </div> </div> `),(0,n.H)({expanded:!!t.thinking_expanded}),e,this._handleToggleThinking,t.thinking_expanded?"true":"false",I,this.hass.localize("ui.dialogs.voice_command.show_details"),t.thinking_expanded?E:R,t.thinking?(0,i.qy)(x||(x=V`<ha-markdown .content="${0}"></ha-markdown>`),t.thinking):i.s6,t.tool_calls&&Object.keys(t.tool_calls).length>0?(0,i.qy)(w||(w=V` <div class="tool-calls"> ${0} </div> `),Object.values(t.tool_calls).map(t=>(0,i.qy)(M||(M=V` <div class="tool-call"> <div class="tool-name"> ${0} </div> <div class="tool-data"> <pre> ${0}</pre> </div> ${0} </div> `),t.tool_name,JSON.stringify(t.tool_args,null,2),t.result?(0,i.qy)(C||(C=V` <div class="tool-data"> <pre> ${0}</pre> </div> `),JSON.stringify(t.result,null,2)):i.s6))):i.s6):i.s6,t.text?(0,i.qy)(A||(A=V` <ha-markdown breaks cache .content="${0}"></ha-markdown> `),t.text):i.s6):i.s6)),this._handleKeyUp,this._handleInput,this.hass.localize("ui.dialogs.voice_command.input_label"),this._showSendButton||!o?(0,i.qy)($||($=V` <ha-icon-button class="listening-icon" .path="${0}" @click="${0}" .disabled="${0}" .label="${0}"> </ha-icon-button> `),O,this._handleSendMessage,this._processing,this.hass.localize("ui.dialogs.voice_command.send_text")):(0,i.qy)(L||(L=V` ${0} <div class="listening-icon"> <ha-icon-button .path="${0}" @click="${0}" .disabled="${0}" .label="${0}"> </ha-icon-button> ${0} </div> `),null!==(e=this._audioRecorder)&&void 0!==e&&e.active?(0,i.qy)(H||(H=V` <div class="bouncer"> <div class="double-bounce1"></div> <div class="double-bounce2"></div> </div> `)):i.s6,T,this._handleListeningButton,this._processing,this.hass.localize("ui.dialogs.voice_command.start_listening"),a?null:(0,i.qy)(S||(S=V` <ha-svg-icon .path="${0}" class="unsupported"></ha-svg-icon> `),U)))}async _scrollMessagesBottom(){const t=this._lastChatMessage;if(t.hasUpdated||await t.updateComplete,this._lastChatMessageImage&&!this._lastChatMessageImage.naturalHeight)try{await this._lastChatMessageImage.decode()}catch(e){console.warn("Failed to decode image:",e)}t.getBoundingClientRect().y<this.getBoundingClientRect().top+24||t.scrollIntoView({behavior:"smooth",block:"start"})}_handleKeyUp(t){const e=t.target;!this._processing&&"Enter"===t.key&&e.value&&(this._processText(e.value),e.value="",this._showSendButton=!1)}_handleInput(t){const e=t.target.value;e&&!this._showSendButton?this._showSendButton=!0:!e&&this._showSendButton&&(this._showSendButton=!1)}_handleSendMessage(){this._messageInput.value&&(this._processText(this._messageInput.value.trim()),this._messageInput.value="",this._showSendButton=!1)}_handleListeningButton(t){t.stopPropagation(),t.preventDefault(),this._toggleListening()}async _toggleListening(){var t;u.N.isSupported?null!==(t=this._audioRecorder)&&void 0!==t&&t.active?this._stopListening():this._startListening():this._showNotSupportedMessage()}_handleToggleThinking(t){const e=t.currentTarget.index;this._conversation[e]=Object.assign(Object.assign({},this._conversation[e]),{},{thinking_expanded:!this._conversation[e].thinking_expanded}),this.requestUpdate("_conversation")}_addMessage(t){this._conversation=[...this._conversation,t]}async _showNotSupportedMessage(){this._addMessage({who:"hass",text:(0,i.qy)(B||(B=V`${0} ${0}`),this.hass.localize("ui.dialogs.voice_command.not_supported_microphone_browser"),this.hass.localize("ui.dialogs.voice_command.not_supported_microphone_documentation",{documentation_link:(0,i.qy)(q||(q=V`<a target="_blank" rel="noopener noreferrer" href="${0}">${0}</a>`),(0,p.o)(this.hass,"/docs/configuration/securing/#remote-access"),this.hass.localize("ui.dialogs.voice_command.not_supported_microphone_documentation_link"))})),thinking:"",tool_calls:{}})}async _startListening(){this._unloadAudio(),this._processing=!0,this._audioRecorder||(this._audioRecorder=new u.N(t=>{this._audioBuffer?this._audioBuffer.push(t):this._sendAudioChunk(t)})),this._stt_binary_handler_id=void 0,this._audioBuffer=[];const t={who:"user",text:"…",thinking:"",tool_calls:{}};await this._audioRecorder.start(),this._addMessage(t);const e=this._createAddHassMessageProcessor();try{var s,a;const i=await(0,l.vU)(this.hass,s=>{if("run-start"===s.type)this._stt_binary_handler_id=s.data.runner_data.stt_binary_handler_id,this._audio=new Audio(s.data.tts_output.url),this._audio.play(),this._audio.addEventListener("ended",()=>{this._unloadAudio(),e.continueConversation&&this._startListening()}),this._audio.addEventListener("pause",this._unloadAudio),this._audio.addEventListener("canplaythrough",()=>{var t;return null===(t=this._audio)||void 0===t?void 0:t.play()}),this._audio.addEventListener("error",()=>{this._unloadAudio(),(0,c.showAlertDialog)(this,{title:"Error playing audio."})});else if("stt-start"===s.type&&this._audioBuffer){for(const t of this._audioBuffer)this._sendAudioChunk(t);this._audioBuffer=void 0}else"stt-end"===s.type?(this._stt_binary_handler_id=void 0,this._stopListening(),t.text=s.data.stt_output.text,this.requestUpdate("_conversation"),e.addMessage()):s.type.startsWith("intent-")?e.processEvent(s):"run-end"===s.type?(this._stt_binary_handler_id=void 0,i()):"error"===s.type&&(this._unloadAudio(),this._stt_binary_handler_id=void 0,"…"===t.text?(t.text=s.data.message,t.error=!0):e.setError(s.data.message),this._stopListening(),this.requestUpdate("_conversation"),i())},{start_stage:"stt",end_stage:null!==(s=this.pipeline)&&void 0!==s&&s.tts_engine?"tts":"intent",input:{sample_rate:this._audioRecorder.sampleRate},pipeline:null===(a=this.pipeline)||void 0===a?void 0:a.id,conversation_id:this._conversationId})}catch(i){await(0,c.showAlertDialog)(this,{title:"Error starting pipeline",text:i.message||i}),this._stopListening()}finally{this._processing=!1}}_stopListening(){var t;if(null===(t=this._audioRecorder)||void 0===t||t.stop(),this.requestUpdate("_audioRecorder"),this._stt_binary_handler_id){if(this._audioBuffer)for(const t of this._audioBuffer)this._sendAudioChunk(t);this._sendAudioChunk(new Int16Array),this._stt_binary_handler_id=void 0}this._audioBuffer=void 0}_sendAudioChunk(t){if(this.hass.connection.socket.binaryType="arraybuffer",null==this._stt_binary_handler_id)return;const e=new Uint8Array(1+2*t.length);e[0]=this._stt_binary_handler_id,e.set(new Uint8Array(t.buffer),1),this.hass.connection.socket.send(e)}async _processText(t){this._unloadAudio(),this._processing=!0,this._addMessage({who:"user",text:t,thinking:"",tool_calls:{}});const e=this._createAddHassMessageProcessor();e.addMessage();try{var s;const a=await(0,l.vU)(this.hass,t=>{t.type.startsWith("intent-")&&e.processEvent(t),"intent-end"===t.type&&a(),"error"===t.type&&(e.setError(t.data.message),a())},{start_stage:"intent",input:{text:t},end_stage:"intent",pipeline:null===(s=this.pipeline)||void 0===s?void 0:s.id,conversation_id:this._conversationId})}catch(a){e.setError(this.hass.localize("ui.dialogs.voice_command.error"))}finally{this._processing=!1}}_createAddHassMessageProcessor(){let t="";const e=()=>{var t;("…"!==s.hassMessage.text||s.hassMessage.thinking||s.hassMessage.tool_calls&&0!==Object.keys(s.hassMessage.tool_calls).length)&&(null!==(t=s.hassMessage.text)&&void 0!==t&&t.endsWith("…")&&(s.hassMessage.text=s.hassMessage.text.slice(0,-1)),s.hassMessage={who:"hass",text:"…",thinking:"",tool_calls:{},error:!1},this._addMessage(s.hassMessage))},s={continueConversation:!1,hassMessage:{who:"hass",text:"…",thinking:"",tool_calls:{},error:!1},addMessage:()=>{this._addMessage(s.hassMessage)},setError:t=>{e(),s.hassMessage.text=t,s.hassMessage.error=!0,this.requestUpdate("_conversation")},processEvent:e=>{if("intent-progress"===e.type&&e.data.chat_log_delta){const a=e.data.chat_log_delta;if(a.role&&(t=a.role),"assistant"===t){if(a.content&&(s.hassMessage.text.endsWith("…")?s.hassMessage.text=s.hassMessage.text.substring(0,s.hassMessage.text.length-1)+a.content+"…":s.hassMessage.text+=a.content+"…"),a.thinking_content&&(s.hassMessage.thinking+=a.thinking_content),a.tool_calls)for(const t of a.tool_calls)s.hassMessage.tool_calls[t.id]=t;this.requestUpdate("_conversation")}else"tool_result"===t&&s.hassMessage.tool_calls[a.tool_call_id]&&(s.hassMessage.tool_calls[a.tool_call_id].result=a.tool_result,this.requestUpdate("_conversation"))}else if("intent-end"===e.type){var a;this._conversationId=e.data.intent_output.conversation_id,s.continueConversation=e.data.intent_output.continue_conversation;const t=null===(a=e.data.intent_output.response.speech)||void 0===a?void 0:a.plain.speech;if(!t)return;"error"===e.data.intent_output.response.response_type?s.setError(t):(s.hassMessage.text=t,this.requestUpdate("_conversation"))}}};return s}static get styles(){return[h.dp,(0,i.AH)(z||(z=V`:host{flex:1;display:flex;flex-direction:column;min-height:0}ha-alert{margin-bottom:var(--ha-space-2)}#message-input::part(wa-base){padding-right:var(--ha-space-1)}.messages{flex:1 1 400px;display:block;box-sizing:border-box;overflow-y:auto;min-height:0;max-height:100%;display:flex;flex-direction:column;padding:0 var(--ha-space-3) var(--ha-space-4)}.input{padding:var(--ha-space-1) var(--ha-space-4) var(--ha-space-6)}.spacer{flex:1}.message-container{display:flex;flex-direction:column;margin:var(--ha-space-2) 0}.message-container.user{align-self:flex-end}.message-container.hass{align-self:flex-start}.message{font-size:var(--ha-font-size-l);clear:both;max-width:-webkit-fill-available;overflow-wrap:break-word;scroll-margin-top:var(--ha-space-6);margin:var(--ha-space-2) 0;padding:var(--ha-space-2);border-radius:var(--ha-border-radius-xl)}@media all and (max-width:450px),all and (max-height:500px){.message{font-size:var(--ha-font-size-l)}}.message.user{margin-left:var(--ha-space-6);margin-inline-start:var(--ha-space-6);margin-inline-end:initial;align-self:flex-end;border-bottom-right-radius:0px;--markdown-link-color:var(--text-primary-color);background-color:var(--chat-background-color-user,var(--primary-color));color:var(--text-primary-color);direction:var(--direction)}.message.hass{margin-right:var(--ha-space-6);margin-inline-end:var(--ha-space-6);margin-inline-start:initial;align-self:flex-start;border-bottom-left-radius:0px;background-color:var(--chat-background-color-hass,var(--secondary-background-color));color:var(--primary-text-color);direction:var(--direction)}.message.error{background-color:var(--error-color);color:var(--text-primary-color)}.thinking-wrapper{margin:calc(var(--ha-space-2) * -1) calc(var(--ha-space-2) * -1) 0 calc(var(--ha-space-2) * -1);overflow:hidden}.thinking-wrapper:last-child{margin-bottom:calc(var(--ha-space-2) * -1)}.thinking-header{display:flex;align-items:center;gap:var(--ha-space-2);width:100%;background:0 0;border:none;padding:var(--ha-space-2);cursor:pointer;text-align:left;color:var(--secondary-text-color);transition:color .2s}.thinking-header:focus,.thinking-header:hover{outline:0;color:var(--primary-text-color)}.thinking-label{font-size:var(--ha-font-size-m);display:flex;align-items:center;gap:var(--ha-space-2)}.thinking-header ha-svg-icon{--mdc-icon-size:16px}.thinking-content{max-height:0;overflow:hidden;transition:max-height .3s ease-in-out,padding .3s;padding:0 var(--ha-space-2);font-size:var(--ha-font-size-m);color:var(--secondary-text-color)}.thinking-wrapper.expanded .thinking-content{max-height:500px;padding:var(--ha-space-2);overflow-y:auto;display:flex;flex-direction:column;gap:var(--ha-space-2)}.tool-calls{display:flex;flex-direction:column;gap:var(--ha-space-1)}.tool-call{padding:var(--ha-space-1) var(--ha-space-2);border-left:2px solid var(--divider-color);margin-bottom:var(--ha-space-1)}.tool-name{font-weight:700;display:flex;align-items:center;gap:var(--ha-space-1)}.tool-data{font-family:var(--code-font-family, monospace);font-size:.9em;background:var(--markdown-code-background-color);padding:var(--ha-space-1);border-radius:var(--ha-border-radius-s);margin-top:var(--ha-space-1);overflow-x:auto}.tool-data pre{margin:0;white-space:pre-wrap;word-break:break-all}ha-markdown{--markdown-image-border-radius:calc(var(--ha-border-radius-xl) / 2);--markdown-table-border-color:var(--divider-color);--markdown-code-background-color:var(--primary-background-color);--markdown-code-text-color:var(--primary-text-color);--markdown-list-indent:1.15em}ha-markdown:not(:has(ha-markdown-element)){min-height:1lh;min-width:1lh;flex-shrink:0}.bouncer{width:48px;height:48px;position:absolute}.double-bounce1,.double-bounce2{width:48px;height:48px;border-radius:var(--ha-border-radius-circle);background-color:var(--primary-color);opacity:.2;position:absolute;top:0;left:0;-webkit-animation:sk-bounce 2s infinite ease-in-out;animation:sk-bounce 2s infinite ease-in-out}.double-bounce2{-webkit-animation-delay:-1s;animation-delay:-1s}@-webkit-keyframes sk-bounce{0%,100%{-webkit-transform:scale(0)}50%{-webkit-transform:scale(1)}}@keyframes sk-bounce{0%,100%{transform:scale(0);-webkit-transform:scale(0)}50%{transform:scale(1);-webkit-transform:scale(1)}}.unsupported{color:var(--error-color);position:absolute;--mdc-icon-size:16px;right:5px;inset-inline-end:5px;inset-inline-start:initial;top:0px}`))]}constructor(...t){super(...t),this.disableSpeech=!1,this._conversation=[],this._showSendButton=!1,this._processing=!1,this._conversationId=null,this._unloadAudio=()=>{this._audio&&(this._audio.pause(),this._audio.removeAttribute("src"),this._audio=void 0)}}}(0,a.Cg)([(0,o.MZ)({attribute:!1})],N.prototype,"hass",void 0),(0,a.Cg)([(0,o.MZ)({attribute:!1})],N.prototype,"pipeline",void 0),(0,a.Cg)([(0,o.MZ)({type:Boolean,attribute:"disable-speech"})],N.prototype,"disableSpeech",void 0),(0,a.Cg)([(0,o.MZ)({attribute:!1})],N.prototype,"startListening",void 0),(0,a.Cg)([(0,o.P)("#message-input")],N.prototype,"_messageInput",void 0),(0,a.Cg)([(0,o.P)(".message:last-child")],N.prototype,"_lastChatMessage",void 0),(0,a.Cg)([(0,o.P)(".message:last-child img:last-of-type")],N.prototype,"_lastChatMessageImage",void 0),(0,a.Cg)([(0,o.wk)()],N.prototype,"_conversation",void 0),(0,a.Cg)([(0,o.wk)()],N.prototype,"_showSendButton",void 0),(0,a.Cg)([(0,o.wk)()],N.prototype,"_processing",void 0),N=(0,a.Cg)([(0,o.EM)("ha-assist-chat")],N),e()}catch(m){e(m)}})},88433:function(t,e,s){if(s.d(e,{RW:function(){return n},ZE:function(){return i},e1:function(){return r},vc:function(){return o}}),66649!=s.j)var a=s(44537);var i=function(t){return t[t.CONTROL=1]="CONTROL",t}({});const o=(t,e,s)=>t.callWS({type:"conversation/agent/list",language:e,country:s}),n=(t,e,s,i)=>t.callWS({type:"conversation/agent/homeassistant/debug",sentences:(0,a.e)(e),language:s,device_id:i}),r=(t,e,s)=>t.callWS({type:"conversation/agent/homeassistant/language_scores",language:e,country:s})},74209:function(t,e,s){s.d(e,{N:function(){return a}});s(3362),s(62953),s(3296),s(27208),s(48408),s(14603),s(47566),s(98721);class a{get active(){return this._active}get sampleRate(){var t;return null===(t=this._context)||void 0===t?void 0:t.sampleRate}static get isSupported(){return window.isSecureContext&&(window.AudioContext||window.webkitAudioContext)}async start(){if(this._context&&this._stream&&this._source&&this._recorder)this._stream.getTracks()[0].enabled=!0,await this._context.resume(),this._active=!0;else try{await this._createContext()}catch(t){console.error(t),this._active=!1}}async stop(){var t;this._active=!1,this._stream&&(this._stream.getTracks()[0].enabled=!1),await(null===(t=this._context)||void 0===t?void 0:t.suspend())}close(){var t,e,s;this._active=!1,null===(t=this._stream)||void 0===t||t.getTracks()[0].stop(),this._recorder&&(this._recorder.port.onmessage=null),null===(e=this._source)||void 0===e||e.disconnect(),null===(s=this._context)||void 0===s||s.close(),this._stream=void 0,this._source=void 0,this._recorder=void 0,this._context=void 0}async _createContext(){const t=new(AudioContext||webkitAudioContext);this._stream=await navigator.mediaDevices.getUserMedia({audio:!0}),await t.audioWorklet.addModule(new URL(s.p+s.u(33921),s.b)),this._context=t,this._source=this._context.createMediaStreamSource(this._stream),this._recorder=new AudioWorkletNode(this._context,"recorder-worklet"),this._recorder.port.onmessage=t=>{this._active&&this._callback(t.data)},this._active=!0,this._source.connect(this._recorder)}constructor(t){this._active=!1,this._callback=t}}}}]);